[igt-dev] [PATCH i-g-t 4/4] tests/kms_legacy_colorkey: Add a real colorkey test

Ville Syrjala ville.syrjala at linux.intel.com
Fri Jan 31 20:15:54 UTC 2020


From: Ville Syrjälä <ville.syrjala at linux.intel.com>

Let's test that the colorkeying really works in hardware. As per
the usual pattern we generate a reference fb with software,
reproduce the same visual effect with the hardware keying, and
compare the crc between the two.

Some difficulty comes from having to use different formats for
each involved plane, and we can't always use the LUT to chop off
extra bits because C8 might be involved.

v2: Use igt_format_is_yuv() so that we may
    try to test more than one yuv format

Signed-off-by: Ville Syrjälä <ville.syrjala at linux.intel.com>
---
 tests/Makefile.sources      |   1 +
 tests/kms_legacy_colorkey.c | 808 ++++++++++++++++++++++++++++++++++++
 tests/meson.build           |   1 +
 3 files changed, 810 insertions(+)
 create mode 100644 tests/kms_legacy_colorkey.c

diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index 7452688e5616..6df5d021aaf3 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -56,6 +56,7 @@ TESTS_progs = \
 	kms_hdmi_inject \
 	kms_invalid_dotclock \
 	kms_lease \
+	kms_legacy_colorkey \
 	kms_legacy_colorkey_basic \
 	kms_mmap_write_crc \
 	kms_panel_fitting \
