Re: [PATCH] drm/imx/dcss: allow using nearest neighbor interpolation scaling
On Do, 2020-11-05 at 16:50 +0200, Laurentiu Palcu wrote: > This patch adds support for using NN interpolation scaling by setting the > SCALING_FILTER plane property to 1. Otherwise, the default method is used. > > Signed-off-by: Laurentiu Palcu Reviewed and pushed into drm-misc-next. Regards, Lucas > --- > I had no retro pixel art games to test this with, so I used modetest to see > the > results: > > To test, I used a 240x135 buffer, upscaled 8 times to 1920x1080: > * default scaling method using gaussian filter: > /usr/bin/modetest -M imx-dcss -w 33:SCALING_FILTER:0 -P 33@38:240x135*8@XR24 > * NN interpolation method: > /usr/bin/modetest -M imx-dcss -w 33:SCALING_FILTER:1 -P 33@38:240x135*8@XR24 > > Thanks, > laurentiu > > drivers/gpu/drm/imx/dcss/dcss-dev.h| 3 ++ > drivers/gpu/drm/imx/dcss/dcss-plane.c | 10 +- > drivers/gpu/drm/imx/dcss/dcss-scaler.c | 47 +- > 3 files changed, 50 insertions(+), 10 deletions(-) > > diff --git a/drivers/gpu/drm/imx/dcss/dcss-dev.h > b/drivers/gpu/drm/imx/dcss/dcss-dev.h > index c642ae17837f..1e582270c6ea 100644 > --- a/drivers/gpu/drm/imx/dcss/dcss-dev.h > +++ b/drivers/gpu/drm/imx/dcss/dcss-dev.h > @@ -7,6 +7,7 @@ > #define __DCSS_PRV_H__ > > #include > +#include > #include > #include > > @@ -165,6 +166,8 @@ void dcss_ss_sync_set(struct dcss_ss *ss, struct > videomode *vm, > /* SCALER */ > int dcss_scaler_init(struct dcss_dev *dcss, unsigned long scaler_base); > void dcss_scaler_exit(struct dcss_scaler *scl); > +void dcss_scaler_set_filter(struct dcss_scaler *scl, int ch_num, > + enum drm_scaling_filter scaling_filter); > void dcss_scaler_setup(struct dcss_scaler *scl, int ch_num, > const struct drm_format_info *format, > int src_xres, int src_yres, int dst_xres, int dst_yres, > diff --git a/drivers/gpu/drm/imx/dcss/dcss-plane.c > b/drivers/gpu/drm/imx/dcss/dcss-plane.c > index 5db093aada2f..03ba88f7f995 100644 > --- a/drivers/gpu/drm/imx/dcss/dcss-plane.c > +++ b/drivers/gpu/drm/imx/dcss/dcss-plane.c > @@ -257,7 +257,8 @@ static bool dcss_plane_needs_setup(struct drm_plane_state > *state, > state->src_h != old_state->src_h || > fb->format->format != old_fb->format->format || > fb->modifier != old_fb->modifier || > -state->rotation != old_state->rotation; > +state->rotation != old_state->rotation || > +state->scaling_filter != old_state->scaling_filter; > } > > static void dcss_plane_atomic_update(struct drm_plane *plane, > @@ -313,6 +314,9 @@ static void dcss_plane_atomic_update(struct drm_plane > *plane, > is_rotation_90_or_270 = state->rotation & (DRM_MODE_ROTATE_90 | > DRM_MODE_ROTATE_270); > > + dcss_scaler_set_filter(dcss->scaler, dcss_plane->ch_num, > +state->scaling_filter); > + > dcss_scaler_setup(dcss->scaler, dcss_plane->ch_num, > state->fb->format, > is_rotation_90_or_270 ? src_h : src_w, > @@ -394,6 +398,10 @@ struct dcss_plane *dcss_plane_init(struct drm_device > *drm, > if (ret) > return ERR_PTR(ret); > > + drm_plane_create_scaling_filter_property(&dcss_plane->base, > + BIT(DRM_SCALING_FILTER_DEFAULT) | > + > BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR)); > + > drm_plane_create_rotation_property(&dcss_plane->base, > DRM_MODE_ROTATE_0, > DRM_MODE_ROTATE_0 | > diff --git a/drivers/gpu/drm/imx/dcss/dcss-scaler.c > b/drivers/gpu/drm/imx/dcss/dcss-scaler.c > index cd21905de580..47852b9dd5ea 100644 > --- a/drivers/gpu/drm/imx/dcss/dcss-scaler.c > +++ b/drivers/gpu/drm/imx/dcss/dcss-scaler.c > @@ -77,6 +77,8 @@ struct dcss_scaler_ch { > > u32 c_vstart; > u32 c_hstart; > + > + bool use_nn_interpolation; > }; > > struct dcss_scaler { > @@ -243,6 +245,17 @@ static void dcss_scaler_gaussian_filter(int fc_q, bool > use_5_taps, > } > } > > +static void dcss_scaler_nearest_neighbor_filter(bool use_5_taps, > + int coef[][PSC_NUM_TAPS]) > +{ > + int i, j; > + > + for (i = 0; i < PSC_STORED_PHASES; i++) > + for (j = 0; j < PSC_NUM_TAPS; j++) > + coef[i][j] = j == PSC_NUM_TAPS >> 1 ? > + (1 << PSC_COEFF_PRECISION) : 0; > +} > + > /** > * dcss_scaler_filter_design() - Compute filter coefficients using > *Gaussian filter. > @@ -253,7 +266,8 @@ static void dcss_scaler_gaussian_filter(int fc_q, bool > use_5_taps, > */ > static void dcss_scaler_filter_design(int src_length, int dst_length, > bool use_5_taps, boo
[PATCH] drm/imx/dcss: allow using nearest neighbor interpolation scaling
This patch adds support for using NN interpolation scaling by setting the SCALING_FILTER plane property to 1. Otherwise, the default method is used. Signed-off-by: Laurentiu Palcu --- I had no retro pixel art games to test this with, so I used modetest to see the results: To test, I used a 240x135 buffer, upscaled 8 times to 1920x1080: * default scaling method using gaussian filter: /usr/bin/modetest -M imx-dcss -w 33:SCALING_FILTER:0 -P 33@38:240x135*8@XR24 * NN interpolation method: /usr/bin/modetest -M imx-dcss -w 33:SCALING_FILTER:1 -P 33@38:240x135*8@XR24 Thanks, laurentiu drivers/gpu/drm/imx/dcss/dcss-dev.h| 3 ++ drivers/gpu/drm/imx/dcss/dcss-plane.c | 10 +- drivers/gpu/drm/imx/dcss/dcss-scaler.c | 47 +- 3 files changed, 50 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/imx/dcss/dcss-dev.h b/drivers/gpu/drm/imx/dcss/dcss-dev.h index c642ae17837f..1e582270c6ea 100644 --- a/drivers/gpu/drm/imx/dcss/dcss-dev.h +++ b/drivers/gpu/drm/imx/dcss/dcss-dev.h @@ -7,6 +7,7 @@ #define __DCSS_PRV_H__ #include +#include #include #include @@ -165,6 +166,8 @@ void dcss_ss_sync_set(struct dcss_ss *ss, struct videomode *vm, /* SCALER */ int dcss_scaler_init(struct dcss_dev *dcss, unsigned long scaler_base); void dcss_scaler_exit(struct dcss_scaler *scl); +void dcss_scaler_set_filter(struct dcss_scaler *scl, int ch_num, + enum drm_scaling_filter scaling_filter); void dcss_scaler_setup(struct dcss_scaler *scl, int ch_num, const struct drm_format_info *format, int src_xres, int src_yres, int dst_xres, int dst_yres, diff --git a/drivers/gpu/drm/imx/dcss/dcss-plane.c b/drivers/gpu/drm/imx/dcss/dcss-plane.c index 5db093aada2f..03ba88f7f995 100644 --- a/drivers/gpu/drm/imx/dcss/dcss-plane.c +++ b/drivers/gpu/drm/imx/dcss/dcss-plane.c @@ -257,7 +257,8 @@ static bool dcss_plane_needs_setup(struct drm_plane_state *state, state->src_h != old_state->src_h || fb->format->format != old_fb->format->format || fb->modifier != old_fb->modifier || - state->rotation != old_state->rotation; + state->rotation != old_state->rotation || + state->scaling_filter != old_state->scaling_filter; } static void dcss_plane_atomic_update(struct drm_plane *plane, @@ -313,6 +314,9 @@ static void dcss_plane_atomic_update(struct drm_plane *plane, is_rotation_90_or_270 = state->rotation & (DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270); + dcss_scaler_set_filter(dcss->scaler, dcss_plane->ch_num, + state->scaling_filter); + dcss_scaler_setup(dcss->scaler, dcss_plane->ch_num, state->fb->format, is_rotation_90_or_270 ? src_h : src_w, @@ -394,6 +398,10 @@ struct dcss_plane *dcss_plane_init(struct drm_device *drm, if (ret) return ERR_PTR(ret); + drm_plane_create_scaling_filter_property(&dcss_plane->base, + BIT(DRM_SCALING_FILTER_DEFAULT) | + BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR)); + drm_plane_create_rotation_property(&dcss_plane->base, DRM_MODE_ROTATE_0, DRM_MODE_ROTATE_0 | diff --git a/drivers/gpu/drm/imx/dcss/dcss-scaler.c b/drivers/gpu/drm/imx/dcss/dcss-scaler.c index cd21905de580..47852b9dd5ea 100644 --- a/drivers/gpu/drm/imx/dcss/dcss-scaler.c +++ b/drivers/gpu/drm/imx/dcss/dcss-scaler.c @@ -77,6 +77,8 @@ struct dcss_scaler_ch { u32 c_vstart; u32 c_hstart; + + bool use_nn_interpolation; }; struct dcss_scaler { @@ -243,6 +245,17 @@ static void dcss_scaler_gaussian_filter(int fc_q, bool use_5_taps, } } +static void dcss_scaler_nearest_neighbor_filter(bool use_5_taps, + int coef[][PSC_NUM_TAPS]) +{ + int i, j; + + for (i = 0; i < PSC_STORED_PHASES; i++) + for (j = 0; j < PSC_NUM_TAPS; j++) + coef[i][j] = j == PSC_NUM_TAPS >> 1 ? + (1 << PSC_COEFF_PRECISION) : 0; +} + /** * dcss_scaler_filter_design() - Compute filter coefficients using * Gaussian filter. @@ -253,7 +266,8 @@ static void dcss_scaler_gaussian_filter(int fc_q, bool use_5_taps, */ static void dcss_scaler_filter_design(int src_length, int dst_length, bool use_5_taps, bool phase0_identity, - int coef[][PSC_NUM_TAPS]) + int coef[][PSC_NUM_TAPS], + bool nn_interpolation) { int fc_q; @@ -263,8 +277,11 @@ static void dcss_scaler_filter_design(int