From de3fffbf7af9d28b5f9d9e118de448a54e2628dd Mon Sep 17 00:00:00 2001
From: Anil Kumar Mamidala <anil.mamidala@xilinx.com>
Date: Wed, 27 Oct 2021 16:04:47 +0530
Subject: [PATCH] modetest: Add YUV444 and X403 format support for modetest

Add YUV44 8-bit and X403 10-bit formats support to modetest
for generating color bar pattern.

Signed-off-by: Anil Kumar Mamidala <anil.mamidala@xilinx.com>
---
 include/drm/drm_fourcc.h |   7 +
 tests/modetest/buffers.c |  32 +++++
 tests/util/format.c      |   4 +
 tests/util/pattern.c     | 270 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 313 insertions(+)

diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h
index 32966bd..b93778c 100644
--- a/include/drm/drm_fourcc.h
+++ b/include/drm/drm_fourcc.h
@@ -352,6 +352,13 @@ extern "C" {
 #define DRM_FORMAT_YUV444	fourcc_code('Y', 'U', '2', '4') /* non-subsampled Cb (1) and Cr (2) planes */
 #define DRM_FORMAT_YVU444	fourcc_code('Y', 'V', '2', '4') /* non-subsampled Cr (1) and Cb (2) planes */
 
+/* 3 plane non-subsampled (444) YCbCr
+ * 10 bits per component
+ * index 0: Y plane, [31:0] x:Y2:Y1:Y0 [2:10:10:10] little endian
+ * index 1: Cb plane, [31:0] x:Cb2:Cb1:Cb0 [2:10:10:10] little endian
+ * index 2: Cr plane, [31:0] x:Cr2:Cr1:Cr0 [2:10:10:10] little endian
+ */
+#define DRM_FORMAT_X403		fourcc_code('X', '4', '0', '3') /* non-subsampled Cb:Cr plane, 10 bit per channel */
 
 /*
  * Format Modifiers:
diff --git a/tests/modetest/buffers.c b/tests/modetest/buffers.c
index 4c15ec8..0529978 100644
--- a/tests/modetest/buffers.c
+++ b/tests/modetest/buffers.c
@@ -142,11 +142,13 @@ bo_create(int fd, unsigned int format,
 	case DRM_FORMAT_NV61:
 	case DRM_FORMAT_YUV420:
 	case DRM_FORMAT_YVU420:
+	case DRM_FORMAT_YUV444:
 		bpp = 8;
 		break;
 
 	case DRM_FORMAT_XV15:
 	case DRM_FORMAT_XV20:
+	case DRM_FORMAT_X403:
 		bpp = 10;
 		break;
 
@@ -230,12 +232,24 @@ bo_create(int fd, unsigned int format,
 		virtual_height = height * 2;
 		break;
 
+	case DRM_FORMAT_X403:
+		virtual_width = (width * 32) / 30;
+		virtual_height = height * 3;
+		break;
+
+
 	case DRM_FORMAT_NV16:
 	case DRM_FORMAT_NV61:
 		virtual_width = width;
 		virtual_height = height * 2;
 		break;
 
+	case DRM_FORMAT_YUV444:
+		virtual_width = width;
+		virtual_height = height * 3;
+		break;
+
+
 	default:
 		virtual_width = width;
 		virtual_height = height;
@@ -286,6 +300,24 @@ bo_create(int fd, unsigned int format,
 		planes[1] = virtual + offsets[1];
 		break;
 
+	case DRM_FORMAT_X403:
+	case DRM_FORMAT_YUV444:
+		offsets[0] = 0;
+		handles[0] = bo->handle;
+		pitches[0] = bo->pitch;
+		pitches[1] = pitches[0];
+		offsets[1] = pitches[0] * height;
+		handles[1] = bo->handle;
+		pitches[2] = pitches[1];
+		offsets[2] = offsets[1] + pitches[1] * height;
+		handles[2] = bo->handle;
+
+
+		planes[0] = virtual;
+		planes[1] = virtual + offsets[1];
+		planes[2] = virtual + offsets[2];
+		break;
+
 	case DRM_FORMAT_YUV420:
 	case DRM_FORMAT_YVU420:
 		offsets[0] = 0;
diff --git a/tests/util/format.c b/tests/util/format.c
index e4b612b..ba7267f 100644
--- a/tests/util/format.c
+++ b/tests/util/format.c
@@ -57,6 +57,10 @@ static const struct util_format_info format_info[] = {
 	/* 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) },
+	{ DRM_FORMAT_YUV444, "YU24", MAKE_YUV_INFO(YUV_YCbCr, 1, 1, 1) },
+	{ DRM_FORMAT_YVU444, "YV24", MAKE_YUV_INFO(YUV_YCrCb, 1, 1, 1) },
+	{ DRM_FORMAT_X403, "X403", MAKE_YUV_INFO(YUV_YCbCr, 1, 1, 1) },
+
 	/* RGB16 */
 	{ DRM_FORMAT_ARGB4444, "AR12", MAKE_RGB_INFO(4, 8, 4, 4, 4, 0, 4, 12) },
 	{ DRM_FORMAT_XRGB4444, "XR12", MAKE_RGB_INFO(4, 8, 4, 4, 4, 0, 0, 0) },
diff --git a/tests/util/pattern.c b/tests/util/pattern.c
index 0fe2e5f..83049eb 100644
--- a/tests/util/pattern.c
+++ b/tests/util/pattern.c
@@ -426,6 +426,175 @@ static void fill_smpte_yuv_semiplanar_10b(
 	}
 }
 