diff --git a/tests/kms_legacy_colorkey.c b/tests/kms_legacy_colorkey.c
new file mode 100644
index 000000000000..6699b6198fff
--- /dev/null
+++ b/tests/kms_legacy_colorkey.c
@@ -0,0 +1,808 @@
+/*
+ * Copyright © 2019 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "igt.h"
+#include "i915_drm.h"
+#include <errno.h>
+
+
+IGT_TEST_DESCRIPTION("Check that colorkeying works.");
+
+#define LUT_MASK 0xf800
+/* We need lower precision with fp16 for some reason */
+#define LUT_MASK_FP16 0xf000
+
+struct color {
+	float r, g, b;
+};
+
+struct rect {
+	int x1, y1, x2, y2;
+};
+
+struct plane {
+	igt_plane_t *plane;
+	uint32_t format;
+	struct igt_fb fb;
+	struct rect rect;
+	const struct color *color;
+};
+
+static int rect_width(const struct rect *r)
+{
+	return r->x2 - r->x1;
+}
+
+static int rect_height(const struct rect *r)
+{
+	return r->y2 - r->y1;
+}
+
+static void rect_init(struct rect *r,
+		      int x, int y, int w, int h)
+{
+	r->x1 = x;
+	r->y1 = y;
+	r->x2 = x + w;
+	r->y2 = y + h;
+}
+
+static void rect_translate(struct rect *r,
+			   int x, int y)
+{
+	r->x1 += x;
+	r->y1 += y;
+	r->x2 += x;
+	r->y2 += y;
+}
+
+static void rect_intersect(struct rect *r,
+			   const struct rect *a,
+			   const struct rect *b)
+{
+	r->x1 = max(a->x1, b->x1);
+	r->y1 = max(a->y1, b->y1);
+	r->x2 = min(a->x2, b->x2);
+	r->y2 = min(a->y2, b->y2);
+}
+
+struct data {
+	igt_display_t display;
+	int drm_fd;
+	enum pipe pipe;
+	uint32_t devid;
+	igt_output_t *output;
+	struct plane primary, sprite;
+	struct igt_fb ref_fb;
+	igt_pipe_crc_t *pipe_crc;
+	igt_crc_t ref_crc, crc;
+};
+
+static void rgb_to_ycbcr(struct color *yuv_color,
+			 const struct color *rgb_color)
+{
+	struct igt_vec4 rgb, yuv;
+	struct igt_mat4 m;
+
+	rgb.d[0] = rgb_color->r * 0xff + 0.5f;
+	rgb.d[1] = rgb_color->g * 0xff + 0.5f;
+	rgb.d[2] = rgb_color->b * 0xff + 0.5f;
+	rgb.d[3] = 1.0f;
+
+	m = igt_rgb_to_ycbcr_matrix(DRM_FORMAT_XRGB8888,
+				    DRM_FORMAT_YUYV,
+				    IGT_COLOR_YCBCR_BT709,
+				    IGT_COLOR_YCBCR_LIMITED_RANGE);
+
+	yuv = igt_matrix_transform(&m, &rgb);
+
+	yuv_color->r = yuv.d[2];
+	yuv_color->g = yuv.d[0];
+	yuv_color->b = yuv.d[1];
+}
+
+static uint32_t ckey_val(uint32_t format, const struct color *color)
+{
+	struct color yuv;
+	uint32_t r, g, b;
+
+	if (igt_format_is_yuv(format)) {
+		rgb_to_ycbcr(&yuv, color);
+
+		r = yuv.r + 0.5f;
+		g = yuv.g + 0.5f;
+		b = yuv.b + 0.5f;
+	} else if (format == DRM_FORMAT_C8) {
+		r = color->r * 0x7 + 0.5f;
+		g = color->g * 0x7 + 0.5f;
+		b = color->b * 0x3 + 0.5f;
+
+		r = g = b = r << 5 | g << 2 | b;
+	} else if (format == DRM_FORMAT_RGB565) {
+		r = color->r * 0x1f + 0.5f;
+		g = color->g * 0x3f + 0.5f;
+		b = color->b * 0x1f + 0.5f;
+
+		r = (r << 3) | (r >> 2);
+		g = (g << 2) | (g >> 4);
+		b = (b << 3) | (b >> 2);
+	} else {
+		r = color->r * 0xff + 0.5f;
+		g = color->g * 0xff + 0.5f;
+		b = color->b * 0xff + 0.5f;
+	}
+
+	igt_debug("key %f %f %f -> %x %x %x\n",
+		  color->r, color->g, color->b, r, g, b);
+
+	return r << 16 | g << 8 | b;
+}
+
+static uint32_t dst_key_mask(uint32_t format)
+{
+	uint32_t r, g, b;
+
+	switch (format) {
+	case DRM_FORMAT_C8:
+		r = g = b = 0xff;
+		break;
+	case DRM_FORMAT_XRGB1555:
+		r = g = b = 0xf8;
+		break;
+	case DRM_FORMAT_RGB565:
+		r = b = 0xf8;
+		g = 0xfc;
+		break;
+	default:
+		r = g = b = 0xff;
+		break;
+	}
+	igt_debug("mask %x %x %x\n", r, g, b);
+
+	return r << 16 | g << 8 | b;
+}
+
+static uint32_t src_key_mask(void)
+{
+	bool r = true, g = true, b = true;
+
+	return r << 26 | g << 25 | b << 24;
+}
+
+static bool set_ckey(struct data *data, uint32_t flags,
+		     uint32_t min, uint32_t max, uint32_t mask)
+{
+	struct drm_intel_sprite_colorkey ckey = {
+		.plane_id = data->sprite.plane->drm_plane->plane_id,
+		.flags = flags,
+		.min_value = min,
+		.max_value = max,
+		.channel_mask = mask,
+	};
+
+	return drmCommandWrite(data->drm_fd,
+			       DRM_I915_SET_SPRITE_COLORKEY, &ckey,
+			       sizeof(ckey)) == 0;
+}
+
+static void paint_keyholes(struct data *data,
+			   struct igt_fb *fb,
+			   const struct rect key_rect[],
+			   int num_key_rect,
+			   const struct color *key_color)
+{
+	cairo_t *cr;
+
+	cr = igt_get_cairo_ctx(data->drm_fd, fb);
+
+	for (int i = 0; i < num_key_rect; i++) {
+		igt_paint_color(cr,
+				key_rect[i].x1, key_rect[i].y1,
+				rect_width(&key_rect[i]),
+				rect_height(&key_rect[i]),
+				key_color->r, key_color->g, key_color->b);
+	}
+
+	igt_put_cairo_ctx(data->drm_fd, fb, cr);
+}
+
+static void create_color_fb(struct data *data, struct plane *plane)
+{
+	igt_create_color_fb(data->drm_fd,
+			    rect_width(&plane->rect),
+			    rect_height(&plane->rect),
+			    plane->format, DRM_FORMAT_MOD_LINEAR,
+			    plane->color->r,
+			    plane->color->g,
+			    plane->color->b,
+			    &plane->fb);
+}
+
+static void create_color_pattern_fb(struct data *data, struct plane *plane)
+{
+	igt_create_color_pattern_fb(data->drm_fd,
+				    rect_width(&plane->rect),
+				    rect_height(&plane->rect),
+				    plane->format, DRM_FORMAT_MOD_LINEAR,
+				    plane->color->r,
+				    plane->color->g,
+				    plane->color->b,
+				    &plane->fb);
+}
+
+static void blit(struct data *data, cairo_t *cr,
+		 struct igt_fb *src_fb,
+		 const struct rect *src_rect,
+		 const struct rect rect[],
+		 int num_rect)
+{
+	cairo_surface_t *surface;
+
+	surface = igt_get_cairo_surface(data->drm_fd, src_fb);
+
+	for (int i = 0; i < num_rect; i++) {
+		struct rect r;
+		int sx, sy;
+
+		rect_intersect(&r, &rect[i], src_rect);
+
+		sx = r.x1 - src_rect->x1;
+		sy = r.y1 - src_rect->y1;
+
+		cairo_set_source_surface(cr, surface,
+					 r.x1 - sx, r.y1 - sy);
+		cairo_rectangle(cr, r.x1, r.y1,
+				rect_width(&r), rect_height(&r));
+		cairo_fill (cr);
+	}
+
+	cairo_surface_destroy(surface);
+}
+
+static void create_dst_key_ref_fb(struct data *data,
+				  struct plane *primary,
+				  struct plane *sprite,
+				  const struct rect key_rect[],
+				  int num_key_rect,
+				  struct igt_fb *fb)
+{
+	cairo_t *cr;
+
+	igt_create_fb(data->drm_fd,
+		      primary->fb.width, primary->fb.height,
+		      primary->fb.drm_format, DRM_FORMAT_MOD_LINEAR, fb);
+
+	cr = igt_get_cairo_ctx(data->drm_fd, fb);
+
+	/* start with primary fb */
+	blit(data, cr, &primary->fb, &primary->rect,
+	     &primary->rect, 1);
+
+	/* cover keyholes with sprite fb */
+	blit(data, cr, &sprite->fb, &sprite->rect,
+	     key_rect, num_key_rect);
+
+	igt_put_cairo_ctx(data->drm_fd, fb, cr);
+}
+
+static void create_src_key_ref_fb(struct data *data,
+				  struct plane *primary,
+				  struct plane *sprite,
+				  const struct rect key_rect[],
+				  int num_key_rect,
+				  struct igt_fb *fb)
+{
+	cairo_t *cr;
+
+	igt_create_fb(data->drm_fd,
+		      primary->fb.width, primary->fb.height,
+		      primary->fb.drm_format, DRM_FORMAT_MOD_LINEAR, fb);
+
+	cr = igt_get_cairo_ctx(data->drm_fd, fb);
+
+	/* start with primary fb */
+	blit(data, cr, &primary->fb, &primary->rect,
+	     &primary->rect, 1);
+
+	/* overlay the full sprite fb */
+	blit(data, cr, &sprite->fb, &sprite->rect,
+	     &sprite->rect, 1);
+
+	/* cover keyholes again with primary fb */
+	blit(data, cr, &primary->fb, &primary->rect,
+	     key_rect, num_key_rect);
+
+	igt_put_cairo_ctx(data->drm_fd, fb, cr);
+}
+
+static void set_ycbcr_encoding(igt_plane_t *plane)
+{
+	enum igt_color_encoding e = IGT_COLOR_YCBCR_BT709;
+	enum igt_color_range r = IGT_COLOR_YCBCR_LIMITED_RANGE;
+
+	igt_plane_try_prop_enum(plane, IGT_PLANE_COLOR_ENCODING,
+				igt_color_encoding_to_str(e));
+
+	igt_plane_try_prop_enum(plane, IGT_PLANE_COLOR_RANGE,
+				igt_color_range_to_str(r));
+}
+
+static void set_legacy_lut(struct data *data, uint16_t mask)
+{
+	igt_pipe_t *pipe_obj = &data->display.pipes[data->pipe];
+	drmModeCrtc *crtc;
+	struct drm_color_lut *lut;
+	int i, lut_size;
+
+	crtc = drmModeGetCrtc(data->drm_fd, pipe_obj->crtc_id);
+	lut_size = crtc->gamma_size;
+	drmModeFreeCrtc(crtc);
+
+	lut = calloc(lut_size, sizeof(lut[0]));
+
+	for (i = 0; i < lut_size; i++) {
+		uint16_t v = (i * 0xffff / (lut_size - 1)) & mask;
+
+		lut[i].red = v;
+		lut[i].green = v;
+		lut[i].blue = v;
+	}
+
+	igt_pipe_obj_replace_prop_blob(pipe_obj, IGT_CRTC_GAMMA_LUT, lut,
+				       lut_size * sizeof(lut[0]));
+	free(lut);
+}
+
+static void set_c8_legacy_lut(struct data *data, uint16_t mask)
+{
+	igt_pipe_t *pipe_obj = &data->display.pipes[data->pipe];
+	drmModeCrtc *crtc;
+	struct drm_color_lut *lut;
+	int i, lut_size;
+
+	crtc = drmModeGetCrtc(data->drm_fd, pipe_obj->crtc_id);
+	lut_size = crtc->gamma_size;
+	drmModeFreeCrtc(crtc);
+
+	lut = calloc(lut_size, sizeof(lut[0]));
+
+	/* igt_fb uses RGB332 for C8 */
+	for (i = 0; i < lut_size; i++) {
+		lut[i].red = (((i & 0xe0) >> 5) * 0xffff / 0x7) & mask;
+		lut[i].green = (((i & 0x1c) >> 2) * 0xffff / 0x7) & mask;
+		lut[i].blue = (((i & 0x03) >> 0) * 0xffff / 0x3) & mask;
+	}
+
+	igt_pipe_obj_replace_prop_blob(pipe_obj, IGT_CRTC_GAMMA_LUT, lut,
+				       lut_size * sizeof(lut[0]));
+	free(lut);
+}
+
+static void init_plane(struct data *data,
+		       struct plane *plane, uint32_t type)
+{
+	igt_pipe_t *pipe_obj = &data->display.pipes[data->pipe];
+
+	plane->plane = igt_pipe_get_plane_type(pipe_obj, type);
+
+	igt_require(igt_plane_has_format_mod(plane->plane, plane->format, DRM_FORMAT_MOD_LINEAR));
+}
+
+static void configure_plane(struct data *data, struct plane *plane)
+{
+	igt_plane_set_fb(plane->plane, &plane->fb);
+	if (igt_format_is_yuv(plane->format))
+		set_ycbcr_encoding(plane->plane);
+	igt_plane_set_position(plane->plane,
+			       plane->rect.x1, plane->rect.y1);
+}
+
+static void do_test_dst_colorkey(struct data *data)
+{
+	drmModeModeInfo *mode;
+	static const struct color key_color = {
+		.r = 1.0f,
+		.g = 0.125f,
+		.b = 0.250f,
+	};
+	static const struct color sprite_color = {
+		.r = 0.5f,
+		.g = 0.0f,
+		.b = 1.0f,
+	};
+	static const struct color sprite_color_c8 = {
+		.r = 0.125,
+		.g = 0.125,
+		.b = 0.0,
+	};
+	static const struct color primary_color = {
+		.r = 1.0f,
+		.g = 0.5f,
+		.b = 0.0f,
+	};
+	struct rect key_rect[5];
+	struct igt_fb temp_fb = {};
+	bool supported = false;
+
+	igt_output_set_pipe(data->output, data->pipe);
+
+	data->pipe_crc = igt_pipe_crc_new(data->drm_fd, data->pipe,
+					  INTEL_PIPE_CRC_SOURCE_AUTO);
+
+	mode = igt_output_get_mode(data->output);
+
+	init_plane(data, &data->primary, DRM_PLANE_TYPE_PRIMARY);
+	rect_init(&data->primary.rect, 0, 0,
+		  mode->hdisplay, mode->vdisplay);
+
+	init_plane(data, &data->sprite, DRM_PLANE_TYPE_OVERLAY);
+	rect_init(&data->sprite.rect,
+		  ALIGN(mode->hdisplay / 3, 2),
+		  ALIGN(mode->vdisplay / 4, 2),
+		  ALIGN(mode->hdisplay / 3, 2),
+		  ALIGN(mode->vdisplay / 2, 2));
+
+	/*
+	 * Straddle each sprite corner with keyholes
+	 * and put one extra keyhole in the middle.
+	 */
+	for (int i = 0; i < ARRAY_SIZE(key_rect); i++)
+		rect_init(&key_rect[i], 0, 0, 64, 64);
+
+	rect_translate(&key_rect[0],
+		       data->sprite.rect.x1 - 32,
+		       data->sprite.rect.y1 - 32);
+	rect_translate(&key_rect[1],
+		       data->sprite.rect.x2 - 32,
+		       data->sprite.rect.y1 - 32);
+	rect_translate(&key_rect[2],
+		       data->sprite.rect.x1 - 32,
+		       data->sprite.rect.y2 - 32);
+	rect_translate(&key_rect[3],
+		       data->sprite.rect.x2 - 32,
+		       data->sprite.rect.y2 - 32);
+	rect_translate(&key_rect[4],
+		       ALIGN((data->sprite.rect.x1 + data->sprite.rect.x2) / 2 - 32, 2),
+		       ALIGN((data->sprite.rect.y1 + data->sprite.rect.y2) / 2 - 32, 2));
+
+	/* select colors to use */
+	data->primary.color = &primary_color;
+	if (data->primary.format == DRM_FORMAT_C8)
+		data->sprite.color = &sprite_color_c8;
+	else
+		data->sprite.color = &sprite_color;
+
+	/* create framebuffers */
+	if (igt_format_is_yuv(data->primary.format))
+		create_color_fb(data, &data->primary);
+	else
+		create_color_pattern_fb(data, &data->primary);
+	paint_keyholes(data, &data->primary.fb,
+		       key_rect, ARRAY_SIZE(key_rect), &key_color);
+
+	if (data->primary.format == DRM_FORMAT_C8 ||
+	    igt_format_is_yuv(data->primary.format) ||
+	    igt_format_is_yuv(data->sprite.format))
+		create_color_fb(data, &data->sprite);
+	else
+		create_color_pattern_fb(data, &data->sprite);
+
+	create_dst_key_ref_fb(data, &data->primary, &data->sprite,
+			      key_rect, ARRAY_SIZE(key_rect),
+			      &data->ref_fb);
+
+	/*
+	 * Need some fb to light up the crtc, but it can't be
+	 * C8 since we've not yet set the LUT.
+	 */
+	if (!data->display.is_atomic &&
+	    data->primary.format == DRM_FORMAT_C8) {
+		igt_create_fb(data->drm_fd,
+			      mode->hdisplay, mode->vdisplay,
+			      DRM_FORMAT_XRGB8888,
+			      DRM_FORMAT_MOD_LINEAR, &temp_fb);
+		igt_plane_set_fb(data->primary.plane, &temp_fb);
+		igt_display_commit2(&data->display, COMMIT_LEGACY);
+	}
+
+	if (data->primary.format == DRM_FORMAT_C8)
+		set_c8_legacy_lut(data, LUT_MASK);
+	else if (data->primary.format == DRM_FORMAT_XBGR16161616F)
+		set_legacy_lut(data, LUT_MASK_FP16);
+	else
+		set_legacy_lut(data, LUT_MASK);
+
+	/* collect reference crc */
+	igt_plane_set_fb(data->primary.plane, &data->ref_fb);
+
+	igt_display_commit2(&data->display, data->display.is_atomic ?
+			    COMMIT_ATOMIC : COMMIT_UNIVERSAL);
+	igt_pipe_crc_collect_crc(data->pipe_crc, &data->ref_crc);
+
+	/* collect test crc */
+	supported = set_ckey(data, I915_SET_COLORKEY_DESTINATION,
+			     ckey_val(data->primary.format, &key_color), 0,
+			     dst_key_mask(data->primary.format));
+	if (supported) {
+		configure_plane(data, &data->primary);
+		configure_plane(data, &data->sprite);
+
+		igt_display_commit2(&data->display, data->display.is_atomic ?
+				    COMMIT_ATOMIC : COMMIT_UNIVERSAL);
+		igt_pipe_crc_collect_crc(data->pipe_crc, &data->crc);
+	}
+
+	/* cleanup */
+	igt_plane_set_fb(data->primary.plane, NULL);
+	igt_plane_set_fb(data->sprite.plane, NULL);
+	igt_display_commit2(&data->display, data->display.is_atomic ?
+			    COMMIT_ATOMIC : COMMIT_UNIVERSAL);
+
+	igt_assert(set_ckey(data, 0, 0, 0, 0));
+
+	igt_output_set_pipe(data->output, PIPE_ANY);
+
+	igt_remove_fb(data->drm_fd, &data->ref_fb);
+	igt_remove_fb(data->drm_fd, &data->sprite.fb);
+	igt_remove_fb(data->drm_fd, &data->primary.fb);
+	igt_remove_fb(data->drm_fd, &temp_fb);
+
+	igt_pipe_crc_free(data->pipe_crc);
+
+	igt_require(supported);
+	if (supported)
+		igt_assert_crc_equal(&data->ref_crc, &data->crc);
+}
+
+static void do_test_src_colorkey(struct data *data)
+{
+	drmModeModeInfo *mode;
+	static const struct color key_color = {
+		.r = 1.0f,
+		.g = 0.250f,
+		.b = 0.125f,
+	};
+	static const struct color sprite_color = {
+		.r = 0.5f,
+		.g = 0.0f,
+		.b = 1.0f,
+	};
+	static const struct color primary_color = {
+		.r = 1.0f,
+		.g = 0.5f,
+		.b = 0.0f,
+	};
+	struct rect key_rect[5];
+	uint32_t ckey, min, max;
+	bool supported = false;
+
+	igt_output_set_pipe(data->output, data->pipe);
+
+	data->pipe_crc = igt_pipe_crc_new(data->drm_fd, data->pipe,
+					  INTEL_PIPE_CRC_SOURCE_AUTO);
+
+	mode = igt_output_get_mode(data->output);
+
+	init_plane(data, &data->primary, DRM_PLANE_TYPE_PRIMARY);
+	rect_init(&data->primary.rect, 0, 0,
+		  mode->hdisplay, mode->vdisplay);
+
+	init_plane(data, &data->sprite, DRM_PLANE_TYPE_OVERLAY);
+	rect_init(&data->sprite.rect,
+		  ALIGN(mode->hdisplay / 3, 2),
+		  ALIGN(mode->vdisplay / 4, 2),
+		  ALIGN(mode->hdisplay / 3, 2),
+		  ALIGN(mode->vdisplay / 2, 2));
+
+	/* Keyholes in sprite corners and middle */
+	for (int i = 0; i < ARRAY_SIZE(key_rect); i++)
+		rect_init(&key_rect[i], 0, 0, 64, 64);
+
+	rect_translate(&key_rect[0],
+		       0, 0);
+	rect_translate(&key_rect[1],
+		       rect_width(&data->sprite.rect) - 64, 0);
+	rect_translate(&key_rect[2],
+		       0,
+		       rect_height(&data->sprite.rect) - 64);
+	rect_translate(&key_rect[3],
+		       rect_width(&data->sprite.rect) - 64,
+		       rect_height(&data->sprite.rect) - 64);
+	rect_translate(&key_rect[4],
+		       ALIGN(rect_width(&data->sprite.rect) / 2 - 32, 2),
+		       ALIGN(rect_height(&data->sprite.rect) / 2 - 32, 2));
+
+	/* select colors */
+	data->primary.color = &primary_color;
+	data->sprite.color = &sprite_color;
+
+	/* create framebuffers */
+	if (igt_format_is_yuv(data->primary.format))
+		create_color_fb(data, &data->primary);
+	else
+		create_color_pattern_fb(data, &data->primary);
+
+	if (igt_format_is_yuv(data->sprite.format))
+		create_color_fb(data, &data->sprite);
+	else
+		create_color_fb(data, &data->sprite);
+	paint_keyholes(data, &data->sprite.fb,
+		       key_rect, ARRAY_SIZE(key_rect),
+		       &key_color);
+
+	/*
+	 * Translate keyholes to primary coordinate space so
+	 * they appear in the correct spot in the reference fb
+	 */
+	for (int i = 0; i < ARRAY_SIZE(key_rect); i++)
+		rect_translate(&key_rect[i],
+			       data->sprite.rect.x1,
+			       data->sprite.rect.y1);
+
+	create_src_key_ref_fb(data, &data->primary, &data->sprite,
+			      key_rect, ARRAY_SIZE(key_rect),
+			      &data->ref_fb);
+
+	/* collect reference crc */
+	igt_plane_set_fb(data->primary.plane, &data->ref_fb);
+	if (!data->display.is_atomic)
+		igt_display_commit2(&data->display, COMMIT_LEGACY);
+
+	if (data->sprite.format == DRM_FORMAT_XBGR16161616F)
+		set_legacy_lut(data, LUT_MASK_FP16);
+	else if (data->sprite.format != DRM_FORMAT_C8)
+		set_legacy_lut(data, LUT_MASK);
+
+	igt_display_commit2(&data->display, data->display.is_atomic ?
+			    COMMIT_ATOMIC : COMMIT_UNIVERSAL);
+	igt_pipe_crc_collect_crc(data->pipe_crc, &data->ref_crc);
+
+	/* collect test crc */
+	ckey = ckey_val(data->sprite.format, &key_color);
+	if (igt_format_is_yuv(data->sprite.format)) {
+		min = ckey - 0x020202;
+		max = ckey + 0x010101;
+	} else {
+		min = ckey;
+		max = 0;
+	}
+	igt_assert(set_ckey(data, I915_SET_COLORKEY_SOURCE,
+			    min, max, src_key_mask()));
+
+	if (data->sprite.format == DRM_FORMAT_C8)
+		set_c8_legacy_lut(data, 0xff00);
+
+	configure_plane(data, &data->primary);
+	configure_plane(data, &data->sprite);
+
+	supported = igt_display_try_commit2(&data->display, data->display.is_atomic ?
+					    COMMIT_ATOMIC : COMMIT_UNIVERSAL) == 0;
+	if (supported)
+		igt_pipe_crc_collect_crc(data->pipe_crc, &data->crc);
+
+	/* cleanup */
+	igt_plane_set_fb(data->primary.plane, NULL);
+	igt_plane_set_fb(data->sprite.plane, NULL);
+	igt_display_commit2(&data->display, data->display.is_atomic ?
+			    COMMIT_ATOMIC : COMMIT_UNIVERSAL);
+
+	igt_assert(set_ckey(data, 0, 0, 0, 0));
+
+	igt_output_set_pipe(data->output, PIPE_ANY);
+
+	igt_remove_fb(data->drm_fd, &data->ref_fb);
+	igt_remove_fb(data->drm_fd, &data->sprite.fb);
+	igt_remove_fb(data->drm_fd, &data->primary.fb);
+
+	igt_pipe_crc_free(data->pipe_crc);
+
+	igt_require(supported);
+	if (supported)
+		igt_assert_crc_equal(&data->ref_crc, &data->crc);
+}
+
+static bool test_dst_colorkey(struct data *data)
+{
+	for_each_pipe_with_valid_output(&data->display,
+					data->pipe, data->output) {
+		do_test_dst_colorkey(data);
+		return true;
+	}
+
+	return false;
+}
+
+static bool test_src_colorkey(struct data *data)
+{
+	for_each_pipe_with_valid_output(&data->display,
+					data->pipe, data->output) {
+		do_test_src_colorkey(data);
+		return true;
+	}
+
+	return false;
+}
+
+static struct data data;
+
+static const uint32_t formats[] = {
+	DRM_FORMAT_C8,
+	DRM_FORMAT_RGB565,
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_XBGR2101010,
+	DRM_FORMAT_XBGR16161616F,
+	DRM_FORMAT_YUYV,
+#if 0
+	/*
+	 * Chroma upsampling makes these
+	 * impossible to to test with crcs :(
+	 */
+	DRM_FORMAT_NV12,
+	DRM_FORMAT_P010,
+#endif
+};
+
+igt_main
+{
+	igt_skip_on_simulation();
+
+	igt_fixture {
+		data.drm_fd = drm_open_driver_master(DRIVER_INTEL);
+
+		data.devid = intel_get_drm_devid(data.drm_fd);
+
+		kmstest_set_vt_graphics_mode();
+
+		igt_display_require(&data.display, data.drm_fd);
+	}
+
+	/*
+	 * FIXME test that key mask/min/max have the
+	 * expected effect beyond the basics
+	 */
+
+	for (int i = 0; i < ARRAY_SIZE(formats); i++) {
+		if (formats[i] != DRM_FORMAT_C8 &&
+		    !igt_fb_supported_format(formats[i]))
+			continue;
+
+		data.primary.format = DRM_FORMAT_XRGB8888;
+		data.sprite.format = formats[i];
+
+		igt_subtest_f("src-colorkey-%s",
+			      igt_format_str(data.sprite.format)) {
+			igt_require(test_src_colorkey(&data));
+		}
+
+		data.primary.format = formats[i];
+		data.sprite.format = DRM_FORMAT_XRGB8888;
+
+		igt_subtest_f("dst-colorkey-%s",
+			      igt_format_str(data.primary.format)) {
+			igt_require(test_dst_colorkey(&data));
+		}
+	}
+
+	igt_fixture
+		igt_display_fini(&data.display);
+}
diff --git a/tests/meson.build b/tests/meson.build
index 481282487e15..fe4c5107524c 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -40,6 +40,7 @@ test_progs = [
 	'kms_hdmi_inject',
 	'kms_invalid_dotclock',
 	'kms_lease',
+	'kms_legacy_colorkey',
 	'kms_legacy_colorkey_basic',
 	'kms_mmap_write_crc',
 	'kms_panel_fitting',
-- 
2.24.1



More information about the igt-dev mailing list