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 <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>
main
Jonas Karlman 2023-10-25 16:15:31 +00:00
parent 8a933c778a
commit de88f74df9
4 changed files with 225 additions and 10 deletions

View 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

View 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;

View 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) },

View 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);