modetest: add support for DRM_FORMAT_NV{15,20,30}
authorJonas Karlman <jonas@kwiboo.se>
Wed, 25 Oct 2023 16:15:31 +0000 (16:15 +0000)
committerJonas Karlman <jonas@kwiboo.se>
Mon, 30 Oct 2023 12:25:09 +0000 (12:25 +0000)
Add smpte and tiles pattern for 10-bit NV15, NV20 and NV30 pixel formats
based on the existing pattern for NV12 with colors simply scaled from
8-bit to 10-bit.

These pixel formats are typically used by video decoder and display
pipeline on Rockchip SoCs, e.g. on RK322X, RK3288, RK3328 and RK3399
the video decoder produce 10-bit video frames in NV15 and NV20 format.

NV20 and NV30 pixel formats was added in drm-misc commit 728c15b4b5f3
("drm/fourcc: Add NV20 and NV30 YUV formats").

This can be tested/validated on Rockchip SoCs with drm-misc commit
d4b384228562 ("drm/rockchip: vop: Add NV15, NV20 and NV30 support").

Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
Reviewed-by: Christopher Obbard <chris.obbard@collabora.com>
Tested-by: Christopher Obbard <chris.obbard@collabora.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
include/drm/drm_fourcc.h
tests/modetest/buffers.c
tests/util/format.c
tests/util/pattern.c

index 6b6235f7a7cdeb968e983fa37d8df03d38ba9331..9b25048022418db03821f03a87bf54de26acc164 100644 (file)
@@ -323,6 +323,8 @@ extern "C" {
  * index 1 = Cr:Cb plane, [39:0] Cr1:Cb1:Cr0:Cb0 little endian
  */
 #define DRM_FORMAT_NV15                fourcc_code('N', 'V', '1', '5') /* 2x2 subsampled Cr:Cb plane */
+#define DRM_FORMAT_NV20                fourcc_code('N', 'V', '2', '0') /* 2x1 subsampled Cr:Cb plane */
+#define DRM_FORMAT_NV30                fourcc_code('N', 'V', '3', '0') /* non-subsampled Cr:Cb plane */
 
 /*
  * 2 plane YCbCr MSB aligned
index 65f1cfb32ab9eeae76b763ecaae2e450cf865b58..cc34ba4737beccfecb96dbe01777318b8be58617 100644 (file)
@@ -148,6 +148,12 @@ bo_create(int fd, unsigned int format,
                bpp = 8;
                break;
 
+       case DRM_FORMAT_NV15:
+       case DRM_FORMAT_NV20:
+       case DRM_FORMAT_NV30:
+               bpp = 10;
+               break;
+
        case DRM_FORMAT_ARGB4444:
        case DRM_FORMAT_XRGB4444:
        case DRM_FORMAT_ABGR4444:
@@ -212,6 +218,7 @@ bo_create(int fd, unsigned int format,
        switch (format) {
        case DRM_FORMAT_NV12:
        case DRM_FORMAT_NV21:
+       case DRM_FORMAT_NV15:
        case DRM_FORMAT_YUV420:
        case DRM_FORMAT_YVU420:
                virtual_height = height * 3 / 2;
@@ -219,11 +226,13 @@ bo_create(int fd, unsigned int format,
 
        case DRM_FORMAT_NV16:
        case DRM_FORMAT_NV61:
+       case DRM_FORMAT_NV20:
                virtual_height = height * 2;
                break;
 
        case DRM_FORMAT_NV24:
        case DRM_FORMAT_NV42:
+       case DRM_FORMAT_NV30:
                virtual_height = height * 3;
                break;
 
@@ -263,6 +272,8 @@ bo_create(int fd, unsigned int format,
        case DRM_FORMAT_NV21:
        case DRM_FORMAT_NV16:
        case DRM_FORMAT_NV61:
+       case DRM_FORMAT_NV15:
+       case DRM_FORMAT_NV20:
                offsets[0] = 0;
                handles[0] = bo->handle;
                pitches[0] = bo->pitch;
@@ -276,6 +287,7 @@ bo_create(int fd, unsigned int format,
 
        case DRM_FORMAT_NV24:
        case DRM_FORMAT_NV42:
+       case DRM_FORMAT_NV30:
                offsets[0] = 0;
                handles[0] = bo->handle;
                pitches[0] = bo->pitch;
index b99cc9c3599d92379fcfb10a6e42b640b9fa5efe..1fb7979bd1be85d5576878ee7274fa215613e7bb 100644 (file)
@@ -56,6 +56,9 @@ static const struct util_format_info format_info[] = {
        { DRM_FORMAT_NV61, "NV61", MAKE_YUV_INFO(YUV_YCrCb, 2, 1, 2) },
        { DRM_FORMAT_NV24, "NV24", MAKE_YUV_INFO(YUV_YCbCr, 1, 1, 2) },
        { DRM_FORMAT_NV42, "NV42", MAKE_YUV_INFO(YUV_YCrCb, 1, 1, 2) },
+       { DRM_FORMAT_NV15, "NV15", MAKE_YUV_INFO(YUV_YCbCr, 2, 2, 2) },
+       { DRM_FORMAT_NV20, "NV20", MAKE_YUV_INFO(YUV_YCbCr, 2, 1, 2) },
+       { DRM_FORMAT_NV30, "NV30", MAKE_YUV_INFO(YUV_YCbCr, 1, 1, 2) },
        /* YUV planar */
        { DRM_FORMAT_YUV420, "YU12", MAKE_YUV_INFO(YUV_YCbCr, 2, 2, 1) },
        { DRM_FORMAT_YVU420, "YV12", MAKE_YUV_INFO(YUV_YCrCb, 2, 2, 1) },
index f69c5206d96eff0231e452c7f957088106c7970b..f9ef2b81a631750be175a0df358136fc5ce97575 100644 (file)
@@ -260,6 +260,148 @@ static void fill_smpte_yuv_planar(const struct util_yuv_info *yuv,
        }
 }
 
