From a640908f70f216cbbb261b7bae02c2a5d54d220c Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Wed, 16 Apr 2025 18:33:54 +0100 Subject: [PATCH] drm/vc4: plane: Use nearest neighbour filter with YUV444 workaround As a follow-up to commit ef79eea9e4b8 ("drm/vc4: plane: Enable scaler for YUV444 on GEN6"), the image looks a little soft when rendering at 1:1 due to the scaling filter being enabled. Switch to using the nearest neighbour filter automatically when not scaling in YUV444 to compensate. Signed-off-by: Dave Stevenson --- drivers/gpu/drm/vc4/vc4_drv.h | 4 ++++ drivers/gpu/drm/vc4/vc4_plane.c | 19 +++++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index a9f3b0dba71d..13c88b7a241b 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -454,6 +454,10 @@ struct vc4_plane_state { enum vc4_scaling_mode x_scaling[2], y_scaling[2]; bool is_unity; bool is_yuv; + /* Allows use of nearest neighbour scaling filter when doing unity YUV444 + * workaround + */ + bool is_yuv444_unity; /* Our allocation in LBM for temporary storage during scaling. */ unsigned int lbm_handle; diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 0faca7015f91..0a813bf3dc90 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -302,6 +302,7 @@ struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane) refcount_inc(&hvs->lbm_refcounts[vc4_state->lbm_handle].refcount); vc4_state->dlist_initialized = 0; + vc4_state->is_yuv444_unity = false; __drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base); @@ -874,6 +875,10 @@ static void vc4_write_scaling_parameters(struct drm_plane_state *state, { struct vc4_dev *vc4 = to_vc4_dev(state->plane->dev); struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); + bool no_interpolate = state->scaling_filter == DRM_SCALING_FILTER_NEAREST_NEIGHBOR; + + if (vc4_state->is_yuv444_unity) + no_interpolate = 1; WARN_ON_ONCE(vc4->gen > VC4_GEN_6_D); @@ -882,7 +887,7 @@ static void vc4_write_scaling_parameters(struct drm_plane_state *state, vc4_write_ppf(vc4_state, vc4_state->src_w[channel], vc4_state->crtc_w, vc4_state->src_x, channel, state->chroma_siting_h, - state->scaling_filter == DRM_SCALING_FILTER_NEAREST_NEIGHBOR); + no_interpolate); } /* Ch0 V-PPF Words 0-1: Scaling Parameters, Context */ @@ -890,7 +895,7 @@ static void vc4_write_scaling_parameters(struct drm_plane_state *state, vc4_write_ppf(vc4_state, vc4_state->src_h[channel], vc4_state->crtc_h, vc4_state->src_y, channel, state->chroma_siting_v, - state->scaling_filter == DRM_SCALING_FILTER_NEAREST_NEIGHBOR); + no_interpolate); vc4_dlist_write(vc4_state, 0xc0c0c0c0); } @@ -1870,12 +1875,19 @@ static int vc6_plane_mode_set(struct drm_plane *plane, if (vc4_state->x_scaling[0] == VC4_SCALING_NONE) { vc4_state->x_scaling[0] = VC4_SCALING_PPF; vc4_state->is_unity = false; + vc4_state->is_yuv444_unity = true; } if (vc4_state->y_scaling[0] == VC4_SCALING_NONE) { vc4_state->y_scaling[0] = VC4_SCALING_PPF; vc4_state->is_unity = false; + } else { + /* Ensure that resizing vertically but not horizontally + * doesn't switch the scaling filter. + */ + vc4_state->is_yuv444_unity = false; } + } if (!vc4_state->src_w[0] || !vc4_state->src_h[0] || @@ -2202,6 +2214,9 @@ static int vc6_plane_mode_set(struct drm_plane *plane, filter = &vc4->hvs->nearest_neighbour_filter; break; } + if (vc4_state->is_yuv444_unity) + filter = &vc4->hvs->nearest_neighbour_filter; + u32 kernel = VC4_SET_FIELD(filter->start, SCALER_PPF_KERNEL_OFFSET);