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
parent
8a933c778a
commit
de88f74df9
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) },
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue