drm: Branch 'master' - 10 commits

[email protected] (GitLab Mirror) Sat, 22 Jun 2019 17:38:02 +0000 (UTC)
Newsgroups gmane.comp.video.dri.patches
Message-ID <[email protected]>
 tests/modetest/buffers.c  |   13 +
 tests/modetest/modetest.c |  109 +++++++++--
 tests/util/format.c       |    7 
 tests/util/pattern.c      |  432 +++++++++++++++++++++++++++++++++++++++++++++-
 tests/util/pattern.h      |    7 
 5 files changed, 543 insertions(+), 25 deletions(-)

New commits:
commit f2da507a049585e4780f67659f7d9d85e0bf0a54
Author: Ilia Mirkin <[email protected]>
Date:   Sun Jun 2 17:54:38 2019 -0400

    modetest: add FP16 format support
    
    Signed-off-by: Ilia Mirkin <[email protected]>
    Reviewed-by: Emil Velikov <[email protected]>

diff --git a/tests/modetest/buffers.c b/tests/modetest/buffers.c
index 5ec4ec8e..8a8d9e01 100644
--- a/tests/modetest/buffers.c
+++ b/tests/modetest/buffers.c
@@ -194,6 +194,13 @@ bo_create(int fd, unsigned int format,
 		bpp = 32;
 		break;
 
+	case DRM_FORMAT_XRGB16161616F:
+	case DRM_FORMAT_XBGR16161616F:
+	case DRM_FORMAT_ARGB16161616F:
+	case DRM_FORMAT_ABGR16161616F:
+		bpp = 64;
+		break;
+
 	default:
 		fprintf(stderr, "unsupported format 0x%08x\n",  format);
 		return NULL;
@@ -313,6 +320,10 @@ bo_create(int fd, unsigned int format,
 	case DRM_FORMAT_RGBX1010102:
 	case DRM_FORMAT_BGRA1010102:
 	case DRM_FORMAT_BGRX1010102:
+	case DRM_FORMAT_XRGB16161616F:
+	case DRM_FORMAT_XBGR16161616F:
+	case DRM_FORMAT_ARGB16161616F:
+	case DRM_FORMAT_ABGR16161616F:
 		offsets[0] = 0;
 		handles[0] = bo->handle;
 		pitches[0] = bo->pitch;
commit 5d0e9dec3fb3eb019bb9fd4b1e3d32484198917f
Author: Ilia Mirkin <[email protected]>
Date:   Sat Jan 5 14:02:19 2019 -0500

    modetest: add the ability to specify fill patterns on the commandline
    
    Instead of hacking the binary every time, we can now specify directly.
    
    Signed-off-by: Ilia Mirkin <[email protected]>
    Reviewed-by: Emil Velikov <[email protected]>

diff --git a/tests/modetest/modetest.c b/tests/modetest/modetest.c
index 7bb21d17..e66be660 100644
--- a/tests/modetest/modetest.c
+++ b/tests/modetest/modetest.c
@@ -67,6 +67,9 @@
 #include "buffers.h"
 #include "cursor.h"
 
+static enum util_fill_pattern primary_fill = UTIL_PATTERN_SMPTE;
+static enum util_fill_pattern secondary_fill = UTIL_PATTERN_TILES;
+
 struct crtc {
 	drmModeCrtc *crtc;
 	drmModeObjectProperties *props;
@@ -1259,7 +1262,7 @@ static int set_plane(struct device *dev, struct plane_arg *p)
 		p->w, p->h, p->format_str, plane_id);
 
 	plane_bo = bo_create(dev->fd, p->fourcc, p->w, p->h, handles,
-			     pitches, offsets, UTIL_PATTERN_TILES);
+			     pitches, offsets, secondary_fill);
 	if (plane_bo == NULL)
 		return -1;
 
@@ -1300,12 +1303,12 @@ static int set_plane(struct device *dev, struct plane_arg *p)
 static void atomic_set_planes(struct device *dev, struct plane_arg *p,
 			      unsigned int count, bool update)
 {
-	unsigned int i, pattern = UTIL_PATTERN_SMPTE;
+	unsigned int i, pattern = primary_fill;
 
 	/* set up planes */
 	for (i = 0; i < count; i++) {
 		if (i > 0)
-			pattern = UTIL_PATTERN_TILES;
+			pattern = secondary_fill;
 		else
 			set_gamma(dev, p[i].crtc_id, p[i].fourcc);
 
@@ -1450,7 +1453,7 @@ static void set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int co
 
 	bo = bo_create(dev->fd, pipes[0].fourcc, dev->mode.width,
 		       dev->mode.height, handles, pitches, offsets,
-		       UTIL_PATTERN_SMPTE);
+		       primary_fill);
 	if (bo == NULL)
 		return;
 
@@ -1794,6 +1797,18 @@ static int parse_property(struct property_arg *p, const char *arg)
 	return 0;
 }
 
+static void parse_fill_patterns(char *arg)
+{
+	char *fill = strtok(arg, ",");
+	if (!fill)
+		return;
+	primary_fill = util_pattern_enum(fill);
+	fill = strtok(NULL, ",");
+	if (!fill)
+		return;
+	secondary_fill = util_pattern_enum(fill);
+}
+
 static void usage(char *name)
 {
 	fprintf(stderr, "usage: %s [-acDdefMPpsCvw]\n", name);
@@ -1811,6 +1826,7 @@ static void usage(char *name)
 	fprintf(stderr, "\t-v\ttest vsynced page flipping\n");
 	fprintf(stderr, "\t-w <obj_id>:<prop_name>:<value>\tset property\n");
 	fprintf(stderr, "\t-a \tuse atomic API\n");
+	fprintf(stderr, "\t-F pattern1,pattern2\tspecify fill patterns\n");
 
 	fprintf(stderr, "\n Generic options:\n\n");
 	fprintf(stderr, "\t-d\tdrop master after mode set\n");
@@ -1874,7 +1890,7 @@ static int pipe_resolve_connectors(struct device *dev, struct pipe_arg *pipe)
 	return 0;
 }
 
-static char optstr[] = "acdD:efM:P:ps:Cvw:";
+static char optstr[] = "acdD:efF:M:P:ps:Cvw:";
 
 int main(int argc, char **argv)
 {
@@ -1923,6 +1939,9 @@ int main(int argc, char **argv)
 		case 'f':
 			framebuffers = 1;
 			break;
+		case 'F':
+			parse_fill_patterns(optarg);
+			break;
 		case 'M':
 			module = optarg;
 			/* Preserve the default behaviour of dumping all information. */
diff --git a/tests/util/pattern.c b/tests/util/pattern.c
index d197c444..42a0e5c7 100644
--- a/tests/util/pattern.c
+++ b/tests/util/pattern.c
@@ -35,6 +35,7 @@
 #include <math.h>
 #endif
 
+#include "common.h"
 #include "format.h"
 #include "pattern.h"
 
@@ -1261,3 +1262,22 @@ void util_fill_pattern(uint32_t format, enum util_fill_pattern pattern,
 		break;
 	}
 }
+
+static const char *pattern_names[] = {
+	[UTIL_PATTERN_TILES] = "tiles",
+	[UTIL_PATTERN_SMPTE] = "smpte",
+	[UTIL_PATTERN_PLAIN] = "plain",
+	[UTIL_PATTERN_GRADIENT] = "gradient",
+};
+
+enum util_fill_pattern util_pattern_enum(const char *name)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(pattern_names); i++)
+		if (!strcmp(pattern_names[i], name))
+			return (enum util_fill_pattern)i;
+
+	printf("Error: unsupported test pattern %s.\n", name);
+	return UTIL_PATTERN_SMPTE;
+}
diff --git a/tests/util/pattern.h b/tests/util/pattern.h
index feac903a..424b0e19 100644
--- a/tests/util/pattern.h
+++ b/tests/util/pattern.h
@@ -41,4 +41,6 @@ void util_fill_pattern(uint32_t format, enum util_fill_pattern pattern,
 
 void util_smpte_c8_gamma(unsigned size, struct drm_color_lut *lut);
 
+enum util_fill_pattern util_pattern_enum(const char *name);
+
 #endif /* UTIL_PATTERN_H */
commit bfc469f241060700837ad3efaf3500265e9a9dd6
Author: Ilia Mirkin <[email protected]>
Date:   Fri Nov 17 23:52:46 2017 -0500

    modetest: add C8 support to generate SMPTE pattern
    
    This includes logic to configure the LUT accordingly.
    
    Signed-off-by: Ilia Mirkin <[email protected]>
    Reviewed-by: Emil Velikov <[email protected]>

diff --git a/tests/modetest/buffers.c b/tests/modetest/buffers.c
index 9b635c0c..5ec4ec8e 100644
--- a/tests/modetest/buffers.c
+++ b/tests/modetest/buffers.c
@@ -135,6 +135,7 @@ bo_create(int fd, unsigned int format,
 	int ret;
 
 	switch (format) {
+	case DRM_FORMAT_C8:
 	case DRM_FORMAT_NV12:
 	case DRM_FORMAT_NV21:
 	case DRM_FORMAT_NV16:
@@ -275,6 +276,7 @@ bo_create(int fd, unsigned int format,
 		planes[2] = virtual + offsets[2];
 		break;
 
+	case DRM_FORMAT_C8:
 	case DRM_FORMAT_ARGB4444:
 	case DRM_FORMAT_XRGB4444:
 	case DRM_FORMAT_ABGR4444:
diff --git a/tests/modetest/modetest.c b/tests/modetest/modetest.c
index 71ddc861..7bb21d17 100644
--- a/tests/modetest/modetest.c
+++ b/tests/modetest/modetest.c
@@ -1089,6 +1089,42 @@ static bool add_property_optional(struct device *dev, uint32_t obj_id,
 	return set_property(dev, &p);
 }
 
+static void set_gamma(struct device *dev, unsigned crtc_id, unsigned fourcc)
+{
+	unsigned blob_id = 0;
+	/* TODO: support 1024-sized LUTs, when the use-case arises */
+	struct drm_color_lut gamma_lut[256];
+	int i, ret;
+
+	if (fourcc == DRM_FORMAT_C8) {
+		/* TODO: Add C8 support for more patterns */
+		util_smpte_c8_gamma(256, gamma_lut);
+		drmModeCreatePropertyBlob(dev->fd, gamma_lut, sizeof(gamma_lut), &blob_id);
+	} else {
+		for (i = 0; i < 256; i++) {
+			gamma_lut[i].red =
+			gamma_lut[i].green =
+			gamma_lut[i].blue = i << 8;
+		}
+	}
+
+	add_property_optional(dev, crtc_id, "DEGAMMA_LUT", 0);
+	add_property_optional(dev, crtc_id, "CTM", 0);
+	if (!add_property_optional(dev, crtc_id, "GAMMA_LUT", blob_id)) {
+		uint16_t r[256], g[256], b[256];
+
+		for (i = 0; i < 256; i++) {
+			r[i] = gamma_lut[i].red;
+			g[i] = gamma_lut[i].green;
+			b[i] = gamma_lut[i].blue;
+		}
+
+		ret = drmModeCrtcSetGamma(dev->fd, crtc_id, 256, r, g, b);
+		if (ret)
+			fprintf(stderr, "failed to set gamma: %s\n", strerror(errno));
+	}
+}
+
 static int atomic_set_plane(struct device *dev, struct plane_arg *p,
 							int pattern, bool update)
 {
@@ -1270,6 +1306,8 @@ static void atomic_set_planes(struct device *dev, struct plane_arg *p,
 	for (i = 0; i < count; i++) {
 		if (i > 0)
 			pattern = UTIL_PATTERN_TILES;
+		else
+			set_gamma(dev, p[i].crtc_id, p[i].fourcc);
 
 		if (atomic_set_plane(dev, &p[i], pattern, update))
 			return;
@@ -1454,6 +1492,8 @@ static void set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int co
 			fprintf(stderr, "failed to set mode: %s\n", strerror(errno));
 			return;
 		}
+
+		set_gamma(dev, pipe->crtc->crtc->crtc_id, pipe->fourcc);
 	}
 }
 
@@ -1728,11 +1768,8 @@ static int parse_plane(struct plane_arg *plane, const char *p)
 	}
 
 	if (*end == '@') {
-		p = end + 1;
-		if (strlen(p) != 4)
-			return -EINVAL;
-
-		strcpy(plane->format_str, p);
+		strncpy(plane->format_str, end + 1, 4);
+		plane->format_str[4] = '\0';
 	} else {
 		strcpy(plane->format_str, "XR24");
 	}
commit 557d1a2e6f0dcaa5db444624d6407564118f1c0f
Author: Ilia Mirkin <[email protected]>
Date:   Sun Jun 2 14:33:26 2019 -0400

    modetest: add an add_property_optional variant that does not print errors
    
    As new features are added and others are declared to be legacy, it's
    nice to be able to implement fallbacks. As such, create a
    property-setting variant that does not generate errors which can very
    well be entirely expected.
    
    Will be used for gamma control in a future change.
    
    Signed-off-by: Ilia Mirkin <[email protected]>
    Reviewed-by: Emil Velikov <[email protected]>

diff --git a/tests/modetest/modetest.c b/tests/modetest/modetest.c
index a1c81f6c..71ddc861 100644
--- a/tests/modetest/modetest.c
+++ b/tests/modetest/modetest.c
@@ -948,9 +948,10 @@ struct property_arg {
 	char name[DRM_PROP_NAME_LEN+1];
 	uint32_t prop_id;
 	uint64_t value;
+	bool optional;
 };
 
-static void set_property(struct device *dev, struct property_arg *p)
+static bool set_property(struct device *dev, struct property_arg *p)
 {
 	drmModeObjectProperties *props = NULL;
 	drmModePropertyRes **props_info = NULL;
@@ -982,13 +983,13 @@ static void set_property(struct device *dev, struct property_arg *p)
 	if (p->obj_type == 0) {
 		fprintf(stderr, "Object %i not found, can't set property\n",
 			p->obj_id);
-			return;
+		return false;
 	}
 
 	if (!props) {
 		fprintf(stderr, "%s %i has no properties\n",
 			obj_type, p->obj_id);
-		return;
+		return false;
 	}
 
 	for (i = 0; i < (int)props->count_props; ++i) {
@@ -999,9 +1000,10 @@ static void set_property(struct device *dev, struct property_arg *p)
 	}
 
 	if (i == (int)props->count_props) {
-		fprintf(stderr, "%s %i has no %s property\n",
-			obj_type, p->obj_id, p->name);
-		return;
+		if (!p->optional)
+			fprintf(stderr, "%s %i has no %s property\n",
+				obj_type, p->obj_id, p->name);
+		return false;
 	}
 
 	p->prop_id = props->props[i];
@@ -1015,6 +1017,8 @@ static void set_property(struct device *dev, struct property_arg *p)
 	if (ret < 0)
 		fprintf(stderr, "failed to set %s %i property %s to %" PRIu64 ": %s\n",
 			obj_type, p->obj_id, p->name, p->value, strerror(errno));
+
+	return true;
 }
 
 /* -------------------------------------------------------------------------- */
@@ -1072,6 +1076,19 @@ static void add_property(struct device *dev, uint32_t obj_id,
 	set_property(dev, &p);
 }
 
+static bool add_property_optional(struct device *dev, uint32_t obj_id,
+				  const char *name, uint64_t value)
+{
+	struct property_arg p;
+
+	p.obj_id = obj_id;
+	strcpy(p.name, name);
+	p.value = value;
+	p.optional = true;
+
+	return set_property(dev, &p);
+}
+
 static int atomic_set_plane(struct device *dev, struct plane_arg *p,
 							int pattern, bool update)
 {
commit 78ea933460ffec691e2dac5393e403064df47d02
Author: Ilia Mirkin <[email protected]>
Date:   Sun Jun 2 20:20:39 2019 -0400

    modetest: don't pretend that atomic mode includes a format
    
    Signed-off-by: Ilia Mirkin <[email protected]>
    Reviewed-by: Emil Velikov <[email protected]>

diff --git a/tests/modetest/modetest.c b/tests/modetest/modetest.c
index 9c85c07b..a1c81f6c 100644
--- a/tests/modetest/modetest.c
+++ b/tests/modetest/modetest.c
@@ -1335,8 +1335,8 @@ static void atomic_set_mode(struct device *dev, struct pipe_arg *pipes, unsigned
 		if (pipe->mode == NULL)
 			continue;
 
-		printf("setting mode %s-%dHz@%s on connectors ",
-		       pipe->mode_str, pipe->mode->vrefresh, pipe->format_str);
+		printf("setting mode %s-%dHz on connectors ",
+		       pipe->mode_str, pipe->mode->vrefresh);
 		for (j = 0; j < pipe->num_cons; ++j) {
 			printf("%s, ", pipe->cons[j]);
 			add_property(dev, pipe->con_ids[j], "CRTC_ID", pipe->crtc->crtc->crtc_id);
commit def955c09ecec3789b03dfdedc1761ad65ab8eb2
Author: Ilia Mirkin <[email protected]>
Date:   Sun Jun 2 17:38:53 2019 -0400

    util: add cairo drawing for 30bpp formats when available
    
    Signed-off-by: Ilia Mirkin <[email protected]>
    Reviewed-by: Emil Velikov <[email protected]>

diff --git a/tests/util/pattern.c b/tests/util/pattern.c
index 37796dbf..d197c444 100644
--- a/tests/util/pattern.c
+++ b/tests/util/pattern.c
@@ -788,6 +788,14 @@ static void make_pwetty(void *data, unsigned int width, unsigned int height,
 	case DRM_FORMAT_BGR565:
 		cairo_format = CAIRO_FORMAT_RGB16_565;
 		break;
+#if CAIRO_VERSION_MAJOR > 1 || (CAIRO_VERSION_MAJOR == 1 && CAIRO_VERSION_MINOR >= 12)
+	case DRM_FORMAT_ARGB2101010:
+	case DRM_FORMAT_XRGB2101010:
+	case DRM_FORMAT_ABGR2101010:
+	case DRM_FORMAT_XBGR2101010:
+		cairo_format = CAIRO_FORMAT_RGB30;
+		break;
+#endif
 	default:
 		return;
 	}
commit b59d14e7fce6b7597511be190f4202bb4bec7919
Author: Ilia Mirkin <[email protected]>
Date:   Mon May 27 18:27:24 2019 -0400

    util: add fp16 format support
    
    This change adds support for all current patterns.
    
    Signed-off-by: Ilia Mirkin <[email protected]>
    Reviewed-by: Emil Velikov <[email protected]>

diff --git a/tests/util/format.c b/tests/util/format.c
index e52213bb..1ca1b82c 100644
--- a/tests/util/format.c
+++ b/tests/util/format.c
@@ -93,6 +93,11 @@ static const struct util_format_info format_info[] = {
 	{ DRM_FORMAT_RGBX1010102, "RX30", MAKE_RGB_INFO(10, 22, 10, 12, 10, 2, 0, 0) },
 	{ DRM_FORMAT_BGRA1010102, "BA30", MAKE_RGB_INFO(10, 2, 10, 12, 10, 22, 2, 0) },
 	{ DRM_FORMAT_BGRX1010102, "BX30", MAKE_RGB_INFO(10, 2, 10, 12, 10, 22, 0, 0) },
+	{ DRM_FORMAT_XRGB16161616F, "XR4H", MAKE_RGB_INFO(16, 32, 16, 16, 16, 0, 0, 0) },
+	{ DRM_FORMAT_XBGR16161616F, "XB4H", MAKE_RGB_INFO(16, 0, 16, 16, 16, 32, 0, 0) },
+	{ DRM_FORMAT_ARGB16161616F, "AR4H", MAKE_RGB_INFO(16, 32, 16, 16, 16, 0, 16, 48) },
+	{ DRM_FORMAT_ABGR16161616F, "AB4H", MAKE_RGB_INFO(16, 0, 16, 16, 16, 32, 16, 48) },
+
 };
 
 uint32_t util_format_fourcc(const char *name)
diff --git a/tests/util/pattern.c b/tests/util/pattern.c
index ff110fd7..37796dbf 100644
--- a/tests/util/pattern.c
+++ b/tests/util/pattern.c
@@ -86,6 +86,17 @@ static inline uint32_t shiftcolor10(const struct util_color_component *comp,
 	return value << comp->offset;
 }
 
+/* This function takes 16-bit color values */
+static inline uint64_t shiftcolor16(const struct util_color_component *comp,
+				    uint64_t value)
+{
+	value &= 0xffff;
+	/* Shift down to remove unwanted low bits */
+	value = value >> (16 - comp->length);
+	/* Shift back up to where the value should be */
+	return value << comp->offset;
+}
+
 #define MAKE_RGBA10(rgb, r, g, b, a) \
 	(shiftcolor10(&(rgb)->red, (r)) | \
 	 shiftcolor10(&(rgb)->green, (g)) | \
@@ -101,6 +112,49 @@ static inline uint32_t shiftcolor10(const struct util_color_component *comp,
 #define MAKE_RGB24(rgb, r, g, b) \
 	{ .value = MAKE_RGBA(rgb, r, g, b, 0) }
 
+
+/**
+  * Takes a uint16_t, divides by 65536, converts the infinite-precision
+  * result to fp16 with round-to-zero.
+  *
+  * Copied from mesa:src/util/half_float.c
+  */
+static uint16_t uint16_div_64k_to_half(uint16_t v)
+{
+	/* Zero or subnormal. Set the mantissa to (v << 8) and return. */
+	if (v < 4)
+		return v << 8;
+
+	/* Count the leading 0s in the uint16_t */
+	int n = __builtin_clz(v) - 16;
+
+	/* Shift the mantissa up so bit 16 is the hidden 1 bit,
+	 * mask it off, then shift back down to 10 bits
+	 */
+	int m = ( ((uint32_t)v << (n + 1)) & 0xffff ) >> 6;
+
+	/*  (0{n} 1 X{15-n}) * 2^-16
+	 * = 1.X * 2^(15-n-16)
+	 * = 1.X * 2^(14-n - 15)
+	 * which is the FP16 form with e = 14 - n
+	 */
+	int e = 14 - n;
+
+	return (e << 10) | m;
+}
+
+#define MAKE_RGBA8FP16(rgb, r, g, b, a) \
+	(shiftcolor16(&(rgb)->red, uint16_div_64k_to_half((r) << 8)) | \
+	 shiftcolor16(&(rgb)->green, uint16_div_64k_to_half((g) << 8)) | \
+	 shiftcolor16(&(rgb)->blue, uint16_div_64k_to_half((b) << 8)) | \
+	 shiftcolor16(&(rgb)->alpha, uint16_div_64k_to_half((a) << 8)))
+
+#define MAKE_RGBA10FP16(rgb, r, g, b, a) \
+	(shiftcolor16(&(rgb)->red, uint16_div_64k_to_half((r) << 6)) | \
+	 shiftcolor16(&(rgb)->green, uint16_div_64k_to_half((g) << 6)) | \
+	 shiftcolor16(&(rgb)->blue, uint16_div_64k_to_half((b) << 6)) | \
+	 shiftcolor16(&(rgb)->alpha, uint16_div_64k_to_half((a) << 6)))
+
 static void fill_smpte_yuv_planar(const struct util_yuv_info *yuv,
 				  unsigned char *y_mem, unsigned char *u_mem,
 				  unsigned char *v_mem, unsigned int width,
@@ -489,6 +543,67 @@ static void fill_smpte_rgb32(const struct util_rgb_info *rgb, void *mem,
 	}
 }
 
+static void fill_smpte_rgb16fp(const struct util_rgb_info *rgb, void *mem,
+			       unsigned int width, unsigned int height,
+			       unsigned int stride)
+{
+	const uint64_t colors_top[] = {
+		MAKE_RGBA8FP16(rgb, 192, 192, 192, 255),/* grey */
+		MAKE_RGBA8FP16(rgb, 192, 192, 0, 255),	/* yellow */
+		MAKE_RGBA8FP16(rgb, 0, 192, 192, 255),	/* cyan */
+		MAKE_RGBA8FP16(rgb, 0, 192, 0, 255),	/* green */
+		MAKE_RGBA8FP16(rgb, 192, 0, 192, 255),	/* magenta */
+		MAKE_RGBA8FP16(rgb, 192, 0, 0, 255),	/* red */
+		MAKE_RGBA8FP16(rgb, 0, 0, 192, 255),	/* blue */
+	};
+	const uint64_t colors_middle[] = {
+		MAKE_RGBA8FP16(rgb, 0, 0, 192, 127),	/* blue */
+		MAKE_RGBA8FP16(rgb, 19, 19, 19, 127),	/* black */
+		MAKE_RGBA8FP16(rgb, 192, 0, 192, 127),	/* magenta */
+		MAKE_RGBA8FP16(rgb, 19, 19, 19, 127),	/* black */
+		MAKE_RGBA8FP16(rgb, 0, 192, 192, 127),	/* cyan */
+		MAKE_RGBA8FP16(rgb, 19, 19, 19, 127),	/* black */
+		MAKE_RGBA8FP16(rgb, 192, 192, 192, 127),/* grey */
+	};
+	const uint64_t colors_bottom[] = {
+		MAKE_RGBA8FP16(rgb, 0, 33, 76, 255),	/* in-phase */
+		MAKE_RGBA8FP16(rgb, 255, 255, 255, 255),/* super white */
+		MAKE_RGBA8FP16(rgb, 50, 0, 106, 255),	/* quadrature */
+		MAKE_RGBA8FP16(rgb, 19, 19, 19, 255),	/* black */
+		MAKE_RGBA8FP16(rgb, 9, 9, 9, 255),	/* 3.5% */
+		MAKE_RGBA8FP16(rgb, 19, 19, 19, 255),	/* 7.5% */
+		MAKE_RGBA8FP16(rgb, 29, 29, 29, 255),	/* 11.5% */
+		MAKE_RGBA8FP16(rgb, 19, 19, 19, 255),	/* black */
+	};
+	unsigned int x;
+	unsigned int y;
+
+	for (y = 0; y < height * 6 / 9; ++y) {
+		for (x = 0; x < width; ++x)
+			((uint64_t *)mem)[x] = colors_top[x * 7 / width];
+		mem += stride;
+	}
+
+	for (; y < height * 7 / 9; ++y) {
+		for (x = 0; x < width; ++x)
+			((uint64_t *)mem)[x] = colors_middle[x * 7 / width];
+		mem += stride;
+	}
+
+	for (; y < height; ++y) {
+		for (x = 0; x < width * 5 / 7; ++x)
+			((uint64_t *)mem)[x] =
+				colors_bottom[x * 4 / (width * 5 / 7)];
+		for (; x < width * 6 / 7; ++x)
+			((uint64_t *)mem)[x] =
+				colors_bottom[(x - width * 5 / 7) * 3
+					      / (width / 7) + 4];
+		for (; x < width; ++x)
+			((uint64_t *)mem)[x] = colors_bottom[7];
+		mem += stride;
+	}
+}
+
 static void fill_smpte_c8(void *mem, unsigned int width, unsigned int height,
 			  unsigned int stride)
 {
@@ -638,6 +753,13 @@ static void fill_smpte(const struct util_format_info *info, void *planes[3],
 	case DRM_FORMAT_BGRX1010102:
 		return fill_smpte_rgb32(&info->rgb, planes[0],
 					width, height, stride);
+
+	case DRM_FORMAT_XRGB16161616F:
+	case DRM_FORMAT_XBGR16161616F:
+	case DRM_FORMAT_ARGB16161616F:
+	case DRM_FORMAT_ABGR16161616F:
+		return fill_smpte_rgb16fp(&info->rgb, planes[0],
+					  width, height, stride);
 	}
 }
 
@@ -849,6 +971,32 @@ static void fill_tiles_rgb32(const struct util_format_info *info, void *mem,
 	make_pwetty(mem_base, width, height, stride, info->format);
 }
 
+static void fill_tiles_rgb16fp(const struct util_format_info *info, void *mem,
+			       unsigned int width, unsigned int height,
+			       unsigned int stride)
+{
+	const struct util_rgb_info *rgb = &info->rgb;
+	void *mem_base = mem;
+	unsigned int x, y;
+
+	/* TODO: Give this actual fp16 precision */
+	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);
+			uint32_t alpha = ((y < height/2) && (x < width/2)) ? 127 : 255;
+			uint64_t color =
+				MAKE_RGBA8FP16(rgb, (rgb32 >> 16) & 0xff,
+					       (rgb32 >> 8) & 0xff, rgb32 & 0xff,
+					       alpha);
+
+			((uint64_t *)mem)[x] = color;
+		}
+		mem += stride;
+	}
+}
+
 static void fill_tiles(const struct util_format_info *info, void *planes[3],
 		       unsigned int width, unsigned int height,
 		       unsigned int stride)
@@ -923,14 +1071,32 @@ static void fill_tiles(const struct util_format_info *info, void *planes[3],
 	case DRM_FORMAT_BGRX1010102:
 		return fill_tiles_rgb32(info, planes[0],
 					width, height, stride);
+
+	case DRM_FORMAT_XRGB16161616F:
+	case DRM_FORMAT_XBGR16161616F:
+	case DRM_FORMAT_ARGB16161616F:
+	case DRM_FORMAT_ABGR16161616F:
+		return fill_tiles_rgb16fp(info, planes[0],
+					  width, height, stride);
 	}
 }
 
-static void fill_plain(void *planes[3],
+static void fill_plain(const struct util_format_info *info, void *planes[3],
 		       unsigned int height,
 		       unsigned int stride)
 {
-	memset(planes[0], 0x77, stride * height);
+	switch (info->format) {
+	case DRM_FORMAT_XRGB16161616F:
+	case DRM_FORMAT_XBGR16161616F:
+	case DRM_FORMAT_ARGB16161616F:
+	case DRM_FORMAT_ABGR16161616F:
+		/* 0x3838 = 0.5273 */
+		memset(planes[0], 0x38, stride * height);
+		break;
+	default:
+		memset(planes[0], 0x77, stride * height);
+		break;
+	}
 }
 
 static void fill_gradient_rgb32(const struct util_rgb_info *rgb,
@@ -961,6 +1127,34 @@ static void fill_gradient_rgb32(const struct util_rgb_info *rgb,
 	}
 }
 
+static void fill_gradient_rgb16fp(const struct util_rgb_info *rgb,
+				  void *mem,
+				  unsigned int width, unsigned int height,
+				  unsigned int stride)
+{
+	int i, j;
+
+	for (i = 0; i < height / 2; i++) {
+		uint64_t *row = mem;
+
+		for (j = 0; j < width / 2; j++) {
+			uint64_t value = MAKE_RGBA10FP16(rgb, j & 0x3ff, j & 0x3ff, j & 0x3ff, 0);
+			row[2*j] = row[2*j+1] = value;
+		}
+		mem += stride;
+	}
+
+	for (; i < height; i++) {
+		uint64_t *row = mem;
+
+		for (j = 0; j < width / 2; j++) {
+			uint64_t value = MAKE_RGBA10FP16(rgb, j & 0x3fc, j & 0x3fc, j & 0x3fc, 0);
+			row[2*j] = row[2*j+1] = value;
+		}
+		mem += stride;
+	}
+}
+
 /* The gradient pattern creates two horizontal gray gradients, split
  * into two halves. The top half has 10bpc precision, the bottom half
  * has 8bpc precision. When using with a 10bpc fb format, there are 3
@@ -1009,6 +1203,13 @@ static void fill_gradient(const struct util_format_info *info, void *planes[3],
 	case DRM_FORMAT_BGRX1010102:
 		return fill_gradient_rgb32(&info->rgb, planes[0],
 					   width, height, stride);
+
+	case DRM_FORMAT_XRGB16161616F:
+	case DRM_FORMAT_XBGR16161616F:
+	case DRM_FORMAT_ARGB16161616F:
+	case DRM_FORMAT_ABGR16161616F:
+		return fill_gradient_rgb16fp(&info->rgb, planes[0],
+					     width, height, stride);
 	}
 }
 
@@ -1042,7 +1243,7 @@ void util_fill_pattern(uint32_t format, enum util_fill_pattern pattern,
 		return fill_smpte(info, planes, width, height, stride);
 
 	case UTIL_PATTERN_PLAIN:
-		return fill_plain(planes, height, stride);
+		return fill_plain(info, planes, height, stride);
 
 	case UTIL_PATTERN_GRADIENT:
 		return fill_gradient(info, planes, width, height, stride);
commit e5442195fbe01df92658d7df7030507e3dc6c89e
Author: Ilia Mirkin <[email protected]>
Date:   Sun Feb 4 18:39:15 2018 -0500

    util: add gradient pattern
    
    The idea is to have a horizontal pattern split into two with the top and
    bottom halves having different precision. This allows one to see whether
    10bpc support is working properly or not, as there are many pieces to
    the puzzle beyond the basic format support (gamma ramps, bpc encodings,
    etc).
    
    This is really only useful on 10bpc formats, but we also add support for
    8bpc formats to ease testing. In the future, this could be applied to
    16bpc formats as well.
    
    Signed-off-by: Ilia Mirkin <[email protected]>
    Reviewed-by: Emil Velikov <[email protected]>

diff --git a/tests/util/pattern.c b/tests/util/pattern.c
index 8bdebd2c..ff110fd7 100644
--- a/tests/util/pattern.c
+++ b/tests/util/pattern.c
@@ -60,9 +60,11 @@ struct color_yuv {
 	  .u = MAKE_YUV_601_U(r, g, b), \
 	  .v = MAKE_YUV_601_V(r, g, b) }
 
-static inline uint32_t shiftcolor(const struct util_color_component *comp,
+/* This function takes 8-bit color values */
+static inline uint32_t shiftcolor8(const struct util_color_component *comp,
 				  uint32_t value)
 {
+	value &= 0xff;
 	/* Fill the low bits with the high bits. */
 	value = (value << 8) | value;
 	/* Shift down to remove unwanted low bits */
@@ -71,11 +73,30 @@ static inline uint32_t shiftcolor(const struct util_color_component *comp,
 	return value << comp->offset;
 }
 
+/* This function takes 10-bit color values */
+static inline uint32_t shiftcolor10(const struct util_color_component *comp,
+				    uint32_t value)
+{
+	value &= 0x3ff;
+	/* Fill the low bits with the high bits. */
+	value = (value << 6) | (value >> 4);
+	/* Shift down to remove unwanted low bits */
+	value = value >> (16 - comp->length);
+	/* Shift back up to where the value should be */
+	return value << comp->offset;
+}
+
+#define MAKE_RGBA10(rgb, r, g, b, a) \
+	(shiftcolor10(&(rgb)->red, (r)) | \
+	 shiftcolor10(&(rgb)->green, (g)) | \
+	 shiftcolor10(&(rgb)->blue, (b)) | \
+	 shiftcolor10(&(rgb)->alpha, (a)))
+
 #define MAKE_RGBA(rgb, r, g, b, a) \
-	(shiftcolor(&(rgb)->red, (r)) | \
-	 shiftcolor(&(rgb)->green, (g)) | \
-	 shiftcolor(&(rgb)->blue, (b)) | \
-	 shiftcolor(&(rgb)->alpha, (a)))
+	(shiftcolor8(&(rgb)->red, (r)) | \
+	 shiftcolor8(&(rgb)->green, (g)) | \
+	 shiftcolor8(&(rgb)->blue, (b)) | \
+	 shiftcolor8(&(rgb)->alpha, (a)))
 
 #define MAKE_RGB24(rgb, r, g, b) \
 	{ .value = MAKE_RGBA(rgb, r, g, b, 0) }
@@ -912,6 +933,85 @@ static void fill_plain(void *planes[3],
 	memset(planes[0], 0x77, stride * height);
 }
 
+static void fill_gradient_rgb32(const struct util_rgb_info *rgb,
+				void *mem,
+				unsigned int width, unsigned int height,
+				unsigned int stride)
+{
+	int i, j;
+
+	for (i = 0; i < height / 2; i++) {
+		uint32_t *row = mem;
+
+		for (j = 0; j < width / 2; j++) {
+			uint32_t value = MAKE_RGBA10(rgb, j & 0x3ff, j & 0x3ff, j & 0x3ff, 0);
+			row[2*j] = row[2*j+1] = value;
+		}
+		mem += stride;
+	}
+
+	for (; i < height; i++) {
+		uint32_t *row = mem;
+
+		for (j = 0; j < width / 2; j++) {
+			uint32_t value = MAKE_RGBA10(rgb, j & 0x3fc, j & 0x3fc, j & 0x3fc, 0);
+			row[2*j] = row[2*j+1] = value;
+		}
+		mem += stride;
+	}
+}
+
+/* The gradient pattern creates two horizontal gray gradients, split
+ * into two halves. The top half has 10bpc precision, the bottom half
+ * has 8bpc precision. When using with a 10bpc fb format, there are 3
+ * possible outcomes:
+ *
+ *  - Pixel data is encoded as 8bpc to the display, no dithering. This
+ *    would lead to the top and bottom halves looking identical.
+ *
+ *  - Pixel data is encoded as 8bpc to the display, with dithering. This
+ *    would lead to there being a visible difference between the two halves,
+ *    but the top half would look a little speck-y due to the dithering.
+ *
+ *  - Pixel data is encoded at 10bpc+ to the display (which implies
+ *    the display is able to show this level of depth). This should
+ *    lead to the top half being a very clean gradient, and visibly different
+ *    from the bottom half.
+ *
+ * Once we support additional fb formats, this approach could be extended
+ * to distinguish even higher bpc precisions.
+ *
+ * Note that due to practical size considerations, for the screens
+ * where this matters, the pattern actually emits stripes 2-pixels
+ * wide for each gradient color. Otherwise the difference may be a bit
+ * hard to notice.
+ */
+static void fill_gradient(const struct util_format_info *info, void *planes[3],
+			  unsigned int width, unsigned int height,
+			  unsigned int stride)
+{
+	switch (info->format) {
+	case DRM_FORMAT_ARGB8888:
+	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_ABGR8888:
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_RGBA8888:
+	case DRM_FORMAT_RGBX8888:
+	case DRM_FORMAT_BGRA8888:
+	case DRM_FORMAT_BGRX8888:
+	case DRM_FORMAT_ARGB2101010:
+	case DRM_FORMAT_XRGB2101010:
+	case DRM_FORMAT_ABGR2101010:
+	case DRM_FORMAT_XBGR2101010:
+	case DRM_FORMAT_RGBA1010102:
+	case DRM_FORMAT_RGBX1010102:
+	case DRM_FORMAT_BGRA1010102:
+	case DRM_FORMAT_BGRX1010102:
+		return fill_gradient_rgb32(&info->rgb, planes[0],
+					   width, height, stride);
+	}
+}
+
 /*
  * util_fill_pattern - Fill a buffer with a test pattern
  * @format: Pixel format
@@ -944,6 +1044,9 @@ void util_fill_pattern(uint32_t format, enum util_fill_pattern pattern,
 	case UTIL_PATTERN_PLAIN:
 		return fill_plain(planes, height, stride);
 
+	case UTIL_PATTERN_GRADIENT:
+		return fill_gradient(info, planes, width, height, stride);
+
 	default:
 		printf("Error: unsupported test pattern %u.\n", pattern);
 		break;
diff --git a/tests/util/pattern.h b/tests/util/pattern.h
index c8708d02..feac903a 100644
--- a/tests/util/pattern.h
+++ b/tests/util/pattern.h
@@ -32,6 +32,7 @@ enum util_fill_pattern {
 	UTIL_PATTERN_TILES,
 	UTIL_PATTERN_PLAIN,
 	UTIL_PATTERN_SMPTE,
+	UTIL_PATTERN_GRADIENT,
 };
 
 void util_fill_pattern(uint32_t format, enum util_fill_pattern pattern,
commit 32401fe5ce2bce0dc38098582c4b06a58a99c930
Author: Ilia Mirkin <[email protected]>
Date:   Thu Nov 23 13:51:45 2017 -0500

    util: fix MAKE_RGBA macro for 10bpp modes
    
    We need to shift the values up, otherwise we'd end up with a negative
    shift. This works for up-to 16-bit components, which is fine for now.
    
    Signed-off-by: Ilia Mirkin <[email protected]>
    Reviewed-by: Emil Velikov <[email protected]>

diff --git a/tests/util/pattern.c b/tests/util/pattern.c
index c84fee5a..8bdebd2c 100644
--- a/tests/util/pattern.c
+++ b/tests/util/pattern.c
@@ -60,11 +60,22 @@ struct color_yuv {
 	  .u = MAKE_YUV_601_U(r, g, b), \
 	  .v = MAKE_YUV_601_V(r, g, b) }
 
+static inline uint32_t shiftcolor(const struct util_color_component *comp,
+				  uint32_t value)
+{
+	/* Fill the low bits with the high bits. */
+	value = (value << 8) | value;
+	/* Shift down to remove unwanted low bits */
+	value = value >> (16 - comp->length);
+	/* Shift back up to where the value should be */
+	return value << comp->offset;
+}
+
 #define MAKE_RGBA(rgb, r, g, b, a) \
-	((((r) >> (8 - (rgb)->red.length)) << (rgb)->red.offset) | \
-	 (((g) >> (8 - (rgb)->green.length)) << (rgb)->green.offset) | \
-	 (((b) >> (8 - (rgb)->blue.length)) << (rgb)->blue.offset) | \
-	 (((a) >> (8 - (rgb)->alpha.length)) << (rgb)->alpha.offset))
+	(shiftcolor(&(rgb)->red, (r)) | \
+	 shiftcolor(&(rgb)->green, (g)) | \
+	 shiftcolor(&(rgb)->blue, (b)) | \
+	 shiftcolor(&(rgb)->alpha, (a)))
 
 #define MAKE_RGB24(rgb, r, g, b) \
 	{ .value = MAKE_RGBA(rgb, r, g, b, 0) }
commit 8d27deced945374813e11e32630bef8bb3d41529
Author: Ilia Mirkin <[email protected]>
Date:   Sun Jun 2 17:51:08 2019 -0400

    util: add C8 format, support it with SMPTE pattern
    
    This also adds a helper to generate a color LUT, which has to be used in
    conjunction with the C8 indexed format.
    
    Signed-off-by: Ilia Mirkin <[email protected]>
    Acked-by: Emil Velikov <[email protected]>

diff --git a/tests/util/format.c b/tests/util/format.c
index 15ac5e1e..e52213bb 100644
--- a/tests/util/format.c
+++ b/tests/util/format.c
@@ -39,6 +39,8 @@
 	.yuv = { (order), (xsub), (ysub), (chroma_stride) }
 
 static const struct util_format_info format_info[] = {
+	/* Indexed */
+	{ DRM_FORMAT_C8, "C8" },
 	/* YUV packed */
 	{ DRM_FORMAT_UYVY, "UYVY", MAKE_YUV_INFO(YUV_YCbCr | YUV_CY, 2, 2, 2) },
 	{ DRM_FORMAT_VYUY, "VYUY", MAKE_YUV_INFO(YUV_YCrCb | YUV_CY, 2, 2, 2) },
diff --git a/tests/util/pattern.c b/tests/util/pattern.c
index 9fa0a417..c84fee5a 100644
--- a/tests/util/pattern.c
+++ b/tests/util/pattern.c
@@ -457,6 +457,79 @@ static void fill_smpte_rgb32(const struct util_rgb_info *rgb, void *mem,
 	}
 }
 
+static void fill_smpte_c8(void *mem, unsigned int width, unsigned int height,
+			  unsigned int stride)
+{
+	unsigned int x;
+	unsigned int y;
+
+	for (y = 0; y < height * 6 / 9; ++y) {
+		for (x = 0; x < width; ++x)
+			((uint8_t *)mem)[x] = x * 7 / width;
+		mem += stride;
+	}
+
+	for (; y < height * 7 / 9; ++y) {
+		for (x = 0; x < width; ++x)
+			((uint8_t *)mem)[x] = 7 + (x * 7 / width);
+		mem += stride;
+	}
+
+	for (; y < height; ++y) {
+		for (x = 0; x < width * 5 / 7; ++x)
+			((uint8_t *)mem)[x] =
+				14 + (x * 4 / (width * 5 / 7));
+		for (; x < width * 6 / 7; ++x)
+			((uint8_t *)mem)[x] =
+				14 + ((x - width * 5 / 7) * 3
+					      / (width / 7) + 4);
+		for (; x < width; ++x)
+			((uint8_t *)mem)[x] = 14 + 7;
+		mem += stride;
+	}
+}
+
+void util_smpte_c8_gamma(unsigned size, struct drm_color_lut *lut)
+{
+	if (size < 7 + 7 + 8) {
+		printf("Error: gamma too small: %d < %d\n", size, 7 + 7 + 8);
+		return;
+	}
+	memset(lut, size * sizeof(struct drm_color_lut), 0);
+
+#define FILL_COLOR(idx, r, g, b) \
+	lut[idx].red = (r) << 8; \
+	lut[idx].green = (g) << 8; \
+	lut[idx].blue = (b) << 8
+
+	FILL_COLOR( 0, 192, 192, 192);	/* grey */
+	FILL_COLOR( 1, 192, 192, 0  );	/* yellow */
+	FILL_COLOR( 2, 0,   192, 192);	/* cyan */
+	FILL_COLOR( 3, 0,   192, 0  );	/* green */
+	FILL_COLOR( 4, 192, 0,   192);	/* magenta */
+	FILL_COLOR( 5, 192, 0,   0  );	/* red */
+	FILL_COLOR( 6, 0,   0,   192);	/* blue */
+
+	FILL_COLOR( 7, 0,   0,   192);	/* blue */
+	FILL_COLOR( 8, 19,  19,  19 );	/* black */
+	FILL_COLOR( 9, 192, 0,   192);	/* magenta */
+	FILL_COLOR(10, 19,  19,  19 );	/* black */
+	FILL_COLOR(11, 0,   192, 192);	/* cyan */
+	FILL_COLOR(12, 19,  19,  19 );	/* black */
+	FILL_COLOR(13, 192, 192, 192);	/* grey */
+
+	FILL_COLOR(14, 0,   33,  76);	/* in-phase */
+	FILL_COLOR(15, 255, 255, 255);	/* super white */
+	FILL_COLOR(16, 50,  0,   106);	/* quadrature */
+	FILL_COLOR(17, 19,  19,  19);	/* black */
+	FILL_COLOR(18, 9,   9,   9);	/* 3.5% */
+	FILL_COLOR(19, 19,  19,  19);	/* 7.5% */
+	FILL_COLOR(20, 29,  29,  29);	/* 11.5% */
+	FILL_COLOR(21, 19,  19,  19);	/* black */
+
+#undef FILL_COLOR
+}
+
 static void fill_smpte(const struct util_format_info *info, void *planes[3],
 		       unsigned int width, unsigned int height,
 		       unsigned int stride)
@@ -464,6 +537,8 @@ static void fill_smpte(const struct util_format_info *info, void *planes[3],
 	unsigned char *u, *v;
 
 	switch (info->format) {
+	case DRM_FORMAT_C8:
+		return fill_smpte_c8(planes[0], width, height, stride);
 	case DRM_FORMAT_UYVY:
 	case DRM_FORMAT_VYUY:
 	case DRM_FORMAT_YUYV:
diff --git a/tests/util/pattern.h b/tests/util/pattern.h
index d5c4260c..c8708d02 100644
--- a/tests/util/pattern.h
+++ b/tests/util/pattern.h
@@ -26,6 +26,8 @@
 #ifndef UTIL_PATTERN_H
 #define UTIL_PATTERN_H
 
+#include <drm/drm_mode.h>
+
 enum util_fill_pattern {
 	UTIL_PATTERN_TILES,
 	UTIL_PATTERN_PLAIN,
@@ -36,4 +38,6 @@ void util_fill_pattern(uint32_t format, enum util_fill_pattern pattern,
 		       void *planes[3], unsigned int width,
 		       unsigned int height, unsigned int stride);
 
+void util_smpte_c8_gamma(unsigned size, struct drm_color_lut *lut);
+
 #endif /* UTIL_PATTERN_H */


--