[Intel-gfx] [PATCH v2 11/12] drm/i915: Deal with NV12 CbCr plane AUX surface on SKL+
Daniel Vetter
daniel at ffwll.ch
Wed Aug 10 10:03:08 UTC 2016
On Wed, Aug 10, 2016 at 12:23:20PM +0300, ville.syrjala at linux.intel.com wrote:
> From: Ville Syrjälä <ville.syrjala at linux.intel.com>
>
> With NV12 we have two color planes to deal with so we must compute the
> surface and x/y offsets for the second plane as well.
>
> What makes this a bit nasty is that the hardware expects the surface
> offset to be specified as a distance from the main surface offset.
> What's worse, the distance must be non-negative (no neat wraparound or
> anything). So we must make sure that the main surface offset is always
> less or equal to the AUX surface offset. We do that by computing the AUX
> offset first and the main surface offset second. If the main surface
> offset ends up being above the AUX offset, we just push it down as far
> as is required while still maintaining the required alignment etc.
>
> Fortunately the AUX offset only reuqires 4K alignment, so we don't need
> to do any of the backwards searching for an acceptable offset that we
> must do for the main surface. And X tiled + NV12 isn't a supported
> combination anyway.
>
> Note that this just computes aux surface offsets, we do not yet program
> them into the actual hardware registers, and hence we can't yet expose
> NV12.
>
> v2: Rebase due to drm_plane_state src/dst rects
> s/TODO.../something else/ in the commit message/ (Daniel)
>
> Signed-off-by: Ville Syrjälä <ville.syrjala at linux.intel.com>
> ---
> drivers/gpu/drm/i915/intel_display.c | 62 ++++++++++++++++++++++++++++++++++--
> drivers/gpu/drm/i915/intel_drv.h | 4 +++
> 2 files changed, 64 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index b719c07599fd..f8487bcdb271 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -2463,8 +2463,14 @@ u32 intel_compute_tile_offset(int *x, int *y,
> const struct drm_i915_private *dev_priv = to_i915(state->base.plane->dev);
> const struct drm_framebuffer *fb = state->base.fb;
> unsigned int rotation = state->base.rotation;
> - u32 alignment = intel_surf_alignment(dev_priv, fb->modifier[plane]);
> int pitch = intel_fb_pitch(fb, plane, rotation);
> + u32 alignment;
> +
> + /* AUX_DIST needs only 4K alignment */
> + if (fb->pixel_format == DRM_FORMAT_NV12 && plane == 1)
> + alignment = 4096;
> + else
> + alignment = intel_surf_alignment(dev_priv, fb->modifier[plane]);
>
> return _intel_compute_tile_offset(dev_priv, x, y, fb, plane, pitch,
> rotation, alignment);
> @@ -2895,7 +2901,7 @@ static int skl_check_main_surface(struct intel_plane_state *plane_state)
> int h = drm_rect_height(&plane_state->base.src) >> 16;
> int max_width = skl_max_plane_width(fb, 0, rotation);
> int max_height = 4096;
> - u32 alignment, offset;
> + u32 alignment, offset, aux_offset = plane_state->aux.offset;
>
> if (w > max_width || h > max_height) {
> DRM_DEBUG_KMS("requested Y/RGB source size %dx%d too big (limit %dx%d)\n",
> @@ -2909,6 +2915,15 @@ static int skl_check_main_surface(struct intel_plane_state *plane_state)
> alignment = intel_surf_alignment(dev_priv, fb->modifier[0]);
>
> /*
> + * AUX surface offset is specified as the distance from the
> + * main surface offset, and it must be non-negative. Make
> + * sure that is what we will get.
> + */
> + if (offset > aux_offset)
> + offset = intel_adjust_tile_offset(&x, &y, plane_state, 0,
> + offset, aux_offset & ~(alignment - 1));
Note to self: Need to make sure that multiplanar fbs all reference the
same underlying bo. But that code isn't yet added to
intel_framebuffer_init().
> +
> + /*
> * When using an X-tiled surface, the plane blows up
> * if the x offset + width exceed the stride.
> *
> @@ -2935,6 +2950,35 @@ static int skl_check_main_surface(struct intel_plane_state *plane_state)
> return 0;
> }
>
> +static int skl_check_nv12_aux_surface(struct intel_plane_state *plane_state)
> +{
> + const struct drm_framebuffer *fb = plane_state->base.fb;
> + unsigned int rotation = plane_state->base.rotation;
> + int max_width = skl_max_plane_width(fb, 1, rotation);
> + int max_height = 4096;
> + int x = plane_state->base.src.x1 >> 17;
> + int y = plane_state->base.src.y1 >> 17;
> + int w = drm_rect_width(&plane_state->base.src) >> 17;
> + int h = drm_rect_height(&plane_state->base.src) >> 17;
> + u32 offset;
> +
> + intel_add_fb_offsets(&x, &y, plane_state, 1);
> + offset = intel_compute_tile_offset(&x, &y, plane_state, 1);
> +
> + /* FIXME not quite sure how/if these apply to the chroma plane */
> + if (w > max_width || h > max_height) {
> + DRM_DEBUG_KMS("CbCr source size %dx%d too big (limit %dx%d)\n",
> + w, h, max_width, max_height);
> + return -EINVAL;
> + }
We also need to check pitch of the 2nd plane, but I guess that's done at
fb_init time, not at atomic_check time. Looks all reasonable as-is.
Reviewed-by: Daniel Vetter <daniel.vetter at ffwll.ch>
> +
> + plane_state->aux.offset = offset;
> + plane_state->aux.x = x;
> + plane_state->aux.y = y;
> +
> + return 0;
> +}
> +
> int skl_check_plane_surface(struct intel_plane_state *plane_state)
> {
> const struct drm_framebuffer *fb = plane_state->base.fb;
> @@ -2946,6 +2990,20 @@ int skl_check_plane_surface(struct intel_plane_state *plane_state)
> drm_rect_rotate(&plane_state->base.src,
> fb->width, fb->height, BIT(DRM_ROTATE_270));
>
> + /*
> + * Handle the AUX surface first since
> + * the main surface setup depends on it.
> + */
> + if (fb->pixel_format == DRM_FORMAT_NV12) {
> + ret = skl_check_nv12_aux_surface(plane_state);
> + if (ret)
> + return ret;
> + } else {
> + plane_state->aux.offset = ~0xfff;
> + plane_state->aux.x = 0;
> + plane_state->aux.y = 0;
> + }
> +
> ret = skl_check_main_surface(plane_state);
> if (ret)
> return ret;
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 2fde13833fcb..df8e7514c08c 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -354,6 +354,10 @@ struct intel_plane_state {
> u32 offset;
> int x, y;
> } main;
> + struct {
> + u32 offset;
> + int x, y;
> + } aux;
>
> /*
> * scaler_id
> --
> 2.7.4
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
More information about the Intel-gfx
mailing list