[Intel-gfx] [PATCH] drm/i915 : clip yuv primary planes to hw constraints
Ville Syrjälä
ville.syrjala at linux.intel.com
Wed May 30 16:58:34 UTC 2018
On Fri, May 25, 2018 at 12:27:40PM -0700, Fritz Koenig wrote:
> YUV planes need to be multiples of 2 to scan out. This was
> handled correctly for planes other than the primary in the
> intel_check_sprite_plane, where the code fixes up the plane
> and makes it compliant. Move this code into a location that
> allows the primary check to access it as well.
intel_check_sprite_plane() is not something we should be spreading.
It's doing way too many platform specific things. I think where I
want to go instead is per-platform plane .check() functions instead.
To that end I think you should just add the relevant checks to eg.
skl_check_plane_surface() for now.
We especially don't want to be moving large chunks of code from
intel_sprite.c to intel_display.c. I'm actually trying to do the
exact opposite and move all the plane code into intel_sprite.c
(or maybe even introduce a new file for the skl+ plane code
entirely).
> Signed-off-by: Fritz Koenig <frkoenig at google.com>
> ---
> drivers/gpu/drm/i915/intel_display.c | 170 +++++++++++++++++++++++++++
> drivers/gpu/drm/i915/intel_drv.h | 2 +
> drivers/gpu/drm/i915/intel_sprite.c | 154 +-----------------------
> 3 files changed, 175 insertions(+), 151 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 5f03af455047..e1eb0fb988a6 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -12856,6 +12856,170 @@ skl_max_scale(struct intel_crtc *intel_crtc, struct intel_crtc_state *crtc_state
> return max_scale;
> }
>
> +int
> +intel_clip_src_rect(struct intel_plane *plane,
> + struct intel_crtc_state *crtc_state,
> + struct intel_plane_state *state)
> +{
> + struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
> + struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
> + struct drm_framebuffer *fb = state->base.fb;
> + int crtc_x, crtc_y;
> + unsigned int crtc_w, crtc_h;
> + uint32_t src_x, src_y, src_w, src_h;
> + struct drm_rect *src = &state->base.src;
> + struct drm_rect *dst = &state->base.dst;
> + struct drm_rect clip = {};
> + int hscale, vscale;
> + int max_scale, min_scale;
> + bool can_scale;
> +
> + *src = drm_plane_state_src(&state->base);
> + *dst = drm_plane_state_dest(&state->base);
> +
> + /* setup can_scale, min_scale, max_scale */
> + if (INTEL_GEN(dev_priv) >= 9) {
> + /* use scaler when colorkey is not required */
> + if (!state->ckey.flags) {
> + can_scale = 1;
> + min_scale = 1;
> + max_scale = skl_max_scale(crtc, crtc_state);
> + } else {
> + can_scale = 0;
> + min_scale = DRM_PLANE_HELPER_NO_SCALING;
> + max_scale = DRM_PLANE_HELPER_NO_SCALING;
> + }
> + } else {
> + can_scale = plane->can_scale;
> + max_scale = plane->max_downscale << 16;
> + min_scale = plane->can_scale ? 1 : (1 << 16);
> + }
> +
> + /*
> + * FIXME the following code does a bunch of fuzzy adjustments to the
> + * coordinates and sizes. We probably need some way to decide whether
> + * more strict checking should be done instead.
> + */
> + drm_rect_rotate(src, fb->width << 16, fb->height << 16,
> + state->base.rotation);
> +
> + hscale = drm_rect_calc_hscale_relaxed(src, dst, min_scale, max_scale);
> + BUG_ON(hscale < 0);
> +
> + vscale = drm_rect_calc_vscale_relaxed(src, dst, min_scale, max_scale);
> + BUG_ON(vscale < 0);
> +
> + if (crtc_state->base.enable)
> + drm_mode_get_hv_timing(&crtc_state->base.mode,
> + &clip.x2, &clip.y2);
> +
> + state->base.visible = drm_rect_clip_scaled(src, dst, &clip, hscale, vscale);
> +
> + crtc_x = dst->x1;
> + crtc_y = dst->y1;
> + crtc_w = drm_rect_width(dst);
> + crtc_h = drm_rect_height(dst);
> +
> + if (state->base.visible) {
> + /* check again in case clipping clamped the results */
> + hscale = drm_rect_calc_hscale(src, dst, min_scale, max_scale);
> + if (hscale < 0) {
> + DRM_DEBUG_KMS("Horizontal scaling factor out of limits\n");
> + drm_rect_debug_print("src: ", src, true);
> + drm_rect_debug_print("dst: ", dst, false);
> +
> + return hscale;
> + }
> +
> + vscale = drm_rect_calc_vscale(src, dst, min_scale, max_scale);
> + if (vscale < 0) {
> + DRM_DEBUG_KMS("Vertical scaling factor out of limits\n");
> + drm_rect_debug_print("src: ", src, true);
> + drm_rect_debug_print("dst: ", dst, false);
> +
> + return vscale;
> + }
> +
> + /* Make the source viewport size an exact multiple of the scaling factors. */
> + drm_rect_adjust_size(src,
> + drm_rect_width(dst) * hscale - drm_rect_width(src),
> + drm_rect_height(dst) * vscale - drm_rect_height(src));
> +
> + drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16,
> + state->base.rotation);
> +
> + /* sanity check to make sure the src viewport wasn't enlarged */
> + WARN_ON(src->x1 < (int) state->base.src_x ||
> + src->y1 < (int) state->base.src_y ||
> + src->x2 > (int) state->base.src_x + state->base.src_w ||
> + src->y2 > (int) state->base.src_y + state->base.src_h);
> +
> + /*
> + * Hardware doesn't handle subpixel coordinates.
> + * Adjust to (macro)pixel boundary, but be careful not to
> + * increase the source viewport size, because that could
> + * push the downscaling factor out of bounds.
> + */
> + src_x = src->x1 >> 16;
> + src_w = drm_rect_width(src) >> 16;
> + src_y = src->y1 >> 16;
> + src_h = drm_rect_height(src) >> 16;
> +
> + if (intel_format_is_yuv(fb->format->format)) {
> + src_x &= ~1;
> + src_w &= ~1;
> +
> + /*
> + * Must keep src and dst the
> + * same if we can't scale.
> + */
> + if (!can_scale)
> + crtc_w &= ~1;
> +
> + if (crtc_w == 0)
> + state->base.visible = false;
> + }
> + }
> +
> + /* Check size restrictions when scaling */
> + if (state->base.visible && (src_w != crtc_w || src_h != crtc_h)) {
> + unsigned int width_bytes;
> + int cpp = fb->format->cpp[0];
> +
> + WARN_ON(!can_scale);
> +
> + /* FIXME interlacing min height is 6 */
> +
> + if (crtc_w < 3 || crtc_h < 3)
> + state->base.visible = false;
> +
> + if (src_w < 3 || src_h < 3)
> + state->base.visible = false;
> +
> + width_bytes = ((src_x * cpp) & 63) + src_w * cpp;
> +
> + if (INTEL_GEN(dev_priv) < 9 && (src_w > 2048 || src_h > 2048 ||
> + width_bytes > 4096 || fb->pitches[0] > 4096)) {
> + DRM_DEBUG_KMS("Source dimensions exceed hardware limits\n");
> + return -EINVAL;
> + }
> + }
> +
> + if (state->base.visible) {
> + src->x1 = src_x << 16;
> + src->x2 = (src_x + src_w) << 16;
> + src->y1 = src_y << 16;
> + src->y2 = (src_y + src_h) << 16;
> + }
> +
> + dst->x1 = crtc_x;
> + dst->x2 = crtc_x + crtc_w;
> + dst->y1 = crtc_y;
> + dst->y2 = crtc_y + crtc_h;
> +
> + return 0;
> +}
> +
> static int
> intel_check_primary_plane(struct intel_plane *plane,
> struct intel_crtc_state *crtc_state,
> @@ -12887,6 +13051,12 @@ intel_check_primary_plane(struct intel_plane *plane,
> if (!state->base.fb)
> return 0;
>
> + if (intel_format_is_yuv(state->base.fb->format->format)) {
> + ret = intel_clip_src_rect(plane, crtc_state, state);
> + if (ret)
> + return ret;
> + }
> +
> if (INTEL_GEN(dev_priv) >= 9) {
> ret = skl_check_plane_surface(crtc_state, state);
> if (ret)
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index a80fbad9be0f..43847927a927 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1591,6 +1591,8 @@ void intel_mode_from_pipe_config(struct drm_display_mode *mode,
>
> int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state);
> int skl_max_scale(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state);
> +int intel_clip_src_rect(struct intel_plane *plane,
> + struct intel_crtc_state *crtc_state, struct intel_plane_state *state);
>
> static inline u32 intel_plane_ggtt_offset(const struct intel_plane_state *state)
> {
> diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
> index dbdcf85032df..892d3247ed69 100644
> --- a/drivers/gpu/drm/i915/intel_sprite.c
> +++ b/drivers/gpu/drm/i915/intel_sprite.c
> @@ -935,21 +935,9 @@ intel_check_sprite_plane(struct intel_plane *plane,
> struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
> struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
> struct drm_framebuffer *fb = state->base.fb;
> - int crtc_x, crtc_y;
> - unsigned int crtc_w, crtc_h;
> - uint32_t src_x, src_y, src_w, src_h;
> - struct drm_rect *src = &state->base.src;
> - struct drm_rect *dst = &state->base.dst;
> - struct drm_rect clip = {};
> int max_stride = INTEL_GEN(dev_priv) >= 9 ? 32768 : 16384;
> - int hscale, vscale;
> - int max_scale, min_scale;
> - bool can_scale;
> int ret;
>
> - *src = drm_plane_state_src(&state->base);
> - *dst = drm_plane_state_dest(&state->base);
> -
> if (!fb) {
> state->base.visible = false;
> return 0;
> @@ -967,145 +955,9 @@ intel_check_sprite_plane(struct intel_plane *plane,
> return -EINVAL;
> }
>
> - /* setup can_scale, min_scale, max_scale */
> - if (INTEL_GEN(dev_priv) >= 9) {
> - /* use scaler when colorkey is not required */
> - if (!state->ckey.flags) {
> - can_scale = 1;
> - min_scale = 1;
> - max_scale = skl_max_scale(crtc, crtc_state);
> - } else {
> - can_scale = 0;
> - min_scale = DRM_PLANE_HELPER_NO_SCALING;
> - max_scale = DRM_PLANE_HELPER_NO_SCALING;
> - }
> - } else {
> - can_scale = plane->can_scale;
> - max_scale = plane->max_downscale << 16;
> - min_scale = plane->can_scale ? 1 : (1 << 16);
> - }
> -
> - /*
> - * FIXME the following code does a bunch of fuzzy adjustments to the
> - * coordinates and sizes. We probably need some way to decide whether
> - * more strict checking should be done instead.
> - */
> - drm_rect_rotate(src, fb->width << 16, fb->height << 16,
> - state->base.rotation);
> -
> - hscale = drm_rect_calc_hscale_relaxed(src, dst, min_scale, max_scale);
> - BUG_ON(hscale < 0);
> -
> - vscale = drm_rect_calc_vscale_relaxed(src, dst, min_scale, max_scale);
> - BUG_ON(vscale < 0);
> -
> - if (crtc_state->base.enable)
> - drm_mode_get_hv_timing(&crtc_state->base.mode,
> - &clip.x2, &clip.y2);
> -
> - state->base.visible = drm_rect_clip_scaled(src, dst, &clip, hscale, vscale);
> -
> - crtc_x = dst->x1;
> - crtc_y = dst->y1;
> - crtc_w = drm_rect_width(dst);
> - crtc_h = drm_rect_height(dst);
> -
> - if (state->base.visible) {
> - /* check again in case clipping clamped the results */
> - hscale = drm_rect_calc_hscale(src, dst, min_scale, max_scale);
> - if (hscale < 0) {
> - DRM_DEBUG_KMS("Horizontal scaling factor out of limits\n");
> - drm_rect_debug_print("src: ", src, true);
> - drm_rect_debug_print("dst: ", dst, false);
> -
> - return hscale;
> - }
> -
> - vscale = drm_rect_calc_vscale(src, dst, min_scale, max_scale);
> - if (vscale < 0) {
> - DRM_DEBUG_KMS("Vertical scaling factor out of limits\n");
> - drm_rect_debug_print("src: ", src, true);
> - drm_rect_debug_print("dst: ", dst, false);
> -
> - return vscale;
> - }
> -
> - /* Make the source viewport size an exact multiple of the scaling factors. */
> - drm_rect_adjust_size(src,
> - drm_rect_width(dst) * hscale - drm_rect_width(src),
> - drm_rect_height(dst) * vscale - drm_rect_height(src));
> -
> - drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16,
> - state->base.rotation);
> -
> - /* sanity check to make sure the src viewport wasn't enlarged */
> - WARN_ON(src->x1 < (int) state->base.src_x ||
> - src->y1 < (int) state->base.src_y ||
> - src->x2 > (int) state->base.src_x + state->base.src_w ||
> - src->y2 > (int) state->base.src_y + state->base.src_h);
> -
> - /*
> - * Hardware doesn't handle subpixel coordinates.
> - * Adjust to (macro)pixel boundary, but be careful not to
> - * increase the source viewport size, because that could
> - * push the downscaling factor out of bounds.
> - */
> - src_x = src->x1 >> 16;
> - src_w = drm_rect_width(src) >> 16;
> - src_y = src->y1 >> 16;
> - src_h = drm_rect_height(src) >> 16;
> -
> - if (intel_format_is_yuv(fb->format->format)) {
> - src_x &= ~1;
> - src_w &= ~1;
> -
> - /*
> - * Must keep src and dst the
> - * same if we can't scale.
> - */
> - if (!can_scale)
> - crtc_w &= ~1;
> -
> - if (crtc_w == 0)
> - state->base.visible = false;
> - }
> - }
> -
> - /* Check size restrictions when scaling */
> - if (state->base.visible && (src_w != crtc_w || src_h != crtc_h)) {
> - unsigned int width_bytes;
> - int cpp = fb->format->cpp[0];
> -
> - WARN_ON(!can_scale);
> -
> - /* FIXME interlacing min height is 6 */
> -
> - if (crtc_w < 3 || crtc_h < 3)
> - state->base.visible = false;
> -
> - if (src_w < 3 || src_h < 3)
> - state->base.visible = false;
> -
> - width_bytes = ((src_x * cpp) & 63) + src_w * cpp;
> -
> - if (INTEL_GEN(dev_priv) < 9 && (src_w > 2048 || src_h > 2048 ||
> - width_bytes > 4096 || fb->pitches[0] > 4096)) {
> - DRM_DEBUG_KMS("Source dimensions exceed hardware limits\n");
> - return -EINVAL;
> - }
> - }
> -
> - if (state->base.visible) {
> - src->x1 = src_x << 16;
> - src->x2 = (src_x + src_w) << 16;
> - src->y1 = src_y << 16;
> - src->y2 = (src_y + src_h) << 16;
> - }
> -
> - dst->x1 = crtc_x;
> - dst->x2 = crtc_x + crtc_w;
> - dst->y1 = crtc_y;
> - dst->y2 = crtc_y + crtc_h;
> + ret = intel_clip_src_rect(plane, crtc_state, state);
> + if (ret)
> + return ret;
>
> if (INTEL_GEN(dev_priv) >= 9) {
> ret = skl_check_plane_surface(crtc_state, state);
> --
> 2.17.0.921.gf22659ad46-goog
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
--
Ville Syrjälä
Intel
More information about the Intel-gfx
mailing list