Use drm_plane_helper_check_state to clip raw user coordinates to crtc bounds. This checks for full plane coverage and scaling already, so we can drop some custom checks. Use the clipped coordinates everywhere.
Suggested-by: Ville Syrjälä ville.syrjala@linux.intel.com Signed-off-by: Philipp Zabel p.zabel@pengutronix.de --- Changes since v3: - Disallow target frames that start offscreen (state->crtc_x/y < 0), to avoid confusing userspace: due to the necessary line start address alignment, we could only support very specific negative values for crtc_x/y, depending on the pixel format. --- drivers/gpu/drm/imx/ipuv3-plane.c | 80 +++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 40 deletions(-)
diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c index e74a0ad52950c..5cefa70bd8d17 100644 --- a/drivers/gpu/drm/imx/ipuv3-plane.c +++ b/drivers/gpu/drm/imx/ipuv3-plane.c @@ -70,8 +70,8 @@ drm_plane_state_to_eba(struct drm_plane_state *state) { struct drm_framebuffer *fb = state->fb; struct drm_gem_cma_object *cma_obj; - int x = state->src_x >> 16; - int y = state->src_y >> 16; + int x = state->src.x1 >> 16; + int y = state->src.y1 >> 16;
cma_obj = drm_fb_cma_get_gem_obj(fb, 0); BUG_ON(!cma_obj); @@ -86,8 +86,8 @@ drm_plane_state_to_ubo(struct drm_plane_state *state) struct drm_framebuffer *fb = state->fb; struct drm_gem_cma_object *cma_obj; unsigned long eba = drm_plane_state_to_eba(state); - int x = state->src_x >> 16; - int y = state->src_y >> 16; + int x = state->src.x1 >> 16; + int y = state->src.y1 >> 16;
cma_obj = drm_fb_cma_get_gem_obj(fb, 1); BUG_ON(!cma_obj); @@ -105,8 +105,8 @@ drm_plane_state_to_vbo(struct drm_plane_state *state) struct drm_framebuffer *fb = state->fb; struct drm_gem_cma_object *cma_obj; unsigned long eba = drm_plane_state_to_eba(state); - int x = state->src_x >> 16; - int y = state->src_y >> 16; + int x = state->src.x1 >> 16; + int y = state->src.y1 >> 16;
cma_obj = drm_fb_cma_get_gem_obj(fb, 2); BUG_ON(!cma_obj); @@ -218,7 +218,10 @@ static int ipu_plane_atomic_check(struct drm_plane *plane, struct drm_framebuffer *fb = state->fb; struct drm_framebuffer *old_fb = old_state->fb; unsigned long eba, ubo, vbo, old_ubo, old_vbo; + bool can_position = (plane->type == DRM_PLANE_TYPE_OVERLAY); + struct drm_rect clip; int hsub, vsub; + int ret;
/* Ok to disable */ if (!fb) @@ -232,44 +235,39 @@ static int ipu_plane_atomic_check(struct drm_plane *plane, if (WARN_ON(!crtc_state)) return -EINVAL;
+ clip.x1 = 0; + clip.y1 = 0; + clip.x2 = crtc_state->adjusted_mode.hdisplay; + clip.y2 = crtc_state->adjusted_mode.vdisplay; + ret = drm_plane_helper_check_state(state, &clip, + DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_HELPER_NO_SCALING, + can_position, true); + if (ret) + return ret; + /* CRTC should be enabled */ if (!crtc_state->enable) return -EINVAL;
- /* no scaling */ - if (state->src_w >> 16 != state->crtc_w || - state->src_h >> 16 != state->crtc_h) + /* Target frame must not start off-screen */ + if (state->crtc_x < 0 || state->crtc_y < 0) return -EINVAL;
switch (plane->type) { case DRM_PLANE_TYPE_PRIMARY: - /* full plane doesn't support partial off screen */ - if (state->crtc_x || state->crtc_y || - state->crtc_w != crtc_state->adjusted_mode.hdisplay || - state->crtc_h != crtc_state->adjusted_mode.vdisplay) - return -EINVAL; - /* full plane minimum width is 13 pixels */ - if (state->crtc_w < 13) + if (drm_rect_width(&state->dst) < 13) return -EINVAL; break; case DRM_PLANE_TYPE_OVERLAY: - if (state->crtc_x < 0 || state->crtc_y < 0) - return -EINVAL; - - if (state->crtc_x + state->crtc_w > - crtc_state->adjusted_mode.hdisplay) - return -EINVAL; - if (state->crtc_y + state->crtc_h > - crtc_state->adjusted_mode.vdisplay) - return -EINVAL; break; default: - dev_warn(dev, "Unsupported plane type\n"); + dev_warn(dev, "Unsupported plane type %d\n", plane->type); return -EINVAL; }
- if (state->crtc_h < 2) + if (drm_rect_height(&state->dst) < 2) return -EINVAL;
/* @@ -279,9 +277,10 @@ static int ipu_plane_atomic_check(struct drm_plane *plane, * callback. The planes will be reenabled in plane's ->atomic_update * callback. */ - if (old_fb && (state->src_w != old_state->src_w || - state->src_h != old_state->src_h || - fb->pixel_format != old_fb->pixel_format)) + if (old_fb && + (drm_rect_width(&state->dst) != drm_rect_width(&old_state->dst) || + drm_rect_height(&state->dst) != drm_rect_height(&old_state->dst) || + fb->pixel_format != old_fb->pixel_format)) crtc_state->mode_changed = true;
eba = drm_plane_state_to_eba(state); @@ -350,8 +349,8 @@ static int ipu_plane_atomic_check(struct drm_plane *plane, */ hsub = drm_format_horz_chroma_subsampling(fb->pixel_format); vsub = drm_format_vert_chroma_subsampling(fb->pixel_format); - if (((state->src_x >> 16) & (hsub - 1)) || - ((state->src_y >> 16) & (vsub - 1))) + if (((state->src.x1 >> 16) & (hsub - 1)) || + ((state->src.y1 >> 16) & (vsub - 1))) return -EINVAL; }
@@ -395,8 +394,8 @@ static void ipu_plane_atomic_update(struct drm_plane *plane, ics = ipu_drm_fourcc_to_colorspace(state->fb->pixel_format); ipu_dp_setup_channel(ipu_plane->dp, ics, IPUV3_COLORSPACE_UNKNOWN); - ipu_dp_set_window_pos(ipu_plane->dp, state->crtc_x, - state->crtc_y); + ipu_dp_set_window_pos(ipu_plane->dp, + state->dst.x1, state->dst.y1); /* Enable local alpha on partial plane */ switch (state->fb->pixel_format) { case DRM_FORMAT_ARGB1555: @@ -416,11 +415,12 @@ static void ipu_plane_atomic_update(struct drm_plane *plane, } }
- ipu_dmfc_config_wait4eot(ipu_plane->dmfc, state->crtc_w); + ipu_dmfc_config_wait4eot(ipu_plane->dmfc, drm_rect_width(&state->dst));
ipu_cpmem_zero(ipu_plane->ipu_ch); - ipu_cpmem_set_resolution(ipu_plane->ipu_ch, state->src_w >> 16, - state->src_h >> 16); + ipu_cpmem_set_resolution(ipu_plane->ipu_ch, + drm_rect_width(&state->src) >> 16, + drm_rect_height(&state->src) >> 16); ipu_cpmem_set_fmt(ipu_plane->ipu_ch, state->fb->pixel_format); ipu_cpmem_set_high_priority(ipu_plane->ipu_ch); ipu_idmac_set_double_buffer(ipu_plane->ipu_ch, 1); @@ -444,7 +444,7 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,
dev_dbg(ipu_plane->base.dev->dev, "phy = %lu %lu %lu, x = %d, y = %d", eba, ubo, vbo, - state->src_x >> 16, state->src_y >> 16); + state->src.x1 >> 16, state->src.y1 >> 16); break; case DRM_FORMAT_NV12: case DRM_FORMAT_NV16: @@ -455,11 +455,11 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,
dev_dbg(ipu_plane->base.dev->dev, "phy = %lu %lu, x = %d, y = %d", eba, ubo, - state->src_x >> 16, state->src_y >> 16); + state->src.x1 >> 16, state->src.y1 >> 16); break; default: dev_dbg(ipu_plane->base.dev->dev, "phys = %lu, x = %d, y = %d", - eba, state->src_x >> 16, state->src_y >> 16); + eba, state->src.x1 >> 16, state->src.y1 >> 16); break; } ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba);
On Fri, Feb 03, 2017 at 10:31:39AM +0100, Philipp Zabel wrote:
Use drm_plane_helper_check_state to clip raw user coordinates to crtc bounds. This checks for full plane coverage and scaling already, so we can drop some custom checks. Use the clipped coordinates everywhere.
Suggested-by: Ville Syrjälä ville.syrjala@linux.intel.com Signed-off-by: Philipp Zabel p.zabel@pengutronix.de
Changes since v3:
- Disallow target frames that start offscreen (state->crtc_x/y < 0), to avoid confusing userspace: due to the necessary line start address alignment, we could only support very specific negative values for crtc_x/y, depending on the pixel format.
That's really no different to the user specifying non-zero src coordinates. So I'm wondering what's the point of special casing crtc coordinates this way because you'll need to check the src coordinates anyway.
drivers/gpu/drm/imx/ipuv3-plane.c | 80 +++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 40 deletions(-)
diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c index e74a0ad52950c..5cefa70bd8d17 100644 --- a/drivers/gpu/drm/imx/ipuv3-plane.c +++ b/drivers/gpu/drm/imx/ipuv3-plane.c @@ -70,8 +70,8 @@ drm_plane_state_to_eba(struct drm_plane_state *state) { struct drm_framebuffer *fb = state->fb; struct drm_gem_cma_object *cma_obj;
- int x = state->src_x >> 16;
- int y = state->src_y >> 16;
int x = state->src.x1 >> 16;
int y = state->src.y1 >> 16;
cma_obj = drm_fb_cma_get_gem_obj(fb, 0); BUG_ON(!cma_obj);
@@ -86,8 +86,8 @@ drm_plane_state_to_ubo(struct drm_plane_state *state) struct drm_framebuffer *fb = state->fb; struct drm_gem_cma_object *cma_obj; unsigned long eba = drm_plane_state_to_eba(state);
- int x = state->src_x >> 16;
- int y = state->src_y >> 16;
int x = state->src.x1 >> 16;
int y = state->src.y1 >> 16;
cma_obj = drm_fb_cma_get_gem_obj(fb, 1); BUG_ON(!cma_obj);
@@ -105,8 +105,8 @@ drm_plane_state_to_vbo(struct drm_plane_state *state) struct drm_framebuffer *fb = state->fb; struct drm_gem_cma_object *cma_obj; unsigned long eba = drm_plane_state_to_eba(state);
- int x = state->src_x >> 16;
- int y = state->src_y >> 16;
int x = state->src.x1 >> 16;
int y = state->src.y1 >> 16;
cma_obj = drm_fb_cma_get_gem_obj(fb, 2); BUG_ON(!cma_obj);
@@ -218,7 +218,10 @@ static int ipu_plane_atomic_check(struct drm_plane *plane, struct drm_framebuffer *fb = state->fb; struct drm_framebuffer *old_fb = old_state->fb; unsigned long eba, ubo, vbo, old_ubo, old_vbo;
bool can_position = (plane->type == DRM_PLANE_TYPE_OVERLAY);
struct drm_rect clip; int hsub, vsub;
int ret;
/* Ok to disable */ if (!fb)
@@ -232,44 +235,39 @@ static int ipu_plane_atomic_check(struct drm_plane *plane, if (WARN_ON(!crtc_state)) return -EINVAL;
- clip.x1 = 0;
- clip.y1 = 0;
- clip.x2 = crtc_state->adjusted_mode.hdisplay;
- clip.y2 = crtc_state->adjusted_mode.vdisplay;
- ret = drm_plane_helper_check_state(state, &clip,
DRM_PLANE_HELPER_NO_SCALING,
DRM_PLANE_HELPER_NO_SCALING,
can_position, true);
- if (ret)
return ret;
- /* CRTC should be enabled */ if (!crtc_state->enable) return -EINVAL;
- /* no scaling */
- if (state->src_w >> 16 != state->crtc_w ||
state->src_h >> 16 != state->crtc_h)
/* Target frame must not start off-screen */
if (state->crtc_x < 0 || state->crtc_y < 0) return -EINVAL;
switch (plane->type) { case DRM_PLANE_TYPE_PRIMARY:
/* full plane doesn't support partial off screen */
if (state->crtc_x || state->crtc_y ||
state->crtc_w != crtc_state->adjusted_mode.hdisplay ||
state->crtc_h != crtc_state->adjusted_mode.vdisplay)
return -EINVAL;
- /* full plane minimum width is 13 pixels */
if (state->crtc_w < 13)
break; case DRM_PLANE_TYPE_OVERLAY:if (drm_rect_width(&state->dst) < 13) return -EINVAL;
if (state->crtc_x < 0 || state->crtc_y < 0)
return -EINVAL;
if (state->crtc_x + state->crtc_w >
crtc_state->adjusted_mode.hdisplay)
return -EINVAL;
if (state->crtc_y + state->crtc_h >
crtc_state->adjusted_mode.vdisplay)
break; default:return -EINVAL;
dev_warn(dev, "Unsupported plane type\n");
return -EINVAL; }dev_warn(dev, "Unsupported plane type %d\n", plane->type);
- if (state->crtc_h < 2)
if (drm_rect_height(&state->dst) < 2) return -EINVAL;
/*
@@ -279,9 +277,10 @@ static int ipu_plane_atomic_check(struct drm_plane *plane, * callback. The planes will be reenabled in plane's ->atomic_update * callback. */
- if (old_fb && (state->src_w != old_state->src_w ||
state->src_h != old_state->src_h ||
fb->pixel_format != old_fb->pixel_format))
if (old_fb &&
(drm_rect_width(&state->dst) != drm_rect_width(&old_state->dst) ||
drm_rect_height(&state->dst) != drm_rect_height(&old_state->dst) ||
fb->pixel_format != old_fb->pixel_format))
crtc_state->mode_changed = true;
eba = drm_plane_state_to_eba(state);
@@ -350,8 +349,8 @@ static int ipu_plane_atomic_check(struct drm_plane *plane, */ hsub = drm_format_horz_chroma_subsampling(fb->pixel_format); vsub = drm_format_vert_chroma_subsampling(fb->pixel_format);
if (((state->src_x >> 16) & (hsub - 1)) ||
((state->src_y >> 16) & (vsub - 1)))
if (((state->src.x1 >> 16) & (hsub - 1)) ||
}((state->src.y1 >> 16) & (vsub - 1))) return -EINVAL;
@@ -395,8 +394,8 @@ static void ipu_plane_atomic_update(struct drm_plane *plane, ics = ipu_drm_fourcc_to_colorspace(state->fb->pixel_format); ipu_dp_setup_channel(ipu_plane->dp, ics, IPUV3_COLORSPACE_UNKNOWN);
ipu_dp_set_window_pos(ipu_plane->dp, state->crtc_x,
state->crtc_y);
ipu_dp_set_window_pos(ipu_plane->dp,
/* Enable local alpha on partial plane */ switch (state->fb->pixel_format) { case DRM_FORMAT_ARGB1555:state->dst.x1, state->dst.y1);
@@ -416,11 +415,12 @@ static void ipu_plane_atomic_update(struct drm_plane *plane, } }
- ipu_dmfc_config_wait4eot(ipu_plane->dmfc, state->crtc_w);
ipu_dmfc_config_wait4eot(ipu_plane->dmfc, drm_rect_width(&state->dst));
ipu_cpmem_zero(ipu_plane->ipu_ch);
- ipu_cpmem_set_resolution(ipu_plane->ipu_ch, state->src_w >> 16,
state->src_h >> 16);
- ipu_cpmem_set_resolution(ipu_plane->ipu_ch,
drm_rect_width(&state->src) >> 16,
ipu_cpmem_set_fmt(ipu_plane->ipu_ch, state->fb->pixel_format); ipu_cpmem_set_high_priority(ipu_plane->ipu_ch); ipu_idmac_set_double_buffer(ipu_plane->ipu_ch, 1);drm_rect_height(&state->src) >> 16);
@@ -444,7 +444,7 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,
dev_dbg(ipu_plane->base.dev->dev, "phy = %lu %lu %lu, x = %d, y = %d", eba, ubo, vbo,
state->src_x >> 16, state->src_y >> 16);
break; case DRM_FORMAT_NV12: case DRM_FORMAT_NV16:state->src.x1 >> 16, state->src.y1 >> 16);
@@ -455,11 +455,11 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,
dev_dbg(ipu_plane->base.dev->dev, "phy = %lu %lu, x = %d, y = %d", eba, ubo,
state->src_x >> 16, state->src_y >> 16);
break; default: dev_dbg(ipu_plane->base.dev->dev, "phys = %lu, x = %d, y = %d",state->src.x1 >> 16, state->src.y1 >> 16);
eba, state->src_x >> 16, state->src_y >> 16);
break; } ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba);eba, state->src.x1 >> 16, state->src.y1 >> 16);
-- 2.11.0
On Fri, 2017-02-03 at 15:20 +0200, Ville Syrjälä wrote:
On Fri, Feb 03, 2017 at 10:31:39AM +0100, Philipp Zabel wrote:
Use drm_plane_helper_check_state to clip raw user coordinates to crtc bounds. This checks for full plane coverage and scaling already, so we can drop some custom checks. Use the clipped coordinates everywhere.
Suggested-by: Ville Syrjälä ville.syrjala@linux.intel.com Signed-off-by: Philipp Zabel p.zabel@pengutronix.de
Changes since v3:
- Disallow target frames that start offscreen (state->crtc_x/y < 0), to avoid confusing userspace: due to the necessary line start address alignment, we could only support very specific negative values for crtc_x/y, depending on the pixel format.
That's really no different to the user specifying non-zero src coordinates. So I'm wondering what's the point of special casing crtc coordinates this way because you'll need to check the src coordinates anyway.
User expectations.
For the src_x/y / src.x1/y1 source coordinates we have format specific alignment requirements due to limitations of the DMA unit, there is no way around it. For the crtc_x/y plane coordinates there are no alignment requirements at all, the partial plane can be positioned at any integer x/y position. If we allow to simulate a partially offscreen plane at negative positions by clipping and setting src.x1/y1, suddenly the crtc_x/y have alignment requirements, but only if the values are negative. I assume that would rather confuse any user space application that tries to reason about which crtc_x/y values are valid, so it's probably better to disallow it altogether.
regards Philipp
On Tue, Feb 07, 2017 at 09:51:50AM +0100, Philipp Zabel wrote:
On Fri, 2017-02-03 at 15:20 +0200, Ville Syrjälä wrote:
On Fri, Feb 03, 2017 at 10:31:39AM +0100, Philipp Zabel wrote:
Use drm_plane_helper_check_state to clip raw user coordinates to crtc bounds. This checks for full plane coverage and scaling already, so we can drop some custom checks. Use the clipped coordinates everywhere.
Suggested-by: Ville Syrjälä ville.syrjala@linux.intel.com Signed-off-by: Philipp Zabel p.zabel@pengutronix.de
Changes since v3:
- Disallow target frames that start offscreen (state->crtc_x/y < 0), to avoid confusing userspace: due to the necessary line start address alignment, we could only support very specific negative values for crtc_x/y, depending on the pixel format.
That's really no different to the user specifying non-zero src coordinates. So I'm wondering what's the point of special casing crtc coordinates this way because you'll need to check the src coordinates anyway.
User expectations.
For the src_x/y / src.x1/y1 source coordinates we have format specific alignment requirements due to limitations of the DMA unit, there is no way around it. For the crtc_x/y plane coordinates there are no alignment requirements at all, the partial plane can be positioned at any integer x/y position. If we allow to simulate a partially offscreen plane at negative positions by clipping and setting src.x1/y1, suddenly the crtc_x/y have alignment requirements, but only if the values are negative. I assume that would rather confuse any user space application that tries to reason about which crtc_x/y values are valid, so it's probably better to disallow it altogether.
I don't really agree. Userspace has to be prepared for anything to fail really. Whether it fails every time or sometimes is not that much different IMO. Given the simple return value userspace can't really draw any real conclusions about the reason for the failure.
A related question is how strict we should really be. In the past we've been very lax in fudging the coordinates to make something appear on the screen. Probably I went a bit too far in the laxness actually, and with atomic we want to tighten things up a little. Just no one has managed to really answer how tight we should make things. Is it OK to round things to pixel boundaries perhaps? Maybe even macropixel boundaries?
On Tue, 2017-02-07 at 13:19 +0200, Ville Syrjälä wrote:
On Tue, Feb 07, 2017 at 09:51:50AM +0100, Philipp Zabel wrote:
On Fri, 2017-02-03 at 15:20 +0200, Ville Syrjälä wrote:
On Fri, Feb 03, 2017 at 10:31:39AM +0100, Philipp Zabel wrote:
Use drm_plane_helper_check_state to clip raw user coordinates to crtc bounds. This checks for full plane coverage and scaling already, so we can drop some custom checks. Use the clipped coordinates everywhere.
Suggested-by: Ville Syrjälä ville.syrjala@linux.intel.com Signed-off-by: Philipp Zabel p.zabel@pengutronix.de
Changes since v3:
- Disallow target frames that start offscreen (state->crtc_x/y < 0), to avoid confusing userspace: due to the necessary line start address alignment, we could only support very specific negative values for crtc_x/y, depending on the pixel format.
That's really no different to the user specifying non-zero src coordinates. So I'm wondering what's the point of special casing crtc coordinates this way because you'll need to check the src coordinates anyway.
User expectations.
For the src_x/y / src.x1/y1 source coordinates we have format specific alignment requirements due to limitations of the DMA unit, there is no way around it. For the crtc_x/y plane coordinates there are no alignment requirements at all, the partial plane can be positioned at any integer x/y position. If we allow to simulate a partially offscreen plane at negative positions by clipping and setting src.x1/y1, suddenly the crtc_x/y have alignment requirements, but only if the values are negative. I assume that would rather confuse any user space application that tries to reason about which crtc_x/y values are valid, so it's probably better to disallow it altogether.
I don't really agree. Userspace has to be prepared for anything to fail really. Whether it fails every time or sometimes is not that much different IMO. Given the simple return value userspace can't really draw any real conclusions about the reason for the failure.
So you say we should allow negative crtc_x, even if the valid range with something on the screen ist [ - plane width ... crtc width ] with the [- plane width ... 0] range in steps of 2, 4, or 8 pixels depending on the pixel format and the [0 ... crtc width] range in steps of 1 pixels?
A related question is how strict we should really be. In the past we've been very lax in fudging the coordinates to make something appear on the screen. Probably I went a bit too far in the laxness actually, and with atomic we want to tighten things up a little. Just no one has managed to really answer how tight we should make things. Is it OK to round things to pixel boundaries perhaps?
In my opinion: yes.
Maybe even macropixel boundaries?
Maybe even memory burst size / line start address boundaries?
regards Philipp
dri-devel@lists.freedesktop.org