+static void fill_smpte_yuv_planar_x403(
+				const struct util_yuv_info *yuv,
+				unsigned char *y_mem, unsigned char *u_mem,
+				unsigned char *v_mem,
+				unsigned int width,
+				unsigned int height, unsigned int stride)
+{
+	const struct color_yuv colors_top[] = {
+		MAKE_YUV_601(191, 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 x;
+	unsigned int y;
+	unsigned int cval = 0;
+
+	for (y = 0; y < height * 6 / 9; ++y) {
+		for (x = 0; x < width; x += 3)
+			((unsigned int *)y_mem)[x/3] =
+				colors_top[x * 7 / width].y << 2 |
+				colors_top[(x+1) * 7 / width].y << 12 |
+				colors_top[(x+2) * 7 / width].y << 22;
+		y_mem += stride;
+	}
+
+	for (; y < height * 7 / 9; ++y) {
+		for (x = 0; x < width; x += 3)
+			((unsigned int *)y_mem)[x/3] =
+				colors_middle[x * 7 / width].y << 2 |
+				colors_middle[(x+1) * 7 / width].y << 12 |
+				colors_middle[(x+2) * 7 / width].y << 22;
+		y_mem += stride;
+	}
+
+	for (; y < height; ++y) {
+		for (x = 0; x < width * 5 / 7; x += 3)
+			((unsigned int *)y_mem)[x/3] =
+				colors_bottom[x * 4 / (width * 5 / 7)].y << 2 |
+				colors_bottom[(x + 1) * 4 / (width * 5 / 7)]
+				.y << 12 | colors_bottom[(x + 2) * 4 /
+				(width * 5 / 7)].y << 22;
+
+		for (; x < width * 6 / 7; x += 3)
+			((unsigned int *)y_mem)[x/3] =
+				colors_bottom[(x - width * 5 / 7) * 3 /
+				(width / 7) + 4].y << 2 |
+				colors_bottom[((x + 1) - width * 5 / 7) * 3 /
+				(width / 7) + 4].y << 12 |
+				colors_bottom[((x + 2) - width * 5 / 7) * 3 /
+				(width / 7) + 4].y << 22;
+
+		for (; x < width; x += 3)
+			((unsigned int *)y_mem)[x/3] = colors_bottom[7].y << 2 |
+				colors_bottom[7].y << 12 |
+				colors_bottom[7].y << 22;
+		y_mem += stride;
+	}
+
+	/* Chroma */
+	unsigned int *cb_mem = (unsigned int *)u_mem;
+	unsigned int *cr_mem = (unsigned int *)v_mem;
+
+	for (y = 0; y < height / ysub * 6 / 9; ++y) {
+		for (x = 0; x < width; x += 3) {
+			cval = (colors_top[x * 7 / width].u << 2) |
+				(colors_top[(x + 1) * 7 / width].u << 12) |
+				(colors_top[(x + 2) * 7 / width].u << 22);
+			cb_mem[x/3] = cval;
+			cval = (colors_top[(x) * 7 / width].v << 2) |
+				(colors_top[(x + 1) * 7 / width].v << 12) |
+				(colors_top[(x + 2) * 7 / width].v << 22);
+			cr_mem[x/3] = cval;
+		}
+		cb_mem += stride/4;
+		cr_mem += stride/4;
+	}
+
+	for (; y < height / ysub * 7 / 9; ++y) {
+		for (x = 0; x < width; x += 3) {
+			cval =  (colors_middle[x * 7 / width].u << 2) |
+				(colors_middle[(x + 1) * 7 / width].u << 12) |
+				(colors_middle[(x + 2) * 7 / width].u << 22);
+			cb_mem[x/3] = cval;
+			cval = (colors_middle[x * 7 / width].v << 2) |
+				(colors_middle[(x + 1) * 7 / width].v << 12) |
+				(colors_middle[(x + 2) * 7 / width].v << 22);
+			cr_mem[x/3] = cval;
+		}
+		cb_mem += stride/4;
+		cr_mem += stride/4;
+	}
+
+	for (; y < height / ysub; ++y) {
+		for (x = 0; x < width * 5 / 7; x += 3) {
+			cval = colors_bottom[x * 4 /
+				(width * 5 / 7)].u << 2 |
+				colors_bottom[(x + 2) * 4 /
+				(width * 5 / 7)].u << 12 |
+				colors_bottom[(x + 4) * 4 /
+				(width * 5 / 7)]. u << 22;
+			cb_mem[x/3] = cval;
+
+			cval = colors_bottom[(x) * 4 /
+				(width * 5 / 7)].v << 2 |
+				colors_bottom[(x + 2) * 4 /
+				(width * 5 / 7)].v << 12 |
+				colors_bottom[(x + 4) * 4 /
+				(width * 5 / 7)].v << 22;
+
+			cr_mem[x/3] = cval;
+		}
+		for (; x < width * 6 / 7; x += 3) {
+			cval = colors_bottom[(x - width * 5 / 7) * 3 /
+				(width / 7) + 4].u << 2 |
+				colors_bottom[((x + 2)- width * 5 / 7) * 3 /
+				(width / 7) + 4].u << 12 |
+				colors_bottom[((x + 4) - width * 5 / 7) * 3 /
+				(width / 7) + 4].u << 22;
+			cb_mem[x/3] = cval;
+
+			cval = colors_bottom[((x) - width * 5 / 7) * 3 /
+				(width / 7) + 4].v << 2 |
+				colors_bottom[((x + 2) - width * 5 / 7) * 3 /
+				(width / 7) + 4].v << 12 |
+				colors_bottom[((x + 4) - width * 5 / 7) * 3 /
+				(width / 7) + 4].v << 22;
+			cr_mem[x/3] = cval;
+		}
+		for (; x < width; x += 3) {
+			cval = colors_bottom[7].u << 2 |
+				colors_bottom[7].u << 12 |
+				colors_bottom[7].u << 22;
+			cb_mem[x/3] = cval;
+			cval = colors_bottom[7].v << 2 |
+				colors_bottom[7].v << 12 |
+				colors_bottom[7].v << 22;
+			cr_mem[x/3] = cval;
+		}
+		cb_mem += stride/4;
+		cr_mem += stride/4;
+	}
+}
+
 static void fill_smpte_yuv_planar_10b(
 				const struct util_yuv_info *yuv,
 				unsigned char *y_mem, unsigned char *u_mem,
@@ -686,6 +855,88 @@ static void fill_tiles_xv20(
 	}
 }
 
+static void fill_tiles_x403(
+				const struct util_format_info *info,
+				unsigned char *y_mem, unsigned char *u_mem,
+				unsigned char *v_mem, uint32_t width,
+				uint32_t height, uint32_t stride)
+{
+	const struct util_yuv_info *yuv = &info->yuv;
+	unsigned int cs = yuv->chroma_stride;
+	unsigned int x;
+	unsigned int y;
+	uint32_t shifter = 0, LumVal = 0;
+	uint32_t lumIndex = 0;
+	uint32_t *Lum;
+	uint32_t *uChrom;
+	uint32_t *vChrom;
+	uint32_t ChromVal = 0;
+	uint32_t uchromIndex = 0;
+	uint32_t vchromIndex = 0;
+
+	/* preparing 10 bit Luma */
+	Lum = (uint32_t *)y_mem;
+	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);
+			//Checking if we got 3 components to pack in 4 bytes
+			if (shifter == 30) {
+				Lum[lumIndex] = LumVal;
+				lumIndex++; shifter = 0; LumVal = 0;
+			}
+			LumVal  = (LumVal | ((color.y << 2) << shifter));
+			shifter += 10; //10 bit precision
+		}
+		lumIndex = 0; shifter = 0; LumVal = 0;
+		y_mem += stride;
+		Lum = (uint32_t *)y_mem;
+	}
+
+	/* Preparing 10 bit Chroma */
+	uChrom = (uint32_t *)u_mem;
+	vChrom = (uint32_t *)v_mem;
+
+	for (y = 0; y < height; ++y) {
+		for (x = 0; x < width; x = x + 3) {
+			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);
+			uint32_t rgb32_2 = 0x00130502 * (d.quot >> 6)
+						+ 0x000a1120 * (d.rem >> 6);
+			struct color_yuv color_2 =
+					MAKE_YUV_601((rgb32_2 >> 16) & 0xff,
+				       (rgb32_2 >> 8) & 0xff, rgb32_2 & 0xff);
+			uint32_t rgb32_3 = 0x00130502 * (d.quot >> 6)
+					+ 0x000a1120 * (d.rem >> 6);
+			struct color_yuv color_3 =
+					MAKE_YUV_601((rgb32_3 >> 16) & 0xff,
+					(rgb32_3 >> 8) & 0xff, rgb32_3 & 0xff);
+
+			ChromVal = ((color.u << 2) << 20)
+				| ((color_2.u << 2) << 10) | (color_3.u << 2);
+			uChrom[uchromIndex++] = ChromVal;
+
+			ChromVal = ((color.v << 2) << 20)
+				| ((color_2.v << 2) << 10) | (color_3.v << 2);
+			vChrom[vchromIndex++] = ChromVal;
+		}
+		uchromIndex = 0; vchromIndex = 0; ChromVal = 0;
+		u_mem += stride;
+		v_mem += stride;
+		uChrom = (uint32_t *)u_mem;
+		vChrom = (uint32_t *)v_mem;
+	}
+}
+
+
 static void fill_smpte_yuv_packed(const struct util_yuv_info *yuv, void *mem,
 				  unsigned int width, unsigned int height,
 				  unsigned int stride)