+static void write_pixels_10bpp(unsigned char *mem,
+                              unsigned short a,
+                              unsigned short b,
+                              unsigned short c,
+                              unsigned short d)
+{
+         mem[0] = (a & 0xff);
+         mem[1] = ((a >> 8) & 0x3) | ((b & 0x3f) << 2);
+         mem[2] = ((b >> 6) & 0xf) | ((c & 0xf) << 4);
+         mem[3] = ((c >> 4) & 0x3f) | ((d & 0x3) << 6);
+         mem[4] = ((d >> 2) & 0xff);
+}
+
+static void fill_smpte_yuv_planar_10bpp(const struct util_yuv_info *yuv,
+                                       unsigned char *y_mem,
+                                       unsigned char *uv_mem,
+                                       unsigned int width,
+                                       unsigned int height,
+                                       unsigned int stride)
+{
+       const struct color_yuv colors_top[] = {
+               MAKE_YUV_601(192, 192, 192),    /* grey */
+               MAKE_YUV_601(192, 192, 0),      /* yellow */
+               MAKE_YUV_601(0, 192, 192),      /* cyan */
+               MAKE_YUV_601(0, 192, 0),        /* green */
+               MAKE_YUV_601(192, 0, 192),      /* magenta */
+               MAKE_YUV_601(192, 0, 0),        /* red */
+               MAKE_YUV_601(0, 0, 192),        /* blue */
+       };
+       const struct color_yuv colors_middle[] = {
+               MAKE_YUV_601(0, 0, 192),        /* blue */
+               MAKE_YUV_601(19, 19, 19),       /* black */
+               MAKE_YUV_601(192, 0, 192),      /* magenta */
+               MAKE_YUV_601(19, 19, 19),       /* black */
+               MAKE_YUV_601(0, 192, 192),      /* cyan */
+               MAKE_YUV_601(19, 19, 19),       /* black */
+               MAKE_YUV_601(192, 192, 192),    /* grey */
+       };
+       const struct color_yuv colors_bottom[] = {
+               MAKE_YUV_601(0, 33, 76),        /* in-phase */
+               MAKE_YUV_601(255, 255, 255),    /* super white */
+               MAKE_YUV_601(50, 0, 106),       /* quadrature */
+               MAKE_YUV_601(19, 19, 19),       /* black */
+               MAKE_YUV_601(9, 9, 9),          /* 3.5% */
+               MAKE_YUV_601(19, 19, 19),       /* 7.5% */
+               MAKE_YUV_601(29, 29, 29),       /* 11.5% */
+               MAKE_YUV_601(19, 19, 19),       /* black */
+       };
+       unsigned int cs = yuv->chroma_stride;
+       unsigned int xsub = yuv->xsub;
+       unsigned int ysub = yuv->ysub;
+       unsigned int xstep = cs * xsub;
+       unsigned int x;
+       unsigned int y;
+
+       /* Luma */
+       for (y = 0; y < height * 6 / 9; ++y) {
+               for (x = 0; x < width; x += 4)
+                       write_pixels_10bpp(&y_mem[(x * 5) / 4],
+                               colors_top[(x+0) * 7 / width].y << 2,
+                               colors_top[(x+1) * 7 / width].y << 2,
+                               colors_top[(x+2) * 7 / width].y << 2,
+                               colors_top[(x+3) * 7 / width].y << 2);
+               y_mem += stride;
+       }
+
+       for (; y < height * 7 / 9; ++y) {
+               for (x = 0; x < width; x += 4)
+                       write_pixels_10bpp(&y_mem[(x * 5) / 4],
+                               colors_middle[(x+0) * 7 / width].y << 2,
+                               colors_middle[(x+1) * 7 / width].y << 2,
+                               colors_middle[(x+2) * 7 / width].y << 2,
+                               colors_middle[(x+3) * 7 / width].y << 2);
+               y_mem += stride;
+       }
+
+       for (; y < height; ++y) {
+               for (x = 0; x < width * 5 / 7; x += 4)
+                       write_pixels_10bpp(&y_mem[(x * 5) / 4],
+                               colors_bottom[(x+0) * 4 / (width * 5 / 7)].y << 2,
+                               colors_bottom[(x+1) * 4 / (width * 5 / 7)].y << 2,
+                               colors_bottom[(x+2) * 4 / (width * 5 / 7)].y << 2,
+                               colors_bottom[(x+3) * 4 / (width * 5 / 7)].y << 2);
+               for (; x < width * 6 / 7; x += 4)
+                       write_pixels_10bpp(&y_mem[(x * 5) / 4],
+                               colors_bottom[((x+0) - width * 5 / 7) * 3 / (width / 7) + 4].y << 2,
+                               colors_bottom[((x+1) - width * 5 / 7) * 3 / (width / 7) + 4].y << 2,
+                               colors_bottom[((x+2) - width * 5 / 7) * 3 / (width / 7) + 4].y << 2,
+                               colors_bottom[((x+3) - width * 5 / 7) * 3 / (width / 7) + 4].y << 2);
+               for (; x < width; x += 4)
+                       write_pixels_10bpp(&y_mem[(x * 5) / 4],
+                               colors_bottom[7].y << 2,
+                               colors_bottom[7].y << 2,
+                               colors_bottom[7].y << 2,
+                               colors_bottom[7].y << 2);
+               y_mem += stride;
+       }
+
+       /* Chroma */
+       for (y = 0; y < height * 6 / 9; y += ysub) {
+               for (x = 0; x < width; x += xstep)
+                       write_pixels_10bpp(&uv_mem[(x * 5) / xstep],
+                               colors_top[(x+0) * 7 / width].u << 2,
+                               colors_top[(x+0) * 7 / width].v << 2,
+                               colors_top[(x+xsub) * 7 / width].u << 2,
+                               colors_top[(x+xsub) * 7 / width].v << 2);
+               uv_mem += stride * cs / xsub;
+       }
+
+       for (; y < height * 7 / 9; y += ysub) {
+               for (x = 0; x < width; x += xstep)
+                       write_pixels_10bpp(&uv_mem[(x * 5) / xstep],
+                               colors_middle[(x+0) * 7 / width].u << 2,
+                               colors_middle[(x+0) * 7 / width].v << 2,
+                               colors_middle[(x+xsub) * 7 / width].u << 2,
+                               colors_middle[(x+xsub) * 7 / width].v << 2);
+               uv_mem += stride * cs / xsub;
+       }
+
+       for (; y < height; y += ysub) {
+               for (x = 0; x < width * 5 / 7; x += xstep)
+                       write_pixels_10bpp(&uv_mem[(x * 5) / xstep],
+                               colors_bottom[(x+0) * 4 / (width * 5 / 7)].u << 2,
+                               colors_bottom[(x+0) * 4 / (width * 5 / 7)].v << 2,
+                               colors_bottom[(x+xsub) * 4 / (width * 5 / 7)].u << 2,
+                               colors_bottom[(x+xsub) * 4 / (width * 5 / 7)].v << 2);
+               for (; x < width * 6 / 7; x += xstep)
+                       write_pixels_10bpp(&uv_mem[(x * 5) / xstep],
+                               colors_bottom[((x+0) - width * 5 / 7) * 3 / (width / 7) + 4].u << 2,
+                               colors_bottom[((x+0) - width * 5 / 7) * 3 / (width / 7) + 4].v << 2,
+                               colors_bottom[((x+xsub) - width * 5 / 7) * 3 / (width / 7) + 4].u << 2,
+                               colors_bottom[((x+xsub) - width * 5 / 7) * 3 / (width / 7) + 4].v << 2);
+               for (; x < width; x += xstep)
+                       write_pixels_10bpp(&uv_mem[(x * 5) / xstep],
+                               colors_bottom[7].u << 2,
+                               colors_bottom[7].v << 2,
+                               colors_bottom[7].u << 2,
+                               colors_bottom[7].v << 2);
+               uv_mem += stride * cs / xsub;
+       }
+}
+
 static void fill_smpte_yuv_packed(const struct util_yuv_info *yuv, void *mem,
                                  unsigned int width, unsigned int height,
                                  unsigned int stride)
