From de88f74df911362ddd7988b2b5b9df4d8c19251f Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Wed, 25 Oct 2023 16:15:31 +0000 Subject: [PATCH] modetest: add support for DRM_FORMAT_NV{15,20,30} 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 Reviewed-by: Christopher Obbard Tested-by: Christopher Obbard Reviewed-by: Dmitry Baryshkov --- include/drm/drm_fourcc.h | 2 + tests/modetest/buffers.c | 12 +++ tests/util/format.c | 3 + tests/util/pattern.c | 218 +++++++++++++++++++++++++++++++++++++-- 4 files changed, 225 insertions(+), 10 deletions(-) diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h index 6b6235f7..9b250480 100644 --- a/include/drm/drm_fourcc.h +++ b/include/drm/drm_fourcc.h @@ -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 diff --git a/tests/modetest/buffers.c b/tests/modetest/buffers.c index 65f1cfb3..cc34ba47 100644 --- a/tests/modetest/buffers.c +++ b/tests/modetest/buffers.c @@ -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; diff --git a/tests/util/format.c b/tests/util/format.c index b99cc9c3..1fb7979b 100644 --- a/tests/util/format.c +++ b/tests/util/format.c @@ -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) }, diff --git a/tests/util/pattern.c b/tests/util/pattern.c index f69c5206..f9ef2b81 100644 --- a/tests/util/pattern.c +++ b/tests/util/pattern.c @@ -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);