@@ -1135,10 +1386,19 @@ static void fill_smpte(const struct util_format_info *info,
 		return fill_smpte_yuv_planar(&info->yuv, planes[0], u, v,
 					     width, height, stride);
 
+	case DRM_FORMAT_X403:
+			return fill_smpte_yuv_planar_x403(&info->yuv, planes[0], planes[1],
+					     planes[2], width, height, stride);
+
+
 	case DRM_FORMAT_YUV420:
 		return fill_smpte_yuv_planar(&info->yuv, planes[0], planes[1],
 					     planes[2], width, height, stride);
 
+	case DRM_FORMAT_YUV444:
+		return fill_smpte_yuv_planar(&info->yuv, planes[0], planes[1],
+					     planes[2], width, height, stride);
+
 	case DRM_FORMAT_YVU420:
 		return fill_smpte_yuv_planar(&info->yuv, planes[0], planes[2],
 					     planes[1], width, height, stride);
@@ -1465,6 +1725,11 @@ static void fill_tiles(const struct util_format_info *info,
 		return fill_tiles_yuv_planar(info, planes[0], planes[1],
 					     planes[2], width, height, stride);
 
+	case DRM_FORMAT_YUV444:
+		return fill_tiles_yuv_planar(info, planes[0], planes[1],
+					     planes[2], width, height, stride);
+
+
 	case DRM_FORMAT_YVU420:
 		return fill_tiles_yuv_planar(info, planes[0], planes[2],
 					     planes[1], width, height, stride);
@@ -1473,6 +1738,11 @@ static void fill_tiles(const struct util_format_info *info,
 		return fill_tiles_xv20(info, planes[0], planes[1],
 			 planes[1], width, height, stride);
 
+	case DRM_FORMAT_X403:
+		return fill_tiles_x403(info, planes[0], planes[1],
+			 planes[2], width, height, stride);
+
+
 	case DRM_FORMAT_XV15:
 		return fill_tiles_xv15(info, planes[0], planes[1],
 			 planes[2], width, height, stride);
-- 
2.17.1