@@ -1051,6 +1193,13 @@ static void fill_smpte(const struct util_format_info *info, void *planes[3],
                return fill_smpte_yuv_planar(&info->yuv, planes[0], u, v,
                                             width, height, stride);
 
+       case DRM_FORMAT_NV15:
+       case DRM_FORMAT_NV20:
+       case DRM_FORMAT_NV30:
+               return fill_smpte_yuv_planar_10bpp(&info->yuv, planes[0],
+                                                  planes[1], width, height,
+                                                  stride);
+
        case DRM_FORMAT_YUV420:
                return fill_smpte_yuv_planar(&info->yuv, planes[0], planes[1],
                                             planes[2], width, height, stride);
@@ -1182,6 +1331,18 @@ static void make_pwetty(void *data, unsigned int width, unsigned int height,
 #endif
 }
 
+static struct color_yuv make_tiles_yuv_color(unsigned int x, unsigned int y,
+                                            unsigned int width)
+{
+       div_t d = div(x+y, width);
+       uint32_t rgb32 = 0x00130502 * (d.quot >> 6)
+                      + 0x000a1120 * (d.rem >> 6);
+       struct color_yuv color =
+               MAKE_YUV_601((rgb32 >> 16) & 0xff, (rgb32 >> 8) & 0xff,
+                            rgb32 & 0xff);
+       return color;
+}
+
 static void fill_tiles_yuv_planar(const struct util_format_info *info,
                                  unsigned char *y_mem, unsigned char *u_mem,
                                  unsigned char *v_mem, unsigned int width,
@@ -1196,12 +1357,8 @@ static void fill_tiles_yuv_planar(const struct util_format_info *info,
 
        for (y = 0; y < height; ++y) {
                for (x = 0; x < width; ++x) {
-                       div_t d = div(x+y, width);
-                       uint32_t rgb32 = 0x00130502 * (d.quot >> 6)
-                                      + 0x000a1120 * (d.rem >> 6);
                        struct color_yuv color =
-                               MAKE_YUV_601((rgb32 >> 16) & 0xff,
-                                            (rgb32 >> 8) & 0xff, rgb32 & 0xff);
+                               make_tiles_yuv_color(x, y, width);
 
                        y_mem[x] = color.y;
                        u_mem[x/xsub*cs] = color.u;
@@ -1216,6 +1373,45 @@ static void fill_tiles_yuv_planar(const struct util_format_info *info,
        }
 }
 
+static void fill_tiles_yuv_planar_10bpp(const struct util_format_info *info,
+                                       unsigned char *y_mem,
+                                       unsigned char *uv_mem,
+                                       unsigned int width,
+                                       unsigned int height,
+                                       unsigned int stride)
+{
+       const struct util_yuv_info *yuv = &info->yuv;
+       unsigned int cs = yuv->chroma_stride;
+       unsigned int xsub = yuv->xsub;
+       unsigned int ysub = yuv->ysub;
+       unsigned int xstep = cs * xsub;
+       unsigned int x;
+       unsigned int y;
+
+       for (y = 0; y < height; ++y) {
+               for (x = 0; x < width; x += 4) {
+                       struct color_yuv a = make_tiles_yuv_color(x+0, y, width);
+                       struct color_yuv b = make_tiles_yuv_color(x+1, y, width);
+                       struct color_yuv c = make_tiles_yuv_color(x+2, y, width);
+                       struct color_yuv d = make_tiles_yuv_color(x+3, y, width);
+
+                       write_pixels_10bpp(&y_mem[(x * 5) / 4],
+                               a.y << 2, b.y << 2, c.y << 2, d.y << 2);
+               }
+               y_mem += stride;
+       }
+       for (y = 0; y < height; y += ysub) {
+               for (x = 0; x < width; x += xstep) {
+                       struct color_yuv a = make_tiles_yuv_color(x+0, y, width);
+                       struct color_yuv b = make_tiles_yuv_color(x+xsub, y, width);
+
+                       write_pixels_10bpp(&uv_mem[(x * 5) / xstep],
+                               a.u << 2, a.v << 2, b.u << 2, b.v << 2);
+               }
+               uv_mem += stride * cs / xsub;
+       }
+}
+
 static void fill_tiles_yuv_packed(const struct util_format_info *info,
                                  void *mem, unsigned int width,
                                  unsigned int height, unsigned int stride)
@@ -1230,12 +1426,8 @@ static void fill_tiles_yuv_packed(const struct util_format_info *info,
 
        for (y = 0; y < height; ++y) {
                for (x = 0; x < width; x += 2) {
-                       div_t d = div(x+y, width);
-                       uint32_t rgb32 = 0x00130502 * (d.quot >> 6)
-                                      + 0x000a1120 * (d.rem >> 6);
                        struct color_yuv color =
-                               MAKE_YUV_601((rgb32 >> 16) & 0xff,
-                                            (rgb32 >> 8) & 0xff, rgb32 & 0xff);
+                               make_tiles_yuv_color(x, y, width);
 
                        y_mem[2*x] = color.y;
                        c_mem[2*x+u] = color.u;
@@ -1373,6 +1565,12 @@ static void fill_tiles(const struct util_format_info *info, void *planes[3],
                return fill_tiles_yuv_planar(info, planes[0], u, v,
                                             width, height, stride);
 
+       case DRM_FORMAT_NV15:
+       case DRM_FORMAT_NV20:
+       case DRM_FORMAT_NV30:
+               return fill_tiles_yuv_planar_10bpp(info, planes[0], planes[1],
+                                                  width, height, stride);
+
        case DRM_FORMAT_YUV420:
                return fill_tiles_yuv_planar(info, planes[0], planes[1],
                                             planes[2], width, height, stride);