Re: [PATCH] drm/imx/dcss: allow using nearest neighbor interpolation scaling

2020-11-26 Thread Lucas Stach
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

2020-11-05 Thread Laurentiu Palcu
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