drm/vc4: plane: Use nearest neighbour filter with YUV444 workaround

As a follow-up to commit ef79eea9e4 ("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 <dave.stevenson@raspberrypi.com>
This commit is contained in:
Dave Stevenson
2025-04-16 18:33:54 +01:00
committed by Dom Cobley
parent 098a83defc
commit e2b8ca9893
2 changed files with 21 additions and 2 deletions

View File

@@ -454,6 +454,10 @@ struct vc4_plane_state {
enum vc4_scaling_mode x_scaling[2], y_scaling[2]; enum vc4_scaling_mode x_scaling[2], y_scaling[2];
bool is_unity; bool is_unity;
bool is_yuv; 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. */ /* Our allocation in LBM for temporary storage during scaling. */
unsigned int lbm_handle; unsigned int lbm_handle;

View File

@@ -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); refcount_inc(&hvs->lbm_refcounts[vc4_state->lbm_handle].refcount);
vc4_state->dlist_initialized = 0; vc4_state->dlist_initialized = 0;
vc4_state->is_yuv444_unity = false;
__drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base); __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_dev *vc4 = to_vc4_dev(state->plane->dev);
struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); 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); 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_write_ppf(vc4_state, vc4_state->src_w[channel],
vc4_state->crtc_w, vc4_state->src_x, channel, vc4_state->crtc_w, vc4_state->src_x, channel,
state->chroma_siting_h, state->chroma_siting_h,
state->scaling_filter == DRM_SCALING_FILTER_NEAREST_NEIGHBOR); no_interpolate);
} }
/* Ch0 V-PPF Words 0-1: Scaling Parameters, Context */ /* 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_write_ppf(vc4_state, vc4_state->src_h[channel],
vc4_state->crtc_h, vc4_state->src_y, channel, vc4_state->crtc_h, vc4_state->src_y, channel,
state->chroma_siting_v, state->chroma_siting_v,
state->scaling_filter == DRM_SCALING_FILTER_NEAREST_NEIGHBOR); no_interpolate);
vc4_dlist_write(vc4_state, 0xc0c0c0c0); 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) { if (vc4_state->x_scaling[0] == VC4_SCALING_NONE) {
vc4_state->x_scaling[0] = VC4_SCALING_PPF; vc4_state->x_scaling[0] = VC4_SCALING_PPF;
vc4_state->is_unity = false; vc4_state->is_unity = false;
vc4_state->is_yuv444_unity = true;
} }
if (vc4_state->y_scaling[0] == VC4_SCALING_NONE) { if (vc4_state->y_scaling[0] == VC4_SCALING_NONE) {
vc4_state->y_scaling[0] = VC4_SCALING_PPF; vc4_state->y_scaling[0] = VC4_SCALING_PPF;
vc4_state->is_unity = false; 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] || 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; filter = &vc4->hvs->nearest_neighbour_filter;
break; break;
} }
if (vc4_state->is_yuv444_unity)
filter = &vc4->hvs->nearest_neighbour_filter;
u32 kernel = VC4_SET_FIELD(filter->start, u32 kernel = VC4_SET_FIELD(filter->start,
SCALER_PPF_KERNEL_OFFSET); SCALER_PPF_KERNEL_OFFSET);