All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH i-g-t v3 1/4] chamelium: Calculate CRC from framebuffer instead of hardcoding it
@ 2017-07-05  8:04 Paul Kocialkowski
  2017-07-05  8:04 ` [PATCH i-g-t v3 2/4] tests/ chamelium: Remove the frame dump tests Paul Kocialkowski
                   ` (5 more replies)
  0 siblings, 6 replies; 57+ messages in thread
From: Paul Kocialkowski @ 2017-07-05  8:04 UTC (permalink / raw)
  To: intel-gfx; +Cc: Lyude

This introduces CRC calculation for reference frames, instead of using
hardcoded values for them. The rendering of reference frames may differ
from machine to machine, especially due to font rendering, and the
frame itself may change with subsequent IGT changes.

These differences would cause the CRC checks to fail on different
setups. This allows them to pass regardless of the setup.

Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
---
 lib/igt_chamelium.c | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/igt_chamelium.h |   5 ++
 tests/chamelium.c   |  76 ++++++-------------------
 3 files changed, 183 insertions(+), 58 deletions(-)

diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
index bff08c0e..b9d80b6b 100644
--- a/lib/igt_chamelium.c
+++ b/lib/igt_chamelium.c
@@ -94,6 +94,14 @@ struct chamelium_frame_dump {
 	struct chamelium_port *port;
 };
 
+struct chamelium_fb_crc {
+	int fd;
+	struct igt_fb *fb;
+
+	pthread_t thread_id;
+	igt_crc_t *ret;
+};
+
 struct chamelium {
 	xmlrpc_env env;
 	xmlrpc_client *client;
@@ -1003,6 +1011,158 @@ int chamelium_get_frame_limit(struct chamelium *chamelium,
 	return ret;
 }
 
+static uint32_t chamelium_xrgb_hash16(unsigned char *buffer, int width,
+				      int height, int k, int m)
+{
+	unsigned char r, g, b;
+	uint64_t sum = 0;
+	uint64_t count = 0;
+	uint64_t value;
+	uint32_t hash;
+	int index;
+	int i;
+
+	for (i=0; i < width * height; i++) {
+		if ((i % m) != k)
+			continue;
+
+		index = i * 4;
+
+		r = buffer[index + 2];
+		g = buffer[index + 1];
+		b = buffer[index + 0];
+
+		value = r | (g << 8) | (b << 16);
+		sum += ++count * value;
+	}
+
+	hash = ((sum >> 0) ^ (sum >> 16) ^ (sum >> 32) ^ (sum >> 48)) & 0xffff;
+
+	return hash;
+}
+
+/**
+ * chamelium_calculate_fb_crc:
+ * @fd: The drm file descriptor
+ * @fb: The framebuffer to calculate the CRC for
+ *
+ * Calculates a CRC for the provided framebuffer, the same way as the Chamelium.
+ * This calculates the CRC in a non-threaded fashion.
+ *
+ * Returns: The calculated CRC
+ */
+igt_crc_t *chamelium_calculate_fb_crc(int fd, struct igt_fb *fb)
+{
+	igt_crc_t *ret;
+	cairo_t *cr;
+	cairo_surface_t *fb_surface;
+	unsigned char *buffer;
+	int n = 4;
+	int w, h;
+	int i, j;
+
+	ret = calloc(1, sizeof(igt_crc_t));
+
+	/* Get the cairo surface for the framebuffer */
+	cr = igt_get_cairo_ctx(fd, fb);
+	fb_surface = cairo_get_target(cr);
+	cairo_surface_reference(fb_surface);
+	cairo_destroy(cr);
+
+	buffer = cairo_image_surface_get_data(fb_surface);
+	w = fb->width;
+	h = fb->height;
+
+	for (i = 0; i < n; i++) {
+		j = n - i - 1;
+		ret->crc[i] = chamelium_xrgb_hash16(buffer, w, h, j, n);
+	}
+
+	ret->n_words = n;
+	cairo_surface_destroy(fb_surface);
+
+	return ret;
+}
+
+static void *chamelium_calculate_fb_crc_thread(void *data)
+{
+	struct chamelium_fb_crc *fb_crc = (struct chamelium_fb_crc *) data;
+	cairo_t *cr;
+	cairo_surface_t *fb_surface;
+	unsigned char *buffer;
+	int n = 4;
+	int w, h;
+	int i, j;
+
+	/* Get the cairo surface for the framebuffer */
+	cr = igt_get_cairo_ctx(fb_crc->fd, fb_crc->fb);
+	fb_surface = cairo_get_target(cr);
+	cairo_surface_reference(fb_surface);
+	cairo_destroy(cr);
+
+	buffer = cairo_image_surface_get_data(fb_surface);
+	w = fb_crc->fb->width;
+	h = fb_crc->fb->height;
+
+	for (i = 0; i < n; i++) {
+		j = n - i - 1;
+		fb_crc->ret->crc[i] = chamelium_xrgb_hash16(buffer, w, h, j, n);
+	}
+
+	fb_crc->ret->n_words = n;
+	cairo_surface_destroy(fb_surface);
+
+	return NULL;
+}
+
+/**
+ * chamelium_calculate_fb_crc_launch:
+ * @fd: The drm file descriptor
+ * @fb: The framebuffer to calculate the CRC for
+ *
+ * Launches the CRC calculation for the provided framebuffer, the same way as
+ * the Chamelium. This calculates the CRC in a threaded fashion.
+ * Thread-related information is returned and should be passed to a subsequent
+ * call to chamelium_calculate_fb_crc_result. It should not be freed.
+ *
+ * Returns: An intermediate structure with thread-related information
+ */
+struct chamelium_fb_crc *chamelium_calculate_fb_crc_launch(int fd,
+							   struct igt_fb *fb)
+{
+	struct chamelium_fb_crc *fb_crc;
+
+	fb_crc = calloc(1, sizeof(struct chamelium_fb_crc));
+	fb_crc->ret = calloc(1, sizeof(igt_crc_t));
+	fb_crc->fd = fd;
+	fb_crc->fb = fb;
+
+	pthread_create(&fb_crc->thread_id, NULL,
+		       chamelium_calculate_fb_crc_thread, fb_crc);
+
+	return fb_crc;
+}
+
+/**
+ * chamelium_calculate_fb_crc_result:
+ * @fb_crc: An intermediate structure with thread-related information
+ *
+ * Provides the result for the previously-launched CRC calculation.
+ *
+ * Returns: The calculated CRC
+ */
+igt_crc_t *chamelium_calculate_fb_crc_result(struct chamelium_fb_crc *fb_crc)
+{
+	igt_crc_t *ret;
+
+	pthread_join(fb_crc->thread_id, NULL);
+
+	ret = fb_crc->ret;
+	free(fb_crc);
+
+	return ret;
+}
+
 static unsigned int chamelium_get_port_type(struct chamelium *chamelium,
 					    struct chamelium_port *port)
 {
diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
index 81322ad2..e51cf4f9 100644
--- a/lib/igt_chamelium.h
+++ b/lib/igt_chamelium.h
@@ -36,6 +36,7 @@
 struct chamelium;
 struct chamelium_port;
 struct chamelium_frame_dump;
+struct chamelium_fb_crc;
 
 struct chamelium *chamelium_init(int drm_fd);
 void chamelium_deinit(struct chamelium *chamelium);
@@ -92,6 +93,10 @@ struct chamelium_frame_dump *chamelium_port_dump_pixels(struct chamelium *chamel
 							struct chamelium_port *port,
 							int x, int y,
 							int w, int h);
+igt_crc_t *chamelium_calculate_fb_crc(int fd, struct igt_fb *fb);
+struct chamelium_fb_crc *chamelium_calculate_fb_crc_launch(int fd,
+							   struct igt_fb *fb);
+igt_crc_t *chamelium_calculate_fb_crc_result(struct chamelium_fb_crc *fb_crc);
 int chamelium_get_captured_frame_count(struct chamelium *chamelium);
 int chamelium_get_frame_limit(struct chamelium *chamelium,
 			      struct chamelium_port *port,
diff --git a/tests/chamelium.c b/tests/chamelium.c
index e3067664..3fd2b02c 100644
--- a/tests/chamelium.c
+++ b/tests/chamelium.c
@@ -49,43 +49,6 @@ typedef struct {
 #define HPD_TOGGLE_COUNT_VGA 5
 #define HPD_TOGGLE_COUNT_DP_HDMI 15
 
-/* Pre-calculated CRCs for the pattern fb, for all the modes in the default
- * chamelium edid
- */
-struct crc_entry {
-	int width;
-	int height;
-	igt_crc_t crc;
-};
-
-#define CRC_ENTRY(w_, h_, ...) \
-	{ w_, h_, { .n_words = 4, .crc = { __VA_ARGS__ } } }
-
-static const struct crc_entry pattern_fb_crcs[] = {
-	CRC_ENTRY(1920, 1080, 0xf859, 0xa751, 0x8c81, 0x45a1),
-	CRC_ENTRY(1280,  720, 0xcec2, 0x4246, 0x6cfd, 0xeb43),
-	CRC_ENTRY(1024,  768, 0x85e5, 0xf0cd, 0xafe3, 0x7f18),
-	CRC_ENTRY( 800,  600, 0x6b39, 0x32b6, 0x831a, 0xb03e),
-	CRC_ENTRY( 640,  480, 0xa121, 0x2473, 0xb150, 0x8c47),
-};
-#undef CRC_ENTRY
-
-static const igt_crc_t *
-get_precalculated_crc(struct chamelium_port *port, int w, int h)
-{
-	int i;
-	const struct crc_entry *entry;
-
-	for (i = 0; i < ARRAY_SIZE(pattern_fb_crcs); i++) {
-		entry = &pattern_fb_crcs[i];
-
-		if (entry->width == w && entry->height == h)
-			return &entry->crc;
-	}
-
-	return NULL;
-}
-
 static void
 require_connector_present(data_t *data, unsigned int type)
 {
@@ -424,7 +387,8 @@ test_display_crc_single(data_t *data, struct chamelium_port *port)
 	igt_output_t *output;
 	igt_plane_t *primary;
 	igt_crc_t *crc;
-	const igt_crc_t *expected_crc;
+	igt_crc_t *expected_crc;
+	struct chamelium_fb_crc *fb_crc;
 	struct igt_fb fb;
 	drmModeModeInfo *mode;
 	drmModeConnector *connector;
@@ -447,24 +411,21 @@ test_display_crc_single(data_t *data, struct chamelium_port *port)
 						    0, 0, 0, &fb);
 		igt_assert(fb_id > 0);
 
-		enable_output(data, port, output, mode, &fb);
+		fb_crc = chamelium_calculate_fb_crc_launch(data->drm_fd, &fb);
 
-		expected_crc = get_precalculated_crc(port,
-						     mode->hdisplay,
-						     mode->vdisplay);
-		if (!expected_crc) {
-			igt_warn("No precalculated CRC found for %dx%d, skipping CRC check\n",
-				 mode->hdisplay, mode->vdisplay);
-			goto next;
-		}
+		enable_output(data, port, output, mode, &fb);
 
 		igt_debug("Testing single CRC fetch\n");
+
 		crc = chamelium_get_crc_for_area(data->chamelium, port,
 						 0, 0, 0, 0);
+
+		expected_crc = chamelium_calculate_fb_crc_result(fb_crc);
+
 		igt_assert_crc_equal(crc, expected_crc);
+		free(expected_crc);
 		free(crc);
 
-next:
 		disable_output(data, port, output);
 		igt_remove_fb(data->drm_fd, &fb);
 	}
@@ -480,7 +441,8 @@ test_display_crc_multiple(data_t *data, struct chamelium_port *port)
 	igt_output_t *output;
 	igt_plane_t *primary;
 	igt_crc_t *crc;
-	const igt_crc_t *expected_crc;
+	igt_crc_t *expected_crc;
+	struct chamelium_fb_crc *fb_crc;
 	struct igt_fb fb;
 	drmModeModeInfo *mode;
 	drmModeConnector *connector;
@@ -503,15 +465,9 @@ test_display_crc_multiple(data_t *data, struct chamelium_port *port)
 						    0, 0, 0, &fb);
 		igt_assert(fb_id > 0);
 
-		enable_output(data, port, output, mode, &fb);
+		fb_crc = chamelium_calculate_fb_crc_launch(data->drm_fd, &fb);
 
-		expected_crc = get_precalculated_crc(port, mode->hdisplay,
-						     mode->vdisplay);
-		if (!expected_crc) {
-			igt_warn("No precalculated CRC found for %dx%d, skipping CRC check\n",
-				 mode->hdisplay, mode->vdisplay);
-			goto next;
-		}
+		enable_output(data, port, output, mode, &fb);
 
 		/* We want to keep the display running for a little bit, since
 		 * there's always the potential the driver isn't able to keep
@@ -522,11 +478,15 @@ test_display_crc_multiple(data_t *data, struct chamelium_port *port)
 						   &captured_frame_count);
 
 		igt_debug("Captured %d frames\n", captured_frame_count);
+
+		expected_crc = chamelium_calculate_fb_crc_result(fb_crc);
+
 		for (j = 0; j < captured_frame_count; j++)
 			igt_assert_crc_equal(&crc[j], expected_crc);
+
+		free(expected_crc);
 		free(crc);
 
-next:
 		disable_output(data, port, output);
 		igt_remove_fb(data->drm_fd, &fb);
 	}
-- 
2.13.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH i-g-t v3 2/4] tests/ chamelium: Remove the frame dump tests
  2017-07-05  8:04 [PATCH i-g-t v3 1/4] chamelium: Calculate CRC from framebuffer instead of hardcoding it Paul Kocialkowski
@ 2017-07-05  8:04 ` Paul Kocialkowski
  2017-07-05 20:53   ` Lyude Paul
  2017-07-05  8:04 ` [PATCH i-g-t v3 3/4] lib/igt_chamelium: Add support for dumping chamelium frames to a png Paul Kocialkowski
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 57+ messages in thread
From: Paul Kocialkowski @ 2017-07-05  8:04 UTC (permalink / raw)
  To: intel-gfx; +Cc: Lyude

The frame dump tests provide no additional functionality over CRC tests
and are considerably slower. Thus, these tests should be considered as
poorer duplicates and removed.

Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
---
 tests/chamelium.c | 53 -----------------------------------------------------
 1 file changed, 53 deletions(-)

diff --git a/tests/chamelium.c b/tests/chamelium.c
index 3fd2b02c..5cf8b3af 100644
--- a/tests/chamelium.c
+++ b/tests/chamelium.c
@@ -496,53 +496,6 @@ test_display_crc_multiple(data_t *data, struct chamelium_port *port)
 }
 
 static void
-test_display_frame_dump(data_t *data, struct chamelium_port *port)
-{
-	igt_display_t display;
-	igt_output_t *output;
-	igt_plane_t *primary;
-	struct igt_fb fb;
-	struct chamelium_frame_dump *frame;
-	drmModeModeInfo *mode;
-	drmModeConnector *connector;
-	int fb_id, i, j;
-
-	reset_state(data, port);
-
-	output = prepare_output(data, &display, port);
-	connector = chamelium_port_get_connector(data->chamelium, port, false);
-	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-	igt_assert(primary);
-
-	for (i = 0; i < connector->count_modes; i++) {
-		mode = &connector->modes[i];
-		fb_id = igt_create_color_pattern_fb(data->drm_fd,
-						    mode->hdisplay, mode->vdisplay,
-						    DRM_FORMAT_XRGB8888,
-						    LOCAL_DRM_FORMAT_MOD_NONE,
-						    0, 0, 0, &fb);
-		igt_assert(fb_id > 0);
-
-		enable_output(data, port, output, mode, &fb);
-
-		igt_debug("Reading frame dumps from Chamelium...\n");
-		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 5);
-		for (j = 0; j < 5; j++) {
-			frame = chamelium_read_captured_frame(
-			    data->chamelium, j);
-			chamelium_assert_frame_eq(data->chamelium, frame, &fb);
-			chamelium_destroy_frame_dump(frame);
-		}
-
-		disable_output(data, port, output);
-		igt_remove_fb(data->drm_fd, &fb);
-	}
-
-	drmModeFreeConnector(connector);
-	igt_display_fini(&display);
-}
-
-static void
 test_hpd_without_ddc(data_t *data, struct chamelium_port *port)
 {
 	struct udev_monitor *mon = igt_watch_hotplug();
@@ -695,9 +648,6 @@ igt_main
 
 		connector_subtest("dp-crc-multiple", DisplayPort)
 			test_display_crc_multiple(&data, port);
-
-		connector_subtest("dp-frame-dump", DisplayPort)
-			test_display_frame_dump(&data, port);
 	}
 
 	igt_subtest_group {
@@ -752,9 +702,6 @@ igt_main
 
 		connector_subtest("hdmi-crc-multiple", HDMIA)
 			test_display_crc_multiple(&data, port);
-
-		connector_subtest("hdmi-frame-dump", HDMIA)
-			test_display_frame_dump(&data, port);
 	}
 
 	igt_subtest_group {
-- 
2.13.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH i-g-t v3 3/4] lib/igt_chamelium: Add support for dumping chamelium frames to a png
  2017-07-05  8:04 [PATCH i-g-t v3 1/4] chamelium: Calculate CRC from framebuffer instead of hardcoding it Paul Kocialkowski
  2017-07-05  8:04 ` [PATCH i-g-t v3 2/4] tests/ chamelium: Remove the frame dump tests Paul Kocialkowski
@ 2017-07-05  8:04 ` Paul Kocialkowski
  2017-07-05 21:16   ` Lyude Paul
  2017-07-05  8:04 ` [PATCH i-g-t v3 4/4] chamelium: Dump obtained and reference frames to png on crc error Paul Kocialkowski
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 57+ messages in thread
From: Paul Kocialkowski @ 2017-07-05  8:04 UTC (permalink / raw)
  To: intel-gfx; +Cc: Lyude

This introduces a chamelium_write_frame_to_png function that saves a
Chamelium frame dump to a png file. This should be useful when a frame
comparison with a reference fails.

Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
---
 lib/igt_chamelium.c | 40 ++++++++++++++++++++++++++++++++++++++++
 lib/igt_chamelium.h |  3 +++
 2 files changed, 43 insertions(+)

diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
index b9d80b6b..ef51ef68 100644
--- a/lib/igt_chamelium.c
+++ b/lib/igt_chamelium.c
@@ -979,6 +979,46 @@ void chamelium_assert_frame_eq(const struct chamelium *chamelium,
 }
 
 /**
+ * chamelium_write_frame_to_png:
+ * @chamelium: The Chamelium instance to use
+ * @dump: The chamelium frame dump to save
+ * @filename: The file name to dump the frame to
+ *
+ * Writes a chamelium frame dump into a png image stored at @filename.
+ */
+void chamelium_write_frame_to_png(const struct chamelium *chamelium,
+				  const struct chamelium_frame_dump *dump,
+				  const char *filename)
+{
+	cairo_surface_t *dump_surface;
+	pixman_image_t *image_bgr;
+	pixman_image_t *image_argb;
+	int w = dump->width, h = dump->height;
+	uint32_t *bits_bgr = (uint32_t *) dump->bgr;
+	unsigned char *bits_argb;
+	cairo_status_t status;
+
+	image_bgr = pixman_image_create_bits(
+	    PIXMAN_b8g8r8, w, h, bits_bgr,
+	    PIXMAN_FORMAT_BPP(PIXMAN_b8g8r8) / 8 * w);
+	image_argb = convert_frame_format(image_bgr, PIXMAN_x8r8g8b8);
+	pixman_image_unref(image_bgr);
+
+	bits_argb = (unsigned char *) pixman_image_get_data(image_argb);
+
+	dump_surface = cairo_image_surface_create_for_data(
+	    bits_argb, CAIRO_FORMAT_ARGB32, w, h,
+	    PIXMAN_FORMAT_BPP(PIXMAN_x8r8g8b8) / 8 * w);
+
+	status = cairo_surface_write_to_png(dump_surface, filename);
+	cairo_surface_destroy(dump_surface);
+
+	pixman_image_unref(image_argb);
+
+	igt_assert(status == CAIRO_STATUS_SUCCESS);
+}
+
+/**
  * chamelium_get_frame_limit:
  * @chamelium: The Chamelium instance to use
  * @port: The port to check the frame limit on
diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
index e51cf4f9..908e03d1 100644
--- a/lib/igt_chamelium.h
+++ b/lib/igt_chamelium.h
@@ -105,6 +105,9 @@ int chamelium_get_frame_limit(struct chamelium *chamelium,
 void chamelium_assert_frame_eq(const struct chamelium *chamelium,
 			       const struct chamelium_frame_dump *dump,
 			       struct igt_fb *fb);
+void chamelium_write_frame_to_png(const struct chamelium *chamelium,
+				  const struct chamelium_frame_dump *dump,
+				  const char *filename);
 void chamelium_destroy_frame_dump(struct chamelium_frame_dump *dump);
 
 #endif /* IGT_CHAMELIUM_H */
-- 
2.13.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH i-g-t v3 4/4] chamelium: Dump obtained and reference frames to png on crc error
  2017-07-05  8:04 [PATCH i-g-t v3 1/4] chamelium: Calculate CRC from framebuffer instead of hardcoding it Paul Kocialkowski
  2017-07-05  8:04 ` [PATCH i-g-t v3 2/4] tests/ chamelium: Remove the frame dump tests Paul Kocialkowski
  2017-07-05  8:04 ` [PATCH i-g-t v3 3/4] lib/igt_chamelium: Add support for dumping chamelium frames to a png Paul Kocialkowski
@ 2017-07-05  8:04 ` Paul Kocialkowski
  2017-07-05 21:44   ` Lyude Paul
  2017-07-05 20:34 ` [PATCH i-g-t v3 1/4] chamelium: Calculate CRC from framebuffer instead of hardcoding it Lyude Paul
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 57+ messages in thread
From: Paul Kocialkowski @ 2017-07-05  8:04 UTC (permalink / raw)
  To: intel-gfx; +Cc: Lyude

When a CRC comparison error occurs, it is quite useful to get a dump
of both the frame obtained from the chamelium and the reference in order
to compare them.

This implements the frame dump, with a configurable path that enables
the use of this feature.

Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
---
 lib/igt_chamelium.c |  21 +++++++++++
 lib/igt_chamelium.h |   1 +
 lib/igt_debugfs.c   |  20 ++++++++++
 lib/igt_debugfs.h   |   1 +
 tests/chamelium.c   | 104 ++++++++++++++++++++--------------------------------
 5 files changed, 82 insertions(+), 65 deletions(-)

diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
index ef51ef68..9aca6842 100644
--- a/lib/igt_chamelium.c
+++ b/lib/igt_chamelium.c
@@ -57,6 +57,7 @@
  * |[<!-- language="plain" -->
  *	[Chamelium]
  *	URL=http://chameleon:9992 # The URL used for connecting to the Chamelium's RPC server
+ *	FrameDumpPath=/tmp # The path to dump frames that fail comparison checks
  *
  *	# The rest of the sections are used for defining connector mappings.
  *	# This is required so any tests using the Chamelium know which connector
@@ -115,11 +116,26 @@ struct chamelium {
 	struct chamelium_edid *edids;
 	struct chamelium_port *ports;
 	int port_count;
+
+	char *frame_dump_path;
 };
 
 static struct chamelium *cleanup_instance;
 
 /**
+ * chamelium_get_frame_dump_path:
+ * @chamelium: The Chamelium instance to use
+ *
+ * Retrieves the path to dump frames to.
+ *
+ * Returns: a string with the frame dump path
+ */
+char *chamelium_get_frame_dump_path(struct chamelium *chamelium)
+{
+	return chamelium->frame_dump_path;
+}
+
+/**
  * chamelium_get_ports:
  * @chamelium: The Chamelium instance to use
  * @count: Where to store the number of ports
@@ -1338,6 +1354,11 @@ static bool chamelium_read_config(struct chamelium *chamelium, int drm_fd)
 		return false;
 	}
 
+	chamelium->frame_dump_path = g_key_file_get_string(igt_key_file,
+							   "Chamelium",
+							   "FrameDumpPath",
+							    &error);
+
 	return chamelium_read_port_mappings(chamelium, drm_fd);
 }
 
diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
index 908e03d1..aa881971 100644
--- a/lib/igt_chamelium.h
+++ b/lib/igt_chamelium.h
@@ -42,6 +42,7 @@ struct chamelium *chamelium_init(int drm_fd);
 void chamelium_deinit(struct chamelium *chamelium);
 void chamelium_reset(struct chamelium *chamelium);
 
+char *chamelium_get_frame_dump_path(struct chamelium *chamelium);
 struct chamelium_port **chamelium_get_ports(struct chamelium *chamelium,
 					    int *count);
 unsigned int chamelium_port_get_type(const struct chamelium_port *port);
diff --git a/lib/igt_debugfs.c b/lib/igt_debugfs.c
index 80f25c61..dcb4e0a7 100644
--- a/lib/igt_debugfs.c
+++ b/lib/igt_debugfs.c
@@ -282,6 +282,26 @@ bool igt_debugfs_search(int device, const char *filename, const char *substring)
  */
 
 /**
+ * igt_check_crc_equal:
+ * @a: first pipe CRC value
+ * @b: second pipe CRC value
+ *
+ * Compares two CRC values and return whether they match.
+ *
+ * Returns: A boolean indicating whether the CRC values match
+ */
+bool igt_check_crc_equal(const igt_crc_t *a, const igt_crc_t *b)
+{
+	int i;
+
+	for (i = 0; i < a->n_words; i++)
+		if (a->crc[i] != b->crc[i])
+			return false;
+
+	return true;
+}
+
+/**
  * igt_assert_crc_equal:
  * @a: first pipe CRC value
  * @b: second pipe CRC value
diff --git a/lib/igt_debugfs.h b/lib/igt_debugfs.h
index 7b846a83..2695cbda 100644
--- a/lib/igt_debugfs.h
+++ b/lib/igt_debugfs.h
@@ -113,6 +113,7 @@ enum intel_pipe_crc_source {
         INTEL_PIPE_CRC_SOURCE_MAX,
 };
 
+bool igt_check_crc_equal(const igt_crc_t *a, const igt_crc_t *b);
 void igt_assert_crc_equal(const igt_crc_t *a, const igt_crc_t *b);
 char *igt_crc_to_string(igt_crc_t *crc);
 
diff --git a/tests/chamelium.c b/tests/chamelium.c
index 5cf8b3af..3d95c05c 100644
--- a/tests/chamelium.c
+++ b/tests/chamelium.c
@@ -381,7 +381,7 @@ disable_output(data_t *data,
 }
 
 static void
-test_display_crc_single(data_t *data, struct chamelium_port *port)
+test_display_crc(data_t *data, struct chamelium_port *port, int count)
 {
 	igt_display_t display;
 	igt_output_t *output;
@@ -390,9 +390,14 @@ test_display_crc_single(data_t *data, struct chamelium_port *port)
 	igt_crc_t *expected_crc;
 	struct chamelium_fb_crc *fb_crc;
 	struct igt_fb fb;
+	struct chamelium_frame_dump *frame;
 	drmModeModeInfo *mode;
 	drmModeConnector *connector;
-	int fb_id, i;
+	int fb_id, i, j, captured_frame_count;
+	const char *connector_name;
+	char *frame_dump_path;
+	char path[PATH_MAX];
+	bool eq;
 
 	reset_state(data, port);
 
@@ -401,6 +406,9 @@ test_display_crc_single(data_t *data, struct chamelium_port *port)
 	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
 	igt_assert(primary);
 
+	connector_name = kmstest_connector_type_str(connector->connector_type);
+	frame_dump_path = chamelium_get_frame_dump_path(data->chamelium);
+
 	for (i = 0; i < connector->count_modes; i++) {
 		mode = &connector->modes[i];
 		fb_id = igt_create_color_pattern_fb(data->drm_fd,
@@ -415,74 +423,40 @@ test_display_crc_single(data_t *data, struct chamelium_port *port)
 
 		enable_output(data, port, output, mode, &fb);
 
-		igt_debug("Testing single CRC fetch\n");
-
-		crc = chamelium_get_crc_for_area(data->chamelium, port,
-						 0, 0, 0, 0);
-
-		expected_crc = chamelium_calculate_fb_crc_result(fb_crc);
-
-		igt_assert_crc_equal(crc, expected_crc);
-		free(expected_crc);
-		free(crc);
-
-		disable_output(data, port, output);
-		igt_remove_fb(data->drm_fd, &fb);
-	}
-
-	drmModeFreeConnector(connector);
-	igt_display_fini(&display);
-}
-
-static void
-test_display_crc_multiple(data_t *data, struct chamelium_port *port)
-{
-	igt_display_t display;
-	igt_output_t *output;
-	igt_plane_t *primary;
-	igt_crc_t *crc;
-	igt_crc_t *expected_crc;
-	struct chamelium_fb_crc *fb_crc;
-	struct igt_fb fb;
-	drmModeModeInfo *mode;
-	drmModeConnector *connector;
-	int fb_id, i, j, captured_frame_count;
+		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, count);
+		crc = chamelium_read_captured_crcs(data->chamelium,
+						   &captured_frame_count);
 
-	reset_state(data, port);
+		igt_assert(captured_frame_count == count);
 
-	output = prepare_output(data, &display, port);
-	connector = chamelium_port_get_connector(data->chamelium, port, false);
-	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-	igt_assert(primary);
+		igt_debug("Captured %d frames\n", captured_frame_count);
 
-	for (i = 0; i < connector->count_modes; i++) {
-		mode = &connector->modes[i];
-		fb_id = igt_create_color_pattern_fb(data->drm_fd,
-						    mode->hdisplay,
-						    mode->vdisplay,
-						    DRM_FORMAT_XRGB8888,
-						    LOCAL_DRM_FORMAT_MOD_NONE,
-						    0, 0, 0, &fb);
-		igt_assert(fb_id > 0);
+		expected_crc = chamelium_calculate_fb_crc_result(fb_crc);
 
-		fb_crc = chamelium_calculate_fb_crc_launch(data->drm_fd, &fb);
+		for (j = 0; j < captured_frame_count; j++) {
+			eq = igt_check_crc_equal(&crc[j], expected_crc);
+			if (!eq && frame_dump_path) {
+				frame = chamelium_read_captured_frame(data->chamelium,
+								      j);
 
-		enable_output(data, port, output, mode, &fb);
+				igt_debug("Dumping reference and chamelium frames to %s...\n",
+					  frame_dump_path);
 
-		/* We want to keep the display running for a little bit, since
-		 * there's always the potential the driver isn't able to keep
-		 * the display running properly for very long
-		 */
-		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 3);
-		crc = chamelium_read_captured_crcs(data->chamelium,
-						   &captured_frame_count);
+				snprintf(path, PATH_MAX, "%s/frame-reference-%s.png",
+					 frame_dump_path, connector_name);
+				igt_write_fb_to_png(data->drm_fd, &fb, path);
 
-		igt_debug("Captured %d frames\n", captured_frame_count);
+				snprintf(path, PATH_MAX, "%s/frame-chamelium-%s.png",
+					 frame_dump_path, connector_name);
+				chamelium_write_frame_to_png(data->chamelium,
+							     frame, path);
 
-		expected_crc = chamelium_calculate_fb_crc_result(fb_crc);
+				chamelium_destroy_frame_dump(frame);
+			}
 
-		for (j = 0; j < captured_frame_count; j++)
-			igt_assert_crc_equal(&crc[j], expected_crc);
+			igt_fail_on_f(!eq,
+				      "Chamelium frame CRC mismatch with reference\n");
+		}
 
 		free(expected_crc);
 		free(crc);
@@ -644,10 +618,10 @@ igt_main
 							edid_id, alt_edid_id);
 
 		connector_subtest("dp-crc-single", DisplayPort)
-			test_display_crc_single(&data, port);
+			test_display_crc(&data, port, 1);
 
 		connector_subtest("dp-crc-multiple", DisplayPort)
-			test_display_crc_multiple(&data, port);
+			test_display_crc(&data, port, 3);
 	}
 
 	igt_subtest_group {
@@ -698,10 +672,10 @@ igt_main
 							edid_id, alt_edid_id);
 
 		connector_subtest("hdmi-crc-single", HDMIA)
-			test_display_crc_single(&data, port);
+			test_display_crc(&data, port, 1);
 
 		connector_subtest("hdmi-crc-multiple", HDMIA)
-			test_display_crc_multiple(&data, port);
+			test_display_crc(&data, port, 3);
 	}
 
 	igt_subtest_group {
-- 
2.13.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* Re: [PATCH i-g-t v3 1/4] chamelium: Calculate CRC from framebuffer instead of hardcoding it
  2017-07-05  8:04 [PATCH i-g-t v3 1/4] chamelium: Calculate CRC from framebuffer instead of hardcoding it Paul Kocialkowski
                   ` (2 preceding siblings ...)
  2017-07-05  8:04 ` [PATCH i-g-t v3 4/4] chamelium: Dump obtained and reference frames to png on crc error Paul Kocialkowski
@ 2017-07-05 20:34 ` Lyude Paul
  2017-07-05 20:49   ` Lyude Paul
                     ` (2 more replies)
  2017-07-12 14:50 ` [PATCH i-g-t v4 0/7] CRC testing with Chamelium improvements Paul Kocialkowski
  2017-07-19 13:46 ` [PATCH i-g-t v5 " Paul Kocialkowski
  5 siblings, 3 replies; 57+ messages in thread
From: Lyude Paul @ 2017-07-05 20:34 UTC (permalink / raw)
  To: Paul Kocialkowski, intel-gfx

So a couple of notes here that will make it a lot easier for me to
review these in the future

 * When you're doing a new revision of a patch series, it's helpful to
   keep it in the same email thread as the original v1 so it's easier
   to keep track of in people's mail clients (as well as avoiding
   accidentally reviewing older patch versions. I usually do something
   like this (other projects might request you do this slightly
   differently, but this should be fine here):
    * [PATCH 0/2] Cleaning up the alignment of various foos
       * [PATCH 1/2] Foo the bar, not the baz
       * [PATCH 2/2] Introduce the amazing new foo_bar
       * [PATCH v2 0/2] Cleaning up the alignment of various foos
          * [PATCH v2 1/2] Foo the bar, not the baz
          * [PATCH v2 2/2] Introduce the amazing new foo_bar
       * [PATCH v3 0/2] Cleaning up the alignment of various foos
          * [PATCH v3 1/2] Foo the bar, not the baz
          * [PATCH v3 2/2] Introduce the amazing new foo_bar
 * Try not to group unrelated patches together in the same thread. This
   also makes sorting through all of them a little more difficult.
 * When you make new revisions of patches, it's very useful if you also
   include a list of changes you made to the patch since the last
   revision. It doesn't need to be very finely detailed, something like
   this would suffice:
    * Various style fixes
    * Rename baz to moo, add cow noises
    * Split init_cow() into init_white_cow() and init_black_cow()
      instead of handling both kinds of cows in the same function
    * Fix documentation
    For intel-gpu-tools, it's fine to just stick this in the commit
    message. Other projects may request you put the changelog below the
    ----- right above the diff stats (this allows the comments not to
    get included in the final commit message)
 * Unless they are all very small and less important fixes, including
   cover letters helps as well since it lets patchwork group together
   patch series like this.

Anyway, back to the actual patch:
A good start! Will need a couple of changes though

On Wed, 2017-07-05 at 11:04 +0300, Paul Kocialkowski wrote:
> This introduces CRC calculation for reference frames, instead of
> using
> hardcoded values for them. The rendering of reference frames may
> differ
> from machine to machine, especially due to font rendering, and the
> frame itself may change with subsequent IGT changes.
> 
> These differences would cause the CRC checks to fail on different
> setups. This allows them to pass regardless of the setup.
> 
> Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
> ---
>  lib/igt_chamelium.c | 160
> ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  lib/igt_chamelium.h |   5 ++
>  tests/chamelium.c   |  76 ++++++-------------------
>  3 files changed, 183 insertions(+), 58 deletions(-)
> 
> diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
> index bff08c0e..b9d80b6b 100644
> --- a/lib/igt_chamelium.c
> +++ b/lib/igt_chamelium.c
> @@ -94,6 +94,14 @@ struct chamelium_frame_dump {
>  	struct chamelium_port *port;
>  };
>  
> +struct chamelium_fb_crc {
> +	int fd;
> +	struct igt_fb *fb;
> +
> +	pthread_t thread_id;
> +	igt_crc_t *ret;
> +};
> +
The name of this structure is a little misleading, because now we have
an API that exposes both a struct chamelium_fb_crc struct in addition
to the igt_crc_t struct. Rename this to something like struct
chamelium_fb_crc_work

>  struct chamelium {
>  	xmlrpc_env env;
>  	xmlrpc_client *client;
> @@ -1003,6 +1011,158 @@ int chamelium_get_frame_limit(struct
> chamelium *chamelium,
>  	return ret;
>  }
>  
> +static uint32_t chamelium_xrgb_hash16(unsigned char *buffer, int
> width,
> +				      int height, int k, int m)
> +{
We're not modifying buffer, so make it a const. As well, feel free to
mark this function as inline.

> +	unsigned char r, g, b;
> +	uint64_t sum = 0;
> +	uint64_t count = 0;
> +	uint64_t value;
> +	uint32_t hash;
> +	int index;
> +	int i;
> +
> +	for (i=0; i < width * height; i++) {
> +		if ((i % m) != k)
> +			continue;
> +
> +		index = i * 4;
> +
> +		r = buffer[index + 2];
> +		g = buffer[index + 1];
> +		b = buffer[index + 0];
> +
> +		value = r | (g << 8) | (b << 16);
> +		sum += ++count * value;
> +	}
> +
> +	hash = ((sum >> 0) ^ (sum >> 16) ^ (sum >> 32) ^ (sum >>
> 48)) & 0xffff;
> +
> +	return hash;
> +}
> +
> +/**
> + * chamelium_calculate_fb_crc:
> + * @fd: The drm file descriptor
> + * @fb: The framebuffer to calculate the CRC for
> + *
> + * Calculates a CRC for the provided framebuffer, the same way as
> the Chamelium.
Calculate the CRC for the provided framebuffer, using the Chamelium's
CRC algorithm
> + * This calculates the CRC in a non-threaded fashion.
> + *
> + * Returns: The calculated CRC
> + */
> +igt_crc_t *chamelium_calculate_fb_crc(int fd, struct igt_fb *fb)
> +{
> +	igt_crc_t *ret;
> +	cairo_t *cr;
> +	cairo_surface_t *fb_surface;
> +	unsigned char *buffer;
> +	int n = 4;
> +	int w, h;
> +	int i, j;
> +
> +	ret = calloc(1, sizeof(igt_crc_t));
> +
> +	/* Get the cairo surface for the framebuffer */
> +	cr = igt_get_cairo_ctx(fd, fb);
> +	fb_surface = cairo_get_target(cr);
> +	cairo_surface_reference(fb_surface);
> +	cairo_destroy(cr);
> +
> +	buffer = cairo_image_surface_get_data(fb_surface);
> +	w = fb->width;
> +	h = fb->height;
> +
> +	for (i = 0; i < n; i++) {
> +		j = n - i - 1;
> +		ret->crc[i] = chamelium_xrgb_hash16(buffer, w, h, j,
> n);
> +	}
> +
> +	ret->n_words = n;
> +	cairo_surface_destroy(fb_surface);
> +
> +	return ret;
> +}
> +
> +static void *chamelium_calculate_fb_crc_thread(void *data)
> +{
> +	struct chamelium_fb_crc *fb_crc = (struct chamelium_fb_crc
> *) data;
> +	cairo_t *cr;
> +	cairo_surface_t *fb_surface;
> +	unsigned char *buffer;
> +	int n = 4;
> +	int w, h;
> +	int i, j;
> +
> +	/* Get the cairo surface for the framebuffer */
> +	cr = igt_get_cairo_ctx(fb_crc->fd, fb_crc->fb);
> +	fb_surface = cairo_get_target(cr);
> +	cairo_surface_reference(fb_surface);
> +	cairo_destroy(cr);
> +
> +	buffer = cairo_image_surface_get_data(fb_surface);
> +	w = fb_crc->fb->width;
> +	h = fb_crc->fb->height;
> +
> +	for (i = 0; i < n; i++) {
> +		j = n - i - 1;
> +		fb_crc->ret->crc[i] = chamelium_xrgb_hash16(buffer,
> w, h, j, n);
> +	}
> +
> +	fb_crc->ret->n_words = n;
> +	cairo_surface_destroy(fb_surface);
> +
> +	return NULL;
> +}
> +
> +/**
> + * chamelium_calculate_fb_crc_launch:
> + * @fd: The drm file descriptor
> + * @fb: The framebuffer to calculate the CRC for
> + *
> + * Launches the CRC calculation for the provided framebuffer, the
> same way as
> + * the Chamelium. This calculates the CRC in a threaded fashion.
> + * Thread-related information is returned and should be passed to a
> subsequent
> + * call to chamelium_calculate_fb_crc_result. It should not be
> freed.
> + *
> + * Returns: An intermediate structure with thread-related
> information
The user doesn't need to know about the magic inside the structure,
since we're not going to expose it's definition outside of this file
anyway.
> + */
> +struct chamelium_fb_crc *chamelium_calculate_fb_crc_launch(int fd,
> +							   struct
> igt_fb *fb)
> +{
> +	struct chamelium_fb_crc *fb_crc;
> +
> +	fb_crc = calloc(1, sizeof(struct chamelium_fb_crc));
> +	fb_crc->ret = calloc(1, sizeof(igt_crc_t));
> +	fb_crc->fd = fd;
> +	fb_crc->fb = fb;
> +
> +	pthread_create(&fb_crc->thread_id, NULL,
> +		       chamelium_calculate_fb_crc_thread, fb_crc);
> +
> +	return fb_crc;
> +}
> +
> +/**
> + * chamelium_calculate_fb_crc_result:
> + * @fb_crc: An intermediate structure with thread-related
> information
> + *
> + * Provides the result for the previously-launched CRC calculation.
Blocks until the async CRC calculation is finished, and then returns
the result.
> + *
> + * Returns: The calculated CRC
> + */
> +igt_crc_t *chamelium_calculate_fb_crc_result(struct chamelium_fb_crc
> *fb_crc)
> +{
> +	igt_crc_t *ret;
> +
> +	pthread_join(fb_crc->thread_id, NULL);
> +
> +	ret = fb_crc->ret;
> +	free(fb_crc);
> +
> +	return ret;
> +}
> +
>  static unsigned int chamelium_get_port_type(struct chamelium
> *chamelium,
>  					    struct chamelium_port
> *port)
>  {
> diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
> index 81322ad2..e51cf4f9 100644
> --- a/lib/igt_chamelium.h
> +++ b/lib/igt_chamelium.h
> @@ -36,6 +36,7 @@
>  struct chamelium;
>  struct chamelium_port;
>  struct chamelium_frame_dump;
> +struct chamelium_fb_crc;
>  
>  struct chamelium *chamelium_init(int drm_fd);
>  void chamelium_deinit(struct chamelium *chamelium);
> @@ -92,6 +93,10 @@ struct chamelium_frame_dump
> *chamelium_port_dump_pixels(struct chamelium *chamel
>  							struct
> chamelium_port *port,
>  							int x, int
> y,
>  							int w, int
> h);
> +igt_crc_t *chamelium_calculate_fb_crc(int fd, struct igt_fb *fb);
> +struct chamelium_fb_crc *chamelium_calculate_fb_crc_launch(int fd,
> +							   struct
> igt_fb *fb);
> +igt_crc_t *chamelium_calculate_fb_crc_result(struct chamelium_fb_crc
> *fb_crc);
>  int chamelium_get_captured_frame_count(struct chamelium *chamelium);
>  int chamelium_get_frame_limit(struct chamelium *chamelium,
>  			      struct chamelium_port *port,
> diff --git a/tests/chamelium.c b/tests/chamelium.c
> index e3067664..3fd2b02c 100644
> --- a/tests/chamelium.c
> +++ b/tests/chamelium.c
> @@ -49,43 +49,6 @@ typedef struct {
>  #define HPD_TOGGLE_COUNT_VGA 5
>  #define HPD_TOGGLE_COUNT_DP_HDMI 15
>  
> -/* Pre-calculated CRCs for the pattern fb, for all the modes in the
> default
> - * chamelium edid
> - */
> -struct crc_entry {
> -	int width;
> -	int height;
> -	igt_crc_t crc;
> -};
> -
> -#define CRC_ENTRY(w_, h_, ...) \
> -	{ w_, h_, { .n_words = 4, .crc = { __VA_ARGS__ } } }
> -
> -static const struct crc_entry pattern_fb_crcs[] = {
> -	CRC_ENTRY(1920, 1080, 0xf859, 0xa751, 0x8c81, 0x45a1),
> -	CRC_ENTRY(1280,  720, 0xcec2, 0x4246, 0x6cfd, 0xeb43),
> -	CRC_ENTRY(1024,  768, 0x85e5, 0xf0cd, 0xafe3, 0x7f18),
> -	CRC_ENTRY( 800,  600, 0x6b39, 0x32b6, 0x831a, 0xb03e),
> -	CRC_ENTRY( 640,  480, 0xa121, 0x2473, 0xb150, 0x8c47),
> -};
> -#undef CRC_ENTRY
> -
> -static const igt_crc_t *
> -get_precalculated_crc(struct chamelium_port *port, int w, int h)
> -{
> -	int i;
> -	const struct crc_entry *entry;
> -
> -	for (i = 0; i < ARRAY_SIZE(pattern_fb_crcs); i++) {
> -		entry = &pattern_fb_crcs[i];
> -
> -		if (entry->width == w && entry->height == h)
> -			return &entry->crc;
> -	}
> -
> -	return NULL;
> -}
> -
>  static void
>  require_connector_present(data_t *data, unsigned int type)
>  {
> @@ -424,7 +387,8 @@ test_display_crc_single(data_t *data, struct
> chamelium_port *port)
>  	igt_output_t *output;
>  	igt_plane_t *primary;
>  	igt_crc_t *crc;
> -	const igt_crc_t *expected_crc;
> +	igt_crc_t *expected_crc;
> +	struct chamelium_fb_crc *fb_crc;
>  	struct igt_fb fb;
>  	drmModeModeInfo *mode;
>  	drmModeConnector *connector;
> @@ -447,24 +411,21 @@ test_display_crc_single(data_t *data, struct
> chamelium_port *port)
>  						    0, 0, 0, &fb);
>  		igt_assert(fb_id > 0);
>  
> -		enable_output(data, port, output, mode, &fb);
> +		fb_crc = chamelium_calculate_fb_crc_launch(data-
> >drm_fd, &fb);
>  
> -		expected_crc = get_precalculated_crc(port,
> -						     mode->hdisplay,
> -						     mode-
> >vdisplay);
> -		if (!expected_crc) {
> -			igt_warn("No precalculated CRC found for
> %dx%d, skipping CRC check\n",
> -				 mode->hdisplay, mode->vdisplay);
> -			goto next;
> -		}
> +		enable_output(data, port, output, mode, &fb);
>  
>  		igt_debug("Testing single CRC fetch\n");
> +
>  		crc = chamelium_get_crc_for_area(data->chamelium,
> port,
>  						 0, 0, 0, 0);
> +
> +		expected_crc =
> chamelium_calculate_fb_crc_result(fb_crc);
> +
>  		igt_assert_crc_equal(crc, expected_crc);
> +		free(expected_crc);
>  		free(crc);
>  
> -next:
>  		disable_output(data, port, output);
>  		igt_remove_fb(data->drm_fd, &fb);
>  	}
> @@ -480,7 +441,8 @@ test_display_crc_multiple(data_t *data, struct
> chamelium_port *port)
>  	igt_output_t *output;
>  	igt_plane_t *primary;
>  	igt_crc_t *crc;
> -	const igt_crc_t *expected_crc;
> +	igt_crc_t *expected_crc;
> +	struct chamelium_fb_crc *fb_crc;
>  	struct igt_fb fb;
>  	drmModeModeInfo *mode;
>  	drmModeConnector *connector;
> @@ -503,15 +465,9 @@ test_display_crc_multiple(data_t *data, struct
> chamelium_port *port)
>  						    0, 0, 0, &fb);
>  		igt_assert(fb_id > 0);
>  
> -		enable_output(data, port, output, mode, &fb);
> +		fb_crc = chamelium_calculate_fb_crc_launch(data-
> >drm_fd, &fb);
>  
> -		expected_crc = get_precalculated_crc(port, mode-
> >hdisplay,
> -						     mode-
> >vdisplay);
> -		if (!expected_crc) {
> -			igt_warn("No precalculated CRC found for
> %dx%d, skipping CRC check\n",
> -				 mode->hdisplay, mode->vdisplay);
> -			goto next;
> -		}
> +		enable_output(data, port, output, mode, &fb);
>  
>  		/* We want to keep the display running for a little
> bit, since
>  		 * there's always the potential the driver isn't
> able to keep
> @@ -522,11 +478,15 @@ test_display_crc_multiple(data_t *data, struct
> chamelium_port *port)
>  						   &captured_frame_c
> ount);
>  
>  		igt_debug("Captured %d frames\n",
> captured_frame_count);
> +
> +		expected_crc =
> chamelium_calculate_fb_crc_result(fb_crc);
> +
>  		for (j = 0; j < captured_frame_count; j++)
>  			igt_assert_crc_equal(&crc[j], expected_crc);
> +
> +		free(expected_crc);
>  		free(crc);
>  
> -next:
>  		disable_output(data, port, output);
>  		igt_remove_fb(data->drm_fd, &fb);
>  	}
-- 
Cheers,
	Lyude
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH i-g-t v3 1/4] chamelium: Calculate CRC from framebuffer instead of hardcoding it
  2017-07-05 20:34 ` [PATCH i-g-t v3 1/4] chamelium: Calculate CRC from framebuffer instead of hardcoding it Lyude Paul
@ 2017-07-05 20:49   ` Lyude Paul
  2017-07-06  8:49   ` Paul Kocialkowski
  2017-07-06 13:14   ` Paul Kocialkowski
  2 siblings, 0 replies; 57+ messages in thread
From: Lyude Paul @ 2017-07-05 20:49 UTC (permalink / raw)
  To: Paul Kocialkowski, intel-gfx

On Wed, 2017-07-05 at 16:34 -0400, Lyude Paul wrote:
> So a couple of notes here that will make it a lot easier for me to
> review these in the future
> 
>  * When you're doing a new revision of a patch series, it's helpful
> to
>    keep it in the same email thread as the original v1 so it's easier
>    to keep track of in people's mail clients (as well as avoiding
>    accidentally reviewing older patch versions. I usually do
> something
>    like this (other projects might request you do this slightly
>    differently, but this should be fine here):
>     * [PATCH 0/2] Cleaning up the alignment of various foos
>        * [PATCH 1/2] Foo the bar, not the baz
>        * [PATCH 2/2] Introduce the amazing new foo_bar
>        * [PATCH v2 0/2] Cleaning up the alignment of various foos
>           * [PATCH v2 1/2] Foo the bar, not the baz
>           * [PATCH v2 2/2] Introduce the amazing new foo_bar
>        * [PATCH v3 0/2] Cleaning up the alignment of various foos
>           * [PATCH v3 1/2] Foo the bar, not the baz
>           * [PATCH v3 2/2] Introduce the amazing new foo_bar
>  * Try not to group unrelated patches together in the same thread.
> This
>    also makes sorting through all of them a little more difficult.
>  * When you make new revisions of patches, it's very useful if you
> also
>    include a list of changes you made to the patch since the last
>    revision. It doesn't need to be very finely detailed, something
> like
>    this would suffice:
>     * Various style fixes
>     * Rename baz to moo, add cow noises
>     * Split init_cow() into init_white_cow() and init_black_cow()
>       instead of handling both kinds of cows in the same function
>     * Fix documentation
>     For intel-gpu-tools, it's fine to just stick this in the commit
>     message. Other projects may request you put the changelog below
> the
>     ----- right above the diff stats (this allows the comments not to
>     get included in the final commit message)
>  * Unless they are all very small and less important fixes, including
>    cover letters helps as well since it lets patchwork group together
>    patch series like this.
> 
> Anyway, back to the actual patch:
> A good start! Will need a couple of changes though
> 
> On Wed, 2017-07-05 at 11:04 +0300, Paul Kocialkowski wrote:
> > This introduces CRC calculation for reference frames, instead of
> > using
> > hardcoded values for them. The rendering of reference frames may
> > differ
> > from machine to machine, especially due to font rendering, and the
> > frame itself may change with subsequent IGT changes.
> > 
> > These differences would cause the CRC checks to fail on different
> > setups. This allows them to pass regardless of the setup.
> > 
> > Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com
> > >
> > ---
> >  lib/igt_chamelium.c | 160
> > ++++++++++++++++++++++++++++++++++++++++++++++++++++
> >  lib/igt_chamelium.h |   5 ++
> >  tests/chamelium.c   |  76 ++++++-------------------
> >  3 files changed, 183 insertions(+), 58 deletions(-)
> > 
> > diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
> > index bff08c0e..b9d80b6b 100644
> > --- a/lib/igt_chamelium.c
> > +++ b/lib/igt_chamelium.c
> > @@ -94,6 +94,14 @@ struct chamelium_frame_dump {
> >  	struct chamelium_port *port;
> >  };
> >  
> > +struct chamelium_fb_crc {
> > +	int fd;
> > +	struct igt_fb *fb;
> > +
> > +	pthread_t thread_id;
> > +	igt_crc_t *ret;
> > +};
> > +
> 
> The name of this structure is a little misleading, because now we
> have
> an API that exposes both a struct chamelium_fb_crc struct in addition
> to the igt_crc_t struct. Rename this to something like struct
> chamelium_fb_crc_work
> 
> >  struct chamelium {
> >  	xmlrpc_env env;
> >  	xmlrpc_client *client;
> > @@ -1003,6 +1011,158 @@ int chamelium_get_frame_limit(struct
> > chamelium *chamelium,
> >  	return ret;
> >  }
> >  
> > +static uint32_t chamelium_xrgb_hash16(unsigned char *buffer, int
> > width,
> > +				      int height, int k, int m)
> > +{
> 
> We're not modifying buffer, so make it a const. As well, feel free to
> mark this function as inline.
> 
> > +	unsigned char r, g, b;
> > +	uint64_t sum = 0;
> > +	uint64_t count = 0;
> > +	uint64_t value;
> > +	uint32_t hash;
> > +	int index;
> > +	int i;
> > +
> > +	for (i=0; i < width * height; i++) {
> > +		if ((i % m) != k)
> > +			continue;
> > +
> > +		index = i * 4;
> > +
> > +		r = buffer[index + 2];
> > +		g = buffer[index + 1];
> > +		b = buffer[index + 0];
> > +
> > +		value = r | (g << 8) | (b << 16);
> > +		sum += ++count * value;
> > +	}
> > +
> > +	hash = ((sum >> 0) ^ (sum >> 16) ^ (sum >> 32) ^ (sum >>
> > 48)) & 0xffff;
> > +
> > +	return hash;
> > +}
> > +
> > +/**
> > + * chamelium_calculate_fb_crc:
> > + * @fd: The drm file descriptor
> > + * @fb: The framebuffer to calculate the CRC for
> > + *
> > + * Calculates a CRC for the provided framebuffer, the same way as
> > the Chamelium.
> 
> Calculate the CRC for the provided framebuffer, using the Chamelium's
> CRC algorithm
> > + * This calculates the CRC in a non-threaded fashion.
> > + *
> > + * Returns: The calculated CRC
> > + */
> > +igt_crc_t *chamelium_calculate_fb_crc(int fd, struct igt_fb *fb)
> > +{
> > +	igt_crc_t *ret;
> > +	cairo_t *cr;
> > +	cairo_surface_t *fb_surface;
> > +	unsigned char *buffer;
> > +	int n = 4;
> > +	int w, h;
> > +	int i, j;
> > +
> > +	ret = calloc(1, sizeof(igt_crc_t));
> > +
> > +	/* Get the cairo surface for the framebuffer */
> > +	cr = igt_get_cairo_ctx(fd, fb);
> > +	fb_surface = cairo_get_target(cr);
> > +	cairo_surface_reference(fb_surface);
> > +	cairo_destroy(cr);
> > +
> > +	buffer = cairo_image_surface_get_data(fb_surface);
> > +	w = fb->width;
> > +	h = fb->height;
> > +
> > +	for (i = 0; i < n; i++) {
> > +		j = n - i - 1;
> > +		ret->crc[i] = chamelium_xrgb_hash16(buffer, w, h,
> > j,
> > n);
> > +	}
> > +
> > +	ret->n_words = n;
> > +	cairo_surface_destroy(fb_surface);
> > +
> > +	return ret;
> > +}
> > +
> > +static void *chamelium_calculate_fb_crc_thread(void *data)
> > +{
> > +	struct chamelium_fb_crc *fb_crc = (struct chamelium_fb_crc
> > *) data;
> > +	cairo_t *cr;
> > +	cairo_surface_t *fb_surface;
> > +	unsigned char *buffer;
> > +	int n = 4;
> > +	int w, h;
> > +	int i, j;
> > +
> > +	/* Get the cairo surface for the framebuffer */
> > +	cr = igt_get_cairo_ctx(fb_crc->fd, fb_crc->fb);
> > +	fb_surface = cairo_get_target(cr);
> > +	cairo_surface_reference(fb_surface);
> > +	cairo_destroy(cr);
> > +
> > +	buffer = cairo_image_surface_get_data(fb_surface);
> > +	w = fb_crc->fb->width;
> > +	h = fb_crc->fb->height;
> > +
> > +	for (i = 0; i < n; i++) {
> > +		j = n - i - 1;
> > +		fb_crc->ret->crc[i] =
> > chamelium_xrgb_hash16(buffer,
> > w, h, j, n);
> > +	}
> > +
> > +	fb_crc->ret->n_words = n;
> > +	cairo_surface_destroy(fb_surface);
> > +
> > +	return NULL;
> > +}
Bleh, I completely forgot to mention this:

This part of code definitely needs to be deduplicated. The only
difference between the threaded version and the non threaded version is
where they take their input from and where/how they store their
results. I would just do something like this (anything marked as static
here is not exposed through the api of course)

static chamelium_do_calculate_fb_crc(fd, fb, out)
    Performs actual CRC calculations

chamelium_calculate_fb_crc(fd, fb)
    Allocates storage for results and runs
    chamelium_do_calculate_fb_crc() in single threaded context

static chamelium_calculate_fb_crc_async_work(data)
    Actual function that's run for the calculation thread, calls
    chamelium_do_calculate_fb_crc with the appropriate arguments given
    to us from the generic data pointer

chamelium_calculate_fb_crc_async(fd, fb)
    Entrypoint for starting an async fb crc calculation, returns a
    fb_crc_async_work struct

chamelium_calculate_fb_crc_finish(work)
    Synchronizes with the calculation thread, waits for the result and
    blocks until it's ready then returns it.

> > +
> > +/**
> > + * chamelium_calculate_fb_crc_launch:
> > + * @fd: The drm file descriptor
> > + * @fb: The framebuffer to calculate the CRC for
> > + *
> > + * Launches the CRC calculation for the provided framebuffer, the
> > same way as
> > + * the Chamelium. This calculates the CRC in a threaded fashion.
> > + * Thread-related information is returned and should be passed to
> > a
> > subsequent
> > + * call to chamelium_calculate_fb_crc_result. It should not be
> > freed.
> > + *
> > + * Returns: An intermediate structure with thread-related
> > information
> 
> The user doesn't need to know about the magic inside the structure,
> since we're not going to expose it's definition outside of this file
> anyway.
> > + */
> > +struct chamelium_fb_crc *chamelium_calculate_fb_crc_launch(int fd,
> > +							   struct
> > igt_fb *fb)
> > +{
> > +	struct chamelium_fb_crc *fb_crc;
> > +
> > +	fb_crc = calloc(1, sizeof(struct chamelium_fb_crc));
> > +	fb_crc->ret = calloc(1, sizeof(igt_crc_t));
> > +	fb_crc->fd = fd;
> > +	fb_crc->fb = fb;
> > +
> > +	pthread_create(&fb_crc->thread_id, NULL,
> > +		       chamelium_calculate_fb_crc_thread, fb_crc);
> > +
> > +	return fb_crc;
> > +}
> > +
> > +/**
> > + * chamelium_calculate_fb_crc_result:
> > + * @fb_crc: An intermediate structure with thread-related
> > information
> > + *
> > + * Provides the result for the previously-launched CRC
> > calculation.
> 
> Blocks until the async CRC calculation is finished, and then returns
> the result.
> > + *
> > + * Returns: The calculated CRC
> > + */
> > +igt_crc_t *chamelium_calculate_fb_crc_result(struct
> > chamelium_fb_crc
> > *fb_crc)
> > +{
> > +	igt_crc_t *ret;
> > +
> > +	pthread_join(fb_crc->thread_id, NULL);
> > +
> > +	ret = fb_crc->ret;
> > +	free(fb_crc);
> > +
> > +	return ret;
> > +}
> > +
> >  static unsigned int chamelium_get_port_type(struct chamelium
> > *chamelium,
> >  					    struct chamelium_port
> > *port)
> >  {
> > diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
> > index 81322ad2..e51cf4f9 100644
> > --- a/lib/igt_chamelium.h
> > +++ b/lib/igt_chamelium.h
> > @@ -36,6 +36,7 @@
> >  struct chamelium;
> >  struct chamelium_port;
> >  struct chamelium_frame_dump;
> > +struct chamelium_fb_crc;
> >  
> >  struct chamelium *chamelium_init(int drm_fd);
> >  void chamelium_deinit(struct chamelium *chamelium);
> > @@ -92,6 +93,10 @@ struct chamelium_frame_dump
> > *chamelium_port_dump_pixels(struct chamelium *chamel
> >  							struct
> > chamelium_port *port,
> >  							int x, int
> > y,
> >  							int w, int
> > h);
> > +igt_crc_t *chamelium_calculate_fb_crc(int fd, struct igt_fb *fb);
> > +struct chamelium_fb_crc *chamelium_calculate_fb_crc_launch(int fd,
> > +							   struct
> > igt_fb *fb);
> > +igt_crc_t *chamelium_calculate_fb_crc_result(struct
> > chamelium_fb_crc
> > *fb_crc);
> >  int chamelium_get_captured_frame_count(struct chamelium
> > *chamelium);
> >  int chamelium_get_frame_limit(struct chamelium *chamelium,
> >  			      struct chamelium_port *port,
> > diff --git a/tests/chamelium.c b/tests/chamelium.c
> > index e3067664..3fd2b02c 100644
> > --- a/tests/chamelium.c
> > +++ b/tests/chamelium.c
> > @@ -49,43 +49,6 @@ typedef struct {
> >  #define HPD_TOGGLE_COUNT_VGA 5
> >  #define HPD_TOGGLE_COUNT_DP_HDMI 15
> >  
> > -/* Pre-calculated CRCs for the pattern fb, for all the modes in
> > the
> > default
> > - * chamelium edid
> > - */
> > -struct crc_entry {
> > -	int width;
> > -	int height;
> > -	igt_crc_t crc;
> > -};
> > -
> > -#define CRC_ENTRY(w_, h_, ...) \
> > -	{ w_, h_, { .n_words = 4, .crc = { __VA_ARGS__ } } }
> > -
> > -static const struct crc_entry pattern_fb_crcs[] = {
> > -	CRC_ENTRY(1920, 1080, 0xf859, 0xa751, 0x8c81, 0x45a1),
> > -	CRC_ENTRY(1280,  720, 0xcec2, 0x4246, 0x6cfd, 0xeb43),
> > -	CRC_ENTRY(1024,  768, 0x85e5, 0xf0cd, 0xafe3, 0x7f18),
> > -	CRC_ENTRY( 800,  600, 0x6b39, 0x32b6, 0x831a, 0xb03e),
> > -	CRC_ENTRY( 640,  480, 0xa121, 0x2473, 0xb150, 0x8c47),
> > -};
> > -#undef CRC_ENTRY
> > -
> > -static const igt_crc_t *
> > -get_precalculated_crc(struct chamelium_port *port, int w, int h)
> > -{
> > -	int i;
> > -	const struct crc_entry *entry;
> > -
> > -	for (i = 0; i < ARRAY_SIZE(pattern_fb_crcs); i++) {
> > -		entry = &pattern_fb_crcs[i];
> > -
> > -		if (entry->width == w && entry->height == h)
> > -			return &entry->crc;
> > -	}
> > -
> > -	return NULL;
> > -}
> > -
> >  static void
> >  require_connector_present(data_t *data, unsigned int type)
> >  {
> > @@ -424,7 +387,8 @@ test_display_crc_single(data_t *data, struct
> > chamelium_port *port)
> >  	igt_output_t *output;
> >  	igt_plane_t *primary;
> >  	igt_crc_t *crc;
> > -	const igt_crc_t *expected_crc;
> > +	igt_crc_t *expected_crc;
> > +	struct chamelium_fb_crc *fb_crc;
> >  	struct igt_fb fb;
> >  	drmModeModeInfo *mode;
> >  	drmModeConnector *connector;
> > @@ -447,24 +411,21 @@ test_display_crc_single(data_t *data, struct
> > chamelium_port *port)
> >  						    0, 0, 0, &fb);
> >  		igt_assert(fb_id > 0);
> >  
> > -		enable_output(data, port, output, mode, &fb);
> > +		fb_crc = chamelium_calculate_fb_crc_launch(data-
> > > drm_fd, &fb);
> > 
> >  
> > -		expected_crc = get_precalculated_crc(port,
> > -						     mode-
> > >hdisplay,
> > -						     mode-
> > > vdisplay);
> > 
> > -		if (!expected_crc) {
> > -			igt_warn("No precalculated CRC found for
> > %dx%d, skipping CRC check\n",
> > -				 mode->hdisplay, mode->vdisplay);
> > -			goto next;
> > -		}
> > +		enable_output(data, port, output, mode, &fb);
> >  
> >  		igt_debug("Testing single CRC fetch\n");
> > +
> >  		crc = chamelium_get_crc_for_area(data->chamelium,
> > port,
> >  						 0, 0, 0, 0);
> > +
> > +		expected_crc =
> > chamelium_calculate_fb_crc_result(fb_crc);
> > +
> >  		igt_assert_crc_equal(crc, expected_crc);
> > +		free(expected_crc);
> >  		free(crc);
> >  
> > -next:
> >  		disable_output(data, port, output);
> >  		igt_remove_fb(data->drm_fd, &fb);
> >  	}
> > @@ -480,7 +441,8 @@ test_display_crc_multiple(data_t *data, struct
> > chamelium_port *port)
> >  	igt_output_t *output;
> >  	igt_plane_t *primary;
> >  	igt_crc_t *crc;
> > -	const igt_crc_t *expected_crc;
> > +	igt_crc_t *expected_crc;
> > +	struct chamelium_fb_crc *fb_crc;
> >  	struct igt_fb fb;
> >  	drmModeModeInfo *mode;
> >  	drmModeConnector *connector;
> > @@ -503,15 +465,9 @@ test_display_crc_multiple(data_t *data, struct
> > chamelium_port *port)
> >  						    0, 0, 0, &fb);
> >  		igt_assert(fb_id > 0);
> >  
> > -		enable_output(data, port, output, mode, &fb);
> > +		fb_crc = chamelium_calculate_fb_crc_launch(data-
> > > drm_fd, &fb);
> > 
> >  
> > -		expected_crc = get_precalculated_crc(port, mode-
> > > hdisplay,
> > 
> > -						     mode-
> > > vdisplay);
> > 
> > -		if (!expected_crc) {
> > -			igt_warn("No precalculated CRC found for
> > %dx%d, skipping CRC check\n",
> > -				 mode->hdisplay, mode->vdisplay);
> > -			goto next;
> > -		}
> > +		enable_output(data, port, output, mode, &fb);
> >  
> >  		/* We want to keep the display running for a
> > little
> > bit, since
> >  		 * there's always the potential the driver isn't
> > able to keep
> > @@ -522,11 +478,15 @@ test_display_crc_multiple(data_t *data,
> > struct
> > chamelium_port *port)
> >  						   &captured_frame
> > _c
> > ount);
> >  
> >  		igt_debug("Captured %d frames\n",
> > captured_frame_count);
> > +
> > +		expected_crc =
> > chamelium_calculate_fb_crc_result(fb_crc);
> > +
> >  		for (j = 0; j < captured_frame_count; j++)
> >  			igt_assert_crc_equal(&crc[j],
> > expected_crc);
> > +
> > +		free(expected_crc);
> >  		free(crc);
> >  
> > -next:
> >  		disable_output(data, port, output);
> >  		igt_remove_fb(data->drm_fd, &fb);
> >  	}
-- 
Cheers,
	Lyude
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH i-g-t v3 2/4] tests/ chamelium: Remove the frame dump tests
  2017-07-05  8:04 ` [PATCH i-g-t v3 2/4] tests/ chamelium: Remove the frame dump tests Paul Kocialkowski
@ 2017-07-05 20:53   ` Lyude Paul
  2017-07-06  7:37     ` Martin Peres
  2017-07-06 13:29     ` Paul Kocialkowski
  0 siblings, 2 replies; 57+ messages in thread
From: Lyude Paul @ 2017-07-05 20:53 UTC (permalink / raw)
  To: Paul Kocialkowski, intel-gfx

NAK. You're right that these don't actually give us any advantage over
just using CRCs and are just slower, however I left these tests in here
moreso just so we had something to actually test the frame dumping
functions so that we could avoid regressing them by accident since
we're the only users of those functions right now.

If I recall properly, isn't there a list of tests in igt's source that
they use for determining which tests to run on the CI? I think a better
solution would be to just disable this for CI runs, and maybe add some
comments pointing out that this test is only really useful for
developers making changes to the chamelium library.

On Wed, 2017-07-05 at 11:04 +0300, Paul Kocialkowski wrote:
> The frame dump tests provide no additional functionality over CRC
> tests
> and are considerably slower. Thus, these tests should be considered
> as
> poorer duplicates and removed.
> 
> Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
> ---
>  tests/chamelium.c | 53 -------------------------------------------
> ----------
>  1 file changed, 53 deletions(-)
> 
> diff --git a/tests/chamelium.c b/tests/chamelium.c
> index 3fd2b02c..5cf8b3af 100644
> --- a/tests/chamelium.c
> +++ b/tests/chamelium.c
> @@ -496,53 +496,6 @@ test_display_crc_multiple(data_t *data, struct
> chamelium_port *port)
>  }
>  
>  static void
> -test_display_frame_dump(data_t *data, struct chamelium_port *port)
> -{
> -	igt_display_t display;
> -	igt_output_t *output;
> -	igt_plane_t *primary;
> -	struct igt_fb fb;
> -	struct chamelium_frame_dump *frame;
> -	drmModeModeInfo *mode;
> -	drmModeConnector *connector;
> -	int fb_id, i, j;
> -
> -	reset_state(data, port);
> -
> -	output = prepare_output(data, &display, port);
> -	connector = chamelium_port_get_connector(data->chamelium,
> port, false);
> -	primary = igt_output_get_plane_type(output,
> DRM_PLANE_TYPE_PRIMARY);
> -	igt_assert(primary);
> -
> -	for (i = 0; i < connector->count_modes; i++) {
> -		mode = &connector->modes[i];
> -		fb_id = igt_create_color_pattern_fb(data->drm_fd,
> -						    mode->hdisplay,
> mode->vdisplay,
> -						    DRM_FORMAT_XRGB8
> 888,
> -						    LOCAL_DRM_FORMAT
> _MOD_NONE,
> -						    0, 0, 0, &fb);
> -		igt_assert(fb_id > 0);
> -
> -		enable_output(data, port, output, mode, &fb);
> -
> -		igt_debug("Reading frame dumps from
> Chamelium...\n");
> -		chamelium_capture(data->chamelium, port, 0, 0, 0, 0,
> 5);
> -		for (j = 0; j < 5; j++) {
> -			frame = chamelium_read_captured_frame(
> -			    data->chamelium, j);
> -			chamelium_assert_frame_eq(data->chamelium,
> frame, &fb);
> -			chamelium_destroy_frame_dump(frame);
> -		}
> -
> -		disable_output(data, port, output);
> -		igt_remove_fb(data->drm_fd, &fb);
> -	}
> -
> -	drmModeFreeConnector(connector);
> -	igt_display_fini(&display);
> -}
> -
> -static void
>  test_hpd_without_ddc(data_t *data, struct chamelium_port *port)
>  {
>  	struct udev_monitor *mon = igt_watch_hotplug();
> @@ -695,9 +648,6 @@ igt_main
>  
>  		connector_subtest("dp-crc-multiple", DisplayPort)
>  			test_display_crc_multiple(&data, port);
> -
> -		connector_subtest("dp-frame-dump", DisplayPort)
> -			test_display_frame_dump(&data, port);
>  	}
>  
>  	igt_subtest_group {
> @@ -752,9 +702,6 @@ igt_main
>  
>  		connector_subtest("hdmi-crc-multiple", HDMIA)
>  			test_display_crc_multiple(&data, port);
> -
> -		connector_subtest("hdmi-frame-dump", HDMIA)
> -			test_display_frame_dump(&data, port);
>  	}
>  
>  	igt_subtest_group {
-- 
Cheers,
	Lyude
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH i-g-t v3 3/4] lib/igt_chamelium: Add support for dumping chamelium frames to a png
  2017-07-05  8:04 ` [PATCH i-g-t v3 3/4] lib/igt_chamelium: Add support for dumping chamelium frames to a png Paul Kocialkowski
@ 2017-07-05 21:16   ` Lyude Paul
  0 siblings, 0 replies; 57+ messages in thread
From: Lyude Paul @ 2017-07-05 21:16 UTC (permalink / raw)
  To: Paul Kocialkowski, intel-gfx

On Wed, 2017-07-05 at 11:04 +0300, Paul Kocialkowski wrote:
> This introduces a chamelium_write_frame_to_png function that saves a
> Chamelium frame dump to a png file. This should be useful when a
> frame
> comparison with a reference fails.
> 
> Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
> ---
>  lib/igt_chamelium.c | 40 ++++++++++++++++++++++++++++++++++++++++
>  lib/igt_chamelium.h |  3 +++
>  2 files changed, 43 insertions(+)
> 
> diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
> index b9d80b6b..ef51ef68 100644
> --- a/lib/igt_chamelium.c
> +++ b/lib/igt_chamelium.c
> @@ -979,6 +979,46 @@ void chamelium_assert_frame_eq(const struct
> chamelium *chamelium,
>  }
>  
>  /**
> + * chamelium_write_frame_to_png:
> + * @chamelium: The Chamelium instance to use
> + * @dump: The chamelium frame dump to save
> + * @filename: The file name to dump the frame to
> + *
> + * Writes a chamelium frame dump into a png image stored at
> @filename.
> + */
> +void chamelium_write_frame_to_png(const struct chamelium *chamelium,
> +				  const struct chamelium_frame_dump
> *dump,
> +				  const char *filename)
> +{
> +	cairo_surface_t *dump_surface;
> +	pixman_image_t *image_bgr;
> +	pixman_image_t *image_argb;
> +	int w = dump->width, h = dump->height;
> +	uint32_t *bits_bgr = (uint32_t *) dump->bgr;
> +	unsigned char *bits_argb;
> +	cairo_status_t status;
> +
> +	image_bgr = pixman_image_create_bits(
> +	    PIXMAN_b8g8r8, w, h, bits_bgr,
> +	    PIXMAN_FORMAT_BPP(PIXMAN_b8g8r8) / 8 * w);
> +	image_argb = convert_frame_format(image_bgr,
> PIXMAN_x8r8g8b8);
> +	pixman_image_unref(image_bgr);
> +
> +	bits_argb = (unsigned char *)
> pixman_image_get_data(image_argb);
> +
> +	dump_surface = cairo_image_surface_create_for_data(
> +	    bits_argb, CAIRO_FORMAT_ARGB32, w, h,
> +	    PIXMAN_FORMAT_BPP(PIXMAN_x8r8g8b8) / 8 * w);
> +
> +	status = cairo_surface_write_to_png(dump_surface, filename);
> +	cairo_surface_destroy(dump_surface);
> +
> +	pixman_image_unref(image_argb);
> +
> +	igt_assert(status == CAIRO_STATUS_SUCCESS);
Use igt_assert_eq()
> +}
> +
> +/**
>   * chamelium_get_frame_limit:
>   * @chamelium: The Chamelium instance to use
>   * @port: The port to check the frame limit on
> diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
> index e51cf4f9..908e03d1 100644
> --- a/lib/igt_chamelium.h
> +++ b/lib/igt_chamelium.h
> @@ -105,6 +105,9 @@ int chamelium_get_frame_limit(struct chamelium
> *chamelium,
>  void chamelium_assert_frame_eq(const struct chamelium *chamelium,
>  			       const struct chamelium_frame_dump
> *dump,
>  			       struct igt_fb *fb);
> +void chamelium_write_frame_to_png(const struct chamelium *chamelium,
> +				  const struct chamelium_frame_dump
> *dump,
> +				  const char *filename);
>  void chamelium_destroy_frame_dump(struct chamelium_frame_dump
> *dump);
>  
>  #endif /* IGT_CHAMELIUM_H */
-- 
Cheers,
	Lyude
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH i-g-t v3 4/4] chamelium: Dump obtained and reference frames to png on crc error
  2017-07-05  8:04 ` [PATCH i-g-t v3 4/4] chamelium: Dump obtained and reference frames to png on crc error Paul Kocialkowski
@ 2017-07-05 21:44   ` Lyude Paul
  2017-07-06  7:41     ` Martin Peres
  2017-07-06 11:31     ` Paul Kocialkowski
  0 siblings, 2 replies; 57+ messages in thread
From: Lyude Paul @ 2017-07-05 21:44 UTC (permalink / raw)
  To: Paul Kocialkowski, intel-gfx

On Wed, 2017-07-05 at 11:04 +0300, Paul Kocialkowski wrote:
> When a CRC comparison error occurs, it is quite useful to get a dump
> of both the frame obtained from the chamelium and the reference in
> order
> to compare them.
> 
> This implements the frame dump, with a configurable path that enables
> the use of this feature.
> 
> Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
> ---
>  lib/igt_chamelium.c |  21 +++++++++++
>  lib/igt_chamelium.h |   1 +
>  lib/igt_debugfs.c   |  20 ++++++++++
>  lib/igt_debugfs.h   |   1 +
>  tests/chamelium.c   | 104 ++++++++++++++++++++--------------------
> ------------
>  5 files changed, 82 insertions(+), 65 deletions(-)
> 
> diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
> index ef51ef68..9aca6842 100644
> --- a/lib/igt_chamelium.c
> +++ b/lib/igt_chamelium.c
> @@ -57,6 +57,7 @@
>   * |[<!-- language="plain" -->
>   *	[Chamelium]
>   *	URL=http://chameleon:9992 # The URL used for connecting to
> the Chamelium's RPC server
> + *	FrameDumpPath=/tmp # The path to dump frames that fail
> comparison checks
While no one else really cares about creating frame dumps yet, it's
possible someone else may in the future if we ever end up taking more
advantage of automated testing systems like this. So I'd stick this in
the generic non-chamelium specific section in the config file

>   *
>   *	# The rest of the sections are used for defining connector
> mappings.
>   *	# This is required so any tests using the Chamelium know
> which connector
> @@ -115,11 +116,26 @@ struct chamelium {
>  	struct chamelium_edid *edids;
>  	struct chamelium_port *ports;
>  	int port_count;
> +
> +	char *frame_dump_path;
>  };
>  
>  static struct chamelium *cleanup_instance;
>  
>  /**
> + * chamelium_get_frame_dump_path:
> + * @chamelium: The Chamelium instance to use
> + *
> + * Retrieves the path to dump frames to.
> + *
> + * Returns: a string with the frame dump path
> + */
> +char *chamelium_get_frame_dump_path(struct chamelium *chamelium)
> +{
> +	return chamelium->frame_dump_path;
> +}
> +
> +/**
>   * chamelium_get_ports:
>   * @chamelium: The Chamelium instance to use
>   * @count: Where to store the number of ports
> @@ -1338,6 +1354,11 @@ static bool chamelium_read_config(struct
> chamelium *chamelium, int drm_fd)
>  		return false;
>  	}
>  
> +	chamelium->frame_dump_path =
> g_key_file_get_string(igt_key_file,
> +							   "Chameliu
> m",
> +							   "FrameDum
> pPath",
> +							    &error);
> +
>  	return chamelium_read_port_mappings(chamelium, drm_fd);
>  }
>  
> diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
> index 908e03d1..aa881971 100644
> --- a/lib/igt_chamelium.h
> +++ b/lib/igt_chamelium.h
> @@ -42,6 +42,7 @@ struct chamelium *chamelium_init(int drm_fd);
>  void chamelium_deinit(struct chamelium *chamelium);
>  void chamelium_reset(struct chamelium *chamelium);
>  
> +char *chamelium_get_frame_dump_path(struct chamelium *chamelium);
>  struct chamelium_port **chamelium_get_ports(struct chamelium
> *chamelium,
>  					    int *count);
>  unsigned int chamelium_port_get_type(const struct chamelium_port
> *port);
> diff --git a/lib/igt_debugfs.c b/lib/igt_debugfs.c
> index 80f25c61..dcb4e0a7 100644
> --- a/lib/igt_debugfs.c
> +++ b/lib/igt_debugfs.c
> @@ -282,6 +282,26 @@ bool igt_debugfs_search(int device, const char
> *filename, const char *substring)
>   */
>  
>  /**
> + * igt_check_crc_equal:
> + * @a: first pipe CRC value
> + * @b: second pipe CRC value
> + *
> + * Compares two CRC values and return whether they match.
> + *
> + * Returns: A boolean indicating whether the CRC values match
> + */
> +bool igt_check_crc_equal(const igt_crc_t *a, const igt_crc_t *b)
> +{
> +	int i;
> +
> +	for (i = 0; i < a->n_words; i++)
> +		if (a->crc[i] != b->crc[i])
> +			return false;
> +
> +	return true;
> +}
> +
Make this a separate patch, and instead of having another function do
the CRC calculations just have something like this:

 * static int igt_find_crc_mismatch(const igt_crc_t *a, const igt_crc_t
   *b): returns the index of the first CRC mismatch, 0 if none was
   found
 * bool igt_check_crc_equal(): uses igt_find_crc_mismatch() to figure
   out if anything mismatched, and return true if something did (as
   well, also spit out some debugging info mentioning there was a
   mismatch)
 * void igt_assert_crc_equal(): uses igt_find_crc_mismatch() to figure
   out if anything mismatched. If the assertion fails, use
   igt_assert_eq() on the mismatched crc so we still get a useful error
   message on CRC failures.

There isn't much code required to actually compare CRCs, however I'd
still prefer only having one function doing the actual comparison logic
here so we only have one piece of code to update if we need to make
changes to it in the future.

Mupuf, your opinion on this? ^

> +/**
>   * igt_assert_crc_equal:
>   * @a: first pipe CRC value
>   * @b: second pipe CRC value
> diff --git a/lib/igt_debugfs.h b/lib/igt_debugfs.h
> index 7b846a83..2695cbda 100644
> --- a/lib/igt_debugfs.h
> +++ b/lib/igt_debugfs.h
> @@ -113,6 +113,7 @@ enum intel_pipe_crc_source {
>          INTEL_PIPE_CRC_SOURCE_MAX,
>  };
>  
> +bool igt_check_crc_equal(const igt_crc_t *a, const igt_crc_t *b);
>  void igt_assert_crc_equal(const igt_crc_t *a, const igt_crc_t *b);
>  char *igt_crc_to_string(igt_crc_t *crc);
>  
> diff --git a/tests/chamelium.c b/tests/chamelium.c
> index 5cf8b3af..3d95c05c 100644
> --- a/tests/chamelium.c
> +++ b/tests/chamelium.c
> @@ -381,7 +381,7 @@ disable_output(data_t *data,
>  }
>  
>  static void
> -test_display_crc_single(data_t *data, struct chamelium_port *port)
> +test_display_crc(data_t *data, struct chamelium_port *port, int
> count)
>  {
>  	igt_display_t display;
>  	igt_output_t *output;
> @@ -390,9 +390,14 @@ test_display_crc_single(data_t *data, struct
> chamelium_port *port)
>  	igt_crc_t *expected_crc;
>  	struct chamelium_fb_crc *fb_crc;
>  	struct igt_fb fb;
> +	struct chamelium_frame_dump *frame;
>  	drmModeModeInfo *mode;
>  	drmModeConnector *connector;
> -	int fb_id, i;
> +	int fb_id, i, j, captured_frame_count;
> +	const char *connector_name;
> +	char *frame_dump_path;
> +	char path[PATH_MAX];
> +	bool eq;
>  
>  	reset_state(data, port);
>  
> @@ -401,6 +406,9 @@ test_display_crc_single(data_t *data, struct
> chamelium_port *port)
>  	primary = igt_output_get_plane_type(output,
> DRM_PLANE_TYPE_PRIMARY);
>  	igt_assert(primary);
>  
> +	connector_name = kmstest_connector_type_str(connector-
> >connector_type);
> +	frame_dump_path = chamelium_get_frame_dump_path(data-
> >chamelium);
> +
>  	for (i = 0; i < connector->count_modes; i++) {
>  		mode = &connector->modes[i];
>  		fb_id = igt_create_color_pattern_fb(data->drm_fd,
> @@ -415,74 +423,40 @@ test_display_crc_single(data_t *data, struct
> chamelium_port *port)
>  
>  		enable_output(data, port, output, mode, &fb);
>  
> -		igt_debug("Testing single CRC fetch\n");
> -
> -		crc = chamelium_get_crc_for_area(data->chamelium,
> port,
> -						 0, 0, 0, 0);
> -
> -		expected_crc =
> chamelium_calculate_fb_crc_result(fb_crc);
> -
> -		igt_assert_crc_equal(crc, expected_crc);
> -		free(expected_crc);
> -		free(crc);
> -
> -		disable_output(data, port, output);
> -		igt_remove_fb(data->drm_fd, &fb);
> -	}
> -
> -	drmModeFreeConnector(connector);
> -	igt_display_fini(&display);
> -}
> -
> -static void
> -test_display_crc_multiple(data_t *data, struct chamelium_port *port)
> -{
> -	igt_display_t display;
> -	igt_output_t *output;
> -	igt_plane_t *primary;
> -	igt_crc_t *crc;
> -	igt_crc_t *expected_crc;
> -	struct chamelium_fb_crc *fb_crc;
> -	struct igt_fb fb;
> -	drmModeModeInfo *mode;
> -	drmModeConnector *connector;
> -	int fb_id, i, j, captured_frame_count;
> +		chamelium_capture(data->chamelium, port, 0, 0, 0, 0,
> count);
> +		crc = chamelium_read_captured_crcs(data->chamelium,
> +						   &captured_frame_c
> ount);
>  
> -	reset_state(data, port);
> +		igt_assert(captured_frame_count == count);
>  
> -	output = prepare_output(data, &display, port);
> -	connector = chamelium_port_get_connector(data->chamelium,
> port, false);
> -	primary = igt_output_get_plane_type(output,
> DRM_PLANE_TYPE_PRIMARY);
> -	igt_assert(primary);
> +		igt_debug("Captured %d frames\n",
> captured_frame_count);
>  
> -	for (i = 0; i < connector->count_modes; i++) {
> -		mode = &connector->modes[i];
> -		fb_id = igt_create_color_pattern_fb(data->drm_fd,
> -						    mode->hdisplay,
> -						    mode->vdisplay,
> -						    DRM_FORMAT_XRGB8
> 888,
> -						    LOCAL_DRM_FORMAT
> _MOD_NONE,
> -						    0, 0, 0, &fb);
> -		igt_assert(fb_id > 0);
> +		expected_crc =
> chamelium_calculate_fb_crc_result(fb_crc);
>  
> -		fb_crc = chamelium_calculate_fb_crc_launch(data-
> >drm_fd, &fb);
> +		for (j = 0; j < captured_frame_count; j++) {
> +			eq = igt_check_crc_equal(&crc[j],
> expected_crc);
> +			if (!eq && frame_dump_path) {
> +				frame =
> chamelium_read_captured_frame(data->chamelium,
> +								    
>   j);
>  
> -		enable_output(data, port, output, mode, &fb);
> +				igt_debug("Dumping reference and
> chamelium frames to %s...\n",
> +					  frame_dump_path);
>  
> -		/* We want to keep the display running for a little
> bit, since
> -		 * there's always the potential the driver isn't
> able to keep
> -		 * the display running properly for very long
> -		 */
> -		chamelium_capture(data->chamelium, port, 0, 0, 0, 0,
> 3);
> -		crc = chamelium_read_captured_crcs(data->chamelium,
> -						   &captured_frame_c
> ount);
> +				snprintf(path, PATH_MAX, "%s/frame-
> reference-%s.png",
> +					 frame_dump_path,
> connector_name);
> +				igt_write_fb_to_png(data->drm_fd,
> &fb, path);
>  
> -		igt_debug("Captured %d frames\n",
> captured_frame_count);
> +				snprintf(path, PATH_MAX, "%s/frame-
> chamelium-%s.png",
> +					 frame_dump_path,
> connector_name);
> +				chamelium_write_frame_to_png(data-
> >chamelium,
> +							     frame,
> path);
>  
> -		expected_crc =
> chamelium_calculate_fb_crc_result(fb_crc);
> +				chamelium_destroy_frame_dump(frame);
> +			}
>  
> -		for (j = 0; j < captured_frame_count; j++)
> -			igt_assert_crc_equal(&crc[j], expected_crc);
> +			igt_fail_on_f(!eq,
> +				      "Chamelium frame CRC mismatch
> with reference\n");
> +		}
There's lots of potential here for copy pasta to form in the future,
since the API here puts a lot of work on the caller to set things up
for frame dumping. IMO, it would be worth it to teach the CRC checking
functions to automatically do frame dumps on mismatch if the CRC source
supports it. This will save us from having to have separate frame dump
APIs in the future if we ever end up adding support for other kinds of
automated test equipment.

As well, I like how you removed the redundancy between
test_display_crc_single() and test_display_crc_multiple(). However
since those are somewhat unrelated changes to the code path for these
tests it would be better to have that re-factoring as a separate patch
so as to make it easier for anyone who might need to bisect this code
in the future.

>  
>  		free(expected_crc);
>  		free(crc);
> @@ -644,10 +618,10 @@ igt_main
>  							edid_id,
> alt_edid_id);
>  
>  		connector_subtest("dp-crc-single", DisplayPort)
> -			test_display_crc_single(&data, port);
> +			test_display_crc(&data, port, 1);
>  
>  		connector_subtest("dp-crc-multiple", DisplayPort)
> -			test_display_crc_multiple(&data, port);
> +			test_display_crc(&data, port, 3);
>  	}
>  
>  	igt_subtest_group {
> @@ -698,10 +672,10 @@ igt_main
>  							edid_id,
> alt_edid_id);
>  
>  		connector_subtest("hdmi-crc-single", HDMIA)
> -			test_display_crc_single(&data, port);
> +			test_display_crc(&data, port, 1);
>  
>  		connector_subtest("hdmi-crc-multiple", HDMIA)
> -			test_display_crc_multiple(&data, port);
> +			test_display_crc(&data, port, 3);
>  	}
>  
>  	igt_subtest_group {
-- 
Cheers,
	Lyude
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH i-g-t v3 2/4] tests/ chamelium: Remove the frame dump tests
  2017-07-05 20:53   ` Lyude Paul
@ 2017-07-06  7:37     ` Martin Peres
  2017-07-06 13:29     ` Paul Kocialkowski
  1 sibling, 0 replies; 57+ messages in thread
From: Martin Peres @ 2017-07-06  7:37 UTC (permalink / raw)
  To: Lyude Paul, Paul Kocialkowski, intel-gfx

On 05/07/17 23:53, Lyude Paul wrote:
> NAK. You're right that these don't actually give us any advantage over
> just using CRCs and are just slower, however I left these tests in here
> moreso just so we had something to actually test the frame dumping
> functions so that we could avoid regressing them by accident since
> we're the only users of those functions right now.
> 
> If I recall properly, isn't there a list of tests in igt's source that
> they use for determining which tests to run on the CI? I think a better
> solution would be to just disable this for CI runs, and maybe add some
> comments pointing out that this test is only really useful for
> developers making changes to the chamelium library.

The general direction of IGT is to make sure that all tests are being 
executed by default, very much alike piglit.

I however do understand what you mean and I would then propose that we 
start defining naming conventions that allow filtering tests based on 
how level directive. For instance, we could have every test that need it 
export a slow and fast version, so as to easily be able to filter stuff 
out. I guess we need to start a separate thread for that.

As for this particular test, I would say that it could be simplified to 
prevent downloading so many images (all the exported resolutions * all 
the connected connectors). We could instead test one resolution per 
connector and call it good-enough. By better testing stuff, we just 
increase the likeliness of the test being completely blacklisted due to 
its excessive execution time. In this case, the better is the enemy of good.
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH i-g-t v3 4/4] chamelium: Dump obtained and reference frames to png on crc error
  2017-07-05 21:44   ` Lyude Paul
@ 2017-07-06  7:41     ` Martin Peres
  2017-07-06 11:35       ` Paul Kocialkowski
  2017-07-06 11:31     ` Paul Kocialkowski
  1 sibling, 1 reply; 57+ messages in thread
From: Martin Peres @ 2017-07-06  7:41 UTC (permalink / raw)
  To: Lyude Paul, Paul Kocialkowski, intel-gfx

On 06/07/17 00:44, Lyude Paul wrote:
> On Wed, 2017-07-05 at 11:04 +0300, Paul Kocialkowski wrote:
>> When a CRC comparison error occurs, it is quite useful to get a dump
>> of both the frame obtained from the chamelium and the reference in
>> order
>> to compare them.
>>
>> This implements the frame dump, with a configurable path that enables
>> the use of this feature.
>>
>> Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
>> ---
>>   lib/igt_chamelium.c |  21 +++++++++++
>>   lib/igt_chamelium.h |   1 +
>>   lib/igt_debugfs.c   |  20 ++++++++++
>>   lib/igt_debugfs.h   |   1 +
>>   tests/chamelium.c   | 104 ++++++++++++++++++++--------------------
>> ------------
>>   5 files changed, 82 insertions(+), 65 deletions(-)
>>
>> diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
>> index ef51ef68..9aca6842 100644
>> --- a/lib/igt_chamelium.c
>> +++ b/lib/igt_chamelium.c
>> @@ -57,6 +57,7 @@
>>    * |[<!-- language="plain" -->
>>    *	[Chamelium]
>>    *	URL=http://chameleon:9992 # The URL used for connecting to
>> the Chamelium's RPC server
>> + *	FrameDumpPath=/tmp # The path to dump frames that fail
>> comparison checks
> While no one else really cares about creating frame dumps yet, it's
> possible someone else may in the future if we ever end up taking more
> advantage of automated testing systems like this. So I'd stick this in
> the generic non-chamelium specific section in the config file
> 
>>    *
>>    *	# The rest of the sections are used for defining connector
>> mappings.
>>    *	# This is required so any tests using the Chamelium know
>> which connector
>> @@ -115,11 +116,26 @@ struct chamelium {
>>   	struct chamelium_edid *edids;
>>   	struct chamelium_port *ports;
>>   	int port_count;
>> +
>> +	char *frame_dump_path;
>>   };
>>   
>>   static struct chamelium *cleanup_instance;
>>   
>>   /**
>> + * chamelium_get_frame_dump_path:
>> + * @chamelium: The Chamelium instance to use
>> + *
>> + * Retrieves the path to dump frames to.
>> + *
>> + * Returns: a string with the frame dump path
>> + */
>> +char *chamelium_get_frame_dump_path(struct chamelium *chamelium)
>> +{
>> +	return chamelium->frame_dump_path;
>> +}
>> +
>> +/**
>>    * chamelium_get_ports:
>>    * @chamelium: The Chamelium instance to use
>>    * @count: Where to store the number of ports
>> @@ -1338,6 +1354,11 @@ static bool chamelium_read_config(struct
>> chamelium *chamelium, int drm_fd)
>>   		return false;
>>   	}
>>   
>> +	chamelium->frame_dump_path =
>> g_key_file_get_string(igt_key_file,
>> +							   "Chameliu
>> m",
>> +							   "FrameDum
>> pPath",
>> +							    &error);
>> +
>>   	return chamelium_read_port_mappings(chamelium, drm_fd);
>>   }
>>   
>> diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
>> index 908e03d1..aa881971 100644
>> --- a/lib/igt_chamelium.h
>> +++ b/lib/igt_chamelium.h
>> @@ -42,6 +42,7 @@ struct chamelium *chamelium_init(int drm_fd);
>>   void chamelium_deinit(struct chamelium *chamelium);
>>   void chamelium_reset(struct chamelium *chamelium);
>>   
>> +char *chamelium_get_frame_dump_path(struct chamelium *chamelium);
>>   struct chamelium_port **chamelium_get_ports(struct chamelium
>> *chamelium,
>>   					    int *count);
>>   unsigned int chamelium_port_get_type(const struct chamelium_port
>> *port);
>> diff --git a/lib/igt_debugfs.c b/lib/igt_debugfs.c
>> index 80f25c61..dcb4e0a7 100644
>> --- a/lib/igt_debugfs.c
>> +++ b/lib/igt_debugfs.c
>> @@ -282,6 +282,26 @@ bool igt_debugfs_search(int device, const char
>> *filename, const char *substring)
>>    */
>>   
>>   /**
>> + * igt_check_crc_equal:
>> + * @a: first pipe CRC value
>> + * @b: second pipe CRC value
>> + *
>> + * Compares two CRC values and return whether they match.
>> + *
>> + * Returns: A boolean indicating whether the CRC values match
>> + */
>> +bool igt_check_crc_equal(const igt_crc_t *a, const igt_crc_t *b)
>> +{
>> +	int i;

I would like to see:

if (a->n_words != b->n_words)
     return false;

>> +
>> +	for (i = 0; i < a->n_words; i++)
>> +		if (a->crc[i] != b->crc[i])
>> +			return false;
>> +
>> +	return true;
>> +}
>> +
> Make this a separate patch, and instead of having another function do
> the CRC calculations just have something like this:
> 
>   * static int igt_find_crc_mismatch(const igt_crc_t *a, const igt_crc_t
>     *b): returns the index of the first CRC mismatch, 0 if none was
>     found

Sounds good, but no error should return -1, as to differentiate if the 
first word was already different.

>   * bool igt_check_crc_equal(): uses igt_find_crc_mismatch() to figure
>     out if anything mismatched, and return true if something did (as
>     well, also spit out some debugging info mentioning there was a
>     mismatch)
>   * void igt_assert_crc_equal(): uses igt_find_crc_mismatch() to figure
>     out if anything mismatched. If the assertion fails, use
>     igt_assert_eq() on the mismatched crc so we still get a useful error
>     message on CRC failures.
> 
> There isn't much code required to actually compare CRCs, however I'd
> still prefer only having one function doing the actual comparison logic
> here so we only have one piece of code to update if we need to make
> changes to it in the future.
> 
> Mupuf, your opinion on this? ^
> 
>> +/**
>>    * igt_assert_crc_equal:
>>    * @a: first pipe CRC value
>>    * @b: second pipe CRC value
>> diff --git a/lib/igt_debugfs.h b/lib/igt_debugfs.h
>> index 7b846a83..2695cbda 100644
>> --- a/lib/igt_debugfs.h
>> +++ b/lib/igt_debugfs.h
>> @@ -113,6 +113,7 @@ enum intel_pipe_crc_source {
>>           INTEL_PIPE_CRC_SOURCE_MAX,
>>   };
>>   
>> +bool igt_check_crc_equal(const igt_crc_t *a, const igt_crc_t *b);
>>   void igt_assert_crc_equal(const igt_crc_t *a, const igt_crc_t *b);
>>   char *igt_crc_to_string(igt_crc_t *crc);
>>   
>> diff --git a/tests/chamelium.c b/tests/chamelium.c
>> index 5cf8b3af..3d95c05c 100644
>> --- a/tests/chamelium.c
>> +++ b/tests/chamelium.c
>> @@ -381,7 +381,7 @@ disable_output(data_t *data,
>>   }
>>   
>>   static void
>> -test_display_crc_single(data_t *data, struct chamelium_port *port)
>> +test_display_crc(data_t *data, struct chamelium_port *port, int
>> count)
>>   {
>>   	igt_display_t display;
>>   	igt_output_t *output;
>> @@ -390,9 +390,14 @@ test_display_crc_single(data_t *data, struct
>> chamelium_port *port)
>>   	igt_crc_t *expected_crc;
>>   	struct chamelium_fb_crc *fb_crc;
>>   	struct igt_fb fb;
>> +	struct chamelium_frame_dump *frame;
>>   	drmModeModeInfo *mode;
>>   	drmModeConnector *connector;
>> -	int fb_id, i;
>> +	int fb_id, i, j, captured_frame_count;
>> +	const char *connector_name;
>> +	char *frame_dump_path;
>> +	char path[PATH_MAX];
>> +	bool eq;
>>   
>>   	reset_state(data, port);
>>   
>> @@ -401,6 +406,9 @@ test_display_crc_single(data_t *data, struct
>> chamelium_port *port)
>>   	primary = igt_output_get_plane_type(output,
>> DRM_PLANE_TYPE_PRIMARY);
>>   	igt_assert(primary);
>>   
>> +	connector_name = kmstest_connector_type_str(connector-
>>> connector_type);
>> +	frame_dump_path = chamelium_get_frame_dump_path(data-
>>> chamelium);
>> +
>>   	for (i = 0; i < connector->count_modes; i++) {
>>   		mode = &connector->modes[i];
>>   		fb_id = igt_create_color_pattern_fb(data->drm_fd,
>> @@ -415,74 +423,40 @@ test_display_crc_single(data_t *data, struct
>> chamelium_port *port)
>>   
>>   		enable_output(data, port, output, mode, &fb);
>>   
>> -		igt_debug("Testing single CRC fetch\n");
>> -
>> -		crc = chamelium_get_crc_for_area(data->chamelium,
>> port,
>> -						 0, 0, 0, 0);
>> -
>> -		expected_crc =
>> chamelium_calculate_fb_crc_result(fb_crc);
>> -
>> -		igt_assert_crc_equal(crc, expected_crc);
>> -		free(expected_crc);
>> -		free(crc);
>> -
>> -		disable_output(data, port, output);
>> -		igt_remove_fb(data->drm_fd, &fb);
>> -	}
>> -
>> -	drmModeFreeConnector(connector);
>> -	igt_display_fini(&display);
>> -}
>> -
>> -static void
>> -test_display_crc_multiple(data_t *data, struct chamelium_port *port)
>> -{
>> -	igt_display_t display;
>> -	igt_output_t *output;
>> -	igt_plane_t *primary;
>> -	igt_crc_t *crc;
>> -	igt_crc_t *expected_crc;
>> -	struct chamelium_fb_crc *fb_crc;
>> -	struct igt_fb fb;
>> -	drmModeModeInfo *mode;
>> -	drmModeConnector *connector;
>> -	int fb_id, i, j, captured_frame_count;
>> +		chamelium_capture(data->chamelium, port, 0, 0, 0, 0,
>> count);
>> +		crc = chamelium_read_captured_crcs(data->chamelium,
>> +						   &captured_frame_c
>> ount);
>>   
>> -	reset_state(data, port);
>> +		igt_assert(captured_frame_count == count);
>>   
>> -	output = prepare_output(data, &display, port);
>> -	connector = chamelium_port_get_connector(data->chamelium,
>> port, false);
>> -	primary = igt_output_get_plane_type(output,
>> DRM_PLANE_TYPE_PRIMARY);
>> -	igt_assert(primary);
>> +		igt_debug("Captured %d frames\n",
>> captured_frame_count);
>>   
>> -	for (i = 0; i < connector->count_modes; i++) {
>> -		mode = &connector->modes[i];
>> -		fb_id = igt_create_color_pattern_fb(data->drm_fd,
>> -						    mode->hdisplay,
>> -						    mode->vdisplay,
>> -						    DRM_FORMAT_XRGB8
>> 888,
>> -						    LOCAL_DRM_FORMAT
>> _MOD_NONE,
>> -						    0, 0, 0, &fb);
>> -		igt_assert(fb_id > 0);
>> +		expected_crc =
>> chamelium_calculate_fb_crc_result(fb_crc);
>>   
>> -		fb_crc = chamelium_calculate_fb_crc_launch(data-
>>> drm_fd, &fb);
>> +		for (j = 0; j < captured_frame_count; j++) {
>> +			eq = igt_check_crc_equal(&crc[j],
>> expected_crc);
>> +			if (!eq && frame_dump_path) {
>> +				frame =
>> chamelium_read_captured_frame(data->chamelium,
>> +								
>>    j);
>>   
>> -		enable_output(data, port, output, mode, &fb);
>> +				igt_debug("Dumping reference and
>> chamelium frames to %s...\n",
>> +					  frame_dump_path);
>>   
>> -		/* We want to keep the display running for a little
>> bit, since
>> -		 * there's always the potential the driver isn't
>> able to keep
>> -		 * the display running properly for very long
>> -		 */
>> -		chamelium_capture(data->chamelium, port, 0, 0, 0, 0,
>> 3);
>> -		crc = chamelium_read_captured_crcs(data->chamelium,
>> -						   &captured_frame_c
>> ount);
>> +				snprintf(path, PATH_MAX, "%s/frame-
>> reference-%s.png",
>> +					 frame_dump_path,
>> connector_name);
>> +				igt_write_fb_to_png(data->drm_fd,
>> &fb, path);
>>   
>> -		igt_debug("Captured %d frames\n",
>> captured_frame_count);
>> +				snprintf(path, PATH_MAX, "%s/frame-
>> chamelium-%s.png",
>> +					 frame_dump_path,
>> connector_name);
>> +				chamelium_write_frame_to_png(data-
>>> chamelium,
>> +							     frame,
>> path);
>>   
>> -		expected_crc =
>> chamelium_calculate_fb_crc_result(fb_crc);
>> +				chamelium_destroy_frame_dump(frame);
>> +			}
>>   
>> -		for (j = 0; j < captured_frame_count; j++)
>> -			igt_assert_crc_equal(&crc[j], expected_crc);
>> +			igt_fail_on_f(!eq,
>> +				      "Chamelium frame CRC mismatch
>> with reference\n");
>> +		}
> There's lots of potential here for copy pasta to form in the future,
> since the API here puts a lot of work on the caller to set things up
> for frame dumping. IMO, it would be worth it to teach the CRC checking
> functions to automatically do frame dumps on mismatch if the CRC source
> supports it. This will save us from having to have separate frame dump
> APIs in the future if we ever end up adding support for other kinds of
> automated test equipment.
> 
> As well, I like how you removed the redundancy between
> test_display_crc_single() and test_display_crc_multiple(). However
> since those are somewhat unrelated changes to the code path for these
> tests it would be better to have that re-factoring as a separate patch
> so as to make it easier for anyone who might need to bisect this code
> in the future.
> 
>>   
>>   		free(expected_crc);
>>   		free(crc);
>> @@ -644,10 +618,10 @@ igt_main
>>   							edid_id,
>> alt_edid_id);
>>   
>>   		connector_subtest("dp-crc-single", DisplayPort)
>> -			test_display_crc_single(&data, port);
>> +			test_display_crc(&data, port, 1);
>>   
>>   		connector_subtest("dp-crc-multiple", DisplayPort)
>> -			test_display_crc_multiple(&data, port);
>> +			test_display_crc(&data, port, 3);
>>   	}
>>   
>>   	igt_subtest_group {
>> @@ -698,10 +672,10 @@ igt_main
>>   							edid_id,
>> alt_edid_id);
>>   
>>   		connector_subtest("hdmi-crc-single", HDMIA)
>> -			test_display_crc_single(&data, port);
>> +			test_display_crc(&data, port, 1);
>>   
>>   		connector_subtest("hdmi-crc-multiple", HDMIA)
>> -			test_display_crc_multiple(&data, port);
>> +			test_display_crc(&data, port, 3);
>>   	}
>>   
>>   	igt_subtest_group {
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH i-g-t v3 1/4] chamelium: Calculate CRC from framebuffer instead of hardcoding it
  2017-07-05 20:34 ` [PATCH i-g-t v3 1/4] chamelium: Calculate CRC from framebuffer instead of hardcoding it Lyude Paul
  2017-07-05 20:49   ` Lyude Paul
@ 2017-07-06  8:49   ` Paul Kocialkowski
  2017-07-06 13:14   ` Paul Kocialkowski
  2 siblings, 0 replies; 57+ messages in thread
From: Paul Kocialkowski @ 2017-07-06  8:49 UTC (permalink / raw)
  To: Lyude Paul, intel-gfx

Hi,

On Wed, 2017-07-05 at 16:34 -0400, Lyude Paul wrote:
> So a couple of notes here that will make it a lot easier for me to
> review these in the future
> 
>  * When you're doing a new revision of a patch series, it's helpful to
>    keep it in the same email thread as the original v1 so it's easier
>    to keep track of in people's mail clients (as well as avoiding
>    accidentally reviewing older patch versions. I usually do something
>    like this (other projects might request you do this slightly
>    differently, but this should be fine here):
>     * [PATCH 0/2] Cleaning up the alignment of various foos
>        * [PATCH 1/2] Foo the bar, not the baz
>        * [PATCH 2/2] Introduce the amazing new foo_bar
>        * [PATCH v2 0/2] Cleaning up the alignment of various foos
>           * [PATCH v2 1/2] Foo the bar, not the baz
>           * [PATCH v2 2/2] Introduce the amazing new foo_bar
>        * [PATCH v3 0/2] Cleaning up the alignment of various foos
>           * [PATCH v3 1/2] Foo the bar, not the baz
>           * [PATCH v3 2/2] Introduce the amazing new foo_bar
>  * Try not to group unrelated patches together in the same thread. This
>    also makes sorting through all of them a little more difficult.
>  * When you make new revisions of patches, it's very useful if you also
>    include a list of changes you made to the patch since the last
>    revision. It doesn't need to be very finely detailed, something like
>    this would suffice:
>     * Various style fixes
>     * Rename baz to moo, add cow noises
>     * Split init_cow() into init_white_cow() and init_black_cow()
>       instead of handling both kinds of cows in the same function
>     * Fix documentation
>     For intel-gpu-tools, it's fine to just stick this in the commit
>     message. Other projects may request you put the changelog below the
>     ----- right above the diff stats (this allows the comments not to
>     get included in the final commit message)
>  * Unless they are all very small and less important fixes, including
>    cover letters helps as well since it lets patchwork group together
>    patch series like this.

Thanks for clarifying these guidelines. I must admit that I have been too lazy
to craft cover letters so far, but I'll definitely do it in the future.

As for grouping unrelated patches in the same series, I mostly did that to
clarify in what order the (unrelated) patches should be applied, but I will
specify these dependencies in the cover letters from now on.

> Anyway, back to the actual patch:
> A good start! Will need a couple of changes though

I agree with yout comments and will craft v4 in that direction.

Thanks a lot for the review!

> On Wed, 2017-07-05 at 11:04 +0300, Paul Kocialkowski wrote:
> > This introduces CRC calculation for reference frames, instead of
> > using
> > hardcoded values for them. The rendering of reference frames may
> > differ
> > from machine to machine, especially due to font rendering, and the
> > frame itself may change with subsequent IGT changes.
> > 
> > These differences would cause the CRC checks to fail on different
> > setups. This allows them to pass regardless of the setup.
> > 
> > Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
> > ---
> >  lib/igt_chamelium.c | 160
> > ++++++++++++++++++++++++++++++++++++++++++++++++++++
> >  lib/igt_chamelium.h |   5 ++
> >  tests/chamelium.c   |  76 ++++++-------------------
> >  3 files changed, 183 insertions(+), 58 deletions(-)
> > 
> > diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
> > index bff08c0e..b9d80b6b 100644
> > --- a/lib/igt_chamelium.c
> > +++ b/lib/igt_chamelium.c
> > @@ -94,6 +94,14 @@ struct chamelium_frame_dump {
> >  	struct chamelium_port *port;
> >  };
> >  
> > +struct chamelium_fb_crc {
> > +	int fd;
> > +	struct igt_fb *fb;
> > +
> > +	pthread_t thread_id;
> > +	igt_crc_t *ret;
> > +};
> > +
> 
> The name of this structure is a little misleading, because now we have
> an API that exposes both a struct chamelium_fb_crc struct in addition
> to the igt_crc_t struct. Rename this to something like struct
> chamelium_fb_crc_work
> 
> >  struct chamelium {
> >  	xmlrpc_env env;
> >  	xmlrpc_client *client;
> > @@ -1003,6 +1011,158 @@ int chamelium_get_frame_limit(struct
> > chamelium *chamelium,
> >  	return ret;
> >  }
> >  
> > +static uint32_t chamelium_xrgb_hash16(unsigned char *buffer, int
> > width,
> > +				      int height, int k, int m)
> > +{
> 
> We're not modifying buffer, so make it a const. As well, feel free to
> mark this function as inline.
> 
> > +	unsigned char r, g, b;
> > +	uint64_t sum = 0;
> > +	uint64_t count = 0;
> > +	uint64_t value;
> > +	uint32_t hash;
> > +	int index;
> > +	int i;
> > +
> > +	for (i=0; i < width * height; i++) {
> > +		if ((i % m) != k)
> > +			continue;
> > +
> > +		index = i * 4;
> > +
> > +		r = buffer[index + 2];
> > +		g = buffer[index + 1];
> > +		b = buffer[index + 0];
> > +
> > +		value = r | (g << 8) | (b << 16);
> > +		sum += ++count * value;
> > +	}
> > +
> > +	hash = ((sum >> 0) ^ (sum >> 16) ^ (sum >> 32) ^ (sum >>
> > 48)) & 0xffff;
> > +
> > +	return hash;
> > +}
> > +
> > +/**
> > + * chamelium_calculate_fb_crc:
> > + * @fd: The drm file descriptor
> > + * @fb: The framebuffer to calculate the CRC for
> > + *
> > + * Calculates a CRC for the provided framebuffer, the same way as
> > the Chamelium.
> 
> Calculate the CRC for the provided framebuffer, using the Chamelium's
> CRC algorithm
> > + * This calculates the CRC in a non-threaded fashion.
> > + *
> > + * Returns: The calculated CRC
> > + */
> > +igt_crc_t *chamelium_calculate_fb_crc(int fd, struct igt_fb *fb)
> > +{
> > +	igt_crc_t *ret;
> > +	cairo_t *cr;
> > +	cairo_surface_t *fb_surface;
> > +	unsigned char *buffer;
> > +	int n = 4;
> > +	int w, h;
> > +	int i, j;
> > +
> > +	ret = calloc(1, sizeof(igt_crc_t));
> > +
> > +	/* Get the cairo surface for the framebuffer */
> > +	cr = igt_get_cairo_ctx(fd, fb);
> > +	fb_surface = cairo_get_target(cr);
> > +	cairo_surface_reference(fb_surface);
> > +	cairo_destroy(cr);
> > +
> > +	buffer = cairo_image_surface_get_data(fb_surface);
> > +	w = fb->width;
> > +	h = fb->height;
> > +
> > +	for (i = 0; i < n; i++) {
> > +		j = n - i - 1;
> > +		ret->crc[i] = chamelium_xrgb_hash16(buffer, w, h, j,
> > n);
> > +	}
> > +
> > +	ret->n_words = n;
> > +	cairo_surface_destroy(fb_surface);
> > +
> > +	return ret;
> > +}
> > +
> > +static void *chamelium_calculate_fb_crc_thread(void *data)
> > +{
> > +	struct chamelium_fb_crc *fb_crc = (struct chamelium_fb_crc
> > *) data;
> > +	cairo_t *cr;
> > +	cairo_surface_t *fb_surface;
> > +	unsigned char *buffer;
> > +	int n = 4;
> > +	int w, h;
> > +	int i, j;
> > +
> > +	/* Get the cairo surface for the framebuffer */
> > +	cr = igt_get_cairo_ctx(fb_crc->fd, fb_crc->fb);
> > +	fb_surface = cairo_get_target(cr);
> > +	cairo_surface_reference(fb_surface);
> > +	cairo_destroy(cr);
> > +
> > +	buffer = cairo_image_surface_get_data(fb_surface);
> > +	w = fb_crc->fb->width;
> > +	h = fb_crc->fb->height;
> > +
> > +	for (i = 0; i < n; i++) {
> > +		j = n - i - 1;
> > +		fb_crc->ret->crc[i] = chamelium_xrgb_hash16(buffer,
> > w, h, j, n);
> > +	}
> > +
> > +	fb_crc->ret->n_words = n;
> > +	cairo_surface_destroy(fb_surface);
> > +
> > +	return NULL;
> > +}
> > +
> > +/**
> > + * chamelium_calculate_fb_crc_launch:
> > + * @fd: The drm file descriptor
> > + * @fb: The framebuffer to calculate the CRC for
> > + *
> > + * Launches the CRC calculation for the provided framebuffer, the
> > same way as
> > + * the Chamelium. This calculates the CRC in a threaded fashion.
> > + * Thread-related information is returned and should be passed to a
> > subsequent
> > + * call to chamelium_calculate_fb_crc_result. It should not be
> > freed.
> > + *
> > + * Returns: An intermediate structure with thread-related
> > information
> 
> The user doesn't need to know about the magic inside the structure,
> since we're not going to expose it's definition outside of this file
> anyway.
> > + */
> > +struct chamelium_fb_crc *chamelium_calculate_fb_crc_launch(int fd,
> > +							   struct
> > igt_fb *fb)
> > +{
> > +	struct chamelium_fb_crc *fb_crc;
> > +
> > +	fb_crc = calloc(1, sizeof(struct chamelium_fb_crc));
> > +	fb_crc->ret = calloc(1, sizeof(igt_crc_t));
> > +	fb_crc->fd = fd;
> > +	fb_crc->fb = fb;
> > +
> > +	pthread_create(&fb_crc->thread_id, NULL,
> > +		       chamelium_calculate_fb_crc_thread, fb_crc);
> > +
> > +	return fb_crc;
> > +}
> > +
> > +/**
> > + * chamelium_calculate_fb_crc_result:
> > + * @fb_crc: An intermediate structure with thread-related
> > information
> > + *
> > + * Provides the result for the previously-launched CRC calculation.
> 
> Blocks until the async CRC calculation is finished, and then returns
> the result.
> > + *
> > + * Returns: The calculated CRC
> > + */
> > +igt_crc_t *chamelium_calculate_fb_crc_result(struct chamelium_fb_crc
> > *fb_crc)
> > +{
> > +	igt_crc_t *ret;
> > +
> > +	pthread_join(fb_crc->thread_id, NULL);
> > +
> > +	ret = fb_crc->ret;
> > +	free(fb_crc);
> > +
> > +	return ret;
> > +}
> > +
> >  static unsigned int chamelium_get_port_type(struct chamelium
> > *chamelium,
> >  					    struct chamelium_port
> > *port)
> >  {
> > diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
> > index 81322ad2..e51cf4f9 100644
> > --- a/lib/igt_chamelium.h
> > +++ b/lib/igt_chamelium.h
> > @@ -36,6 +36,7 @@
> >  struct chamelium;
> >  struct chamelium_port;
> >  struct chamelium_frame_dump;
> > +struct chamelium_fb_crc;
> >  
> >  struct chamelium *chamelium_init(int drm_fd);
> >  void chamelium_deinit(struct chamelium *chamelium);
> > @@ -92,6 +93,10 @@ struct chamelium_frame_dump
> > *chamelium_port_dump_pixels(struct chamelium *chamel
> >  							struct
> > chamelium_port *port,
> >  							int x, int
> > y,
> >  							int w, int
> > h);
> > +igt_crc_t *chamelium_calculate_fb_crc(int fd, struct igt_fb *fb);
> > +struct chamelium_fb_crc *chamelium_calculate_fb_crc_launch(int fd,
> > +							   struct
> > igt_fb *fb);
> > +igt_crc_t *chamelium_calculate_fb_crc_result(struct chamelium_fb_crc
> > *fb_crc);
> >  int chamelium_get_captured_frame_count(struct chamelium *chamelium);
> >  int chamelium_get_frame_limit(struct chamelium *chamelium,
> >  			      struct chamelium_port *port,
> > diff --git a/tests/chamelium.c b/tests/chamelium.c
> > index e3067664..3fd2b02c 100644
> > --- a/tests/chamelium.c
> > +++ b/tests/chamelium.c
> > @@ -49,43 +49,6 @@ typedef struct {
> >  #define HPD_TOGGLE_COUNT_VGA 5
> >  #define HPD_TOGGLE_COUNT_DP_HDMI 15
> >  
> > -/* Pre-calculated CRCs for the pattern fb, for all the modes in the
> > default
> > - * chamelium edid
> > - */
> > -struct crc_entry {
> > -	int width;
> > -	int height;
> > -	igt_crc_t crc;
> > -};
> > -
> > -#define CRC_ENTRY(w_, h_, ...) \
> > -	{ w_, h_, { .n_words = 4, .crc = { __VA_ARGS__ } } }
> > -
> > -static const struct crc_entry pattern_fb_crcs[] = {
> > -	CRC_ENTRY(1920, 1080, 0xf859, 0xa751, 0x8c81, 0x45a1),
> > -	CRC_ENTRY(1280,  720, 0xcec2, 0x4246, 0x6cfd, 0xeb43),
> > -	CRC_ENTRY(1024,  768, 0x85e5, 0xf0cd, 0xafe3, 0x7f18),
> > -	CRC_ENTRY( 800,  600, 0x6b39, 0x32b6, 0x831a, 0xb03e),
> > -	CRC_ENTRY( 640,  480, 0xa121, 0x2473, 0xb150, 0x8c47),
> > -};
> > -#undef CRC_ENTRY
> > -
> > -static const igt_crc_t *
> > -get_precalculated_crc(struct chamelium_port *port, int w, int h)
> > -{
> > -	int i;
> > -	const struct crc_entry *entry;
> > -
> > -	for (i = 0; i < ARRAY_SIZE(pattern_fb_crcs); i++) {
> > -		entry = &pattern_fb_crcs[i];
> > -
> > -		if (entry->width == w && entry->height == h)
> > -			return &entry->crc;
> > -	}
> > -
> > -	return NULL;
> > -}
> > -
> >  static void
> >  require_connector_present(data_t *data, unsigned int type)
> >  {
> > @@ -424,7 +387,8 @@ test_display_crc_single(data_t *data, struct
> > chamelium_port *port)
> >  	igt_output_t *output;
> >  	igt_plane_t *primary;
> >  	igt_crc_t *crc;
> > -	const igt_crc_t *expected_crc;
> > +	igt_crc_t *expected_crc;
> > +	struct chamelium_fb_crc *fb_crc;
> >  	struct igt_fb fb;
> >  	drmModeModeInfo *mode;
> >  	drmModeConnector *connector;
> > @@ -447,24 +411,21 @@ test_display_crc_single(data_t *data, struct
> > chamelium_port *port)
> >  						    0, 0, 0, &fb);
> >  		igt_assert(fb_id > 0);
> >  
> > -		enable_output(data, port, output, mode, &fb);
> > +		fb_crc = chamelium_calculate_fb_crc_launch(data-
> > > drm_fd, &fb);
> > 
> >  
> > -		expected_crc = get_precalculated_crc(port,
> > -						     mode->hdisplay,
> > -						     mode-
> > > vdisplay);
> > 
> > -		if (!expected_crc) {
> > -			igt_warn("No precalculated CRC found for
> > %dx%d, skipping CRC check\n",
> > -				 mode->hdisplay, mode->vdisplay);
> > -			goto next;
> > -		}
> > +		enable_output(data, port, output, mode, &fb);
> >  
> >  		igt_debug("Testing single CRC fetch\n");
> > +
> >  		crc = chamelium_get_crc_for_area(data->chamelium,
> > port,
> >  						 0, 0, 0, 0);
> > +
> > +		expected_crc =
> > chamelium_calculate_fb_crc_result(fb_crc);
> > +
> >  		igt_assert_crc_equal(crc, expected_crc);
> > +		free(expected_crc);
> >  		free(crc);
> >  
> > -next:
> >  		disable_output(data, port, output);
> >  		igt_remove_fb(data->drm_fd, &fb);
> >  	}
> > @@ -480,7 +441,8 @@ test_display_crc_multiple(data_t *data, struct
> > chamelium_port *port)
> >  	igt_output_t *output;
> >  	igt_plane_t *primary;
> >  	igt_crc_t *crc;
> > -	const igt_crc_t *expected_crc;
> > +	igt_crc_t *expected_crc;
> > +	struct chamelium_fb_crc *fb_crc;
> >  	struct igt_fb fb;
> >  	drmModeModeInfo *mode;
> >  	drmModeConnector *connector;
> > @@ -503,15 +465,9 @@ test_display_crc_multiple(data_t *data, struct
> > chamelium_port *port)
> >  						    0, 0, 0, &fb);
> >  		igt_assert(fb_id > 0);
> >  
> > -		enable_output(data, port, output, mode, &fb);
> > +		fb_crc = chamelium_calculate_fb_crc_launch(data-
> > > drm_fd, &fb);
> > 
> >  
> > -		expected_crc = get_precalculated_crc(port, mode-
> > > hdisplay,
> > 
> > -						     mode-
> > > vdisplay);
> > 
> > -		if (!expected_crc) {
> > -			igt_warn("No precalculated CRC found for
> > %dx%d, skipping CRC check\n",
> > -				 mode->hdisplay, mode->vdisplay);
> > -			goto next;
> > -		}
> > +		enable_output(data, port, output, mode, &fb);
> >  
> >  		/* We want to keep the display running for a little
> > bit, since
> >  		 * there's always the potential the driver isn't
> > able to keep
> > @@ -522,11 +478,15 @@ test_display_crc_multiple(data_t *data, struct
> > chamelium_port *port)
> >  						   &captured_frame_c
> > ount);
> >  
> >  		igt_debug("Captured %d frames\n",
> > captured_frame_count);
> > +
> > +		expected_crc =
> > chamelium_calculate_fb_crc_result(fb_crc);
> > +
> >  		for (j = 0; j < captured_frame_count; j++)
> >  			igt_assert_crc_equal(&crc[j], expected_crc);
> > +
> > +		free(expected_crc);
> >  		free(crc);
> >  
> > -next:
> >  		disable_output(data, port, output);
> >  		igt_remove_fb(data->drm_fd, &fb);
> >  	}
-- 
Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo, FInland
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH i-g-t v3 4/4] chamelium: Dump obtained and reference frames to png on crc error
  2017-07-05 21:44   ` Lyude Paul
  2017-07-06  7:41     ` Martin Peres
@ 2017-07-06 11:31     ` Paul Kocialkowski
  2017-07-06 13:33       ` Paul Kocialkowski
  1 sibling, 1 reply; 57+ messages in thread
From: Paul Kocialkowski @ 2017-07-06 11:31 UTC (permalink / raw)
  To: Lyude Paul, intel-gfx

Hi,

On Wed, 2017-07-05 at 17:44 -0400, Lyude Paul wrote:
> On Wed, 2017-07-05 at 11:04 +0300, Paul Kocialkowski wrote:
> > When a CRC comparison error occurs, it is quite useful to get a dump
> > of both the frame obtained from the chamelium and the reference in
> > order
> > to compare them.
> > 
> > This implements the frame dump, with a configurable path that enables
> > the use of this feature.
> > 
> > Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
> > ---
> >  lib/igt_chamelium.c |  21 +++++++++++
> >  lib/igt_chamelium.h |   1 +
> >  lib/igt_debugfs.c   |  20 ++++++++++
> >  lib/igt_debugfs.h   |   1 +
> >  tests/chamelium.c   | 104 ++++++++++++++++++++--------------------
> > ------------
> >  5 files changed, 82 insertions(+), 65 deletions(-)
> > 
> > diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
> > index ef51ef68..9aca6842 100644
> > --- a/lib/igt_chamelium.c
> > +++ b/lib/igt_chamelium.c
> > @@ -57,6 +57,7 @@
> >   * |[<!-- language="plain" -->
> >   *	[Chamelium]
> >   *	URL=http://chameleon:9992 # The URL used for connecting to
> > the Chamelium's RPC server
> > + *	FrameDumpPath=/tmp # The path to dump frames that fail
> > comparison checks
> 
> While no one else really cares about creating frame dumps yet, it's
> possible someone else may in the future if we ever end up taking more
> advantage of automated testing systems like this. So I'd stick this in
> the generic non-chamelium specific section in the config file

That definitely makes sense. By the way, what approach would you recommend for
thishandling? Mupuf was suggesting to have a common configuration structure
instead of declaring either global variables or static ones with
getters/setters. This is probably becoming more and more of a necessity as we
add more common config options.

However, I think we should still allow specific parts of IGT to do the parsing
themselves (especially in the case of chamelium) so that the common config
structure only has common fields (and does not, for instance, contain the
chamelium port configuration).

> >   *
> >   *	# The rest of the sections are used for defining connector
> > mappings.
> >   *	# This is required so any tests using the Chamelium know
> > which connector
> > @@ -115,11 +116,26 @@ struct chamelium {
> >  	struct chamelium_edid *edids;
> >  	struct chamelium_port *ports;
> >  	int port_count;
> > +
> > +	char *frame_dump_path;
> >  };
> >  
> >  static struct chamelium *cleanup_instance;
> >  
> >  /**
> > + * chamelium_get_frame_dump_path:
> > + * @chamelium: The Chamelium instance to use
> > + *
> > + * Retrieves the path to dump frames to.
> > + *
> > + * Returns: a string with the frame dump path
> > + */
> > +char *chamelium_get_frame_dump_path(struct chamelium *chamelium)
> > +{
> > +	return chamelium->frame_dump_path;
> > +}
> > +
> > +/**
> >   * chamelium_get_ports:
> >   * @chamelium: The Chamelium instance to use
> >   * @count: Where to store the number of ports
> > @@ -1338,6 +1354,11 @@ static bool chamelium_read_config(struct
> > chamelium *chamelium, int drm_fd)
> >  		return false;
> >  	}
> >  
> > +	chamelium->frame_dump_path =
> > g_key_file_get_string(igt_key_file,
> > +							   "Chameliu
> > m",
> > +							   "FrameDum
> > pPath",
> > +							    &error);
> > +
> >  	return chamelium_read_port_mappings(chamelium, drm_fd);
> >  }
> >  
> > diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
> > index 908e03d1..aa881971 100644
> > --- a/lib/igt_chamelium.h
> > +++ b/lib/igt_chamelium.h
> > @@ -42,6 +42,7 @@ struct chamelium *chamelium_init(int drm_fd);
> >  void chamelium_deinit(struct chamelium *chamelium);
> >  void chamelium_reset(struct chamelium *chamelium);
> >  
> > +char *chamelium_get_frame_dump_path(struct chamelium *chamelium);
> >  struct chamelium_port **chamelium_get_ports(struct chamelium
> > *chamelium,
> >  					    int *count);
> >  unsigned int chamelium_port_get_type(const struct chamelium_port
> > *port);
> > diff --git a/lib/igt_debugfs.c b/lib/igt_debugfs.c
> > index 80f25c61..dcb4e0a7 100644
> > --- a/lib/igt_debugfs.c
> > +++ b/lib/igt_debugfs.c
> > @@ -282,6 +282,26 @@ bool igt_debugfs_search(int device, const char
> > *filename, const char *substring)
> >   */
> >  
> >  /**
> > + * igt_check_crc_equal:
> > + * @a: first pipe CRC value
> > + * @b: second pipe CRC value
> > + *
> > + * Compares two CRC values and return whether they match.
> > + *
> > + * Returns: A boolean indicating whether the CRC values match
> > + */
> > +bool igt_check_crc_equal(const igt_crc_t *a, const igt_crc_t *b)
> > +{
> > +	int i;
> > +
> > +	for (i = 0; i < a->n_words; i++)
> > +		if (a->crc[i] != b->crc[i])
> > +			return false;
> > +
> > +	return true;
> > +}
> > +
> 
> Make this a separate patch, and instead of having another function do
> the CRC calculations just have something like this:
> 
>  * static int igt_find_crc_mismatch(const igt_crc_t *a, const igt_crc_t
>    *b): returns the index of the first CRC mismatch, 0 if none was
>    found
>  * bool igt_check_crc_equal(): uses igt_find_crc_mismatch() to figure
>    out if anything mismatched, and return true if something did (as
>    well, also spit out some debugging info mentioning there was a
>    mismatch)
>  * void igt_assert_crc_equal(): uses igt_find_crc_mismatch() to figure
>    out if anything mismatched. If the assertion fails, use
>    igt_assert_eq() on the mismatched crc so we still get a useful error
>    message on CRC failures.
> 
> There isn't much code required to actually compare CRCs, however I'd
> still prefer only having one function doing the actual comparison logic
> here so we only have one piece of code to update if we need to make
> changes to it in the future.
> 
> Mupuf, your opinion on this? ^
> 
> > +/**
> >   * igt_assert_crc_equal:
> >   * @a: first pipe CRC value
> >   * @b: second pipe CRC value
> > diff --git a/lib/igt_debugfs.h b/lib/igt_debugfs.h
> > index 7b846a83..2695cbda 100644
> > --- a/lib/igt_debugfs.h
> > +++ b/lib/igt_debugfs.h
> > @@ -113,6 +113,7 @@ enum intel_pipe_crc_source {
> >          INTEL_PIPE_CRC_SOURCE_MAX,
> >  };
> >  
> > +bool igt_check_crc_equal(const igt_crc_t *a, const igt_crc_t *b);
> >  void igt_assert_crc_equal(const igt_crc_t *a, const igt_crc_t *b);
> >  char *igt_crc_to_string(igt_crc_t *crc);
> >  
> > diff --git a/tests/chamelium.c b/tests/chamelium.c
> > index 5cf8b3af..3d95c05c 100644
> > --- a/tests/chamelium.c
> > +++ b/tests/chamelium.c
> > @@ -381,7 +381,7 @@ disable_output(data_t *data,
> >  }
> >  
> >  static void
> > -test_display_crc_single(data_t *data, struct chamelium_port *port)
> > +test_display_crc(data_t *data, struct chamelium_port *port, int
> > count)
> >  {
> >  	igt_display_t display;
> >  	igt_output_t *output;
> > @@ -390,9 +390,14 @@ test_display_crc_single(data_t *data, struct
> > chamelium_port *port)
> >  	igt_crc_t *expected_crc;
> >  	struct chamelium_fb_crc *fb_crc;
> >  	struct igt_fb fb;
> > +	struct chamelium_frame_dump *frame;
> >  	drmModeModeInfo *mode;
> >  	drmModeConnector *connector;
> > -	int fb_id, i;
> > +	int fb_id, i, j, captured_frame_count;
> > +	const char *connector_name;
> > +	char *frame_dump_path;
> > +	char path[PATH_MAX];
> > +	bool eq;
> >  
> >  	reset_state(data, port);
> >  
> > @@ -401,6 +406,9 @@ test_display_crc_single(data_t *data, struct
> > chamelium_port *port)
> >  	primary = igt_output_get_plane_type(output,
> > DRM_PLANE_TYPE_PRIMARY);
> >  	igt_assert(primary);
> >  
> > +	connector_name = kmstest_connector_type_str(connector-
> > > connector_type);
> > 
> > +	frame_dump_path = chamelium_get_frame_dump_path(data-
> > > chamelium);
> > 
> > +
> >  	for (i = 0; i < connector->count_modes; i++) {
> >  		mode = &connector->modes[i];
> >  		fb_id = igt_create_color_pattern_fb(data->drm_fd,
> > @@ -415,74 +423,40 @@ test_display_crc_single(data_t *data, struct
> > chamelium_port *port)
> >  
> >  		enable_output(data, port, output, mode, &fb);
> >  
> > -		igt_debug("Testing single CRC fetch\n");
> > -
> > -		crc = chamelium_get_crc_for_area(data->chamelium,
> > port,
> > -						 0, 0, 0, 0);
> > -
> > -		expected_crc =
> > chamelium_calculate_fb_crc_result(fb_crc);
> > -
> > -		igt_assert_crc_equal(crc, expected_crc);
> > -		free(expected_crc);
> > -		free(crc);
> > -
> > -		disable_output(data, port, output);
> > -		igt_remove_fb(data->drm_fd, &fb);
> > -	}
> > -
> > -	drmModeFreeConnector(connector);
> > -	igt_display_fini(&display);
> > -}
> > -
> > -static void
> > -test_display_crc_multiple(data_t *data, struct chamelium_port *port)
> > -{
> > -	igt_display_t display;
> > -	igt_output_t *output;
> > -	igt_plane_t *primary;
> > -	igt_crc_t *crc;
> > -	igt_crc_t *expected_crc;
> > -	struct chamelium_fb_crc *fb_crc;
> > -	struct igt_fb fb;
> > -	drmModeModeInfo *mode;
> > -	drmModeConnector *connector;
> > -	int fb_id, i, j, captured_frame_count;
> > +		chamelium_capture(data->chamelium, port, 0, 0, 0, 0,
> > count);
> > +		crc = chamelium_read_captured_crcs(data->chamelium,
> > +						   &captured_frame_c
> > ount);
> >  
> > -	reset_state(data, port);
> > +		igt_assert(captured_frame_count == count);
> >  
> > -	output = prepare_output(data, &display, port);
> > -	connector = chamelium_port_get_connector(data->chamelium,
> > port, false);
> > -	primary = igt_output_get_plane_type(output,
> > DRM_PLANE_TYPE_PRIMARY);
> > -	igt_assert(primary);
> > +		igt_debug("Captured %d frames\n",
> > captured_frame_count);
> >  
> > -	for (i = 0; i < connector->count_modes; i++) {
> > -		mode = &connector->modes[i];
> > -		fb_id = igt_create_color_pattern_fb(data->drm_fd,
> > -						    mode->hdisplay,
> > -						    mode->vdisplay,
> > -						    DRM_FORMAT_XRGB8
> > 888,
> > -						    LOCAL_DRM_FORMAT
> > _MOD_NONE,
> > -						    0, 0, 0, &fb);
> > -		igt_assert(fb_id > 0);
> > +		expected_crc =
> > chamelium_calculate_fb_crc_result(fb_crc);
> >  
> > -		fb_crc = chamelium_calculate_fb_crc_launch(data-
> > > drm_fd, &fb);
> > 
> > +		for (j = 0; j < captured_frame_count; j++) {
> > +			eq = igt_check_crc_equal(&crc[j],
> > expected_crc);
> > +			if (!eq && frame_dump_path) {
> > +				frame =
> > chamelium_read_captured_frame(data->chamelium,
> > +								    
> >   j);
> >  
> > -		enable_output(data, port, output, mode, &fb);
> > +				igt_debug("Dumping reference and
> > chamelium frames to %s...\n",
> > +					  frame_dump_path);
> >  
> > -		/* We want to keep the display running for a little
> > bit, since
> > -		 * there's always the potential the driver isn't
> > able to keep
> > -		 * the display running properly for very long
> > -		 */
> > -		chamelium_capture(data->chamelium, port, 0, 0, 0, 0,
> > 3);
> > -		crc = chamelium_read_captured_crcs(data->chamelium,
> > -						   &captured_frame_c
> > ount);
> > +				snprintf(path, PATH_MAX, "%s/frame-
> > reference-%s.png",
> > +					 frame_dump_path,
> > connector_name);
> > +				igt_write_fb_to_png(data->drm_fd,
> > &fb, path);
> >  
> > -		igt_debug("Captured %d frames\n",
> > captured_frame_count);
> > +				snprintf(path, PATH_MAX, "%s/frame-
> > chamelium-%s.png",
> > +					 frame_dump_path,
> > connector_name);
> > +				chamelium_write_frame_to_png(data-
> > > chamelium,
> > 
> > +							     frame,
> > path);
> >  
> > -		expected_crc =
> > chamelium_calculate_fb_crc_result(fb_crc);
> > +				chamelium_destroy_frame_dump(frame);
> > +			}
> >  
> > -		for (j = 0; j < captured_frame_count; j++)
> > -			igt_assert_crc_equal(&crc[j], expected_crc);
> > +			igt_fail_on_f(!eq,
> > +				      "Chamelium frame CRC mismatch
> > with reference\n");
> > +		}
> 
> There's lots of potential here for copy pasta to form in the future,
> since the API here puts a lot of work on the caller to set things up
> for frame dumping. IMO, it would be worth it to teach the CRC checking
> functions to automatically do frame dumps on mismatch if the CRC source
> supports it. This will save us from having to have separate frame dump
> APIs in the future if we ever end up adding support for other kinds of
> automated test equipment.

I don't think it makes so much sense to do this in the CRC checking functions,
just because they are semantically expected to do one thing: CRC checking, and
doing frame dumps seems like going overboard.

On the other hand, I do agree that the dumping and saving part can and should be
made common, but maybe as a separate function. So that would be two calls for
the tests: one to check the crc and one to dump and save the frame.

I have also duplicated that logic in upcoming VGA frame testing, so there is
definitely a need for less duplication.

> As well, I like how you removed the redundancy between
> test_display_crc_single() and test_display_crc_multiple(). However
> since those are somewhat unrelated changes to the code path for these
> tests it would be better to have that re-factoring as a separate patch
> so as to make it easier for anyone who might need to bisect this code
> in the future.

Fair enough, it just felt weird to commit two functions that were nearly the
exact same, but I have no problem with doing this in two separate patches.

> >  
> >  		free(expected_crc);
> >  		free(crc);
> > @@ -644,10 +618,10 @@ igt_main
> >  							edid_id,
> > alt_edid_id);
> >  
> >  		connector_subtest("dp-crc-single", DisplayPort)
> > -			test_display_crc_single(&data, port);
> > +			test_display_crc(&data, port, 1);
> >  
> >  		connector_subtest("dp-crc-multiple", DisplayPort)
> > -			test_display_crc_multiple(&data, port);
> > +			test_display_crc(&data, port, 3);
> >  	}
> >  
> >  	igt_subtest_group {
> > @@ -698,10 +672,10 @@ igt_main
> >  							edid_id,
> > alt_edid_id);
> >  
> >  		connector_subtest("hdmi-crc-single", HDMIA)
> > -			test_display_crc_single(&data, port);
> > +			test_display_crc(&data, port, 1);
> >  
> >  		connector_subtest("hdmi-crc-multiple", HDMIA)
> > -			test_display_crc_multiple(&data, port);
> > +			test_display_crc(&data, port, 3);
> >  	}
> >  
> >  	igt_subtest_group {
-- 
Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo, FInland
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH i-g-t v3 4/4] chamelium: Dump obtained and reference frames to png on crc error
  2017-07-06  7:41     ` Martin Peres
@ 2017-07-06 11:35       ` Paul Kocialkowski
  2017-07-06 22:23         ` Lyude Paul
  0 siblings, 1 reply; 57+ messages in thread
From: Paul Kocialkowski @ 2017-07-06 11:35 UTC (permalink / raw)
  To: Martin Peres, Lyude Paul, intel-gfx

On Thu, 2017-07-06 at 10:41 +0300, Martin Peres wrote:
> On 06/07/17 00:44, Lyude Paul wrote:
> > On Wed, 2017-07-05 at 11:04 +0300, Paul Kocialkowski wrote:
> > > When a CRC comparison error occurs, it is quite useful to get a dump
> > > of both the frame obtained from the chamelium and the reference in
> > > order
> > > to compare them.
> > > 
> > > This implements the frame dump, with a configurable path that enables
> > > the use of this feature.
> > > 
> > > Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
> > > ---
> > >   lib/igt_chamelium.c |  21 +++++++++++
> > >   lib/igt_chamelium.h |   1 +
> > >   lib/igt_debugfs.c   |  20 ++++++++++
> > >   lib/igt_debugfs.h   |   1 +
> > >   tests/chamelium.c   | 104 ++++++++++++++++++++--------------------
> > > ------------
> > >   5 files changed, 82 insertions(+), 65 deletions(-)
> > > 
> > > diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
> > > index ef51ef68..9aca6842 100644
> > > --- a/lib/igt_chamelium.c
> > > +++ b/lib/igt_chamelium.c
> > > @@ -57,6 +57,7 @@
> > >    * |[<!-- language="plain" -->
> > >    *	[Chamelium]
> > >    *	URL=http://chameleon:9992 # The URL used for connecting to
> > > the Chamelium's RPC server
> > > + *	FrameDumpPath=/tmp # The path to dump frames that fail
> > > comparison checks
> > 
> > While no one else really cares about creating frame dumps yet, it's
> > possible someone else may in the future if we ever end up taking more
> > advantage of automated testing systems like this. So I'd stick this in
> > the generic non-chamelium specific section in the config file
> > 
> > >    *
> > >    *	# The rest of the sections are used for defining connector
> > > mappings.
> > >    *	# This is required so any tests using the Chamelium know
> > > which connector
> > > @@ -115,11 +116,26 @@ struct chamelium {
> > >   	struct chamelium_edid *edids;
> > >   	struct chamelium_port *ports;
> > >   	int port_count;
> > > +
> > > +	char *frame_dump_path;
> > >   };
> > >   
> > >   static struct chamelium *cleanup_instance;
> > >   
> > >   /**
> > > + * chamelium_get_frame_dump_path:
> > > + * @chamelium: The Chamelium instance to use
> > > + *
> > > + * Retrieves the path to dump frames to.
> > > + *
> > > + * Returns: a string with the frame dump path
> > > + */
> > > +char *chamelium_get_frame_dump_path(struct chamelium *chamelium)
> > > +{
> > > +	return chamelium->frame_dump_path;
> > > +}
> > > +
> > > +/**
> > >    * chamelium_get_ports:
> > >    * @chamelium: The Chamelium instance to use
> > >    * @count: Where to store the number of ports
> > > @@ -1338,6 +1354,11 @@ static bool chamelium_read_config(struct
> > > chamelium *chamelium, int drm_fd)
> > >   		return false;
> > >   	}
> > >   
> > > +	chamelium->frame_dump_path =
> > > g_key_file_get_string(igt_key_file,
> > > +							   "Chameliu
> > > m",
> > > +							   "FrameDum
> > > pPath",
> > > +							    &error);
> > > +
> > >   	return chamelium_read_port_mappings(chamelium, drm_fd);
> > >   }
> > >   
> > > diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
> > > index 908e03d1..aa881971 100644
> > > --- a/lib/igt_chamelium.h
> > > +++ b/lib/igt_chamelium.h
> > > @@ -42,6 +42,7 @@ struct chamelium *chamelium_init(int drm_fd);
> > >   void chamelium_deinit(struct chamelium *chamelium);
> > >   void chamelium_reset(struct chamelium *chamelium);
> > >   
> > > +char *chamelium_get_frame_dump_path(struct chamelium *chamelium);
> > >   struct chamelium_port **chamelium_get_ports(struct chamelium
> > > *chamelium,
> > >   					    int *count);
> > >   unsigned int chamelium_port_get_type(const struct chamelium_port
> > > *port);
> > > diff --git a/lib/igt_debugfs.c b/lib/igt_debugfs.c
> > > index 80f25c61..dcb4e0a7 100644
> > > --- a/lib/igt_debugfs.c
> > > +++ b/lib/igt_debugfs.c
> > > @@ -282,6 +282,26 @@ bool igt_debugfs_search(int device, const char
> > > *filename, const char *substring)
> > >    */
> > >   
> > >   /**
> > > + * igt_check_crc_equal:
> > > + * @a: first pipe CRC value
> > > + * @b: second pipe CRC value
> > > + *
> > > + * Compares two CRC values and return whether they match.
> > > + *
> > > + * Returns: A boolean indicating whether the CRC values match
> > > + */
> > > +bool igt_check_crc_equal(const igt_crc_t *a, const igt_crc_t *b)
> > > +{
> > > +	int i;
> 
> I would like to see:
> 
> if (a->n_words != b->n_words)
>      return false;

Very good suggestion! I'll take that in in the next revision.

> > > +
> > > +	for (i = 0; i < a->n_words; i++)
> > > +		if (a->crc[i] != b->crc[i])
> > > +			return false;
> > > +
> > > +	return true;
> > > +}
> > > +
> > 
> > Make this a separate patch, and instead of having another function do
> > the CRC calculations just have something like this:
> > 
> >   * static int igt_find_crc_mismatch(const igt_crc_t *a, const igt_crc_t
> >     *b): returns the index of the first CRC mismatch, 0 if none was
> >     found
> 
> Sounds good, but no error should return -1, as to differentiate if the 
> first word was already different.

I don't understand the point of getting the index of the CRC mismatch at all.
The only relevant information here should be whether it matches or not (which
would be covered by igt_check_crc_equal). Can you ellaborate on this?

> >   * bool igt_check_crc_equal(): uses igt_find_crc_mismatch() to figure
> >     out if anything mismatched, and return true if something did (as
> >     well, also spit out some debugging info mentioning there was a
> >     mismatch)
> >   * void igt_assert_crc_equal(): uses igt_find_crc_mismatch() to figure
> >     out if anything mismatched. If the assertion fails, use
> >     igt_assert_eq() on the mismatched crc so we still get a useful error
> >     message on CRC failures.
> > 
> > There isn't much code required to actually compare CRCs, however I'd
> > still prefer only having one function doing the actual comparison logic
> > here so we only have one piece of code to update if we need to make
> > changes to it in the future.
> > 
> > Mupuf, your opinion on this? ^
> > 
> > > +/**
> > >    * igt_assert_crc_equal:
> > >    * @a: first pipe CRC value
> > >    * @b: second pipe CRC value
> > > diff --git a/lib/igt_debugfs.h b/lib/igt_debugfs.h
> > > index 7b846a83..2695cbda 100644
> > > --- a/lib/igt_debugfs.h
> > > +++ b/lib/igt_debugfs.h
> > > @@ -113,6 +113,7 @@ enum intel_pipe_crc_source {
> > >           INTEL_PIPE_CRC_SOURCE_MAX,
> > >   };
> > >   
> > > +bool igt_check_crc_equal(const igt_crc_t *a, const igt_crc_t *b);
> > >   void igt_assert_crc_equal(const igt_crc_t *a, const igt_crc_t *b);
> > >   char *igt_crc_to_string(igt_crc_t *crc);
> > >   
> > > diff --git a/tests/chamelium.c b/tests/chamelium.c
> > > index 5cf8b3af..3d95c05c 100644
> > > --- a/tests/chamelium.c
> > > +++ b/tests/chamelium.c
> > > @@ -381,7 +381,7 @@ disable_output(data_t *data,
> > >   }
> > >   
> > >   static void
> > > -test_display_crc_single(data_t *data, struct chamelium_port *port)
> > > +test_display_crc(data_t *data, struct chamelium_port *port, int
> > > count)
> > >   {
> > >   	igt_display_t display;
> > >   	igt_output_t *output;
> > > @@ -390,9 +390,14 @@ test_display_crc_single(data_t *data, struct
> > > chamelium_port *port)
> > >   	igt_crc_t *expected_crc;
> > >   	struct chamelium_fb_crc *fb_crc;
> > >   	struct igt_fb fb;
> > > +	struct chamelium_frame_dump *frame;
> > >   	drmModeModeInfo *mode;
> > >   	drmModeConnector *connector;
> > > -	int fb_id, i;
> > > +	int fb_id, i, j, captured_frame_count;
> > > +	const char *connector_name;
> > > +	char *frame_dump_path;
> > > +	char path[PATH_MAX];
> > > +	bool eq;
> > >   
> > >   	reset_state(data, port);
> > >   
> > > @@ -401,6 +406,9 @@ test_display_crc_single(data_t *data, struct
> > > chamelium_port *port)
> > >   	primary = igt_output_get_plane_type(output,
> > > DRM_PLANE_TYPE_PRIMARY);
> > >   	igt_assert(primary);
> > >   
> > > +	connector_name = kmstest_connector_type_str(connector-
> > > > connector_type);
> > > 
> > > +	frame_dump_path = chamelium_get_frame_dump_path(data-
> > > > chamelium);
> > > 
> > > +
> > >   	for (i = 0; i < connector->count_modes; i++) {
> > >   		mode = &connector->modes[i];
> > >   		fb_id = igt_create_color_pattern_fb(data->drm_fd,
> > > @@ -415,74 +423,40 @@ test_display_crc_single(data_t *data, struct
> > > chamelium_port *port)
> > >   
> > >   		enable_output(data, port, output, mode, &fb);
> > >   
> > > -		igt_debug("Testing single CRC fetch\n");
> > > -
> > > -		crc = chamelium_get_crc_for_area(data->chamelium,
> > > port,
> > > -						 0, 0, 0, 0);
> > > -
> > > -		expected_crc =
> > > chamelium_calculate_fb_crc_result(fb_crc);
> > > -
> > > -		igt_assert_crc_equal(crc, expected_crc);
> > > -		free(expected_crc);
> > > -		free(crc);
> > > -
> > > -		disable_output(data, port, output);
> > > -		igt_remove_fb(data->drm_fd, &fb);
> > > -	}
> > > -
> > > -	drmModeFreeConnector(connector);
> > > -	igt_display_fini(&display);
> > > -}
> > > -
> > > -static void
> > > -test_display_crc_multiple(data_t *data, struct chamelium_port *port)
> > > -{
> > > -	igt_display_t display;
> > > -	igt_output_t *output;
> > > -	igt_plane_t *primary;
> > > -	igt_crc_t *crc;
> > > -	igt_crc_t *expected_crc;
> > > -	struct chamelium_fb_crc *fb_crc;
> > > -	struct igt_fb fb;
> > > -	drmModeModeInfo *mode;
> > > -	drmModeConnector *connector;
> > > -	int fb_id, i, j, captured_frame_count;
> > > +		chamelium_capture(data->chamelium, port, 0, 0, 0, 0,
> > > count);
> > > +		crc = chamelium_read_captured_crcs(data->chamelium,
> > > +						   &captured_frame_c
> > > ount);
> > >   
> > > -	reset_state(data, port);
> > > +		igt_assert(captured_frame_count == count);
> > >   
> > > -	output = prepare_output(data, &display, port);
> > > -	connector = chamelium_port_get_connector(data->chamelium,
> > > port, false);
> > > -	primary = igt_output_get_plane_type(output,
> > > DRM_PLANE_TYPE_PRIMARY);
> > > -	igt_assert(primary);
> > > +		igt_debug("Captured %d frames\n",
> > > captured_frame_count);
> > >   
> > > -	for (i = 0; i < connector->count_modes; i++) {
> > > -		mode = &connector->modes[i];
> > > -		fb_id = igt_create_color_pattern_fb(data->drm_fd,
> > > -						    mode->hdisplay,
> > > -						    mode->vdisplay,
> > > -						    DRM_FORMAT_XRGB8
> > > 888,
> > > -						    LOCAL_DRM_FORMAT
> > > _MOD_NONE,
> > > -						    0, 0, 0, &fb);
> > > -		igt_assert(fb_id > 0);
> > > +		expected_crc =
> > > chamelium_calculate_fb_crc_result(fb_crc);
> > >   
> > > -		fb_crc = chamelium_calculate_fb_crc_launch(data-
> > > > drm_fd, &fb);
> > > 
> > > +		for (j = 0; j < captured_frame_count; j++) {
> > > +			eq = igt_check_crc_equal(&crc[j],
> > > expected_crc);
> > > +			if (!eq && frame_dump_path) {
> > > +				frame =
> > > chamelium_read_captured_frame(data->chamelium,
> > > +								
> > >    j);
> > >   
> > > -		enable_output(data, port, output, mode, &fb);
> > > +				igt_debug("Dumping reference and
> > > chamelium frames to %s...\n",
> > > +					  frame_dump_path);
> > >   
> > > -		/* We want to keep the display running for a little
> > > bit, since
> > > -		 * there's always the potential the driver isn't
> > > able to keep
> > > -		 * the display running properly for very long
> > > -		 */
> > > -		chamelium_capture(data->chamelium, port, 0, 0, 0, 0,
> > > 3);
> > > -		crc = chamelium_read_captured_crcs(data->chamelium,
> > > -						   &captured_frame_c
> > > ount);
> > > +				snprintf(path, PATH_MAX, "%s/frame-
> > > reference-%s.png",
> > > +					 frame_dump_path,
> > > connector_name);
> > > +				igt_write_fb_to_png(data->drm_fd,
> > > &fb, path);
> > >   
> > > -		igt_debug("Captured %d frames\n",
> > > captured_frame_count);
> > > +				snprintf(path, PATH_MAX, "%s/frame-
> > > chamelium-%s.png",
> > > +					 frame_dump_path,
> > > connector_name);
> > > +				chamelium_write_frame_to_png(data-
> > > > chamelium,
> > > 
> > > +							     frame,
> > > path);
> > >   
> > > -		expected_crc =
> > > chamelium_calculate_fb_crc_result(fb_crc);
> > > +				chamelium_destroy_frame_dump(frame);
> > > +			}
> > >   
> > > -		for (j = 0; j < captured_frame_count; j++)
> > > -			igt_assert_crc_equal(&crc[j], expected_crc);
> > > +			igt_fail_on_f(!eq,
> > > +				      "Chamelium frame CRC mismatch
> > > with reference\n");
> > > +		}
> > 
> > There's lots of potential here for copy pasta to form in the future,
> > since the API here puts a lot of work on the caller to set things up
> > for frame dumping. IMO, it would be worth it to teach the CRC checking
> > functions to automatically do frame dumps on mismatch if the CRC source
> > supports it. This will save us from having to have separate frame dump
> > APIs in the future if we ever end up adding support for other kinds of
> > automated test equipment.
> > 
> > As well, I like how you removed the redundancy between
> > test_display_crc_single() and test_display_crc_multiple(). However
> > since those are somewhat unrelated changes to the code path for these
> > tests it would be better to have that re-factoring as a separate patch
> > so as to make it easier for anyone who might need to bisect this code
> > in the future.
> > 
> > >   
> > >   		free(expected_crc);
> > >   		free(crc);
> > > @@ -644,10 +618,10 @@ igt_main
> > >   							edid_id,
> > > alt_edid_id);
> > >   
> > >   		connector_subtest("dp-crc-single", DisplayPort)
> > > -			test_display_crc_single(&data, port);
> > > +			test_display_crc(&data, port, 1);
> > >   
> > >   		connector_subtest("dp-crc-multiple", DisplayPort)
> > > -			test_display_crc_multiple(&data, port);
> > > +			test_display_crc(&data, port, 3);
> > >   	}
> > >   
> > >   	igt_subtest_group {
> > > @@ -698,10 +672,10 @@ igt_main
> > >   							edid_id,
> > > alt_edid_id);
> > >   
> > >   		connector_subtest("hdmi-crc-single", HDMIA)
> > > -			test_display_crc_single(&data, port);
> > > +			test_display_crc(&data, port, 1);
> > >   
> > >   		connector_subtest("hdmi-crc-multiple", HDMIA)
> > > -			test_display_crc_multiple(&data, port);
> > > +			test_display_crc(&data, port, 3);
> > >   	}
> > >   
> > >   	igt_subtest_group {
-- 
Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo, FInland
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH i-g-t v3 1/4] chamelium: Calculate CRC from framebuffer instead of hardcoding it
  2017-07-05 20:34 ` [PATCH i-g-t v3 1/4] chamelium: Calculate CRC from framebuffer instead of hardcoding it Lyude Paul
  2017-07-05 20:49   ` Lyude Paul
  2017-07-06  8:49   ` Paul Kocialkowski
@ 2017-07-06 13:14   ` Paul Kocialkowski
  2017-07-06 22:33     ` Lyude Paul
  2 siblings, 1 reply; 57+ messages in thread
From: Paul Kocialkowski @ 2017-07-06 13:14 UTC (permalink / raw)
  To: Lyude Paul, intel-gfx

On Wed, 2017-07-05 at 16:34 -0400, Lyude Paul wrote:
> So a couple of notes here that will make it a lot easier for me to
> review these in the future
> 
>  * When you're doing a new revision of a patch series, it's helpful to
>    keep it in the same email thread as the original v1 so it's easier
>    to keep track of in people's mail clients (as well as avoiding
>    accidentally reviewing older patch versions. I usually do something
>    like this (other projects might request you do this slightly
>    differently, but this should be fine here):
>     * [PATCH 0/2] Cleaning up the alignment of various foos
>        * [PATCH 1/2] Foo the bar, not the baz
>        * [PATCH 2/2] Introduce the amazing new foo_bar
>        * [PATCH v2 0/2] Cleaning up the alignment of various foos
>           * [PATCH v2 1/2] Foo the bar, not the baz
>           * [PATCH v2 2/2] Introduce the amazing new foo_bar
>        * [PATCH v3 0/2] Cleaning up the alignment of various foos
>           * [PATCH v3 1/2] Foo the bar, not the baz
>           * [PATCH v3 2/2] Introduce the amazing new foo_bar
>  * Try not to group unrelated patches together in the same thread.
> This
>    also makes sorting through all of them a little more difficult.
>  * When you make new revisions of patches, it's very useful if you
> also
>    include a list of changes you made to the patch since the last
>    revision. It doesn't need to be very finely detailed, something
> like
>    this would suffice:
>     * Various style fixes
>     * Rename baz to moo, add cow noises
>     * Split init_cow() into init_white_cow() and init_black_cow()
>       instead of handling both kinds of cows in the same function
>     * Fix documentation
>     For intel-gpu-tools, it's fine to just stick this in the commit
>     message. Other projects may request you put the changelog below
> the
>     ----- right above the diff stats (this allows the comments not to
>     get included in the final commit message)
>  * Unless they are all very small and less important fixes, including
>    cover letters helps as well since it lets patchwork group together
>    patch series like this.

What would you prefer that I do regarding follow-up versions to this
patchset (and the other one that is still under review)?

I could split the series per-topic (crc, frame save, time improvements)
and keep those in the same parent thread as their v1.

> Anyway, back to the actual patch:
> A good start! Will need a couple of changes though
> 
> On Wed, 2017-07-05 at 11:04 +0300, Paul Kocialkowski wrote:
> > This introduces CRC calculation for reference frames, instead of
> > using
> > hardcoded values for them. The rendering of reference frames may
> > differ
> > from machine to machine, especially due to font rendering, and the
> > frame itself may change with subsequent IGT changes.
> > 
> > These differences would cause the CRC checks to fail on different
> > setups. This allows them to pass regardless of the setup.
> > 
> > Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
> > ---
> >  lib/igt_chamelium.c | 160
> > ++++++++++++++++++++++++++++++++++++++++++++++++++++
> >  lib/igt_chamelium.h |   5 ++
> >  tests/chamelium.c   |  76 ++++++-------------------
> >  3 files changed, 183 insertions(+), 58 deletions(-)
> > 
> > diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
> > index bff08c0e..b9d80b6b 100644
> > --- a/lib/igt_chamelium.c
> > +++ b/lib/igt_chamelium.c
> > @@ -94,6 +94,14 @@ struct chamelium_frame_dump {
> >  	struct chamelium_port *port;
> >  };
> >  
> > +struct chamelium_fb_crc {
> > +	int fd;
> > +	struct igt_fb *fb;
> > +
> > +	pthread_t thread_id;
> > +	igt_crc_t *ret;
> > +};
> > +
> 
> The name of this structure is a little misleading, because now we have
> an API that exposes both a struct chamelium_fb_crc struct in addition
> to the igt_crc_t struct. Rename this to something like struct
> chamelium_fb_crc_work
> 
> >  struct chamelium {
> >  	xmlrpc_env env;
> >  	xmlrpc_client *client;
> > @@ -1003,6 +1011,158 @@ int chamelium_get_frame_limit(struct
> > chamelium *chamelium,
> >  	return ret;
> >  }
> >  
> > +static uint32_t chamelium_xrgb_hash16(unsigned char *buffer, int
> > width,
> > +				      int height, int k, int m)
> > +{
> 
> We're not modifying buffer, so make it a const. As well, feel free to
> mark this function as inline.
> 
> > +	unsigned char r, g, b;
> > +	uint64_t sum = 0;
> > +	uint64_t count = 0;
> > +	uint64_t value;
> > +	uint32_t hash;
> > +	int index;
> > +	int i;
> > +
> > +	for (i=0; i < width * height; i++) {
> > +		if ((i % m) != k)
> > +			continue;
> > +
> > +		index = i * 4;
> > +
> > +		r = buffer[index + 2];
> > +		g = buffer[index + 1];
> > +		b = buffer[index + 0];
> > +
> > +		value = r | (g << 8) | (b << 16);
> > +		sum += ++count * value;
> > +	}
> > +
> > +	hash = ((sum >> 0) ^ (sum >> 16) ^ (sum >> 32) ^ (sum >>
> > 48)) & 0xffff;
> > +
> > +	return hash;
> > +}
> > +
> > +/**
> > + * chamelium_calculate_fb_crc:
> > + * @fd: The drm file descriptor
> > + * @fb: The framebuffer to calculate the CRC for
> > + *
> > + * Calculates a CRC for the provided framebuffer, the same way as
> > the Chamelium.
> 
> Calculate the CRC for the provided framebuffer, using the Chamelium's
> CRC algorithm
> > + * This calculates the CRC in a non-threaded fashion.
> > + *
> > + * Returns: The calculated CRC
> > + */
> > +igt_crc_t *chamelium_calculate_fb_crc(int fd, struct igt_fb *fb)
> > +{
> > +	igt_crc_t *ret;
> > +	cairo_t *cr;
> > +	cairo_surface_t *fb_surface;
> > +	unsigned char *buffer;
> > +	int n = 4;
> > +	int w, h;
> > +	int i, j;
> > +
> > +	ret = calloc(1, sizeof(igt_crc_t));
> > +
> > +	/* Get the cairo surface for the framebuffer */
> > +	cr = igt_get_cairo_ctx(fd, fb);
> > +	fb_surface = cairo_get_target(cr);
> > +	cairo_surface_reference(fb_surface);
> > +	cairo_destroy(cr);
> > +
> > +	buffer = cairo_image_surface_get_data(fb_surface);
> > +	w = fb->width;
> > +	h = fb->height;
> > +
> > +	for (i = 0; i < n; i++) {
> > +		j = n - i - 1;
> > +		ret->crc[i] = chamelium_xrgb_hash16(buffer, w, h,
> > j,
> > n);
> > +	}
> > +
> > +	ret->n_words = n;
> > +	cairo_surface_destroy(fb_surface);
> > +
> > +	return ret;
> > +}
> > +
> > +static void *chamelium_calculate_fb_crc_thread(void *data)
> > +{
> > +	struct chamelium_fb_crc *fb_crc = (struct chamelium_fb_crc
> > *) data;
> > +	cairo_t *cr;
> > +	cairo_surface_t *fb_surface;
> > +	unsigned char *buffer;
> > +	int n = 4;
> > +	int w, h;
> > +	int i, j;
> > +
> > +	/* Get the cairo surface for the framebuffer */
> > +	cr = igt_get_cairo_ctx(fb_crc->fd, fb_crc->fb);
> > +	fb_surface = cairo_get_target(cr);
> > +	cairo_surface_reference(fb_surface);
> > +	cairo_destroy(cr);
> > +
> > +	buffer = cairo_image_surface_get_data(fb_surface);
> > +	w = fb_crc->fb->width;
> > +	h = fb_crc->fb->height;
> > +
> > +	for (i = 0; i < n; i++) {
> > +		j = n - i - 1;
> > +		fb_crc->ret->crc[i] = chamelium_xrgb_hash16(buffer,
> > w, h, j, n);
> > +	}
> > +
> > +	fb_crc->ret->n_words = n;
> > +	cairo_surface_destroy(fb_surface);
> > +
> > +	return NULL;
> > +}
> > +
> > +/**
> > + * chamelium_calculate_fb_crc_launch:
> > + * @fd: The drm file descriptor
> > + * @fb: The framebuffer to calculate the CRC for
> > + *
> > + * Launches the CRC calculation for the provided framebuffer, the
> > same way as
> > + * the Chamelium. This calculates the CRC in a threaded fashion.
> > + * Thread-related information is returned and should be passed to a
> > subsequent
> > + * call to chamelium_calculate_fb_crc_result. It should not be
> > freed.
> > + *
> > + * Returns: An intermediate structure with thread-related
> > information
> 
> The user doesn't need to know about the magic inside the structure,
> since we're not going to expose it's definition outside of this file
> anyway.
> > + */
> > +struct chamelium_fb_crc *chamelium_calculate_fb_crc_launch(int fd,
> > +							   struct
> > igt_fb *fb)
> > +{
> > +	struct chamelium_fb_crc *fb_crc;
> > +
> > +	fb_crc = calloc(1, sizeof(struct chamelium_fb_crc));
> > +	fb_crc->ret = calloc(1, sizeof(igt_crc_t));
> > +	fb_crc->fd = fd;
> > +	fb_crc->fb = fb;
> > +
> > +	pthread_create(&fb_crc->thread_id, NULL,
> > +		       chamelium_calculate_fb_crc_thread, fb_crc);
> > +
> > +	return fb_crc;
> > +}
> > +
> > +/**
> > + * chamelium_calculate_fb_crc_result:
> > + * @fb_crc: An intermediate structure with thread-related
> > information
> > + *
> > + * Provides the result for the previously-launched CRC calculation.
> 
> Blocks until the async CRC calculation is finished, and then returns
> the result.
> > + *
> > + * Returns: The calculated CRC
> > + */
> > +igt_crc_t *chamelium_calculate_fb_crc_result(struct
> > chamelium_fb_crc
> > *fb_crc)
> > +{
> > +	igt_crc_t *ret;
> > +
> > +	pthread_join(fb_crc->thread_id, NULL);
> > +
> > +	ret = fb_crc->ret;
> > +	free(fb_crc);
> > +
> > +	return ret;
> > +}
> > +
> >  static unsigned int chamelium_get_port_type(struct chamelium
> > *chamelium,
> >  					    struct chamelium_port
> > *port)
> >  {
> > diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
> > index 81322ad2..e51cf4f9 100644
> > --- a/lib/igt_chamelium.h
> > +++ b/lib/igt_chamelium.h
> > @@ -36,6 +36,7 @@
> >  struct chamelium;
> >  struct chamelium_port;
> >  struct chamelium_frame_dump;
> > +struct chamelium_fb_crc;
> >  
> >  struct chamelium *chamelium_init(int drm_fd);
> >  void chamelium_deinit(struct chamelium *chamelium);
> > @@ -92,6 +93,10 @@ struct chamelium_frame_dump
> > *chamelium_port_dump_pixels(struct chamelium *chamel
> >  							struct
> > chamelium_port *port,
> >  							int x, int
> > y,
> >  							int w, int
> > h);
> > +igt_crc_t *chamelium_calculate_fb_crc(int fd, struct igt_fb *fb);
> > +struct chamelium_fb_crc *chamelium_calculate_fb_crc_launch(int fd,
> > +							   struct
> > igt_fb *fb);
> > +igt_crc_t *chamelium_calculate_fb_crc_result(struct
> > chamelium_fb_crc
> > *fb_crc);
> >  int chamelium_get_captured_frame_count(struct chamelium
> > *chamelium);
> >  int chamelium_get_frame_limit(struct chamelium *chamelium,
> >  			      struct chamelium_port *port,
> > diff --git a/tests/chamelium.c b/tests/chamelium.c
> > index e3067664..3fd2b02c 100644
> > --- a/tests/chamelium.c
> > +++ b/tests/chamelium.c
> > @@ -49,43 +49,6 @@ typedef struct {
> >  #define HPD_TOGGLE_COUNT_VGA 5
> >  #define HPD_TOGGLE_COUNT_DP_HDMI 15
> >  
> > -/* Pre-calculated CRCs for the pattern fb, for all the modes in the
> > default
> > - * chamelium edid
> > - */
> > -struct crc_entry {
> > -	int width;
> > -	int height;
> > -	igt_crc_t crc;
> > -};
> > -
> > -#define CRC_ENTRY(w_, h_, ...) \
> > -	{ w_, h_, { .n_words = 4, .crc = { __VA_ARGS__ } } }
> > -
> > -static const struct crc_entry pattern_fb_crcs[] = {
> > -	CRC_ENTRY(1920, 1080, 0xf859, 0xa751, 0x8c81, 0x45a1),
> > -	CRC_ENTRY(1280,  720, 0xcec2, 0x4246, 0x6cfd, 0xeb43),
> > -	CRC_ENTRY(1024,  768, 0x85e5, 0xf0cd, 0xafe3, 0x7f18),
> > -	CRC_ENTRY( 800,  600, 0x6b39, 0x32b6, 0x831a, 0xb03e),
> > -	CRC_ENTRY( 640,  480, 0xa121, 0x2473, 0xb150, 0x8c47),
> > -};
> > -#undef CRC_ENTRY
> > -
> > -static const igt_crc_t *
> > -get_precalculated_crc(struct chamelium_port *port, int w, int h)
> > -{
> > -	int i;
> > -	const struct crc_entry *entry;
> > -
> > -	for (i = 0; i < ARRAY_SIZE(pattern_fb_crcs); i++) {
> > -		entry = &pattern_fb_crcs[i];
> > -
> > -		if (entry->width == w && entry->height == h)
> > -			return &entry->crc;
> > -	}
> > -
> > -	return NULL;
> > -}
> > -
> >  static void
> >  require_connector_present(data_t *data, unsigned int type)
> >  {
> > @@ -424,7 +387,8 @@ test_display_crc_single(data_t *data, struct
> > chamelium_port *port)
> >  	igt_output_t *output;
> >  	igt_plane_t *primary;
> >  	igt_crc_t *crc;
> > -	const igt_crc_t *expected_crc;
> > +	igt_crc_t *expected_crc;
> > +	struct chamelium_fb_crc *fb_crc;
> >  	struct igt_fb fb;
> >  	drmModeModeInfo *mode;
> >  	drmModeConnector *connector;
> > @@ -447,24 +411,21 @@ test_display_crc_single(data_t *data, struct
> > chamelium_port *port)
> >  						    0, 0, 0, &fb);
> >  		igt_assert(fb_id > 0);
> >  
> > -		enable_output(data, port, output, mode, &fb);
> > +		fb_crc = chamelium_calculate_fb_crc_launch(data-
> > > drm_fd, &fb);
> > 
> >  
> > -		expected_crc = get_precalculated_crc(port,
> > -						     mode-
> > >hdisplay,
> > -						     mode-
> > > vdisplay);
> > 
> > -		if (!expected_crc) {
> > -			igt_warn("No precalculated CRC found for
> > %dx%d, skipping CRC check\n",
> > -				 mode->hdisplay, mode->vdisplay);
> > -			goto next;
> > -		}
> > +		enable_output(data, port, output, mode, &fb);
> >  
> >  		igt_debug("Testing single CRC fetch\n");
> > +
> >  		crc = chamelium_get_crc_for_area(data->chamelium,
> > port,
> >  						 0, 0, 0, 0);
> > +
> > +		expected_crc =
> > chamelium_calculate_fb_crc_result(fb_crc);
> > +
> >  		igt_assert_crc_equal(crc, expected_crc);
> > +		free(expected_crc);
> >  		free(crc);
> >  
> > -next:
> >  		disable_output(data, port, output);
> >  		igt_remove_fb(data->drm_fd, &fb);
> >  	}
> > @@ -480,7 +441,8 @@ test_display_crc_multiple(data_t *data, struct
> > chamelium_port *port)
> >  	igt_output_t *output;
> >  	igt_plane_t *primary;
> >  	igt_crc_t *crc;
> > -	const igt_crc_t *expected_crc;
> > +	igt_crc_t *expected_crc;
> > +	struct chamelium_fb_crc *fb_crc;
> >  	struct igt_fb fb;
> >  	drmModeModeInfo *mode;
> >  	drmModeConnector *connector;
> > @@ -503,15 +465,9 @@ test_display_crc_multiple(data_t *data, struct
> > chamelium_port *port)
> >  						    0, 0, 0, &fb);
> >  		igt_assert(fb_id > 0);
> >  
> > -		enable_output(data, port, output, mode, &fb);
> > +		fb_crc = chamelium_calculate_fb_crc_launch(data-
> > > drm_fd, &fb);
> > 
> >  
> > -		expected_crc = get_precalculated_crc(port, mode-
> > > hdisplay,
> > 
> > -						     mode-
> > > vdisplay);
> > 
> > -		if (!expected_crc) {
> > -			igt_warn("No precalculated CRC found for
> > %dx%d, skipping CRC check\n",
> > -				 mode->hdisplay, mode->vdisplay);
> > -			goto next;
> > -		}
> > +		enable_output(data, port, output, mode, &fb);
> >  
> >  		/* We want to keep the display running for a little
> > bit, since
> >  		 * there's always the potential the driver isn't
> > able to keep
> > @@ -522,11 +478,15 @@ test_display_crc_multiple(data_t *data, struct
> > chamelium_port *port)
> >  						   &captured_frame_
> > c
> > ount);
> >  
> >  		igt_debug("Captured %d frames\n",
> > captured_frame_count);
> > +
> > +		expected_crc =
> > chamelium_calculate_fb_crc_result(fb_crc);
> > +
> >  		for (j = 0; j < captured_frame_count; j++)
> >  			igt_assert_crc_equal(&crc[j],
> > expected_crc);
> > +
> > +		free(expected_crc);
> >  		free(crc);
> >  
> > -next:
> >  		disable_output(data, port, output);
> >  		igt_remove_fb(data->drm_fd, &fb);
> >  	}
-- 
Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo, Finland
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH i-g-t v3 2/4] tests/ chamelium: Remove the frame dump tests
  2017-07-05 20:53   ` Lyude Paul
  2017-07-06  7:37     ` Martin Peres
@ 2017-07-06 13:29     ` Paul Kocialkowski
  1 sibling, 0 replies; 57+ messages in thread
From: Paul Kocialkowski @ 2017-07-06 13:29 UTC (permalink / raw)
  To: Lyude Paul, intel-gfx

On Wed, 2017-07-05 at 16:53 -0400, Lyude Paul wrote:
> NAK. You're right that these don't actually give us any advantage over
> just using CRCs and are just slower, however I left these tests in
> here
> moreso just so we had something to actually test the frame dumping
> functions so that we could avoid regressing them by accident since
> we're the only users of those functions right now.

Also, note that the VGA testing patch (that I just sent to the list)
does make use of these functions (maybe not all of them though), since
using the CRC is not possible for VGA.

> If I recall properly, isn't there a list of tests in igt's source that
> they use for determining which tests to run on the CI? I think a
> better
> solution would be to just disable this for CI runs, and maybe add some
> comments pointing out that this test is only really useful for
> developers making changes to the chamelium library.
> 
> On Wed, 2017-07-05 at 11:04 +0300, Paul Kocialkowski wrote:
> > The frame dump tests provide no additional functionality over CRC
> > tests
> > and are considerably slower. Thus, these tests should be considered
> > as
> > poorer duplicates and removed.
> > 
> > Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
> > ---
> >  tests/chamelium.c | 53 -------------------------------------------
> > ----------
> >  1 file changed, 53 deletions(-)
> > 
> > diff --git a/tests/chamelium.c b/tests/chamelium.c
> > index 3fd2b02c..5cf8b3af 100644
> > --- a/tests/chamelium.c
> > +++ b/tests/chamelium.c
> > @@ -496,53 +496,6 @@ test_display_crc_multiple(data_t *data, struct
> > chamelium_port *port)
> >  }
> >  
> >  static void
> > -test_display_frame_dump(data_t *data, struct chamelium_port *port)
> > -{
> > -	igt_display_t display;
> > -	igt_output_t *output;
> > -	igt_plane_t *primary;
> > -	struct igt_fb fb;
> > -	struct chamelium_frame_dump *frame;
> > -	drmModeModeInfo *mode;
> > -	drmModeConnector *connector;
> > -	int fb_id, i, j;
> > -
> > -	reset_state(data, port);
> > -
> > -	output = prepare_output(data, &display, port);
> > -	connector = chamelium_port_get_connector(data->chamelium,
> > port, false);
> > -	primary = igt_output_get_plane_type(output,
> > DRM_PLANE_TYPE_PRIMARY);
> > -	igt_assert(primary);
> > -
> > -	for (i = 0; i < connector->count_modes; i++) {
> > -		mode = &connector->modes[i];
> > -		fb_id = igt_create_color_pattern_fb(data->drm_fd,
> > -						    mode->hdisplay,
> > mode->vdisplay,
> > -						    DRM_FORMAT_XRGB
> > 8
> > 888,
> > -						    LOCAL_DRM_FORMA
> > T
> > _MOD_NONE,
> > -						    0, 0, 0, &fb);
> > -		igt_assert(fb_id > 0);
> > -
> > -		enable_output(data, port, output, mode, &fb);
> > -
> > -		igt_debug("Reading frame dumps from
> > Chamelium...\n");
> > -		chamelium_capture(data->chamelium, port, 0, 0, 0,
> > 0,
> > 5);
> > -		for (j = 0; j < 5; j++) {
> > -			frame = chamelium_read_captured_frame(
> > -			    data->chamelium, j);
> > -			chamelium_assert_frame_eq(data->chamelium,
> > frame, &fb);
> > -			chamelium_destroy_frame_dump(frame);
> > -		}
> > -
> > -		disable_output(data, port, output);
> > -		igt_remove_fb(data->drm_fd, &fb);
> > -	}
> > -
> > -	drmModeFreeConnector(connector);
> > -	igt_display_fini(&display);
> > -}
> > -
> > -static void
> >  test_hpd_without_ddc(data_t *data, struct chamelium_port *port)
> >  {
> >  	struct udev_monitor *mon = igt_watch_hotplug();
> > @@ -695,9 +648,6 @@ igt_main
> >  
> >  		connector_subtest("dp-crc-multiple", DisplayPort)
> >  			test_display_crc_multiple(&data, port);
> > -
> > -		connector_subtest("dp-frame-dump", DisplayPort)
> > -			test_display_frame_dump(&data, port);
> >  	}
> >  
> >  	igt_subtest_group {
> > @@ -752,9 +702,6 @@ igt_main
> >  
> >  		connector_subtest("hdmi-crc-multiple", HDMIA)
> >  			test_display_crc_multiple(&data, port);
> > -
> > -		connector_subtest("hdmi-frame-dump", HDMIA)
> > -			test_display_frame_dump(&data, port);
> >  	}
> >  
> >  	igt_subtest_group {
-- 
Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo, Finland
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH i-g-t v3 4/4] chamelium: Dump obtained and reference frames to png on crc error
  2017-07-06 11:31     ` Paul Kocialkowski
@ 2017-07-06 13:33       ` Paul Kocialkowski
  2017-07-06 21:57         ` Lyude Paul
  0 siblings, 1 reply; 57+ messages in thread
From: Paul Kocialkowski @ 2017-07-06 13:33 UTC (permalink / raw)
  To: Lyude Paul, intel-gfx

On Thu, 2017-07-06 at 14:31 +0300, Paul Kocialkowski wrote:
> Hi,
> 
> On Wed, 2017-07-05 at 17:44 -0400, Lyude Paul wrote:
> > On Wed, 2017-07-05 at 11:04 +0300, Paul Kocialkowski wrote:
> > > When a CRC comparison error occurs, it is quite useful to get a
> > > dump
> > > of both the frame obtained from the chamelium and the reference in
> > > order
> > > to compare them.
> > > 
> > > This implements the frame dump, with a configurable path that
> > > enables
> > > the use of this feature.
> > > 
> > > Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.co
> > > m>
> > > ---
> > >  lib/igt_chamelium.c |  21 +++++++++++
> > >  lib/igt_chamelium.h |   1 +
> > >  lib/igt_debugfs.c   |  20 ++++++++++
> > >  lib/igt_debugfs.h   |   1 +
> > >  tests/chamelium.c   | 104 ++++++++++++++++++++-------------------
> > > -
> > > ------------
> > >  5 files changed, 82 insertions(+), 65 deletions(-)
> > > 
> > > diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
> > > index ef51ef68..9aca6842 100644
> > > --- a/lib/igt_chamelium.c
> > > +++ b/lib/igt_chamelium.c
> > > @@ -57,6 +57,7 @@
> > >   * |[<!-- language="plain" -->
> > >   *	[Chamelium]
> > >   *	URL=http://chameleon:9992 # The URL used for connecting
> > > to
> > > the Chamelium's RPC server
> > > + *	FrameDumpPath=/tmp # The path to dump frames that fail
> > > comparison checks
> > 
> > While no one else really cares about creating frame dumps yet, it's
> > possible someone else may in the future if we ever end up taking
> > more
> > advantage of automated testing systems like this. So I'd stick this
> > in
> > the generic non-chamelium specific section in the config file
> 
> That definitely makes sense. By the way, what approach would you
> recommend for
> thishandling? Mupuf was suggesting to have a common configuration
> structure
> instead of declaring either global variables or static ones with
> getters/setters. This is probably becoming more and more of a
> necessity as we
> add more common config options.
> 
> However, I think we should still allow specific parts of IGT to do the
> parsing
> themselves (especially in the case of chamelium) so that the common
> config
> structure only has common fields (and does not, for instance, contain
> the
> chamelium port configuration).
> 
> > >   *
> > >   *	# The rest of the sections are used for defining
> > > connector
> > > mappings.
> > >   *	# This is required so any tests using the Chamelium
> > > know
> > > which connector
> > > @@ -115,11 +116,26 @@ struct chamelium {
> > >  	struct chamelium_edid *edids;
> > >  	struct chamelium_port *ports;
> > >  	int port_count;
> > > +
> > > +	char *frame_dump_path;
> > >  };
> > >  
> > >  static struct chamelium *cleanup_instance;
> > >  
> > >  /**
> > > + * chamelium_get_frame_dump_path:
> > > + * @chamelium: The Chamelium instance to use
> > > + *
> > > + * Retrieves the path to dump frames to.
> > > + *
> > > + * Returns: a string with the frame dump path
> > > + */
> > > +char *chamelium_get_frame_dump_path(struct chamelium *chamelium)
> > > +{
> > > +	return chamelium->frame_dump_path;
> > > +}
> > > +
> > > +/**
> > >   * chamelium_get_ports:
> > >   * @chamelium: The Chamelium instance to use
> > >   * @count: Where to store the number of ports
> > > @@ -1338,6 +1354,11 @@ static bool chamelium_read_config(struct
> > > chamelium *chamelium, int drm_fd)
> > >  		return false;
> > >  	}
> > >  
> > > +	chamelium->frame_dump_path =
> > > g_key_file_get_string(igt_key_file,
> > > +							   "Chame
> > > liu
> > > m",
> > > +							   "Frame
> > > Dum
> > > pPath",
> > > +							    &erro
> > > r);
> > > +
> > >  	return chamelium_read_port_mappings(chamelium, drm_fd);
> > >  }
> > >  
> > > diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
> > > index 908e03d1..aa881971 100644
> > > --- a/lib/igt_chamelium.h
> > > +++ b/lib/igt_chamelium.h
> > > @@ -42,6 +42,7 @@ struct chamelium *chamelium_init(int drm_fd);
> > >  void chamelium_deinit(struct chamelium *chamelium);
> > >  void chamelium_reset(struct chamelium *chamelium);
> > >  
> > > +char *chamelium_get_frame_dump_path(struct chamelium *chamelium);
> > >  struct chamelium_port **chamelium_get_ports(struct chamelium
> > > *chamelium,
> > >  					    int *count);
> > >  unsigned int chamelium_port_get_type(const struct chamelium_port
> > > *port);
> > > diff --git a/lib/igt_debugfs.c b/lib/igt_debugfs.c
> > > index 80f25c61..dcb4e0a7 100644
> > > --- a/lib/igt_debugfs.c
> > > +++ b/lib/igt_debugfs.c
> > > @@ -282,6 +282,26 @@ bool igt_debugfs_search(int device, const
> > > char
> > > *filename, const char *substring)
> > >   */
> > >  
> > >  /**
> > > + * igt_check_crc_equal:
> > > + * @a: first pipe CRC value
> > > + * @b: second pipe CRC value
> > > + *
> > > + * Compares two CRC values and return whether they match.
> > > + *
> > > + * Returns: A boolean indicating whether the CRC values match
> > > + */
> > > +bool igt_check_crc_equal(const igt_crc_t *a, const igt_crc_t *b)
> > > +{
> > > +	int i;
> > > +
> > > +	for (i = 0; i < a->n_words; i++)
> > > +		if (a->crc[i] != b->crc[i])
> > > +			return false;
> > > +
> > > +	return true;
> > > +}
> > > +
> > 
> > Make this a separate patch, and instead of having another function
> > do
> > the CRC calculations just have something like this:
> > 
> >  * static int igt_find_crc_mismatch(const igt_crc_t *a, const
> > igt_crc_t
> >    *b): returns the index of the first CRC mismatch, 0 if none was
> >    found
> >  * bool igt_check_crc_equal(): uses igt_find_crc_mismatch() to
> > figure
> >    out if anything mismatched, and return true if something did (as
> >    well, also spit out some debugging info mentioning there was a
> >    mismatch)
> >  * void igt_assert_crc_equal(): uses igt_find_crc_mismatch() to
> > figure
> >    out if anything mismatched. If the assertion fails, use
> >    igt_assert_eq() on the mismatched crc so we still get a useful
> > error
> >    message on CRC failures.
> > 
> > There isn't much code required to actually compare CRCs, however I'd
> > still prefer only having one function doing the actual comparison
> > logic
> > here so we only have one piece of code to update if we need to make
> > changes to it in the future.
> > 
> > Mupuf, your opinion on this? ^
> > 
> > > +/**
> > >   * igt_assert_crc_equal:
> > >   * @a: first pipe CRC value
> > >   * @b: second pipe CRC value
> > > diff --git a/lib/igt_debugfs.h b/lib/igt_debugfs.h
> > > index 7b846a83..2695cbda 100644
> > > --- a/lib/igt_debugfs.h
> > > +++ b/lib/igt_debugfs.h
> > > @@ -113,6 +113,7 @@ enum intel_pipe_crc_source {
> > >          INTEL_PIPE_CRC_SOURCE_MAX,
> > >  };
> > >  
> > > +bool igt_check_crc_equal(const igt_crc_t *a, const igt_crc_t *b);
> > >  void igt_assert_crc_equal(const igt_crc_t *a, const igt_crc_t
> > > *b);
> > >  char *igt_crc_to_string(igt_crc_t *crc);
> > >  
> > > diff --git a/tests/chamelium.c b/tests/chamelium.c
> > > index 5cf8b3af..3d95c05c 100644
> > > --- a/tests/chamelium.c
> > > +++ b/tests/chamelium.c
> > > @@ -381,7 +381,7 @@ disable_output(data_t *data,
> > >  }
> > >  
> > >  static void
> > > -test_display_crc_single(data_t *data, struct chamelium_port
> > > *port)
> > > +test_display_crc(data_t *data, struct chamelium_port *port, int
> > > count)
> > >  {
> > >  	igt_display_t display;
> > >  	igt_output_t *output;
> > > @@ -390,9 +390,14 @@ test_display_crc_single(data_t *data, struct
> > > chamelium_port *port)
> > >  	igt_crc_t *expected_crc;
> > >  	struct chamelium_fb_crc *fb_crc;
> > >  	struct igt_fb fb;
> > > +	struct chamelium_frame_dump *frame;
> > >  	drmModeModeInfo *mode;
> > >  	drmModeConnector *connector;
> > > -	int fb_id, i;
> > > +	int fb_id, i, j, captured_frame_count;
> > > +	const char *connector_name;
> > > +	char *frame_dump_path;
> > > +	char path[PATH_MAX];
> > > +	bool eq;
> > >  
> > >  	reset_state(data, port);
> > >  
> > > @@ -401,6 +406,9 @@ test_display_crc_single(data_t *data, struct
> > > chamelium_port *port)
> > >  	primary = igt_output_get_plane_type(output,
> > > DRM_PLANE_TYPE_PRIMARY);
> > >  	igt_assert(primary);
> > >  
> > > +	connector_name = kmstest_connector_type_str(connector-
> > > > connector_type);
> > > 
> > > +	frame_dump_path = chamelium_get_frame_dump_path(data-
> > > > chamelium);
> > > 
> > > +
> > >  	for (i = 0; i < connector->count_modes; i++) {
> > >  		mode = &connector->modes[i];
> > >  		fb_id = igt_create_color_pattern_fb(data->drm_fd,
> > > @@ -415,74 +423,40 @@ test_display_crc_single(data_t *data, struct
> > > chamelium_port *port)
> > >  
> > >  		enable_output(data, port, output, mode, &fb);
> > >  
> > > -		igt_debug("Testing single CRC fetch\n");
> > > -
> > > -		crc = chamelium_get_crc_for_area(data->chamelium,
> > > port,
> > > -						 0, 0, 0, 0);
> > > -
> > > -		expected_crc =
> > > chamelium_calculate_fb_crc_result(fb_crc);
> > > -
> > > -		igt_assert_crc_equal(crc, expected_crc);
> > > -		free(expected_crc);
> > > -		free(crc);
> > > -
> > > -		disable_output(data, port, output);
> > > -		igt_remove_fb(data->drm_fd, &fb);
> > > -	}
> > > -
> > > -	drmModeFreeConnector(connector);
> > > -	igt_display_fini(&display);
> > > -}
> > > -
> > > -static void
> > > -test_display_crc_multiple(data_t *data, struct chamelium_port
> > > *port)
> > > -{
> > > -	igt_display_t display;
> > > -	igt_output_t *output;
> > > -	igt_plane_t *primary;
> > > -	igt_crc_t *crc;
> > > -	igt_crc_t *expected_crc;
> > > -	struct chamelium_fb_crc *fb_crc;
> > > -	struct igt_fb fb;
> > > -	drmModeModeInfo *mode;
> > > -	drmModeConnector *connector;
> > > -	int fb_id, i, j, captured_frame_count;
> > > +		chamelium_capture(data->chamelium, port, 0, 0, 0,
> > > 0,
> > > count);
> > > +		crc = chamelium_read_captured_crcs(data-
> > > >chamelium,
> > > +						   &captured_fram
> > > e_c
> > > ount);
> > >  
> > > -	reset_state(data, port);
> > > +		igt_assert(captured_frame_count == count);
> > >  
> > > -	output = prepare_output(data, &display, port);
> > > -	connector = chamelium_port_get_connector(data->chamelium,
> > > port, false);
> > > -	primary = igt_output_get_plane_type(output,
> > > DRM_PLANE_TYPE_PRIMARY);
> > > -	igt_assert(primary);
> > > +		igt_debug("Captured %d frames\n",
> > > captured_frame_count);
> > >  
> > > -	for (i = 0; i < connector->count_modes; i++) {
> > > -		mode = &connector->modes[i];
> > > -		fb_id = igt_create_color_pattern_fb(data->drm_fd,
> > > -						    mode-
> > > >hdisplay,
> > > -						    mode-
> > > >vdisplay,
> > > -						    DRM_FORMAT_XR
> > > GB8
> > > 888,
> > > -						    LOCAL_DRM_FOR
> > > MAT
> > > _MOD_NONE,
> > > -						    0, 0, 0,
> > > &fb);
> > > -		igt_assert(fb_id > 0);
> > > +		expected_crc =
> > > chamelium_calculate_fb_crc_result(fb_crc);
> > >  
> > > -		fb_crc = chamelium_calculate_fb_crc_launch(data-
> > > > drm_fd, &fb);
> > > 
> > > +		for (j = 0; j < captured_frame_count; j++) {
> > > +			eq = igt_check_crc_equal(&crc[j],
> > > expected_crc);
> > > +			if (!eq && frame_dump_path) {
> > > +				frame =
> > > chamelium_read_captured_frame(data->chamelium,
> > > +								 
> > >    
> > >   j);
> > >  
> > > -		enable_output(data, port, output, mode, &fb);
> > > +				igt_debug("Dumping reference and
> > > chamelium frames to %s...\n",
> > > +					  frame_dump_path);
> > >  
> > > -		/* We want to keep the display running for a
> > > little
> > > bit, since
> > > -		 * there's always the potential the driver isn't
> > > able to keep
> > > -		 * the display running properly for very long
> > > -		 */
> > > -		chamelium_capture(data->chamelium, port, 0, 0, 0,
> > > 0,
> > > 3);
> > > -		crc = chamelium_read_captured_crcs(data-
> > > >chamelium,
> > > -						   &captured_fram
> > > e_c
> > > ount);
> > > +				snprintf(path, PATH_MAX,
> > > "%s/frame-
> > > reference-%s.png",
> > > +					 frame_dump_path,
> > > connector_name);
> > > +				igt_write_fb_to_png(data->drm_fd,
> > > &fb, path);
> > >  
> > > -		igt_debug("Captured %d frames\n",
> > > captured_frame_count);
> > > +				snprintf(path, PATH_MAX,
> > > "%s/frame-
> > > chamelium-%s.png",
> > > +					 frame_dump_path,
> > > connector_name);
> > > +				chamelium_write_frame_to_png(data
> > > -
> > > > chamelium,
> > > 
> > > +							     fram
> > > e,
> > > path);
> > >  
> > > -		expected_crc =
> > > chamelium_calculate_fb_crc_result(fb_crc);
> > > +				chamelium_destroy_frame_dump(fram
> > > e);
> > > +			}
> > >  
> > > -		for (j = 0; j < captured_frame_count; j++)
> > > -			igt_assert_crc_equal(&crc[j],
> > > expected_crc);
> > > +			igt_fail_on_f(!eq,
> > > +				      "Chamelium frame CRC
> > > mismatch
> > > with reference\n");
> > > +		}
> > 
> > There's lots of potential here for copy pasta to form in the future,
> > since the API here puts a lot of work on the caller to set things up
> > for frame dumping. IMO, it would be worth it to teach the CRC
> > checking
> > functions to automatically do frame dumps on mismatch if the CRC
> > source
> > supports it. This will save us from having to have separate frame
> > dump
> > APIs in the future if we ever end up adding support for other kinds
> > of
> > automated test equipment.
> 
> I don't think it makes so much sense to do this in the CRC checking
> functions,
> just because they are semantically expected to do one thing: CRC
> checking, and
> doing frame dumps seems like going overboard.
> 
> On the other hand, I do agree that the dumping and saving part can and
> should be
> made common, but maybe as a separate function. So that would be two
> calls for
> the tests: one to check the crc and one to dump and save the frame.

A strong case to support this vision: in VGA frame testing, we have
already dumped the frame and don't do CRC checking, yet we also need to
save the frames if there is a mismatch.

It would be a shame that the dumping logic becomes part of the CRC
functions, since that would mean duplicating that logic for VGA testing
(as it's currently done in the version I just sent out).

In spite of that, I think having a common function, called from the test
itself is probably the best approach here.

> I have also duplicated that logic in upcoming VGA frame testing, so
> there is definitely a need for less duplication.
> 
> > As well, I like how you removed the redundancy between
> > test_display_crc_single() and test_display_crc_multiple(). However
> > since those are somewhat unrelated changes to the code path for
> > these
> > tests it would be better to have that re-factoring as a separate
> > patch
> > so as to make it easier for anyone who might need to bisect this
> > code
> > in the future.
> 
> Fair enough, it just felt weird to commit two functions that were
> nearly the
> exact same, but I have no problem with doing this in two separate
> patches.
> 
> > >  
> > >  		free(expected_crc);
> > >  		free(crc);
> > > @@ -644,10 +618,10 @@ igt_main
> > >  							edid_id,
> > > alt_edid_id);
> > >  
> > >  		connector_subtest("dp-crc-single", DisplayPort)
> > > -			test_display_crc_single(&data, port);
> > > +			test_display_crc(&data, port, 1);
> > >  
> > >  		connector_subtest("dp-crc-multiple", DisplayPort)
> > > -			test_display_crc_multiple(&data, port);
> > > +			test_display_crc(&data, port, 3);
> > >  	}
> > >  
> > >  	igt_subtest_group {
> > > @@ -698,10 +672,10 @@ igt_main
> > >  							edid_id,
> > > alt_edid_id);
> > >  
> > >  		connector_subtest("hdmi-crc-single", HDMIA)
> > > -			test_display_crc_single(&data, port);
> > > +			test_display_crc(&data, port, 1);
> > >  
> > >  		connector_subtest("hdmi-crc-multiple", HDMIA)
> > > -			test_display_crc_multiple(&data, port);
> > > +			test_display_crc(&data, port, 3);
> > >  	}
> > >  
> > >  	igt_subtest_group {
-- 
Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo, Finland
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH i-g-t v3 4/4] chamelium: Dump obtained and reference frames to png on crc error
  2017-07-06 13:33       ` Paul Kocialkowski
@ 2017-07-06 21:57         ` Lyude Paul
  2017-07-10 10:27           ` Paul Kocialkowski
  2017-07-10 10:31           ` Paul Kocialkowski
  0 siblings, 2 replies; 57+ messages in thread
From: Lyude Paul @ 2017-07-06 21:57 UTC (permalink / raw)
  To: Paul Kocialkowski, intel-gfx

--snip--
(also sorry this one took a while to get to, had to do a lot of
thinking because I never really solved the problems mentioned here when
I tried working on this...)

On Thu, 2017-07-06 at 16:33 +0300, Paul Kocialkowski wrote:
> On Thu, 2017-07-06 at 14:31 +0300, Paul Kocialkowski wrote:
> > > 
> > > There's lots of potential here for copy pasta to form in the
> > > future,
> > > since the API here puts a lot of work on the caller to set things
> > > up
> > > for frame dumping. IMO, it would be worth it to teach the CRC
> > > checking
> > > functions to automatically do frame dumps on mismatch if the CRC
> > > source
> > > supports it. This will save us from having to have separate frame
> > > dump
> > > APIs in the future if we ever end up adding support for other
> > > kinds
> > > of
> > > automated test equipment.
> > 
> > I don't think it makes so much sense to do this in the CRC checking
> > functions,
> > just because they are semantically expected to do one thing: CRC
> > checking, and
> > doing frame dumps seems like going overboard.
> > 
> > On the other hand, I do agree that the dumping and saving part can
> > and
> > should be
> > made common, but maybe as a separate function. So that would be two
> > calls for
> > the tests: one to check the crc and one to dump and save the frame.
> 
> A strong case to support this vision: in VGA frame testing, we have
> already dumped the frame and don't do CRC checking, yet we also need
> to
> save the frames if there is a mismatch.
> 
> It would be a shame that the dumping logic becomes part of the CRC
> functions, since that would mean duplicating that logic for VGA
> testing
> (as it's currently done in the version I just sent out).
That is a good point, but there's some things I think you might want to
consider. Mainly that in a test that passes, we of course don't write
any framedumps back to the disk since nothing failed. IMO, I would
-think- that we care a bit more about the performance hit that happens
on passing tests vs. failing tests, since tests aren't really supposed
to fail under ideal conditions anyway. Might be better to verify with
the mupuf and the other people actually running Intel's CI though,
since I'm not one of them.

As well, one advantage we do have here from the chamelium end is that
you can only really be screen grabbing from one port at a time. So you
could actually just track stuff internally in the igt_chamelium API and
when a user tries to download a framedump that we've already
downloaded, we can just hand them back a cached copy of it.

> 
> In spite of that, I think having a common function, called from the
> test
> itself is probably the best approach here.
Not sure if I misspoke here but I didn't mean to imply that I'm against
having functions for doing frame dumping exposed to the callers. I had
already figured there'd probably be situations where just having the
CRC checking do the frame dumping wouldn't be enough.

This being said though, your viewpoint does make me realize it might
not be a great idea to do autoframe dumping in -all- crc checking
functions necessarily, but also makes me realize that this might even
be a requirement if we still want to try keeping around
igt_assert_crc_equal() and not just replace it outright with a function
that doesn't fail the whole test (if we fail the test, there isn't
really a way we can do a framedump from it afterwards). So I would
think we can at least exclude igt_check_crc_equal() from doing
automatic framedumping, but I still think it would be a good idea to
implement igt_assert_crc_equal().

As for the what you're talking about, e.g. doing frame dump comparisons
on VGA, I think the solution might be not to make any of the code for
doing the actual frame comparisons chamelium specific either (except
maybe for the part where we trim the framebuffer we get so it only
contains the actual image dump).

So how about this: let's introduce a generic frame comparison API using
the code you've already written for doing this on VGA with the
chamelium. Make it part of the igt library, and have it just accept
normal pixman images and perform fuzzy comparisons between them. In
doing that, we can introduce a generic dump-frames-on-error API through
there much more easily.

My big aim here is just to make it so that people using igt don't have
to do anything to get frame dumping in their tests, it just "works".

> 
> > I have also duplicated that logic in upcoming VGA frame testing, so
> > there is definitely a need for less duplication.
> > 
> > > As well, I like how you removed the redundancy between
> > > test_display_crc_single() and test_display_crc_multiple().
> > > However
> > > since those are somewhat unrelated changes to the code path for
> > > these
> > > tests it would be better to have that re-factoring as a separate
> > > patch
> > > so as to make it easier for anyone who might need to bisect this
> > > code
> > > in the future.
> > 
> > Fair enough, it just felt weird to commit two functions that were
> > nearly the
> > exact same, but I have no problem with doing this in two separate
> > patches.
> > 
> > > >  
> > > >  		free(expected_crc);
> > > >  		free(crc);
> > > > @@ -644,10 +618,10 @@ igt_main
> > > >  							edid_i
> > > > d,
> > > > alt_edid_id);
> > > >  
> > > >  		connector_subtest("dp-crc-single",
> > > > DisplayPort)
> > > > -			test_display_crc_single(&data, port);
> > > > +			test_display_crc(&data, port, 1);
> > > >  
> > > >  		connector_subtest("dp-crc-multiple",
> > > > DisplayPort)
> > > > -			test_display_crc_multiple(&data,
> > > > port);
> > > > +			test_display_crc(&data, port, 3);
> > > >  	}
> > > >  
> > > >  	igt_subtest_group {
> > > > @@ -698,10 +672,10 @@ igt_main
> > > >  							edid_i
> > > > d,
> > > > alt_edid_id);
> > > >  
> > > >  		connector_subtest("hdmi-crc-single", HDMIA)
> > > > -			test_display_crc_single(&data, port);
> > > > +			test_display_crc(&data, port, 1);
> > > >  
> > > >  		connector_subtest("hdmi-crc-multiple", HDMIA)
> > > > -			test_display_crc_multiple(&data,
> > > > port);
> > > > +			test_display_crc(&data, port, 3);
> > > >  	}
> > > >  
> > > >  	igt_subtest_group {
-- 
Cheers,
	Lyude
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH i-g-t v3 4/4] chamelium: Dump obtained and reference frames to png on crc error
  2017-07-06 11:35       ` Paul Kocialkowski
@ 2017-07-06 22:23         ` Lyude Paul
  2017-07-10 10:12           ` Paul Kocialkowski
  0 siblings, 1 reply; 57+ messages in thread
From: Lyude Paul @ 2017-07-06 22:23 UTC (permalink / raw)
  To: Paul Kocialkowski, Martin Peres, intel-gfx

On Thu, 2017-07-06 at 14:35 +0300, Paul Kocialkowski wrote:
> On Thu, 2017-07-06 at 10:41 +0300, Martin Peres wrote:
> > On 06/07/17 00:44, Lyude Paul wrote:
> > > On Wed, 2017-07-05 at 11:04 +0300, Paul Kocialkowski wrote:
> > > > When a CRC comparison error occurs, it is quite useful to get a
> > > > dump
> > > > of both the frame obtained from the chamelium and the reference
> > > > in
> > > > order
> > > > to compare them.
> > > > 
> > > > This implements the frame dump, with a configurable path that
> > > > enables
> > > > the use of this feature.
> > > > 
> > > > Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel
> > > > .com>
> > > > ---
> > > >   lib/igt_chamelium.c |  21 +++++++++++
> > > >   lib/igt_chamelium.h |   1 +
> > > >   lib/igt_debugfs.c   |  20 ++++++++++
> > > >   lib/igt_debugfs.h   |   1 +
> > > >   tests/chamelium.c   | 104 ++++++++++++++++++++---------------
> > > > -----
> > > > ------------
> > > >   5 files changed, 82 insertions(+), 65 deletions(-)
> > > > 
> > > > diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
> > > > index ef51ef68..9aca6842 100644
> > > > --- a/lib/igt_chamelium.c
> > > > +++ b/lib/igt_chamelium.c
> > > > @@ -57,6 +57,7 @@
> > > >    * |[<!-- language="plain" -->
> > > >    *	[Chamelium]
> > > >    *	URL=http://chameleon:9992 # The URL used for
> > > > connecting to
> > > > the Chamelium's RPC server
> > > > + *	FrameDumpPath=/tmp # The path to dump frames that
> > > > fail
> > > > comparison checks
> > > 
> > > While no one else really cares about creating frame dumps yet,
> > > it's
> > > possible someone else may in the future if we ever end up taking
> > > more
> > > advantage of automated testing systems like this. So I'd stick
> > > this in
> > > the generic non-chamelium specific section in the config file
> > > 
> > > >    *
> > > >    *	# The rest of the sections are used for defining
> > > > connector
> > > > mappings.
> > > >    *	# This is required so any tests using the Chamelium
> > > > know
> > > > which connector
> > > > @@ -115,11 +116,26 @@ struct chamelium {
> > > >   	struct chamelium_edid *edids;
> > > >   	struct chamelium_port *ports;
> > > >   	int port_count;
> > > > +
> > > > +	char *frame_dump_path;
> > > >   };
> > > >   
> > > >   static struct chamelium *cleanup_instance;
> > > >   
> > > >   /**
> > > > + * chamelium_get_frame_dump_path:
> > > > + * @chamelium: The Chamelium instance to use
> > > > + *
> > > > + * Retrieves the path to dump frames to.
> > > > + *
> > > > + * Returns: a string with the frame dump path
> > > > + */
> > > > +char *chamelium_get_frame_dump_path(struct chamelium
> > > > *chamelium)
> > > > +{
> > > > +	return chamelium->frame_dump_path;
> > > > +}
> > > > +
> > > > +/**
> > > >    * chamelium_get_ports:
> > > >    * @chamelium: The Chamelium instance to use
> > > >    * @count: Where to store the number of ports
> > > > @@ -1338,6 +1354,11 @@ static bool chamelium_read_config(struct
> > > > chamelium *chamelium, int drm_fd)
> > > >   		return false;
> > > >   	}
> > > >   
> > > > +	chamelium->frame_dump_path =
> > > > g_key_file_get_string(igt_key_file,
> > > > +							   "Ch
> > > > ameliu
> > > > m",
> > > > +							   "Fr
> > > > ameDum
> > > > pPath",
> > > > +							    &e
> > > > rror);
> > > > +
> > > >   	return chamelium_read_port_mappings(chamelium,
> > > > drm_fd);
> > > >   }
> > > >   
> > > > diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
> > > > index 908e03d1..aa881971 100644
> > > > --- a/lib/igt_chamelium.h
> > > > +++ b/lib/igt_chamelium.h
> > > > @@ -42,6 +42,7 @@ struct chamelium *chamelium_init(int drm_fd);
> > > >   void chamelium_deinit(struct chamelium *chamelium);
> > > >   void chamelium_reset(struct chamelium *chamelium);
> > > >   
> > > > +char *chamelium_get_frame_dump_path(struct chamelium
> > > > *chamelium);
> > > >   struct chamelium_port **chamelium_get_ports(struct chamelium
> > > > *chamelium,
> > > >   					    int *count);
> > > >   unsigned int chamelium_port_get_type(const struct
> > > > chamelium_port
> > > > *port);
> > > > diff --git a/lib/igt_debugfs.c b/lib/igt_debugfs.c
> > > > index 80f25c61..dcb4e0a7 100644
> > > > --- a/lib/igt_debugfs.c
> > > > +++ b/lib/igt_debugfs.c
> > > > @@ -282,6 +282,26 @@ bool igt_debugfs_search(int device, const
> > > > char
> > > > *filename, const char *substring)
> > > >    */
> > > >   
> > > >   /**
> > > > + * igt_check_crc_equal:
> > > > + * @a: first pipe CRC value
> > > > + * @b: second pipe CRC value
> > > > + *
> > > > + * Compares two CRC values and return whether they match.
> > > > + *
> > > > + * Returns: A boolean indicating whether the CRC values match
> > > > + */
> > > > +bool igt_check_crc_equal(const igt_crc_t *a, const igt_crc_t
> > > > *b)
> > > > +{
> > > > +	int i;
> > 
> > I would like to see:
> > 
> > if (a->n_words != b->n_words)
> >      return false;
> 
> Very good suggestion! I'll take that in in the next revision.
> 
> > > > +
> > > > +	for (i = 0; i < a->n_words; i++)
> > > > +		if (a->crc[i] != b->crc[i])
> > > > +			return false;
> > > > +
> > > > +	return true;
> > > > +}
> > > > +
> > > 
> > > Make this a separate patch, and instead of having another
> > > function do
> > > the CRC calculations just have something like this:
> > > 
> > >   * static int igt_find_crc_mismatch(const igt_crc_t *a, const
> > > igt_crc_t
> > >     *b): returns the index of the first CRC mismatch, 0 if none
> > > was
> > >     found
> > 
> > Sounds good, but no error should return -1, as to differentiate if
> > the 
> > first word was already different.
> 
> I don't understand the point of getting the index of the CRC mismatch
> at all.
> The only relevant information here should be whether it matches or
> not (which
> would be covered by igt_check_crc_equal). Can you ellaborate on this?
It's just so that we can print more detailed debugging info that
actually notes which part of the CRC didn't match. This sounds a little
useless, but sometimes you can actually tell what's going on by looking
at how much of the CRC didn't match.

For instance, when I was trying to figure out the (I didn't know this
was the cause at the time) ESD issues I was hitting with DisplayPort on
the chamelium, the chromeos guys were immediately able to tell it was
only a single pixel that was off because only one section of the CRC
didn't match, while the rest of it did.
> 
> > >   * bool igt_check_crc_equal(): uses igt_find_crc_mismatch() to
> > > figure
> > >     out if anything mismatched, and return true if something did
> > > (as
> > >     well, also spit out some debugging info mentioning there was
> > > a
> > >     mismatch)
> > >   * void igt_assert_crc_equal(): uses igt_find_crc_mismatch() to
> > > figure
> > >     out if anything mismatched. If the assertion fails, use
> > >     igt_assert_eq() on the mismatched crc so we still get a
> > > useful error
> > >     message on CRC failures.
> > > 
> > > There isn't much code required to actually compare CRCs, however
> > > I'd
> > > still prefer only having one function doing the actual comparison
> > > logic
> > > here so we only have one piece of code to update if we need to
> > > make
> > > changes to it in the future.
> > > 
> > > Mupuf, your opinion on this? ^
> > > 
> > > > +/**
> > > >    * igt_assert_crc_equal:
> > > >    * @a: first pipe CRC value
> > > >    * @b: second pipe CRC value
> > > > diff --git a/lib/igt_debugfs.h b/lib/igt_debugfs.h
> > > > index 7b846a83..2695cbda 100644
> > > > --- a/lib/igt_debugfs.h
> > > > +++ b/lib/igt_debugfs.h
> > > > @@ -113,6 +113,7 @@ enum intel_pipe_crc_source {
> > > >           INTEL_PIPE_CRC_SOURCE_MAX,
> > > >   };
> > > >   
> > > > +bool igt_check_crc_equal(const igt_crc_t *a, const igt_crc_t
> > > > *b);
> > > >   void igt_assert_crc_equal(const igt_crc_t *a, const igt_crc_t
> > > > *b);
> > > >   char *igt_crc_to_string(igt_crc_t *crc);
> > > >   
> > > > diff --git a/tests/chamelium.c b/tests/chamelium.c
> > > > index 5cf8b3af..3d95c05c 100644
> > > > --- a/tests/chamelium.c
> > > > +++ b/tests/chamelium.c
> > > > @@ -381,7 +381,7 @@ disable_output(data_t *data,
> > > >   }
> > > >   
> > > >   static void
> > > > -test_display_crc_single(data_t *data, struct chamelium_port
> > > > *port)
> > > > +test_display_crc(data_t *data, struct chamelium_port *port,
> > > > int
> > > > count)
> > > >   {
> > > >   	igt_display_t display;
> > > >   	igt_output_t *output;
> > > > @@ -390,9 +390,14 @@ test_display_crc_single(data_t *data,
> > > > struct
> > > > chamelium_port *port)
> > > >   	igt_crc_t *expected_crc;
> > > >   	struct chamelium_fb_crc *fb_crc;
> > > >   	struct igt_fb fb;
> > > > +	struct chamelium_frame_dump *frame;
> > > >   	drmModeModeInfo *mode;
> > > >   	drmModeConnector *connector;
> > > > -	int fb_id, i;
> > > > +	int fb_id, i, j, captured_frame_count;
> > > > +	const char *connector_name;
> > > > +	char *frame_dump_path;
> > > > +	char path[PATH_MAX];
> > > > +	bool eq;
> > > >   
> > > >   	reset_state(data, port);
> > > >   
> > > > @@ -401,6 +406,9 @@ test_display_crc_single(data_t *data,
> > > > struct
> > > > chamelium_port *port)
> > > >   	primary = igt_output_get_plane_type(output,
> > > > DRM_PLANE_TYPE_PRIMARY);
> > > >   	igt_assert(primary);
> > > >   
> > > > +	connector_name = kmstest_connector_type_str(connector-
> > > > > connector_type);
> > > > 
> > > > +	frame_dump_path = chamelium_get_frame_dump_path(data-
> > > > > chamelium);
> > > > 
> > > > +
> > > >   	for (i = 0; i < connector->count_modes; i++) {
> > > >   		mode = &connector->modes[i];
> > > >   		fb_id = igt_create_color_pattern_fb(data-
> > > > >drm_fd,
> > > > @@ -415,74 +423,40 @@ test_display_crc_single(data_t *data,
> > > > struct
> > > > chamelium_port *port)
> > > >   
> > > >   		enable_output(data, port, output, mode, &fb);
> > > >   
> > > > -		igt_debug("Testing single CRC fetch\n");
> > > > -
> > > > -		crc = chamelium_get_crc_for_area(data-
> > > > >chamelium,
> > > > port,
> > > > -						 0, 0, 0, 0);
> > > > -
> > > > -		expected_crc =
> > > > chamelium_calculate_fb_crc_result(fb_crc);
> > > > -
> > > > -		igt_assert_crc_equal(crc, expected_crc);
> > > > -		free(expected_crc);
> > > > -		free(crc);
> > > > -
> > > > -		disable_output(data, port, output);
> > > > -		igt_remove_fb(data->drm_fd, &fb);
> > > > -	}
> > > > -
> > > > -	drmModeFreeConnector(connector);
> > > > -	igt_display_fini(&display);
> > > > -}
> > > > -
> > > > -static void
> > > > -test_display_crc_multiple(data_t *data, struct chamelium_port
> > > > *port)
> > > > -{
> > > > -	igt_display_t display;
> > > > -	igt_output_t *output;
> > > > -	igt_plane_t *primary;
> > > > -	igt_crc_t *crc;
> > > > -	igt_crc_t *expected_crc;
> > > > -	struct chamelium_fb_crc *fb_crc;
> > > > -	struct igt_fb fb;
> > > > -	drmModeModeInfo *mode;
> > > > -	drmModeConnector *connector;
> > > > -	int fb_id, i, j, captured_frame_count;
> > > > +		chamelium_capture(data->chamelium, port, 0, 0,
> > > > 0, 0,
> > > > count);
> > > > +		crc = chamelium_read_captured_crcs(data-
> > > > >chamelium,
> > > > +						   &captured_f
> > > > rame_c
> > > > ount);
> > > >   
> > > > -	reset_state(data, port);
> > > > +		igt_assert(captured_frame_count == count);
> > > >   
> > > > -	output = prepare_output(data, &display, port);
> > > > -	connector = chamelium_port_get_connector(data-
> > > > >chamelium,
> > > > port, false);
> > > > -	primary = igt_output_get_plane_type(output,
> > > > DRM_PLANE_TYPE_PRIMARY);
> > > > -	igt_assert(primary);
> > > > +		igt_debug("Captured %d frames\n",
> > > > captured_frame_count);
> > > >   
> > > > -	for (i = 0; i < connector->count_modes; i++) {
> > > > -		mode = &connector->modes[i];
> > > > -		fb_id = igt_create_color_pattern_fb(data-
> > > > >drm_fd,
> > > > -						    mode-
> > > > >hdisplay,
> > > > -						    mode-
> > > > >vdisplay,
> > > > -						    DRM_FORMAT
> > > > _XRGB8
> > > > 888,
> > > > -						    LOCAL_DRM_
> > > > FORMAT
> > > > _MOD_NONE,
> > > > -						    0, 0, 0,
> > > > &fb);
> > > > -		igt_assert(fb_id > 0);
> > > > +		expected_crc =
> > > > chamelium_calculate_fb_crc_result(fb_crc);
> > > >   
> > > > -		fb_crc =
> > > > chamelium_calculate_fb_crc_launch(data-
> > > > > drm_fd, &fb);
> > > > 
> > > > +		for (j = 0; j < captured_frame_count; j++) {
> > > > +			eq = igt_check_crc_equal(&crc[j],
> > > > expected_crc);
> > > > +			if (!eq && frame_dump_path) {
> > > > +				frame =
> > > > chamelium_read_captured_frame(data->chamelium,
> > > > +								
> > > >    j);
> > > >   
> > > > -		enable_output(data, port, output, mode, &fb);
> > > > +				igt_debug("Dumping reference
> > > > and
> > > > chamelium frames to %s...\n",
> > > > +					  frame_dump_path);
> > > >   
> > > > -		/* We want to keep the display running for a
> > > > little
> > > > bit, since
> > > > -		 * there's always the potential the driver
> > > > isn't
> > > > able to keep
> > > > -		 * the display running properly for very long
> > > > -		 */
> > > > -		chamelium_capture(data->chamelium, port, 0, 0,
> > > > 0, 0,
> > > > 3);
> > > > -		crc = chamelium_read_captured_crcs(data-
> > > > >chamelium,
> > > > -						   &captured_f
> > > > rame_c
> > > > ount);
> > > > +				snprintf(path, PATH_MAX,
> > > > "%s/frame-
> > > > reference-%s.png",
> > > > +					 frame_dump_path,
> > > > connector_name);
> > > > +				igt_write_fb_to_png(data-
> > > > >drm_fd,
> > > > &fb, path);
> > > >   
> > > > -		igt_debug("Captured %d frames\n",
> > > > captured_frame_count);
> > > > +				snprintf(path, PATH_MAX,
> > > > "%s/frame-
> > > > chamelium-%s.png",
> > > > +					 frame_dump_path,
> > > > connector_name);
> > > > +				chamelium_write_frame_to_png(d
> > > > ata-
> > > > > chamelium,
> > > > 
> > > > +							     f
> > > > rame,
> > > > path);
> > > >   
> > > > -		expected_crc =
> > > > chamelium_calculate_fb_crc_result(fb_crc);
> > > > +				chamelium_destroy_frame_dump(f
> > > > rame);
> > > > +			}
> > > >   
> > > > -		for (j = 0; j < captured_frame_count; j++)
> > > > -			igt_assert_crc_equal(&crc[j],
> > > > expected_crc);
> > > > +			igt_fail_on_f(!eq,
> > > > +				      "Chamelium frame CRC
> > > > mismatch
> > > > with reference\n");
> > > > +		}
> > > 
> > > There's lots of potential here for copy pasta to form in the
> > > future,
> > > since the API here puts a lot of work on the caller to set things
> > > up
> > > for frame dumping. IMO, it would be worth it to teach the CRC
> > > checking
> > > functions to automatically do frame dumps on mismatch if the CRC
> > > source
> > > supports it. This will save us from having to have separate frame
> > > dump
> > > APIs in the future if we ever end up adding support for other
> > > kinds of
> > > automated test equipment.
> > > 
> > > As well, I like how you removed the redundancy between
> > > test_display_crc_single() and test_display_crc_multiple().
> > > However
> > > since those are somewhat unrelated changes to the code path for
> > > these
> > > tests it would be better to have that re-factoring as a separate
> > > patch
> > > so as to make it easier for anyone who might need to bisect this
> > > code
> > > in the future.
> > > 
> > > >   
> > > >   		free(expected_crc);
> > > >   		free(crc);
> > > > @@ -644,10 +618,10 @@ igt_main
> > > >   							edid_
> > > > id,
> > > > alt_edid_id);
> > > >   
> > > >   		connector_subtest("dp-crc-single",
> > > > DisplayPort)
> > > > -			test_display_crc_single(&data, port);
> > > > +			test_display_crc(&data, port, 1);
> > > >   
> > > >   		connector_subtest("dp-crc-multiple",
> > > > DisplayPort)
> > > > -			test_display_crc_multiple(&data,
> > > > port);
> > > > +			test_display_crc(&data, port, 3);
> > > >   	}
> > > >   
> > > >   	igt_subtest_group {
> > > > @@ -698,10 +672,10 @@ igt_main
> > > >   							edid_
> > > > id,
> > > > alt_edid_id);
> > > >   
> > > >   		connector_subtest("hdmi-crc-single", HDMIA)
> > > > -			test_display_crc_single(&data, port);
> > > > +			test_display_crc(&data, port, 1);
> > > >   
> > > >   		connector_subtest("hdmi-crc-multiple", HDMIA)
> > > > -			test_display_crc_multiple(&data,
> > > > port);
> > > > +			test_display_crc(&data, port, 3);
> > > >   	}
> > > >   
> > > >   	igt_subtest_group {
-- 
Cheers,
	Lyude
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH i-g-t v3 1/4] chamelium: Calculate CRC from framebuffer instead of hardcoding it
  2017-07-06 13:14   ` Paul Kocialkowski
@ 2017-07-06 22:33     ` Lyude Paul
  0 siblings, 0 replies; 57+ messages in thread
From: Lyude Paul @ 2017-07-06 22:33 UTC (permalink / raw)
  To: Paul Kocialkowski, intel-gfx

On Thu, 2017-07-06 at 16:14 +0300, Paul Kocialkowski wrote:
> On Wed, 2017-07-05 at 16:34 -0400, Lyude Paul wrote:
> > So a couple of notes here that will make it a lot easier for me to
> > review these in the future
> > 
> >  * When you're doing a new revision of a patch series, it's helpful
> > to
> >    keep it in the same email thread as the original v1 so it's
> > easier
> >    to keep track of in people's mail clients (as well as avoiding
> >    accidentally reviewing older patch versions. I usually do
> > something
> >    like this (other projects might request you do this slightly
> >    differently, but this should be fine here):
> >     * [PATCH 0/2] Cleaning up the alignment of various foos
> >        * [PATCH 1/2] Foo the bar, not the baz
> >        * [PATCH 2/2] Introduce the amazing new foo_bar
> >        * [PATCH v2 0/2] Cleaning up the alignment of various foos
> >           * [PATCH v2 1/2] Foo the bar, not the baz
> >           * [PATCH v2 2/2] Introduce the amazing new foo_bar
> >        * [PATCH v3 0/2] Cleaning up the alignment of various foos
> >           * [PATCH v3 1/2] Foo the bar, not the baz
> >           * [PATCH v3 2/2] Introduce the amazing new foo_bar
> >  * Try not to group unrelated patches together in the same thread.
> > This
> >    also makes sorting through all of them a little more difficult.
> >  * When you make new revisions of patches, it's very useful if you
> > also
> >    include a list of changes you made to the patch since the last
> >    revision. It doesn't need to be very finely detailed, something
> > like
> >    this would suffice:
> >     * Various style fixes
> >     * Rename baz to moo, add cow noises
> >     * Split init_cow() into init_white_cow() and init_black_cow()
> >       instead of handling both kinds of cows in the same function
> >     * Fix documentation
> >     For intel-gpu-tools, it's fine to just stick this in the commit
> >     message. Other projects may request you put the changelog below
> > the
> >     ----- right above the diff stats (this allows the comments not
> > to
> >     get included in the final commit message)
> >  * Unless they are all very small and less important fixes,
> > including
> >    cover letters helps as well since it lets patchwork group
> > together
> >    patch series like this.
> 
> What would you prefer that I do regarding follow-up versions to this
> patchset (and the other one that is still under review)?
Don't worry about that, I went through all the other patches and
reviewed them anyway so there shouldn't be anything left to do :). just
use the guidelines for the future.
> 
> I could split the series per-topic (crc, frame save, time
> improvements)
> and keep those in the same parent thread as their v1.
> 
> > Anyway, back to the actual patch:
> > A good start! Will need a couple of changes though
> > 
> > On Wed, 2017-07-05 at 11:04 +0300, Paul Kocialkowski wrote:
> > > This introduces CRC calculation for reference frames, instead of
> > > using
> > > hardcoded values for them. The rendering of reference frames may
> > > differ
> > > from machine to machine, especially due to font rendering, and
> > > the
> > > frame itself may change with subsequent IGT changes.
> > > 
> > > These differences would cause the CRC checks to fail on different
> > > setups. This allows them to pass regardless of the setup.
> > > 
> > > Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.c
> > > om>
> > > ---
> > >  lib/igt_chamelium.c | 160
> > > ++++++++++++++++++++++++++++++++++++++++++++++++++++
> > >  lib/igt_chamelium.h |   5 ++
> > >  tests/chamelium.c   |  76 ++++++-------------------
> > >  3 files changed, 183 insertions(+), 58 deletions(-)
> > > 
> > > diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
> > > index bff08c0e..b9d80b6b 100644
> > > --- a/lib/igt_chamelium.c
> > > +++ b/lib/igt_chamelium.c
> > > @@ -94,6 +94,14 @@ struct chamelium_frame_dump {
> > >  	struct chamelium_port *port;
> > >  };
> > >  
> > > +struct chamelium_fb_crc {
> > > +	int fd;
> > > +	struct igt_fb *fb;
> > > +
> > > +	pthread_t thread_id;
> > > +	igt_crc_t *ret;
> > > +};
> > > +
> > 
> > The name of this structure is a little misleading, because now we
> > have
> > an API that exposes both a struct chamelium_fb_crc struct in
> > addition
> > to the igt_crc_t struct. Rename this to something like struct
> > chamelium_fb_crc_work
> > 
> > >  struct chamelium {
> > >  	xmlrpc_env env;
> > >  	xmlrpc_client *client;
> > > @@ -1003,6 +1011,158 @@ int chamelium_get_frame_limit(struct
> > > chamelium *chamelium,
> > >  	return ret;
> > >  }
> > >  
> > > +static uint32_t chamelium_xrgb_hash16(unsigned char *buffer, int
> > > width,
> > > +				      int height, int k, int m)
> > > +{
> > 
> > We're not modifying buffer, so make it a const. As well, feel free
> > to
> > mark this function as inline.
> > 
> > > +	unsigned char r, g, b;
> > > +	uint64_t sum = 0;
> > > +	uint64_t count = 0;
> > > +	uint64_t value;
> > > +	uint32_t hash;
> > > +	int index;
> > > +	int i;
> > > +
> > > +	for (i=0; i < width * height; i++) {
> > > +		if ((i % m) != k)
> > > +			continue;
> > > +
> > > +		index = i * 4;
> > > +
> > > +		r = buffer[index + 2];
> > > +		g = buffer[index + 1];
> > > +		b = buffer[index + 0];
> > > +
> > > +		value = r | (g << 8) | (b << 16);
> > > +		sum += ++count * value;
> > > +	}
> > > +
> > > +	hash = ((sum >> 0) ^ (sum >> 16) ^ (sum >> 32) ^ (sum >>
> > > 48)) & 0xffff;
> > > +
> > > +	return hash;
> > > +}
> > > +
> > > +/**
> > > + * chamelium_calculate_fb_crc:
> > > + * @fd: The drm file descriptor
> > > + * @fb: The framebuffer to calculate the CRC for
> > > + *
> > > + * Calculates a CRC for the provided framebuffer, the same way
> > > as
> > > the Chamelium.
> > 
> > Calculate the CRC for the provided framebuffer, using the
> > Chamelium's
> > CRC algorithm
> > > + * This calculates the CRC in a non-threaded fashion.
> > > + *
> > > + * Returns: The calculated CRC
> > > + */
> > > +igt_crc_t *chamelium_calculate_fb_crc(int fd, struct igt_fb *fb)
> > > +{
> > > +	igt_crc_t *ret;
> > > +	cairo_t *cr;
> > > +	cairo_surface_t *fb_surface;
> > > +	unsigned char *buffer;
> > > +	int n = 4;
> > > +	int w, h;
> > > +	int i, j;
> > > +
> > > +	ret = calloc(1, sizeof(igt_crc_t));
> > > +
> > > +	/* Get the cairo surface for the framebuffer */
> > > +	cr = igt_get_cairo_ctx(fd, fb);
> > > +	fb_surface = cairo_get_target(cr);
> > > +	cairo_surface_reference(fb_surface);
> > > +	cairo_destroy(cr);
> > > +
> > > +	buffer = cairo_image_surface_get_data(fb_surface);
> > > +	w = fb->width;
> > > +	h = fb->height;
> > > +
> > > +	for (i = 0; i < n; i++) {
> > > +		j = n - i - 1;
> > > +		ret->crc[i] = chamelium_xrgb_hash16(buffer, w,
> > > h,
> > > j,
> > > n);
> > > +	}
> > > +
> > > +	ret->n_words = n;
> > > +	cairo_surface_destroy(fb_surface);
> > > +
> > > +	return ret;
> > > +}
> > > +
> > > +static void *chamelium_calculate_fb_crc_thread(void *data)
> > > +{
> > > +	struct chamelium_fb_crc *fb_crc = (struct
> > > chamelium_fb_crc
> > > *) data;
> > > +	cairo_t *cr;
> > > +	cairo_surface_t *fb_surface;
> > > +	unsigned char *buffer;
> > > +	int n = 4;
> > > +	int w, h;
> > > +	int i, j;
> > > +
> > > +	/* Get the cairo surface for the framebuffer */
> > > +	cr = igt_get_cairo_ctx(fb_crc->fd, fb_crc->fb);
> > > +	fb_surface = cairo_get_target(cr);
> > > +	cairo_surface_reference(fb_surface);
> > > +	cairo_destroy(cr);
> > > +
> > > +	buffer = cairo_image_surface_get_data(fb_surface);
> > > +	w = fb_crc->fb->width;
> > > +	h = fb_crc->fb->height;
> > > +
> > > +	for (i = 0; i < n; i++) {
> > > +		j = n - i - 1;
> > > +		fb_crc->ret->crc[i] =
> > > chamelium_xrgb_hash16(buffer,
> > > w, h, j, n);
> > > +	}
> > > +
> > > +	fb_crc->ret->n_words = n;
> > > +	cairo_surface_destroy(fb_surface);
> > > +
> > > +	return NULL;
> > > +}
> > > +
> > > +/**
> > > + * chamelium_calculate_fb_crc_launch:
> > > + * @fd: The drm file descriptor
> > > + * @fb: The framebuffer to calculate the CRC for
> > > + *
> > > + * Launches the CRC calculation for the provided framebuffer,
> > > the
> > > same way as
> > > + * the Chamelium. This calculates the CRC in a threaded fashion.
> > > + * Thread-related information is returned and should be passed
> > > to a
> > > subsequent
> > > + * call to chamelium_calculate_fb_crc_result. It should not be
> > > freed.
> > > + *
> > > + * Returns: An intermediate structure with thread-related
> > > information
> > 
> > The user doesn't need to know about the magic inside the structure,
> > since we're not going to expose it's definition outside of this
> > file
> > anyway.
> > > + */
> > > +struct chamelium_fb_crc *chamelium_calculate_fb_crc_launch(int
> > > fd,
> > > +							   struc
> > > t
> > > igt_fb *fb)
> > > +{
> > > +	struct chamelium_fb_crc *fb_crc;
> > > +
> > > +	fb_crc = calloc(1, sizeof(struct chamelium_fb_crc));
> > > +	fb_crc->ret = calloc(1, sizeof(igt_crc_t));
> > > +	fb_crc->fd = fd;
> > > +	fb_crc->fb = fb;
> > > +
> > > +	pthread_create(&fb_crc->thread_id, NULL,
> > > +		       chamelium_calculate_fb_crc_thread,
> > > fb_crc);
> > > +
> > > +	return fb_crc;
> > > +}
> > > +
> > > +/**
> > > + * chamelium_calculate_fb_crc_result:
> > > + * @fb_crc: An intermediate structure with thread-related
> > > information
> > > + *
> > > + * Provides the result for the previously-launched CRC
> > > calculation.
> > 
> > Blocks until the async CRC calculation is finished, and then
> > returns
> > the result.
> > > + *
> > > + * Returns: The calculated CRC
> > > + */
> > > +igt_crc_t *chamelium_calculate_fb_crc_result(struct
> > > chamelium_fb_crc
> > > *fb_crc)
> > > +{
> > > +	igt_crc_t *ret;
> > > +
> > > +	pthread_join(fb_crc->thread_id, NULL);
> > > +
> > > +	ret = fb_crc->ret;
> > > +	free(fb_crc);
> > > +
> > > +	return ret;
> > > +}
> > > +
> > >  static unsigned int chamelium_get_port_type(struct chamelium
> > > *chamelium,
> > >  					    struct
> > > chamelium_port
> > > *port)
> > >  {
> > > diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
> > > index 81322ad2..e51cf4f9 100644
> > > --- a/lib/igt_chamelium.h
> > > +++ b/lib/igt_chamelium.h
> > > @@ -36,6 +36,7 @@
> > >  struct chamelium;
> > >  struct chamelium_port;
> > >  struct chamelium_frame_dump;
> > > +struct chamelium_fb_crc;
> > >  
> > >  struct chamelium *chamelium_init(int drm_fd);
> > >  void chamelium_deinit(struct chamelium *chamelium);
> > > @@ -92,6 +93,10 @@ struct chamelium_frame_dump
> > > *chamelium_port_dump_pixels(struct chamelium *chamel
> > >  							struct
> > > chamelium_port *port,
> > >  							int x,
> > > int
> > > y,
> > >  							int w,
> > > int
> > > h);
> > > +igt_crc_t *chamelium_calculate_fb_crc(int fd, struct igt_fb
> > > *fb);
> > > +struct chamelium_fb_crc *chamelium_calculate_fb_crc_launch(int
> > > fd,
> > > +							   struc
> > > t
> > > igt_fb *fb);
> > > +igt_crc_t *chamelium_calculate_fb_crc_result(struct
> > > chamelium_fb_crc
> > > *fb_crc);
> > >  int chamelium_get_captured_frame_count(struct chamelium
> > > *chamelium);
> > >  int chamelium_get_frame_limit(struct chamelium *chamelium,
> > >  			      struct chamelium_port *port,
> > > diff --git a/tests/chamelium.c b/tests/chamelium.c
> > > index e3067664..3fd2b02c 100644
> > > --- a/tests/chamelium.c
> > > +++ b/tests/chamelium.c
> > > @@ -49,43 +49,6 @@ typedef struct {
> > >  #define HPD_TOGGLE_COUNT_VGA 5
> > >  #define HPD_TOGGLE_COUNT_DP_HDMI 15
> > >  
> > > -/* Pre-calculated CRCs for the pattern fb, for all the modes in
> > > the
> > > default
> > > - * chamelium edid
> > > - */
> > > -struct crc_entry {
> > > -	int width;
> > > -	int height;
> > > -	igt_crc_t crc;
> > > -};
> > > -
> > > -#define CRC_ENTRY(w_, h_, ...) \
> > > -	{ w_, h_, { .n_words = 4, .crc = { __VA_ARGS__ } } }
> > > -
> > > -static const struct crc_entry pattern_fb_crcs[] = {
> > > -	CRC_ENTRY(1920, 1080, 0xf859, 0xa751, 0x8c81, 0x45a1),
> > > -	CRC_ENTRY(1280,  720, 0xcec2, 0x4246, 0x6cfd, 0xeb43),
> > > -	CRC_ENTRY(1024,  768, 0x85e5, 0xf0cd, 0xafe3, 0x7f18),
> > > -	CRC_ENTRY( 800,  600, 0x6b39, 0x32b6, 0x831a, 0xb03e),
> > > -	CRC_ENTRY( 640,  480, 0xa121, 0x2473, 0xb150, 0x8c47),
> > > -};
> > > -#undef CRC_ENTRY
> > > -
> > > -static const igt_crc_t *
> > > -get_precalculated_crc(struct chamelium_port *port, int w, int h)
> > > -{
> > > -	int i;
> > > -	const struct crc_entry *entry;
> > > -
> > > -	for (i = 0; i < ARRAY_SIZE(pattern_fb_crcs); i++) {
> > > -		entry = &pattern_fb_crcs[i];
> > > -
> > > -		if (entry->width == w && entry->height == h)
> > > -			return &entry->crc;
> > > -	}
> > > -
> > > -	return NULL;
> > > -}
> > > -
> > >  static void
> > >  require_connector_present(data_t *data, unsigned int type)
> > >  {
> > > @@ -424,7 +387,8 @@ test_display_crc_single(data_t *data, struct
> > > chamelium_port *port)
> > >  	igt_output_t *output;
> > >  	igt_plane_t *primary;
> > >  	igt_crc_t *crc;
> > > -	const igt_crc_t *expected_crc;
> > > +	igt_crc_t *expected_crc;
> > > +	struct chamelium_fb_crc *fb_crc;
> > >  	struct igt_fb fb;
> > >  	drmModeModeInfo *mode;
> > >  	drmModeConnector *connector;
> > > @@ -447,24 +411,21 @@ test_display_crc_single(data_t *data,
> > > struct
> > > chamelium_port *port)
> > >  						    0, 0, 0,
> > > &fb);
> > >  		igt_assert(fb_id > 0);
> > >  
> > > -		enable_output(data, port, output, mode, &fb);
> > > +		fb_crc = chamelium_calculate_fb_crc_launch(data-
> > > > drm_fd, &fb);
> > > 
> > >  
> > > -		expected_crc = get_precalculated_crc(port,
> > > -						     mode-
> > > > hdisplay,
> > > 
> > > -						     mode-
> > > > vdisplay);
> > > 
> > > -		if (!expected_crc) {
> > > -			igt_warn("No precalculated CRC found for
> > > %dx%d, skipping CRC check\n",
> > > -				 mode->hdisplay, mode-
> > > >vdisplay);
> > > -			goto next;
> > > -		}
> > > +		enable_output(data, port, output, mode, &fb);
> > >  
> > >  		igt_debug("Testing single CRC fetch\n");
> > > +
> > >  		crc = chamelium_get_crc_for_area(data-
> > > >chamelium,
> > > port,
> > >  						 0, 0, 0, 0);
> > > +
> > > +		expected_crc =
> > > chamelium_calculate_fb_crc_result(fb_crc);
> > > +
> > >  		igt_assert_crc_equal(crc, expected_crc);
> > > +		free(expected_crc);
> > >  		free(crc);
> > >  
> > > -next:
> > >  		disable_output(data, port, output);
> > >  		igt_remove_fb(data->drm_fd, &fb);
> > >  	}
> > > @@ -480,7 +441,8 @@ test_display_crc_multiple(data_t *data,
> > > struct
> > > chamelium_port *port)
> > >  	igt_output_t *output;
> > >  	igt_plane_t *primary;
> > >  	igt_crc_t *crc;
> > > -	const igt_crc_t *expected_crc;
> > > +	igt_crc_t *expected_crc;
> > > +	struct chamelium_fb_crc *fb_crc;
> > >  	struct igt_fb fb;
> > >  	drmModeModeInfo *mode;
> > >  	drmModeConnector *connector;
> > > @@ -503,15 +465,9 @@ test_display_crc_multiple(data_t *data,
> > > struct
> > > chamelium_port *port)
> > >  						    0, 0, 0,
> > > &fb);
> > >  		igt_assert(fb_id > 0);
> > >  
> > > -		enable_output(data, port, output, mode, &fb);
> > > +		fb_crc = chamelium_calculate_fb_crc_launch(data-
> > > > drm_fd, &fb);
> > > 
> > >  
> > > -		expected_crc = get_precalculated_crc(port, mode-
> > > > hdisplay,
> > > 
> > > -						     mode-
> > > > vdisplay);
> > > 
> > > -		if (!expected_crc) {
> > > -			igt_warn("No precalculated CRC found for
> > > %dx%d, skipping CRC check\n",
> > > -				 mode->hdisplay, mode-
> > > >vdisplay);
> > > -			goto next;
> > > -		}
> > > +		enable_output(data, port, output, mode, &fb);
> > >  
> > >  		/* We want to keep the display running for a
> > > little
> > > bit, since
> > >  		 * there's always the potential the driver isn't
> > > able to keep
> > > @@ -522,11 +478,15 @@ test_display_crc_multiple(data_t *data,
> > > struct
> > > chamelium_port *port)
> > >  						   &captured_fra
> > > me_
> > > c
> > > ount);
> > >  
> > >  		igt_debug("Captured %d frames\n",
> > > captured_frame_count);
> > > +
> > > +		expected_crc =
> > > chamelium_calculate_fb_crc_result(fb_crc);
> > > +
> > >  		for (j = 0; j < captured_frame_count; j++)
> > >  			igt_assert_crc_equal(&crc[j],
> > > expected_crc);
> > > +
> > > +		free(expected_crc);
> > >  		free(crc);
> > >  
> > > -next:
> > >  		disable_output(data, port, output);
> > >  		igt_remove_fb(data->drm_fd, &fb);
> > >  	}
-- 
Cheers,
	Lyude
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH i-g-t v3 4/4] chamelium: Dump obtained and reference frames to png on crc error
  2017-07-06 22:23         ` Lyude Paul
@ 2017-07-10 10:12           ` Paul Kocialkowski
  0 siblings, 0 replies; 57+ messages in thread
From: Paul Kocialkowski @ 2017-07-10 10:12 UTC (permalink / raw)
  To: Lyude Paul, Martin Peres, intel-gfx

On Thu, 2017-07-06 at 18:23 -0400, Lyude Paul wrote:
> On Thu, 2017-07-06 at 14:35 +0300, Paul Kocialkowski wrote:
> > On Thu, 2017-07-06 at 10:41 +0300, Martin Peres wrote:
> > > On 06/07/17 00:44, Lyude Paul wrote:
> > > > On Wed, 2017-07-05 at 11:04 +0300, Paul Kocialkowski wrote:
> > > > > When a CRC comparison error occurs, it is quite useful to get
> > > > > a
> > > > > dump
> > > > > of both the frame obtained from the chamelium and the
> > > > > reference
> > > > > in
> > > > > order
> > > > > to compare them.
> > > > > 
> > > > > This implements the frame dump, with a configurable path that
> > > > > enables
> > > > > the use of this feature.
> > > > > 
> > > > > Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.inte
> > > > > l
> > > > > .com>
> > > > > ---
> > > > >   lib/igt_chamelium.c |  21 +++++++++++
> > > > >   lib/igt_chamelium.h |   1 +
> > > > >   lib/igt_debugfs.c   |  20 ++++++++++
> > > > >   lib/igt_debugfs.h   |   1 +
> > > > >   tests/chamelium.c   | 104 ++++++++++++++++++++------------
> > > > > ---
> > > > > -----
> > > > > ------------
> > > > >   5 files changed, 82 insertions(+), 65 deletions(-)
> > > > > 
> > > > > diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
> > > > > index ef51ef68..9aca6842 100644
> > > > > --- a/lib/igt_chamelium.c
> > > > > +++ b/lib/igt_chamelium.c
> > > > > @@ -57,6 +57,7 @@
> > > > >    * |[<!-- language="plain" -->
> > > > >    *	[Chamelium]
> > > > >    *	URL=http://chameleon:9992 # The URL used for
> > > > > connecting to
> > > > > the Chamelium's RPC server
> > > > > + *	FrameDumpPath=/tmp # The path to dump frames that
> > > > > fail
> > > > > comparison checks
> > > > 
> > > > While no one else really cares about creating frame dumps yet,
> > > > it's
> > > > possible someone else may in the future if we ever end up taking
> > > > more
> > > > advantage of automated testing systems like this. So I'd stick
> > > > this in
> > > > the generic non-chamelium specific section in the config file
> > > > 
> > > > >    *
> > > > >    *	# The rest of the sections are used for defining
> > > > > connector
> > > > > mappings.
> > > > >    *	# This is required so any tests using the
> > > > > Chamelium
> > > > > know
> > > > > which connector
> > > > > @@ -115,11 +116,26 @@ struct chamelium {
> > > > >   	struct chamelium_edid *edids;
> > > > >   	struct chamelium_port *ports;
> > > > >   	int port_count;
> > > > > +
> > > > > +	char *frame_dump_path;
> > > > >   };
> > > > >   
> > > > >   static struct chamelium *cleanup_instance;
> > > > >   
> > > > >   /**
> > > > > + * chamelium_get_frame_dump_path:
> > > > > + * @chamelium: The Chamelium instance to use
> > > > > + *
> > > > > + * Retrieves the path to dump frames to.
> > > > > + *
> > > > > + * Returns: a string with the frame dump path
> > > > > + */
> > > > > +char *chamelium_get_frame_dump_path(struct chamelium
> > > > > *chamelium)
> > > > > +{
> > > > > +	return chamelium->frame_dump_path;
> > > > > +}
> > > > > +
> > > > > +/**
> > > > >    * chamelium_get_ports:
> > > > >    * @chamelium: The Chamelium instance to use
> > > > >    * @count: Where to store the number of ports
> > > > > @@ -1338,6 +1354,11 @@ static bool
> > > > > chamelium_read_config(struct
> > > > > chamelium *chamelium, int drm_fd)
> > > > >   		return false;
> > > > >   	}
> > > > >   
> > > > > +	chamelium->frame_dump_path =
> > > > > g_key_file_get_string(igt_key_file,
> > > > > +							   "C
> > > > > h
> > > > > ameliu
> > > > > m",
> > > > > +							   "F
> > > > > r
> > > > > ameDum
> > > > > pPath",
> > > > > +							    &
> > > > > e
> > > > > rror);
> > > > > +
> > > > >   	return chamelium_read_port_mappings(chamelium,
> > > > > drm_fd);
> > > > >   }
> > > > >   
> > > > > diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
> > > > > index 908e03d1..aa881971 100644
> > > > > --- a/lib/igt_chamelium.h
> > > > > +++ b/lib/igt_chamelium.h
> > > > > @@ -42,6 +42,7 @@ struct chamelium *chamelium_init(int
> > > > > drm_fd);
> > > > >   void chamelium_deinit(struct chamelium *chamelium);
> > > > >   void chamelium_reset(struct chamelium *chamelium);
> > > > >   
> > > > > +char *chamelium_get_frame_dump_path(struct chamelium
> > > > > *chamelium);
> > > > >   struct chamelium_port **chamelium_get_ports(struct chamelium
> > > > > *chamelium,
> > > > >   					    int *count);
> > > > >   unsigned int chamelium_port_get_type(const struct
> > > > > chamelium_port
> > > > > *port);
> > > > > diff --git a/lib/igt_debugfs.c b/lib/igt_debugfs.c
> > > > > index 80f25c61..dcb4e0a7 100644
> > > > > --- a/lib/igt_debugfs.c
> > > > > +++ b/lib/igt_debugfs.c
> > > > > @@ -282,6 +282,26 @@ bool igt_debugfs_search(int device, const
> > > > > char
> > > > > *filename, const char *substring)
> > > > >    */
> > > > >   
> > > > >   /**
> > > > > + * igt_check_crc_equal:
> > > > > + * @a: first pipe CRC value
> > > > > + * @b: second pipe CRC value
> > > > > + *
> > > > > + * Compares two CRC values and return whether they match.
> > > > > + *
> > > > > + * Returns: A boolean indicating whether the CRC values match
> > > > > + */
> > > > > +bool igt_check_crc_equal(const igt_crc_t *a, const igt_crc_t
> > > > > *b)
> > > > > +{
> > > > > +	int i;
> > > 
> > > I would like to see:
> > > 
> > > if (a->n_words != b->n_words)
> > >      return false;
> > 
> > Very good suggestion! I'll take that in in the next revision.
> > 
> > > > > +
> > > > > +	for (i = 0; i < a->n_words; i++)
> > > > > +		if (a->crc[i] != b->crc[i])
> > > > > +			return false;
> > > > > +
> > > > > +	return true;
> > > > > +}
> > > > > +
> > > > 
> > > > Make this a separate patch, and instead of having another
> > > > function do
> > > > the CRC calculations just have something like this:
> > > > 
> > > >   * static int igt_find_crc_mismatch(const igt_crc_t *a, const
> > > > igt_crc_t
> > > >     *b): returns the index of the first CRC mismatch, 0 if none
> > > > was
> > > >     found
> > > 
> > > Sounds good, but no error should return -1, as to differentiate if
> > > the 
> > > first word was already different.
> > 
> > I don't understand the point of getting the index of the CRC
> > mismatch
> > at all.
> > The only relevant information here should be whether it matches or
> > not (which
> > would be covered by igt_check_crc_equal). Can you ellaborate on
> > this?
> 
> It's just so that we can print more detailed debugging info that
> actually notes which part of the CRC didn't match. This sounds a
> little
> useless, but sometimes you can actually tell what's going on by
> looking
> at how much of the CRC didn't match.
> 
> For instance, when I was trying to figure out the (I didn't know this
> was the cause at the time) ESD issues I was hitting with DisplayPort
> on
> the chamelium, the chromeos guys were immediately able to tell it was
> only a single pixel that was off because only one section of the CRC
> didn't match, while the rest of it did.

Okay, thanks for the explanation. I understand the intent here and
definitely agree that it would be useful. However, note that
igt_assert_crc_equal is already implemented and calls igt_assert_eq_u32
directly, which will print an error on mismatch.

So I wonder if it's really worth having a separate function
(igt_find_crc_mismatch) only for getting the index. We could just keep
igt_assert_crc_equal as it is and implement igt_check_crc_equal with
similar debug output. That is a duplication of the logic, but it's so
simple that I don't think it's really a problem.

With that in mind, if you still really prefer that we use a separate
function and rewrite igt_assert_crc_equal, then I will do that.

> > > >   * bool igt_check_crc_equal(): uses igt_find_crc_mismatch() to
> > > > figure
> > > >     out if anything mismatched, and return true if something did
> > > > (as
> > > >     well, also spit out some debugging info mentioning there was
> > > > a
> > > >     mismatch)
> > > >   * void igt_assert_crc_equal(): uses igt_find_crc_mismatch() to
> > > > figure
> > > >     out if anything mismatched. If the assertion fails, use
> > > >     igt_assert_eq() on the mismatched crc so we still get a
> > > > useful error
> > > >     message on CRC failures.
> > > > 
> > > > There isn't much code required to actually compare CRCs, however
> > > > I'd
> > > > still prefer only having one function doing the actual
> > > > comparison
> > > > logic
> > > > here so we only have one piece of code to update if we need to
> > > > make
> > > > changes to it in the future.
> > > > 
> > > > Mupuf, your opinion on this? ^
> > > > 
> > > > > +/**
> > > > >    * igt_assert_crc_equal:
> > > > >    * @a: first pipe CRC value
> > > > >    * @b: second pipe CRC value
> > > > > diff --git a/lib/igt_debugfs.h b/lib/igt_debugfs.h
> > > > > index 7b846a83..2695cbda 100644
> > > > > --- a/lib/igt_debugfs.h
> > > > > +++ b/lib/igt_debugfs.h
> > > > > @@ -113,6 +113,7 @@ enum intel_pipe_crc_source {
> > > > >           INTEL_PIPE_CRC_SOURCE_MAX,
> > > > >   };
> > > > >   
> > > > > +bool igt_check_crc_equal(const igt_crc_t *a, const igt_crc_t
> > > > > *b);
> > > > >   void igt_assert_crc_equal(const igt_crc_t *a, const
> > > > > igt_crc_t
> > > > > *b);
> > > > >   char *igt_crc_to_string(igt_crc_t *crc);
> > > > >   
> > > > > diff --git a/tests/chamelium.c b/tests/chamelium.c
> > > > > index 5cf8b3af..3d95c05c 100644
> > > > > --- a/tests/chamelium.c
> > > > > +++ b/tests/chamelium.c
> > > > > @@ -381,7 +381,7 @@ disable_output(data_t *data,
> > > > >   }
> > > > >   
> > > > >   static void
> > > > > -test_display_crc_single(data_t *data, struct chamelium_port
> > > > > *port)
> > > > > +test_display_crc(data_t *data, struct chamelium_port *port,
> > > > > int
> > > > > count)
> > > > >   {
> > > > >   	igt_display_t display;
> > > > >   	igt_output_t *output;
> > > > > @@ -390,9 +390,14 @@ test_display_crc_single(data_t *data,
> > > > > struct
> > > > > chamelium_port *port)
> > > > >   	igt_crc_t *expected_crc;
> > > > >   	struct chamelium_fb_crc *fb_crc;
> > > > >   	struct igt_fb fb;
> > > > > +	struct chamelium_frame_dump *frame;
> > > > >   	drmModeModeInfo *mode;
> > > > >   	drmModeConnector *connector;
> > > > > -	int fb_id, i;
> > > > > +	int fb_id, i, j, captured_frame_count;
> > > > > +	const char *connector_name;
> > > > > +	char *frame_dump_path;
> > > > > +	char path[PATH_MAX];
> > > > > +	bool eq;
> > > > >   
> > > > >   	reset_state(data, port);
> > > > >   
> > > > > @@ -401,6 +406,9 @@ test_display_crc_single(data_t *data,
> > > > > struct
> > > > > chamelium_port *port)
> > > > >   	primary = igt_output_get_plane_type(output,
> > > > > DRM_PLANE_TYPE_PRIMARY);
> > > > >   	igt_assert(primary);
> > > > >   
> > > > > +	connector_name =
> > > > > kmstest_connector_type_str(connector-
> > > > > > connector_type);
> > > > > 
> > > > > +	frame_dump_path = chamelium_get_frame_dump_path(data-
> > > > > > chamelium);
> > > > > 
> > > > > +
> > > > >   	for (i = 0; i < connector->count_modes; i++) {
> > > > >   		mode = &connector->modes[i];
> > > > >   		fb_id = igt_create_color_pattern_fb(data-
> > > > > > drm_fd,
> > > > > 
> > > > > @@ -415,74 +423,40 @@ test_display_crc_single(data_t *data,
> > > > > struct
> > > > > chamelium_port *port)
> > > > >   
> > > > >   		enable_output(data, port, output, mode,
> > > > > &fb);
> > > > >   
> > > > > -		igt_debug("Testing single CRC fetch\n");
> > > > > -
> > > > > -		crc = chamelium_get_crc_for_area(data-
> > > > > > chamelium,
> > > > > 
> > > > > port,
> > > > > -						 0, 0, 0, 0);
> > > > > -
> > > > > -		expected_crc =
> > > > > chamelium_calculate_fb_crc_result(fb_crc);
> > > > > -
> > > > > -		igt_assert_crc_equal(crc, expected_crc);
> > > > > -		free(expected_crc);
> > > > > -		free(crc);
> > > > > -
> > > > > -		disable_output(data, port, output);
> > > > > -		igt_remove_fb(data->drm_fd, &fb);
> > > > > -	}
> > > > > -
> > > > > -	drmModeFreeConnector(connector);
> > > > > -	igt_display_fini(&display);
> > > > > -}
> > > > > -
> > > > > -static void
> > > > > -test_display_crc_multiple(data_t *data, struct chamelium_port
> > > > > *port)
> > > > > -{
> > > > > -	igt_display_t display;
> > > > > -	igt_output_t *output;
> > > > > -	igt_plane_t *primary;
> > > > > -	igt_crc_t *crc;
> > > > > -	igt_crc_t *expected_crc;
> > > > > -	struct chamelium_fb_crc *fb_crc;
> > > > > -	struct igt_fb fb;
> > > > > -	drmModeModeInfo *mode;
> > > > > -	drmModeConnector *connector;
> > > > > -	int fb_id, i, j, captured_frame_count;
> > > > > +		chamelium_capture(data->chamelium, port, 0,
> > > > > 0,
> > > > > 0, 0,
> > > > > count);
> > > > > +		crc = chamelium_read_captured_crcs(data-
> > > > > > chamelium,
> > > > > 
> > > > > +						   &captured_
> > > > > f
> > > > > rame_c
> > > > > ount);
> > > > >   
> > > > > -	reset_state(data, port);
> > > > > +		igt_assert(captured_frame_count == count);
> > > > >   
> > > > > -	output = prepare_output(data, &display, port);
> > > > > -	connector = chamelium_port_get_connector(data-
> > > > > > chamelium,
> > > > > 
> > > > > port, false);
> > > > > -	primary = igt_output_get_plane_type(output,
> > > > > DRM_PLANE_TYPE_PRIMARY);
> > > > > -	igt_assert(primary);
> > > > > +		igt_debug("Captured %d frames\n",
> > > > > captured_frame_count);
> > > > >   
> > > > > -	for (i = 0; i < connector->count_modes; i++) {
> > > > > -		mode = &connector->modes[i];
> > > > > -		fb_id = igt_create_color_pattern_fb(data-
> > > > > > drm_fd,
> > > > > 
> > > > > -						    mode-
> > > > > > hdisplay,
> > > > > 
> > > > > -						    mode-
> > > > > > vdisplay,
> > > > > 
> > > > > -						    DRM_FORMA
> > > > > T
> > > > > _XRGB8
> > > > > 888,
> > > > > -						    LOCAL_DRM
> > > > > _
> > > > > FORMAT
> > > > > _MOD_NONE,
> > > > > -						    0, 0, 0,
> > > > > &fb);
> > > > > -		igt_assert(fb_id > 0);
> > > > > +		expected_crc =
> > > > > chamelium_calculate_fb_crc_result(fb_crc);
> > > > >   
> > > > > -		fb_crc =
> > > > > chamelium_calculate_fb_crc_launch(data-
> > > > > > drm_fd, &fb);
> > > > > 
> > > > > +		for (j = 0; j < captured_frame_count; j++) {
> > > > > +			eq = igt_check_crc_equal(&crc[j],
> > > > > expected_crc);
> > > > > +			if (!eq && frame_dump_path) {
> > > > > +				frame =
> > > > > chamelium_read_captured_frame(data->chamelium,
> > > > > +								
> > > > >    j);
> > > > >   
> > > > > -		enable_output(data, port, output, mode, &fb);
> > > > > +				igt_debug("Dumping reference
> > > > > and
> > > > > chamelium frames to %s...\n",
> > > > > +					  frame_dump_path);
> > > > >   
> > > > > -		/* We want to keep the display running for a
> > > > > little
> > > > > bit, since
> > > > > -		 * there's always the potential the driver
> > > > > isn't
> > > > > able to keep
> > > > > -		 * the display running properly for very long
> > > > > -		 */
> > > > > -		chamelium_capture(data->chamelium, port, 0,
> > > > > 0,
> > > > > 0, 0,
> > > > > 3);
> > > > > -		crc = chamelium_read_captured_crcs(data-
> > > > > > chamelium,
> > > > > 
> > > > > -						   &captured_
> > > > > f
> > > > > rame_c
> > > > > ount);
> > > > > +				snprintf(path, PATH_MAX,
> > > > > "%s/frame-
> > > > > reference-%s.png",
> > > > > +					 frame_dump_path,
> > > > > connector_name);
> > > > > +				igt_write_fb_to_png(data-
> > > > > > drm_fd,
> > > > > 
> > > > > &fb, path);
> > > > >   
> > > > > -		igt_debug("Captured %d frames\n",
> > > > > captured_frame_count);
> > > > > +				snprintf(path, PATH_MAX,
> > > > > "%s/frame-
> > > > > chamelium-%s.png",
> > > > > +					 frame_dump_path,
> > > > > connector_name);
> > > > > +				chamelium_write_frame_to_png(
> > > > > d
> > > > > ata-
> > > > > > chamelium,
> > > > > 
> > > > > +							     
> > > > > f
> > > > > rame,
> > > > > path);
> > > > >   
> > > > > -		expected_crc =
> > > > > chamelium_calculate_fb_crc_result(fb_crc);
> > > > > +				chamelium_destroy_frame_dump(
> > > > > f
> > > > > rame);
> > > > > +			}
> > > > >   
> > > > > -		for (j = 0; j < captured_frame_count; j++)
> > > > > -			igt_assert_crc_equal(&crc[j],
> > > > > expected_crc);
> > > > > +			igt_fail_on_f(!eq,
> > > > > +				      "Chamelium frame CRC
> > > > > mismatch
> > > > > with reference\n");
> > > > > +		}
> > > > 
> > > > There's lots of potential here for copy pasta to form in the
> > > > future,
> > > > since the API here puts a lot of work on the caller to set
> > > > things
> > > > up
> > > > for frame dumping. IMO, it would be worth it to teach the CRC
> > > > checking
> > > > functions to automatically do frame dumps on mismatch if the CRC
> > > > source
> > > > supports it. This will save us from having to have separate
> > > > frame
> > > > dump
> > > > APIs in the future if we ever end up adding support for other
> > > > kinds of
> > > > automated test equipment.
> > > > 
> > > > As well, I like how you removed the redundancy between
> > > > test_display_crc_single() and test_display_crc_multiple().
> > > > However
> > > > since those are somewhat unrelated changes to the code path for
> > > > these
> > > > tests it would be better to have that re-factoring as a separate
> > > > patch
> > > > so as to make it easier for anyone who might need to bisect this
> > > > code
> > > > in the future.
> > > > 
> > > > >   
> > > > >   		free(expected_crc);
> > > > >   		free(crc);
> > > > > @@ -644,10 +618,10 @@ igt_main
> > > > >   							edid
> > > > > _
> > > > > id,
> > > > > alt_edid_id);
> > > > >   
> > > > >   		connector_subtest("dp-crc-single",
> > > > > DisplayPort)
> > > > > -			test_display_crc_single(&data, port);
> > > > > +			test_display_crc(&data, port, 1);
> > > > >   
> > > > >   		connector_subtest("dp-crc-multiple",
> > > > > DisplayPort)
> > > > > -			test_display_crc_multiple(&data,
> > > > > port);
> > > > > +			test_display_crc(&data, port, 3);
> > > > >   	}
> > > > >   
> > > > >   	igt_subtest_group {
> > > > > @@ -698,10 +672,10 @@ igt_main
> > > > >   							edid
> > > > > _
> > > > > id,
> > > > > alt_edid_id);
> > > > >   
> > > > >   		connector_subtest("hdmi-crc-single", HDMIA)
> > > > > -			test_display_crc_single(&data, port);
> > > > > +			test_display_crc(&data, port, 1);
> > > > >   
> > > > >   		connector_subtest("hdmi-crc-multiple",
> > > > > HDMIA)
> > > > > -			test_display_crc_multiple(&data,
> > > > > port);
> > > > > +			test_display_crc(&data, port, 3);
> > > > >   	}
> > > > >   
> > > > >   	igt_subtest_group {
-- 
Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo, Finland
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH i-g-t v3 4/4] chamelium: Dump obtained and reference frames to png on crc error
  2017-07-06 21:57         ` Lyude Paul
@ 2017-07-10 10:27           ` Paul Kocialkowski
  2017-07-11 17:27             ` Lyude Paul
  2017-07-10 10:31           ` Paul Kocialkowski
  1 sibling, 1 reply; 57+ messages in thread
From: Paul Kocialkowski @ 2017-07-10 10:27 UTC (permalink / raw)
  To: Lyude Paul, intel-gfx

On Thu, 2017-07-06 at 17:57 -0400, Lyude Paul wrote:
> --snip--
> (also sorry this one took a while to get to, had to do a lot of
> thinking because I never really solved the problems mentioned here
> when
> I tried working on this...)
> 
> On Thu, 2017-07-06 at 16:33 +0300, Paul Kocialkowski wrote:
> > On Thu, 2017-07-06 at 14:31 +0300, Paul Kocialkowski wrote:
> > > > 
> > > > There's lots of potential here for copy pasta to form in the
> > > > future,
> > > > since the API here puts a lot of work on the caller to set
> > > > things
> > > > up
> > > > for frame dumping. IMO, it would be worth it to teach the CRC
> > > > checking
> > > > functions to automatically do frame dumps on mismatch if the CRC
> > > > source
> > > > supports it. This will save us from having to have separate
> > > > frame
> > > > dump
> > > > APIs in the future if we ever end up adding support for other
> > > > kinds
> > > > of
> > > > automated test equipment.
> > > 
> > > I don't think it makes so much sense to do this in the CRC
> > > checking
> > > functions,
> > > just because they are semantically expected to do one thing: CRC
> > > checking, and
> > > doing frame dumps seems like going overboard.
> > > 
> > > On the other hand, I do agree that the dumping and saving part can
> > > and
> > > should be
> > > made common, but maybe as a separate function. So that would be
> > > two
> > > calls for
> > > the tests: one to check the crc and one to dump and save the
> > > frame.
> > 
> > A strong case to support this vision: in VGA frame testing, we have
> > already dumped the frame and don't do CRC checking, yet we also need
> > to
> > save the frames if there is a mismatch.
> > 
> > It would be a shame that the dumping logic becomes part of the CRC
> > functions, since that would mean duplicating that logic for VGA
> > testing
> > (as it's currently done in the version I just sent out).
> 
> That is a good point, but there's some things I think you might want
> to
> consider. Mainly that in a test that passes, we of course don't write
> any framedumps back to the disk since nothing failed. IMO, I would
> -think- that we care a bit more about the performance hit that happens
> on passing tests vs. failing tests, since tests aren't really supposed
> to fail under ideal conditions anyway. Might be better to verify with
> the mupuf and the other people actually running Intel's CI though,
> since I'm not one of them.
> 
> As well, one advantage we do have here from the chamelium end is that
> you can only really be screen grabbing from one port at a time. So you
> could actually just track stuff internally in the igt_chamelium API
> and
> when a user tries to download a framedump that we've already
> downloaded, we can just hand them back a cached copy of it.

Either way, it is definitely okay to take the time to dump the frame
when a mismatch occurs if we don't have it already (in the CRC case).

> > 
> > In spite of that, I think having a common function, called from the
> > test
> > itself is probably the best approach here.
> 
> Not sure if I misspoke here but I didn't mean to imply that I'm
> against
> having functions for doing frame dumping exposed to the callers. I had
> already figured there'd probably be situations where just having the
> CRC checking do the frame dumping wouldn't be enough.
> 
> This being said though, your viewpoint does make me realize it might
> not be a great idea to do autoframe dumping in -all- crc checking
> functions necessarily, but also makes me realize that this might even
> be a requirement if we still want to try keeping around
> igt_assert_crc_equal() and not just replace it outright with a
> function
> that doesn't fail the whole test (if we fail the test, there isn't
> really a way we can do a framedump from it afterwards). So I would
> think we can at least exclude igt_check_crc_equal() from doing
> automatic framedumping, but I still think it would be a good idea to
> implement igt_assert_crc_equal().

igt_assert_crc_equal already exists and is used by many other tests, so
we really cannot embed the frame dumping logic there, since these tests
have nothing to do with the chamelium. That's another reason to really
keep the frame dump and crc comparison logic separate.

> As for the what you're talking about, e.g. doing frame dump
> comparisons
> on VGA, I think the solution might be not to make any of the code for
> doing the actual frame comparisons chamelium specific either (except
> maybe for the part where we trim the framebuffer we get so it only
> contains the actual image dump).
> 
> So how about this: let's introduce a generic frame comparison API
> using
> the code you've already written for doing this on VGA with the
> chamelium. Make it part of the igt library, and have it just accept
> normal pixman images and perform fuzzy comparisons between them. In
> doing that, we can introduce a generic dump-frames-on-error API
> through
> there much more easily.
> 
> My big aim here is just to make it so that people using igt don't have
> to do anything to get frame dumping in their tests, it just "works".

I totally agree with this direction.

What I suggest we should do is the following:
* keep CRC functions (igt_assert_crc_equal and igt_check_crc_equal)
common and fully independent from the frame dumping logic, either with a
common crc mismatch detection logic or not (because it's so simple)
* have common frame dump functions that just take a cairo surface and
handle filenames and actually writing the frames
* have the analogue frame detection code made common
* have two assert-style chamnelium-specific wrappers to link frame
comparison (either CRC or analogue) and frame dumping on failure while
still ending with an assert; the CRC fashion would be in charge of
dumping the frame on failure while the frame would be provided to the
analogue comparison fashion.

I will prepare patches in this direction so that you can get a more
concrete idea and we can follow-up the discussion on that basis.

> > > I have also duplicated that logic in upcoming VGA frame testing,
> > > so
> > > there is definitely a need for less duplication.
> > > 
> > > > As well, I like how you removed the redundancy between
> > > > test_display_crc_single() and test_display_crc_multiple().
> > > > However
> > > > since those are somewhat unrelated changes to the code path for
> > > > these
> > > > tests it would be better to have that re-factoring as a separate
> > > > patch
> > > > so as to make it easier for anyone who might need to bisect this
> > > > code
> > > > in the future.
> > > 
> > > Fair enough, it just felt weird to commit two functions that were
> > > nearly the
> > > exact same, but I have no problem with doing this in two separate
> > > patches.
> > > 
> > > > >  
> > > > >  		free(expected_crc);
> > > > >  		free(crc);
> > > > > @@ -644,10 +618,10 @@ igt_main
> > > > >  							edid_
> > > > > i
> > > > > d,
> > > > > alt_edid_id);
> > > > >  
> > > > >  		connector_subtest("dp-crc-single",
> > > > > DisplayPort)
> > > > > -			test_display_crc_single(&data, port);
> > > > > +			test_display_crc(&data, port, 1);
> > > > >  
> > > > >  		connector_subtest("dp-crc-multiple",
> > > > > DisplayPort)
> > > > > -			test_display_crc_multiple(&data,
> > > > > port);
> > > > > +			test_display_crc(&data, port, 3);
> > > > >  	}
> > > > >  
> > > > >  	igt_subtest_group {
> > > > > @@ -698,10 +672,10 @@ igt_main
> > > > >  							edid_
> > > > > i
> > > > > d,
> > > > > alt_edid_id);
> > > > >  
> > > > >  		connector_subtest("hdmi-crc-single", HDMIA)
> > > > > -			test_display_crc_single(&data, port);
> > > > > +			test_display_crc(&data, port, 1);
> > > > >  
> > > > >  		connector_subtest("hdmi-crc-multiple", HDMIA)
> > > > > -			test_display_crc_multiple(&data,
> > > > > port);
> > > > > +			test_display_crc(&data, port, 3);
> > > > >  	}
> > > > >  
> > > > >  	igt_subtest_group {
-- 
Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo, Finland
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH i-g-t v3 4/4] chamelium: Dump obtained and reference frames to png on crc error
  2017-07-06 21:57         ` Lyude Paul
  2017-07-10 10:27           ` Paul Kocialkowski
@ 2017-07-10 10:31           ` Paul Kocialkowski
  2017-07-10 10:33             ` Martin Peres
  1 sibling, 1 reply; 57+ messages in thread
From: Paul Kocialkowski @ 2017-07-10 10:31 UTC (permalink / raw)
  To: Lyude Paul, intel-gfx

On Thu, 2017-07-06 at 17:57 -0400, Lyude Paul wrote:
> --snip--
> (also sorry this one took a while to get to, had to do a lot of
> thinking because I never really solved the problems mentioned here
> when
> I tried working on this...)
> 
> On Thu, 2017-07-06 at 16:33 +0300, Paul Kocialkowski wrote:
> > On Thu, 2017-07-06 at 14:31 +0300, Paul Kocialkowski wrote:
> > > > 
> > > > There's lots of potential here for copy pasta to form in the
> > > > future,
> > > > since the API here puts a lot of work on the caller to set
> > > > things
> > > > up
> > > > for frame dumping. IMO, it would be worth it to teach the CRC
> > > > checking
> > > > functions to automatically do frame dumps on mismatch if the CRC
> > > > source
> > > > supports it. This will save us from having to have separate
> > > > frame
> > > > dump
> > > > APIs in the future if we ever end up adding support for other
> > > > kinds
> > > > of
> > > > automated test equipment.
> > > 
> > > I don't think it makes so much sense to do this in the CRC
> > > checking
> > > functions,
> > > just because they are semantically expected to do one thing: CRC
> > > checking, and
> > > doing frame dumps seems like going overboard.
> > > 
> > > On the other hand, I do agree that the dumping and saving part can
> > > and
> > > should be
> > > made common, but maybe as a separate function. So that would be
> > > two
> > > calls for
> > > the tests: one to check the crc and one to dump and save the
> > > frame.
> > 
> > A strong case to support this vision: in VGA frame testing, we have
> > already dumped the frame and don't do CRC checking, yet we also need
> > to
> > save the frames if there is a mismatch.
> > 
> > It would be a shame that the dumping logic becomes part of the CRC
> > functions, since that would mean duplicating that logic for VGA
> > testing
> > (as it's currently done in the version I just sent out).
> 
> That is a good point, but there's some things I think you might want
> to
> consider. Mainly that in a test that passes, we of course don't write
> any framedumps back to the disk since nothing failed. IMO, I would
> -think- that we care a bit more about the performance hit that happens
> on passing tests vs. failing tests, since tests aren't really supposed
> to fail under ideal conditions anyway. Might be better to verify with
> the mupuf and the other people actually running Intel's CI though,
> since I'm not one of them.
> 
> As well, one advantage we do have here from the chamelium end is that
> you can only really be screen grabbing from one port at a time. So you
> could actually just track stuff internally in the igt_chamelium API
> and when a user tries to download a framedump that we've already
> downloaded, we can just hand them back a cached copy of it.

I forgot to answer this point. I think this bring way too much overhead
and is not really necessary anyway. With the solution I proposed in my
previous email on this thread, the two wrapper functions (one for CRC,
one for analogue frame comparison) will either dump the frame for CRC
comparison (because it was never dumped before) or use the provided one
for analogue comparison, so there is no particular need to track what
was or wasn't dumped before.

> > In spite of that, I think having a common function, called from the
> > test
> > itself is probably the best approach here.
> 
> Not sure if I misspoke here but I didn't mean to imply that I'm
> against
> having functions for doing frame dumping exposed to the callers. I had
> already figured there'd probably be situations where just having the
> CRC checking do the frame dumping wouldn't be enough.
> 
> This being said though, your viewpoint does make me realize it might
> not be a great idea to do autoframe dumping in -all- crc checking
> functions necessarily, but also makes me realize that this might even
> be a requirement if we still want to try keeping around
> igt_assert_crc_equal() and not just replace it outright with a
> function
> that doesn't fail the whole test (if we fail the test, there isn't
> really a way we can do a framedump from it afterwards). So I would
> think we can at least exclude igt_check_crc_equal() from doing
> automatic framedumping, but I still think it would be a good idea to
> implement igt_assert_crc_equal().
> 
> As for the what you're talking about, e.g. doing frame dump
> comparisons
> on VGA, I think the solution might be not to make any of the code for
> doing the actual frame comparisons chamelium specific either (except
> maybe for the part where we trim the framebuffer we get so it only
> contains the actual image dump).
> 
> So how about this: let's introduce a generic frame comparison API
> using
> the code you've already written for doing this on VGA with the
> chamelium. Make it part of the igt library, and have it just accept
> normal pixman images and perform fuzzy comparisons between them. In
> doing that, we can introduce a generic dump-frames-on-error API
> through
> there much more easily.
> 
> My big aim here is just to make it so that people using igt don't have
> to do anything to get frame dumping in their tests, it just "works".
> 
> > 
> > > I have also duplicated that logic in upcoming VGA frame testing,
> > > so
> > > there is definitely a need for less duplication.
> > > 
> > > > As well, I like how you removed the redundancy between
> > > > test_display_crc_single() and test_display_crc_multiple().
> > > > However
> > > > since those are somewhat unrelated changes to the code path for
> > > > these
> > > > tests it would be better to have that re-factoring as a separate
> > > > patch
> > > > so as to make it easier for anyone who might need to bisect this
> > > > code
> > > > in the future.
> > > 
> > > Fair enough, it just felt weird to commit two functions that were
> > > nearly the
> > > exact same, but I have no problem with doing this in two separate
> > > patches.
> > > 
> > > > >  
> > > > >  		free(expected_crc);
> > > > >  		free(crc);
> > > > > @@ -644,10 +618,10 @@ igt_main
> > > > >  							edid_
> > > > > i
> > > > > d,
> > > > > alt_edid_id);
> > > > >  
> > > > >  		connector_subtest("dp-crc-single",
> > > > > DisplayPort)
> > > > > -			test_display_crc_single(&data, port);
> > > > > +			test_display_crc(&data, port, 1);
> > > > >  
> > > > >  		connector_subtest("dp-crc-multiple",
> > > > > DisplayPort)
> > > > > -			test_display_crc_multiple(&data,
> > > > > port);
> > > > > +			test_display_crc(&data, port, 3);
> > > > >  	}
> > > > >  
> > > > >  	igt_subtest_group {
> > > > > @@ -698,10 +672,10 @@ igt_main
> > > > >  							edid_
> > > > > i
> > > > > d,
> > > > > alt_edid_id);
> > > > >  
> > > > >  		connector_subtest("hdmi-crc-single", HDMIA)
> > > > > -			test_display_crc_single(&data, port);
> > > > > +			test_display_crc(&data, port, 1);
> > > > >  
> > > > >  		connector_subtest("hdmi-crc-multiple", HDMIA)
> > > > > -			test_display_crc_multiple(&data,
> > > > > port);
> > > > > +			test_display_crc(&data, port, 3);
> > > > >  	}
> > > > >  
> > > > >  	igt_subtest_group {
-- 
Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo, Finland
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH i-g-t v3 4/4] chamelium: Dump obtained and reference frames to png on crc error
  2017-07-10 10:31           ` Paul Kocialkowski
@ 2017-07-10 10:33             ` Martin Peres
  2017-07-10 12:06               ` Paul Kocialkowski
  0 siblings, 1 reply; 57+ messages in thread
From: Martin Peres @ 2017-07-10 10:33 UTC (permalink / raw)
  To: Paul Kocialkowski, Lyude Paul, intel-gfx

On 10/07/17 13:31, Paul Kocialkowski wrote:
> On Thu, 2017-07-06 at 17:57 -0400, Lyude Paul wrote:
>>
>> As well, one advantage we do have here from the chamelium end is that
>> you can only really be screen grabbing from one port at a time. So you
>> could actually just track stuff internally in the igt_chamelium API
>> and when a user tries to download a framedump that we've already
>> downloaded, we can just hand them back a cached copy of it.
> 
> I forgot to answer this point. I think this bring way too much overhead
> and is not really necessary anyway. With the solution I proposed in my
> previous email on this thread, the two wrapper functions (one for CRC,
> one for analogue frame comparison) will either dump the frame for CRC
> comparison (because it was never dumped before) or use the provided one
> for analogue comparison, so there is no particular need to track what
> was or wasn't dumped before.

No need to track, just encode it in the filename:
$test-$subtest-error-crc-$crc.png

Just do not override existing files, and you are done :)
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH i-g-t v3 4/4] chamelium: Dump obtained and reference frames to png on crc error
  2017-07-10 10:33             ` Martin Peres
@ 2017-07-10 12:06               ` Paul Kocialkowski
  2017-07-10 13:56                 ` Martin Peres
  0 siblings, 1 reply; 57+ messages in thread
From: Paul Kocialkowski @ 2017-07-10 12:06 UTC (permalink / raw)
  To: Martin Peres, Lyude Paul, intel-gfx

On Mon, 2017-07-10 at 13:33 +0300, Martin Peres wrote:
> On 10/07/17 13:31, Paul Kocialkowski wrote:
> > On Thu, 2017-07-06 at 17:57 -0400, Lyude Paul wrote:
> > > 
> > > As well, one advantage we do have here from the chamelium end is
> > > that
> > > you can only really be screen grabbing from one port at a time. So
> > > you
> > > could actually just track stuff internally in the igt_chamelium
> > > API
> > > and when a user tries to download a framedump that we've already
> > > downloaded, we can just hand them back a cached copy of it.
> > 
> > I forgot to answer this point. I think this bring way too much
> > overhead
> > and is not really necessary anyway. With the solution I proposed in
> > my
> > previous email on this thread, the two wrapper functions (one for
> > CRC,
> > one for analogue frame comparison) will either dump the frame for
> > CRC
> > comparison (because it was never dumped before) or use the provided
> > one
> > for analogue comparison, so there is no particular need to track
> > what
> > was or wasn't dumped before.
> 
> No need to track, just encode it in the filename:
> $test-$subtest-error-crc-$crc.png
> 
> Just do not override existing files, and you are done :)

I suppose it would be best to have predictible filenames (so not
including the crc) to make it easier to grab the frame for an automated
testing framework, right?

So what about: frame-$test-$subtest-$qualifier.png, with $qualifier
being either "reference" or "dump". I don't think it's necessary to
indicate whether the error comes from crc or analogue frame testing:
this will already be contained in the subtest name.

-- 
Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo, Finland
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH i-g-t v3 4/4] chamelium: Dump obtained and reference frames to png on crc error
  2017-07-10 12:06               ` Paul Kocialkowski
@ 2017-07-10 13:56                 ` Martin Peres
  2017-07-10 14:11                   ` Paul Kocialkowski
  0 siblings, 1 reply; 57+ messages in thread
From: Martin Peres @ 2017-07-10 13:56 UTC (permalink / raw)
  To: Paul Kocialkowski, Lyude Paul, intel-gfx

On 10/07/17 15:06, Paul Kocialkowski wrote:
> On Mon, 2017-07-10 at 13:33 +0300, Martin Peres wrote:
>> On 10/07/17 13:31, Paul Kocialkowski wrote:
>>> On Thu, 2017-07-06 at 17:57 -0400, Lyude Paul wrote:
>>>>
>>>> As well, one advantage we do have here from the chamelium end is
>>>> that
>>>> you can only really be screen grabbing from one port at a time. So
>>>> you
>>>> could actually just track stuff internally in the igt_chamelium
>>>> API
>>>> and when a user tries to download a framedump that we've already
>>>> downloaded, we can just hand them back a cached copy of it.
>>>
>>> I forgot to answer this point. I think this bring way too much
>>> overhead
>>> and is not really necessary anyway. With the solution I proposed in
>>> my
>>> previous email on this thread, the two wrapper functions (one for
>>> CRC,
>>> one for analogue frame comparison) will either dump the frame for
>>> CRC
>>> comparison (because it was never dumped before) or use the provided
>>> one
>>> for analogue comparison, so there is no particular need to track
>>> what
>>> was or wasn't dumped before.
>>
>> No need to track, just encode it in the filename:
>> $test-$subtest-error-crc-$crc.png
>>
>> Just do not override existing files, and you are done :)
> 
> I suppose it would be best to have predictible filenames (so not
> including the crc) to make it easier to grab the frame for an automated
> testing framework, right? >
> So what about: frame-$test-$subtest-$qualifier.png, with $qualifier
> being either "reference" or "dump". I don't think it's necessary to
> indicate whether the error comes from crc or analogue frame testing:
> this will already be contained in the subtest name.
> 

Well, predictable is actually problematic, since automated systems try 
to reproduce issues, and your idea will lead to overriding (which is 
only not a problem if the CRC is the same).

In the end, what we want is to say in the logs what are the files 
(reference and dump). We'll need to agree on a format, so as an 
automated system can pick it up :)
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH i-g-t v3 4/4] chamelium: Dump obtained and reference frames to png on crc error
  2017-07-10 13:56                 ` Martin Peres
@ 2017-07-10 14:11                   ` Paul Kocialkowski
  2017-07-10 16:02                     ` Martin Peres
  0 siblings, 1 reply; 57+ messages in thread
From: Paul Kocialkowski @ 2017-07-10 14:11 UTC (permalink / raw)
  To: Martin Peres, Lyude Paul, intel-gfx

On Mon, 2017-07-10 at 16:56 +0300, Martin Peres wrote:
> On 10/07/17 15:06, Paul Kocialkowski wrote:
> > On Mon, 2017-07-10 at 13:33 +0300, Martin Peres wrote:
> > > On 10/07/17 13:31, Paul Kocialkowski wrote:
> > > > On Thu, 2017-07-06 at 17:57 -0400, Lyude Paul wrote:
> > > > > 
> > > > > As well, one advantage we do have here from the chamelium end
> > > > > is
> > > > > that
> > > > > you can only really be screen grabbing from one port at a
> > > > > time. So
> > > > > you
> > > > > could actually just track stuff internally in the
> > > > > igt_chamelium
> > > > > API
> > > > > and when a user tries to download a framedump that we've
> > > > > already
> > > > > downloaded, we can just hand them back a cached copy of it.
> > > > 
> > > > I forgot to answer this point. I think this bring way too much
> > > > overhead
> > > > and is not really necessary anyway. With the solution I proposed
> > > > in
> > > > my
> > > > previous email on this thread, the two wrapper functions (one
> > > > for
> > > > CRC,
> > > > one for analogue frame comparison) will either dump the frame
> > > > for
> > > > CRC
> > > > comparison (because it was never dumped before) or use the
> > > > provided
> > > > one
> > > > for analogue comparison, so there is no particular need to track
> > > > what
> > > > was or wasn't dumped before.
> > > 
> > > No need to track, just encode it in the filename:
> > > $test-$subtest-error-crc-$crc.png
> > > 
> > > Just do not override existing files, and you are done :)
> > 
> > I suppose it would be best to have predictible filenames (so not
> > including the crc) to make it easier to grab the frame for an
> > automated
> > testing framework, right? >
> > So what about: frame-$test-$subtest-$qualifier.png, with $qualifier
> > being either "reference" or "dump". I don't think it's necessary to
> > indicate whether the error comes from crc or analogue frame testing:
> > this will already be contained in the subtest name.
> > 
> 
> Well, predictable is actually problematic, since automated systems
> try 
> to reproduce issues, and your idea will lead to overriding (which is 
> only not a problem if the CRC is the same).

That is, unless the automated system moves the file around from the
predictable name to whatever suits it best (that may include which
run the result is part of).

> In the end, what we want is to say in the logs what are the files 
> (reference and dump). We'll need to agree on a format, so as an 
> automated system can pick it up :)

Parsing logs sound like a hackish way to do things quite honestly. Just
having a predictable name and moving the file wherever relevant seems a
lot easier on all sides.

Also, since we're making the code for frame dumping independent from
whether it comes from crc or full frame testing, it doesn't play out too
well to carry the crc result until the point of writing the png file.

-- 
Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo, Finland
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH i-g-t v3 4/4] chamelium: Dump obtained and reference frames to png on crc error
  2017-07-10 14:11                   ` Paul Kocialkowski
@ 2017-07-10 16:02                     ` Martin Peres
  0 siblings, 0 replies; 57+ messages in thread
From: Martin Peres @ 2017-07-10 16:02 UTC (permalink / raw)
  To: Paul Kocialkowski, Lyude Paul, intel-gfx

On 10/07/17 17:11, Paul Kocialkowski wrote:
> On Mon, 2017-07-10 at 16:56 +0300, Martin Peres wrote:
>> On 10/07/17 15:06, Paul Kocialkowski wrote:
>>> On Mon, 2017-07-10 at 13:33 +0300, Martin Peres wrote:
>>>> On 10/07/17 13:31, Paul Kocialkowski wrote:
>>>>> On Thu, 2017-07-06 at 17:57 -0400, Lyude Paul wrote:
>>>>>>
>>>>>> As well, one advantage we do have here from the chamelium end
>>>>>> is
>>>>>> that
>>>>>> you can only really be screen grabbing from one port at a
>>>>>> time. So
>>>>>> you
>>>>>> could actually just track stuff internally in the
>>>>>> igt_chamelium
>>>>>> API
>>>>>> and when a user tries to download a framedump that we've
>>>>>> already
>>>>>> downloaded, we can just hand them back a cached copy of it.
>>>>>
>>>>> I forgot to answer this point. I think this bring way too much
>>>>> overhead
>>>>> and is not really necessary anyway. With the solution I proposed
>>>>> in
>>>>> my
>>>>> previous email on this thread, the two wrapper functions (one
>>>>> for
>>>>> CRC,
>>>>> one for analogue frame comparison) will either dump the frame
>>>>> for
>>>>> CRC
>>>>> comparison (because it was never dumped before) or use the
>>>>> provided
>>>>> one
>>>>> for analogue comparison, so there is no particular need to track
>>>>> what
>>>>> was or wasn't dumped before.
>>>>
>>>> No need to track, just encode it in the filename:
>>>> $test-$subtest-error-crc-$crc.png
>>>>
>>>> Just do not override existing files, and you are done :)
>>>
>>> I suppose it would be best to have predictible filenames (so not
>>> including the crc) to make it easier to grab the frame for an
>>> automated
>>> testing framework, right? >
>>> So what about: frame-$test-$subtest-$qualifier.png, with $qualifier
>>> being either "reference" or "dump". I don't think it's necessary to
>>> indicate whether the error comes from crc or analogue frame testing:
>>> this will already be contained in the subtest name.
>>>
>>
>> Well, predictable is actually problematic, since automated systems
>> try
>> to reproduce issues, and your idea will lead to overriding (which is
>> only not a problem if the CRC is the same).
> 
> That is, unless the automated system moves the file around from the
> predictable name to whatever suits it best (that may include which
> run the result is part of).

In this case, I would like to see a way to add a prefix, so as we can 
avoid having another step to move files afterwards.

> 
>> In the end, what we want is to say in the logs what are the files
>> (reference and dump). We'll need to agree on a format, so as an
>> automated system can pick it up :)
> 
> Parsing logs sound like a hackish way to do things quite honestly. Just
> having a predictable name and moving the file wherever relevant seems a
> lot easier on all sides.
> 
> Also, since we're making the code for frame dumping independent from
> whether it comes from crc or full frame testing, it doesn't play out too
> well to carry the crc result until the point of writing the png file.
> 

I don't like the idea of not de-duplicating images. Let's say that we 
have 20 frames that fail, it takes 1 month to fix the issue and we have 
10 runs per day, that would amount to 9.3G of redundant data (for a 
frame being 1.5MB), instead of 30 MB.

So, maybe we could have a compromise. Images are stored in $CRC.png and 
new files $prefix-frame-$test-$subtest-$qualifier are generated, 
containing the path to the right file. This is how we solved this issue 
for image comparison in ezbench. This way, we only add 4K per image 
instead of 1.5 MB.
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH i-g-t v3 4/4] chamelium: Dump obtained and reference frames to png on crc error
  2017-07-10 10:27           ` Paul Kocialkowski
@ 2017-07-11 17:27             ` Lyude Paul
  0 siblings, 0 replies; 57+ messages in thread
From: Lyude Paul @ 2017-07-11 17:27 UTC (permalink / raw)
  To: Paul Kocialkowski, intel-gfx

On Mon, 2017-07-10 at 13:27 +0300, Paul Kocialkowski wrote:
> On Thu, 2017-07-06 at 17:57 -0400, Lyude Paul wrote:
> > --snip--
> > (also sorry this one took a while to get to, had to do a lot of
> > thinking because I never really solved the problems mentioned here
> > when
> > I tried working on this...)
> > 
> > On Thu, 2017-07-06 at 16:33 +0300, Paul Kocialkowski wrote:
> > > On Thu, 2017-07-06 at 14:31 +0300, Paul Kocialkowski wrote:
> > > > > 
> > > > > There's lots of potential here for copy pasta to form in the
> > > > > future,
> > > > > since the API here puts a lot of work on the caller to set
> > > > > things
> > > > > up
> > > > > for frame dumping. IMO, it would be worth it to teach the CRC
> > > > > checking
> > > > > functions to automatically do frame dumps on mismatch if the
> > > > > CRC
> > > > > source
> > > > > supports it. This will save us from having to have separate
> > > > > frame
> > > > > dump
> > > > > APIs in the future if we ever end up adding support for other
> > > > > kinds
> > > > > of
> > > > > automated test equipment.
> > > > 
> > > > I don't think it makes so much sense to do this in the CRC
> > > > checking
> > > > functions,
> > > > just because they are semantically expected to do one thing:
> > > > CRC
> > > > checking, and
> > > > doing frame dumps seems like going overboard.
> > > > 
> > > > On the other hand, I do agree that the dumping and saving part
> > > > can
> > > > and
> > > > should be
> > > > made common, but maybe as a separate function. So that would be
> > > > two
> > > > calls for
> > > > the tests: one to check the crc and one to dump and save the
> > > > frame.
> > > 
> > > A strong case to support this vision: in VGA frame testing, we
> > > have
> > > already dumped the frame and don't do CRC checking, yet we also
> > > need
> > > to
> > > save the frames if there is a mismatch.
> > > 
> > > It would be a shame that the dumping logic becomes part of the
> > > CRC
> > > functions, since that would mean duplicating that logic for VGA
> > > testing
> > > (as it's currently done in the version I just sent out).
> > 
> > That is a good point, but there's some things I think you might
> > want
> > to
> > consider. Mainly that in a test that passes, we of course don't
> > write
> > any framedumps back to the disk since nothing failed. IMO, I would
> > -think- that we care a bit more about the performance hit that
> > happens
> > on passing tests vs. failing tests, since tests aren't really
> > supposed
> > to fail under ideal conditions anyway. Might be better to verify
> > with
> > the mupuf and the other people actually running Intel's CI though,
> > since I'm not one of them.
> > 
> > As well, one advantage we do have here from the chamelium end is
> > that
> > you can only really be screen grabbing from one port at a time. So
> > you
> > could actually just track stuff internally in the igt_chamelium API
> > and
> > when a user tries to download a framedump that we've already
> > downloaded, we can just hand them back a cached copy of it.
> 
> Either way, it is definitely okay to take the time to dump the frame
> when a mismatch occurs if we don't have it already (in the CRC case).
> 
> > > 
> > > In spite of that, I think having a common function, called from
> > > the
> > > test
> > > itself is probably the best approach here.
> > 
> > Not sure if I misspoke here but I didn't mean to imply that I'm
> > against
> > having functions for doing frame dumping exposed to the callers. I
> > had
> > already figured there'd probably be situations where just having
> > the
> > CRC checking do the frame dumping wouldn't be enough.
> > 
> > This being said though, your viewpoint does make me realize it
> > might
> > not be a great idea to do autoframe dumping in -all- crc checking
> > functions necessarily, but also makes me realize that this might
> > even
> > be a requirement if we still want to try keeping around
> > igt_assert_crc_equal() and not just replace it outright with a
> > function
> > that doesn't fail the whole test (if we fail the test, there isn't
> > really a way we can do a framedump from it afterwards). So I would
> > think we can at least exclude igt_check_crc_equal() from doing
> > automatic framedumping, but I still think it would be a good idea
> > to
> > implement igt_assert_crc_equal().
> 
> igt_assert_crc_equal already exists and is used by many other tests,
> so
> we really cannot embed the frame dumping logic there, since these
> tests
> have nothing to do with the chamelium. That's another reason to
> really
> keep the frame dump and crc comparison logic separate.
> 
> > As for the what you're talking about, e.g. doing frame dump
> > comparisons
> > on VGA, I think the solution might be not to make any of the code
> > for
> > doing the actual frame comparisons chamelium specific either
> > (except
> > maybe for the part where we trim the framebuffer we get so it only
> > contains the actual image dump).
> > 
> > So how about this: let's introduce a generic frame comparison API
> > using
> > the code you've already written for doing this on VGA with the
> > chamelium. Make it part of the igt library, and have it just accept
> > normal pixman images and perform fuzzy comparisons between them. In
> > doing that, we can introduce a generic dump-frames-on-error API
> > through
> > there much more easily.
> > 
> > My big aim here is just to make it so that people using igt don't
> > have
> > to do anything to get frame dumping in their tests, it just
> > "works".
> 
> I totally agree with this direction.
> 
> What I suggest we should do is the following:
> * keep CRC functions (igt_assert_crc_equal and igt_check_crc_equal)
> common and fully independent from the frame dumping logic, either
> with a
> common crc mismatch detection logic or not (because it's so simple)
> * have common frame dump functions that just take a cairo surface and
> handle filenames and actually writing the frames
> * have the analogue frame detection code made common
> * have two assert-style chamnelium-specific wrappers to link frame
> comparison (either CRC or analogue) and frame dumping on failure
> while
> still ending with an assert; the CRC fashion would be in charge of
> dumping the frame on failure while the frame would be provided to the
> analogue comparison fashion.

Sounds good to me!
> 
> I will prepare patches in this direction so that you can get a more
> concrete idea and we can follow-up the discussion on that basis.
> 
> > > > I have also duplicated that logic in upcoming VGA frame
> > > > testing,
> > > > so
> > > > there is definitely a need for less duplication.
> > > > 
> > > > > As well, I like how you removed the redundancy between
> > > > > test_display_crc_single() and test_display_crc_multiple().
> > > > > However
> > > > > since those are somewhat unrelated changes to the code path
> > > > > for
> > > > > these
> > > > > tests it would be better to have that re-factoring as a
> > > > > separate
> > > > > patch
> > > > > so as to make it easier for anyone who might need to bisect
> > > > > this
> > > > > code
> > > > > in the future.
> > > > 
> > > > Fair enough, it just felt weird to commit two functions that
> > > > were
> > > > nearly the
> > > > exact same, but I have no problem with doing this in two
> > > > separate
> > > > patches.
> > > > 
> > > > > >  
> > > > > >  		free(expected_crc);
> > > > > >  		free(crc);
> > > > > > @@ -644,10 +618,10 @@ igt_main
> > > > > >  							ed
> > > > > > id_
> > > > > > i
> > > > > > d,
> > > > > > alt_edid_id);
> > > > > >  
> > > > > >  		connector_subtest("dp-crc-single",
> > > > > > DisplayPort)
> > > > > > -			test_display_crc_single(&data,
> > > > > > port);
> > > > > > +			test_display_crc(&data, port, 1);
> > > > > >  
> > > > > >  		connector_subtest("dp-crc-multiple",
> > > > > > DisplayPort)
> > > > > > -			test_display_crc_multiple(&data,
> > > > > > port);
> > > > > > +			test_display_crc(&data, port, 3);
> > > > > >  	}
> > > > > >  
> > > > > >  	igt_subtest_group {
> > > > > > @@ -698,10 +672,10 @@ igt_main
> > > > > >  							ed
> > > > > > id_
> > > > > > i
> > > > > > d,
> > > > > > alt_edid_id);
> > > > > >  
> > > > > >  		connector_subtest("hdmi-crc-single",
> > > > > > HDMIA)
> > > > > > -			test_display_crc_single(&data,
> > > > > > port);
> > > > > > +			test_display_crc(&data, port, 1);
> > > > > >  
> > > > > >  		connector_subtest("hdmi-crc-multiple",
> > > > > > HDMIA)
> > > > > > -			test_display_crc_multiple(&data,
> > > > > > port);
> > > > > > +			test_display_crc(&data, port, 3);
> > > > > >  	}
> > > > > >  
> > > > > >  	igt_subtest_group {
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCH i-g-t v4 0/7] CRC testing with Chamelium improvements
  2017-07-05  8:04 [PATCH i-g-t v3 1/4] chamelium: Calculate CRC from framebuffer instead of hardcoding it Paul Kocialkowski
                   ` (3 preceding siblings ...)
  2017-07-05 20:34 ` [PATCH i-g-t v3 1/4] chamelium: Calculate CRC from framebuffer instead of hardcoding it Lyude Paul
@ 2017-07-12 14:50 ` Paul Kocialkowski
  2017-07-12 14:50   ` [PATCH i-g-t v4 1/7] lib/igt_fb: Export the cairo surface instead of writing to a png Paul Kocialkowski
                     ` (8 more replies)
  2017-07-19 13:46 ` [PATCH i-g-t v5 " Paul Kocialkowski
  5 siblings, 9 replies; 57+ messages in thread
From: Paul Kocialkowski @ 2017-07-12 14:50 UTC (permalink / raw)
  To: intel-gfx; +Cc: Lyude

Changes since v3:
* Renamed structure used by async crc calculation for more clarity
* Used const qualifier for untouched buffer when hashing
* Split actual calculation to a dedicated function
* Reworked async functions names for more clarity
* Reworked descriptions for better accuracy
* Exported framebuffer cairo surface and use it directly instead of
  (unused) png dumping
* Fix how the framebuffer cairo surface is obtained to avoid destroying
  it too early

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCH i-g-t v4 1/7] lib/igt_fb: Export the cairo surface instead of writing to a png
  2017-07-12 14:50 ` [PATCH i-g-t v4 0/7] CRC testing with Chamelium improvements Paul Kocialkowski
@ 2017-07-12 14:50   ` Paul Kocialkowski
  2017-07-12 14:50   ` [PATCH i-g-t v4 2/7] chamelium: Calculate CRC from framebuffer instead of hardcoding it Paul Kocialkowski
                     ` (7 subsequent siblings)
  8 siblings, 0 replies; 57+ messages in thread
From: Paul Kocialkowski @ 2017-07-12 14:50 UTC (permalink / raw)
  To: intel-gfx; +Cc: Lyude

This removes the igt_write_fb_to_png function (that was unused thus far)
and exports the igt_get_cairo_surface function to grab the matching
cairo surface. Writing to a png is now handled by the common frame
handling code in lib/igt_frame.

This also fixes how the surface is retreived in chamelium code,
which avoids destroying it too early.

Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
---
 lib/igt_chamelium.c |  7 +------
 lib/igt_fb.c        | 36 +++++++++++++-----------------------
 lib/igt_fb.h        |  2 +-
 3 files changed, 15 insertions(+), 30 deletions(-)

diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
index bff08c0e..93392af7 100644
--- a/lib/igt_chamelium.c
+++ b/lib/igt_chamelium.c
@@ -936,17 +936,13 @@ void chamelium_assert_frame_eq(const struct chamelium *chamelium,
 			       const struct chamelium_frame_dump *dump,
 			       struct igt_fb *fb)
 {
-	cairo_t *cr;
 	cairo_surface_t *fb_surface;
 	pixman_image_t *reference_src, *reference_bgr;
 	int w = dump->width, h = dump->height;
 	bool eq;
 
 	/* Get the cairo surface for the framebuffer */
-	cr = igt_get_cairo_ctx(chamelium->drm_fd, fb);
-	fb_surface = cairo_get_target(cr);
-	cairo_surface_reference(fb_surface);
-	cairo_destroy(cr);
+	fb_surface = igt_get_cairo_surface(chamelium->drm_fd, fb);
 
 	/*
 	 * Convert the reference image into the same format as the chamelium
@@ -964,7 +960,6 @@ void chamelium_assert_frame_eq(const struct chamelium *chamelium,
 		    dump->size) == 0;
 
 	pixman_image_unref(reference_bgr);
-	cairo_surface_destroy(fb_surface);
 
 	igt_fail_on_f(!eq,
 		      "Chamelium frame dump didn't match reference image\n");
diff --git a/lib/igt_fb.c b/lib/igt_fb.c
index d2b7e9e3..93e21c17 100644
--- a/lib/igt_fb.c
+++ b/lib/igt_fb.c
@@ -1124,7 +1124,18 @@ static void create_cairo_surface__gtt(int fd, struct igt_fb *fb)
 				    fb, destroy_cairo_surface__gtt);
 }
 
-static cairo_surface_t *get_cairo_surface(int fd, struct igt_fb *fb)
+/**
+ * igt_get_cairo_surface:
+ * @fd: open drm file descriptor
+ * @fb: pointer to an #igt_fb structure
+ *
+ * This function stores the contents of the supplied framebuffer into a cairo
+ * surface and returns it.
+ *
+ * Returns:
+ * A pointer to a cairo surface with the contents of the framebuffer.
+ */
+cairo_surface_t *igt_get_cairo_surface(int fd, struct igt_fb *fb)
 {
 	if (fb->cairo_surface == NULL) {
 		if (fb->tiling == LOCAL_I915_FORMAT_MOD_Y_TILED ||
@@ -1160,7 +1171,7 @@ cairo_t *igt_get_cairo_ctx(int fd, struct igt_fb *fb)
 	cairo_surface_t *surface;
 	cairo_t *cr;
 
-	surface = get_cairo_surface(fd, fb);
+	surface = igt_get_cairo_surface(fd, fb);
 	cr = cairo_create(surface);
 	cairo_surface_destroy(surface);
 	igt_assert(cairo_status(cr) == CAIRO_STATUS_SUCCESS);
@@ -1173,27 +1184,6 @@ cairo_t *igt_get_cairo_ctx(int fd, struct igt_fb *fb)
 }
 
 /**
- * igt_write_fb_to_png:
- * @fd: open i915 drm file descriptor
- * @fb: pointer to an #igt_fb structure
- * @filename: target name for the png image
- *
- * This function stores the contents of the supplied framebuffer into a png
- * image stored at @filename.
- */
-void igt_write_fb_to_png(int fd, struct igt_fb *fb, const char *filename)
-{
-	cairo_surface_t *surface;
-	cairo_status_t status;
-
-	surface = get_cairo_surface(fd, fb);
-	status = cairo_surface_write_to_png(surface, filename);
-	cairo_surface_destroy(surface);
-
-	igt_assert(status == CAIRO_STATUS_SUCCESS);
-}
-
-/**
  * igt_remove_fb:
  * @fd: open i915 drm file descriptor
  * @fb: pointer to an #igt_fb structure
diff --git a/lib/igt_fb.h b/lib/igt_fb.h
index 4a680cef..f8a845cc 100644
--- a/lib/igt_fb.h
+++ b/lib/igt_fb.h
@@ -132,6 +132,7 @@ int igt_create_bo_with_dimensions(int fd, int width, int height, uint32_t format
 uint64_t igt_fb_mod_to_tiling(uint64_t modifier);
 
 /* cairo-based painting */
+cairo_surface_t *igt_get_cairo_surface(int fd, struct igt_fb *fb);
 cairo_t *igt_get_cairo_ctx(int fd, struct igt_fb *fb);
 void igt_paint_color(cairo_t *cr, int x, int y, int w, int h,
 			 double r, double g, double b);
@@ -145,7 +146,6 @@ void igt_paint_color_gradient_range(cairo_t *cr, int x, int y, int w, int h,
 void igt_paint_test_pattern(cairo_t *cr, int width, int height);
 void igt_paint_image(cairo_t *cr, const char *filename,
 			 int dst_x, int dst_y, int dst_width, int dst_height);
-void igt_write_fb_to_png(int fd, struct igt_fb *fb, const char *filename);
 int igt_cairo_printf_line(cairo_t *cr, enum igt_text_align align,
 			       double yspacing, const char *fmt, ...)
 			       __attribute__((format (printf, 4, 5)));
-- 
2.13.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH i-g-t v4 2/7] chamelium: Calculate CRC from framebuffer instead of hardcoding it
  2017-07-12 14:50 ` [PATCH i-g-t v4 0/7] CRC testing with Chamelium improvements Paul Kocialkowski
  2017-07-12 14:50   ` [PATCH i-g-t v4 1/7] lib/igt_fb: Export the cairo surface instead of writing to a png Paul Kocialkowski
@ 2017-07-12 14:50   ` Paul Kocialkowski
  2017-07-17 16:29     ` Lyude Paul
  2017-07-12 14:50   ` [PATCH i-g-t v4 3/7] lib/igt_debugfs: Introduce CRC check function, with logic made common Paul Kocialkowski
                     ` (6 subsequent siblings)
  8 siblings, 1 reply; 57+ messages in thread
From: Paul Kocialkowski @ 2017-07-12 14:50 UTC (permalink / raw)
  To: intel-gfx; +Cc: Lyude

This introduces CRC calculation for reference frames, instead of using
hardcoded values for them. The rendering of reference frames may differ
from machine to machine, especially due to font rendering, and the
frame itself may change with subsequent IGT changes.

These differences would cause the CRC checks to fail on different
setups. This allows them to pass regardless of the setup.

Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
---
 lib/igt_chamelium.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/igt_chamelium.h |   5 ++
 tests/chamelium.c   |  77 +++++++---------------------
 3 files changed, 167 insertions(+), 58 deletions(-)

diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
index 93392af7..baa6399c 100644
--- a/lib/igt_chamelium.c
+++ b/lib/igt_chamelium.c
@@ -94,6 +94,14 @@ struct chamelium_frame_dump {
 	struct chamelium_port *port;
 };
 
+struct chamelium_fb_crc_async_data {
+	int fd;
+	struct igt_fb *fb;
+
+	pthread_t thread_id;
+	igt_crc_t *ret;
+};
+
 struct chamelium {
 	xmlrpc_env env;
 	xmlrpc_client *client;
@@ -998,6 +1006,141 @@ int chamelium_get_frame_limit(struct chamelium *chamelium,
 	return ret;
 }
 
+static uint32_t chamelium_xrgb_hash16(const unsigned char *buffer, int width,
+				      int height, int k, int m)
+{
+	unsigned char r, g, b;
+	uint64_t sum = 0;
+	uint64_t count = 0;
+	uint64_t value;
+	uint32_t hash;
+	int index;
+	int i;
+
+	for (i=0; i < width * height; i++) {
+		if ((i % m) != k)
+			continue;
+
+		index = i * 4;
+
+		r = buffer[index + 2];
+		g = buffer[index + 1];
+		b = buffer[index + 0];
+
+		value = r | (g << 8) | (b << 16);
+		sum += ++count * value;
+	}
+
+	hash = ((sum >> 0) ^ (sum >> 16) ^ (sum >> 32) ^ (sum >> 48)) & 0xffff;
+
+	return hash;
+}
+
+static void chamelium_do_calculate_fb_crc(int fd, struct igt_fb *fb,
+					  igt_crc_t *out)
+{
+	unsigned char *buffer;
+	cairo_surface_t *fb_surface;
+	int n = 4;
+	int w, h;
+	int i, j;
+
+	/* Get the cairo surface for the framebuffer */
+	fb_surface = igt_get_cairo_surface(fd, fb);
+
+	buffer = cairo_image_surface_get_data(fb_surface);
+	w = fb->width;
+	h = fb->height;
+
+	for (i = 0; i < n; i++) {
+		j = n - i - 1;
+		out->crc[i] = chamelium_xrgb_hash16(buffer, w, h, j, n);
+	}
+
+	out->n_words = n;
+}
+
+/**
+ * chamelium_calculate_fb_crc:
+ * @fd: The drm file descriptor
+ * @fb: The framebuffer to calculate the CRC for
+ *
+ * Calculates the CRC for the provided framebuffer, using the Chamelium's CRC
+ * algorithm. This calculates the CRC in a synchronous fashion.
+ *
+ * Returns: The calculated CRC
+ */
+igt_crc_t *chamelium_calculate_fb_crc(int fd, struct igt_fb *fb)
+{
+	igt_crc_t *ret = calloc(1, sizeof(igt_crc_t));
+
+	chamelium_do_calculate_fb_crc(fd, fb, ret);
+
+	return ret;
+}
+
+static void *chamelium_calculate_fb_crc_async_work(void *data)
+{
+	struct chamelium_fb_crc_async_data *fb_crc;
+
+	fb_crc = (struct chamelium_fb_crc_async_data *) data;
+
+	chamelium_do_calculate_fb_crc(fb_crc->fd, fb_crc->fb, fb_crc->ret);
+
+	return NULL;
+}
+
+/**
+ * chamelium_calculate_fb_crc_launch:
+ * @fd: The drm file descriptor
+ * @fb: The framebuffer to calculate the CRC for
+ *
+ * Launches the CRC calculation for the provided framebuffer, using the
+ * Chamelium's CRC algorithm. This calculates the CRC in an asynchronous
+ * fashion.
+ *
+ * The returned structure should be passed to a subsequent call to
+ * chamelium_calculate_fb_crc_result. It should not be freed.
+ *
+ * Returns: An intermediate structure for the CRC calculation work.
+ */
+struct chamelium_fb_crc_async_data *chamelium_calculate_fb_crc_async_start(int fd,
+									   struct igt_fb *fb)
+{
+	struct chamelium_fb_crc_async_data *fb_crc;
+
+	fb_crc = calloc(1, sizeof(struct chamelium_fb_crc_async_data));
+	fb_crc->ret = calloc(1, sizeof(igt_crc_t));
+	fb_crc->fd = fd;
+	fb_crc->fb = fb;
+
+	pthread_create(&fb_crc->thread_id, NULL,
+		       chamelium_calculate_fb_crc_async_work, fb_crc);
+
+	return fb_crc;
+}
+
+/**
+ * chamelium_calculate_fb_crc_result:
+ * @fb_crc: An intermediate structure with thread-related information
+ *
+ * Blocks until the asynchronous CRC calculation is finished, and then returns
+ * its result.
+ *
+ * Returns: The calculated CRC
+ */
+igt_crc_t *chamelium_calculate_fb_crc_async_finish(struct chamelium_fb_crc_async_data *fb_crc)
+{
+	igt_crc_t *ret;
+
+	pthread_join(fb_crc->thread_id, NULL);
+
+	ret = fb_crc->ret;
+	free(fb_crc);
+
+	return ret;
+}
+
 static unsigned int chamelium_get_port_type(struct chamelium *chamelium,
 					    struct chamelium_port *port)
 {
diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
index 81322ad2..2bfbfdc7 100644
--- a/lib/igt_chamelium.h
+++ b/lib/igt_chamelium.h
@@ -36,6 +36,7 @@
 struct chamelium;
 struct chamelium_port;
 struct chamelium_frame_dump;
+struct chamelium_fb_crc_async_data;
 
 struct chamelium *chamelium_init(int drm_fd);
 void chamelium_deinit(struct chamelium *chamelium);
@@ -92,6 +93,10 @@ struct chamelium_frame_dump *chamelium_port_dump_pixels(struct chamelium *chamel
 							struct chamelium_port *port,
 							int x, int y,
 							int w, int h);
+igt_crc_t *chamelium_calculate_fb_crc(int fd, struct igt_fb *fb);
+struct chamelium_fb_crc_async_data *chamelium_calculate_fb_crc_async_start(int fd,
+									   struct igt_fb *fb);
+igt_crc_t *chamelium_calculate_fb_crc_async_finish(struct chamelium_fb_crc_async_data *fb_crc);
 int chamelium_get_captured_frame_count(struct chamelium *chamelium);
 int chamelium_get_frame_limit(struct chamelium *chamelium,
 			      struct chamelium_port *port,
diff --git a/tests/chamelium.c b/tests/chamelium.c
index e26f0557..da98de47 100644
--- a/tests/chamelium.c
+++ b/tests/chamelium.c
@@ -49,43 +49,6 @@ typedef struct {
 #define HPD_TOGGLE_COUNT_VGA 5
 #define HPD_TOGGLE_COUNT_DP_HDMI 15
 
-/* Pre-calculated CRCs for the pattern fb, for all the modes in the default
- * chamelium edid
- */
-struct crc_entry {
-	int width;
-	int height;
-	igt_crc_t crc;
-};
-
-#define CRC_ENTRY(w_, h_, ...) \
-	{ w_, h_, { .n_words = 4, .crc = { __VA_ARGS__ } } }
-
-static const struct crc_entry pattern_fb_crcs[] = {
-	CRC_ENTRY(1920, 1080, 0xf859, 0xa751, 0x8c81, 0x45a1),
-	CRC_ENTRY(1280,  720, 0xcec2, 0x4246, 0x6cfd, 0xeb43),
-	CRC_ENTRY(1024,  768, 0x85e5, 0xf0cd, 0xafe3, 0x7f18),
-	CRC_ENTRY( 800,  600, 0x6b39, 0x32b6, 0x831a, 0xb03e),
-	CRC_ENTRY( 640,  480, 0xa121, 0x2473, 0xb150, 0x8c47),
-};
-#undef CRC_ENTRY
-
-static const igt_crc_t *
-get_precalculated_crc(struct chamelium_port *port, int w, int h)
-{
-	int i;
-	const struct crc_entry *entry;
-
-	for (i = 0; i < ARRAY_SIZE(pattern_fb_crcs); i++) {
-		entry = &pattern_fb_crcs[i];
-
-		if (entry->width == w && entry->height == h)
-			return &entry->crc;
-	}
-
-	return NULL;
-}
-
 static void
 require_connector_present(data_t *data, unsigned int type)
 {
@@ -422,7 +385,8 @@ test_display_crc_single(data_t *data, struct chamelium_port *port)
 	igt_output_t *output;
 	igt_plane_t *primary;
 	igt_crc_t *crc;
-	const igt_crc_t *expected_crc;
+	igt_crc_t *expected_crc;
+	struct chamelium_fb_crc_async_data *fb_crc;
 	struct igt_fb fb;
 	drmModeModeInfo *mode;
 	drmModeConnector *connector;
@@ -445,24 +409,21 @@ test_display_crc_single(data_t *data, struct chamelium_port *port)
 						    0, 0, 0, &fb);
 		igt_assert(fb_id > 0);
 
+		fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd,
+								&fb);
 		enable_output(data, port, output, mode, &fb);
 
-		expected_crc = get_precalculated_crc(port,
-						     mode->hdisplay,
-						     mode->vdisplay);
-		if (!expected_crc) {
-			igt_warn("No precalculated CRC found for %dx%d, skipping CRC check\n",
-				 mode->hdisplay, mode->vdisplay);
-			goto next;
-		}
-
 		igt_debug("Testing single CRC fetch\n");
+
 		crc = chamelium_get_crc_for_area(data->chamelium, port,
 						 0, 0, 0, 0);
+
+		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
+
 		igt_assert_crc_equal(crc, expected_crc);
+		free(expected_crc);
 		free(crc);
 
-next:
 		disable_output(data, port, output);
 		igt_remove_fb(data->drm_fd, &fb);
 	}
@@ -478,7 +439,8 @@ test_display_crc_multiple(data_t *data, struct chamelium_port *port)
 	igt_output_t *output;
 	igt_plane_t *primary;
 	igt_crc_t *crc;
-	const igt_crc_t *expected_crc;
+	igt_crc_t *expected_crc;
+	struct chamelium_fb_crc_async_data *fb_crc;
 	struct igt_fb fb;
 	drmModeModeInfo *mode;
 	drmModeConnector *connector;
@@ -501,15 +463,10 @@ test_display_crc_multiple(data_t *data, struct chamelium_port *port)
 						    0, 0, 0, &fb);
 		igt_assert(fb_id > 0);
 
-		enable_output(data, port, output, mode, &fb);
+		fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd,
+								&fb);
 
-		expected_crc = get_precalculated_crc(port, mode->hdisplay,
-						     mode->vdisplay);
-		if (!expected_crc) {
-			igt_warn("No precalculated CRC found for %dx%d, skipping CRC check\n",
-				 mode->hdisplay, mode->vdisplay);
-			goto next;
-		}
+		enable_output(data, port, output, mode, &fb);
 
 		/* We want to keep the display running for a little bit, since
 		 * there's always the potential the driver isn't able to keep
@@ -520,11 +477,15 @@ test_display_crc_multiple(data_t *data, struct chamelium_port *port)
 						   &captured_frame_count);
 
 		igt_debug("Captured %d frames\n", captured_frame_count);
+
+		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
+
 		for (j = 0; j < captured_frame_count; j++)
 			igt_assert_crc_equal(&crc[j], expected_crc);
+
+		free(expected_crc);
 		free(crc);
 
-next:
 		disable_output(data, port, output);
 		igt_remove_fb(data->drm_fd, &fb);
 	}
-- 
2.13.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH i-g-t v4 3/7] lib/igt_debugfs: Introduce CRC check function, with logic made common
  2017-07-12 14:50 ` [PATCH i-g-t v4 0/7] CRC testing with Chamelium improvements Paul Kocialkowski
  2017-07-12 14:50   ` [PATCH i-g-t v4 1/7] lib/igt_fb: Export the cairo surface instead of writing to a png Paul Kocialkowski
  2017-07-12 14:50   ` [PATCH i-g-t v4 2/7] chamelium: Calculate CRC from framebuffer instead of hardcoding it Paul Kocialkowski
@ 2017-07-12 14:50   ` Paul Kocialkowski
  2017-07-12 14:50   ` [PATCH i-g-t v4 4/7] Introduce common frame dumping configuration and helpers Paul Kocialkowski
                     ` (5 subsequent siblings)
  8 siblings, 0 replies; 57+ messages in thread
From: Paul Kocialkowski @ 2017-07-12 14:50 UTC (permalink / raw)
  To: intel-gfx; +Cc: Lyude

This introduces an igt_check_crc_equal function in addition to
igt_assert_crc_equal and makes the CRC comparison logic from the latter
common. In particular, an igt_find_crc_mismatch function indicates
whether there is a mistmatch and at what index, so that the calling
functions can print the diverging values.

Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
---
 lib/igt_debugfs.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++---
 lib/igt_debugfs.h |  1 +
 2 files changed, 51 insertions(+), 3 deletions(-)

diff --git a/lib/igt_debugfs.c b/lib/igt_debugfs.c
index 80f25c61..78c22e67 100644
--- a/lib/igt_debugfs.c
+++ b/lib/igt_debugfs.c
@@ -281,6 +281,26 @@ bool igt_debugfs_search(int device, const char *filename, const char *substring)
  * Pipe CRC
  */
 
+static bool igt_find_crc_mismatch(const igt_crc_t *a, const igt_crc_t *b,
+				  int *index)
+{
+	int i;
+
+	if (a->n_words != b->n_words)
+		return true;
+
+	for (i = 0; i < a->n_words; i++) {
+		if (a->crc[i] != b->crc[i]) {
+			if (index)
+				*index = i;
+
+			return true;
+		}
+	}
+
+	return false;
+}
+
 /**
  * igt_assert_crc_equal:
  * @a: first pipe CRC value
@@ -294,10 +314,37 @@ bool igt_debugfs_search(int device, const char *filename, const char *substring)
  */
 void igt_assert_crc_equal(const igt_crc_t *a, const igt_crc_t *b)
 {
-	int i;
+	int index;
+	bool mismatch;
+
+	mismatch = igt_find_crc_mismatch(a, b, &index);
+	if (mismatch)
+		igt_debug("CRC mismatch at index %d: 0x%x != 0x%x\n", index,
+			  a->crc[index], b->crc[index]);
+
+	igt_assert(!mismatch);
+}
+
+/**
+ * igt_check_crc_equal:
+ * @a: first pipe CRC value
+ * @b: second pipe CRC value
+ *
+ * Compares two CRC values and return whether they match.
+ *
+ * Returns: A boolean indicating whether the CRC values match
+ */
+bool igt_check_crc_equal(const igt_crc_t *a, const igt_crc_t *b)
+{
+	int index;
+	bool mismatch;
+
+	mismatch = igt_find_crc_mismatch(a, b, &index);
+	if (mismatch)
+		igt_debug("CRC mismatch at index %d: 0x%x != 0x%x\n", index,
+			  a->crc[index], b->crc[index]);
 
-	for (i = 0; i < a->n_words; i++)
-		igt_assert_eq_u32(a->crc[i], b->crc[i]);
+	return !mismatch;
 }
 
 /**
diff --git a/lib/igt_debugfs.h b/lib/igt_debugfs.h
index 7b846a83..fe355919 100644
--- a/lib/igt_debugfs.h
+++ b/lib/igt_debugfs.h
@@ -114,6 +114,7 @@ enum intel_pipe_crc_source {
 };
 
 void igt_assert_crc_equal(const igt_crc_t *a, const igt_crc_t *b);
+bool igt_check_crc_equal(const igt_crc_t *a, const igt_crc_t *b);
 char *igt_crc_to_string(igt_crc_t *crc);
 
 void igt_require_pipe_crc(int fd);
-- 
2.13.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH i-g-t v4 4/7] Introduce common frame dumping configuration and helpers
  2017-07-12 14:50 ` [PATCH i-g-t v4 0/7] CRC testing with Chamelium improvements Paul Kocialkowski
                     ` (2 preceding siblings ...)
  2017-07-12 14:50   ` [PATCH i-g-t v4 3/7] lib/igt_debugfs: Introduce CRC check function, with logic made common Paul Kocialkowski
@ 2017-07-12 14:50   ` Paul Kocialkowski
  2017-07-12 14:50   ` [PATCH i-g-t v4 5/7] lib/igt_debugfs: Add extended helper to format crc to string Paul Kocialkowski
                     ` (4 subsequent siblings)
  8 siblings, 0 replies; 57+ messages in thread
From: Paul Kocialkowski @ 2017-07-12 14:50 UTC (permalink / raw)
  To: intel-gfx; +Cc: Lyude

This introduces a common FrameDumpPath configuration field, as well as
helper functions in dedicated igt_frame for writing cairo surfaces
to png files.

Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
---
 lib/Makefile.sources |   2 +
 lib/igt.h            |   1 +
 lib/igt_core.c       |  12 +++++
 lib/igt_core.h       |   2 +-
 lib/igt_frame.c      | 137 +++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/igt_frame.h      |  43 ++++++++++++++++
 6 files changed, 196 insertions(+), 1 deletion(-)
 create mode 100644 lib/igt_frame.c
 create mode 100644 lib/igt_frame.h

diff --git a/lib/Makefile.sources b/lib/Makefile.sources
index 53fdb54c..c2e58809 100644
--- a/lib/Makefile.sources
+++ b/lib/Makefile.sources
@@ -83,6 +83,8 @@ lib_source_list =	 	\
 	uwildmat/uwildmat.c	\
 	igt_kmod.c		\
 	igt_kmod.h		\
+	igt_frame.c		\
+	igt_frame.h		\
 	$(NULL)
 
 .PHONY: version.h.tmp
diff --git a/lib/igt.h b/lib/igt.h
index a069deb3..d16a4991 100644
--- a/lib/igt.h
+++ b/lib/igt.h
@@ -34,6 +34,7 @@
 #include "igt_draw.h"
 #include "igt_dummyload.h"
 #include "igt_fb.h"
+#include "igt_frame.h"
 #include "igt_gt.h"
 #include "igt_kms.h"
 #include "igt_pm.h"
diff --git a/lib/igt_core.c b/lib/igt_core.c
index 1ba79361..5a3b00e8 100644
--- a/lib/igt_core.c
+++ b/lib/igt_core.c
@@ -235,6 +235,10 @@
  * An example configuration follows:
  *
  * |[<!-- language="plain" -->
+ *	# The common configuration secton follows.
+ *	[Common]
+ *	FrameDumpPath=/tmp # The path to dump frames that fail comparison checks
+ *
  *	# The following section is used for configuring the Device Under Test.
  *	# It is not mandatory and allows overriding default values.
  *	[DUT]
@@ -290,6 +294,7 @@ static struct {
 static pthread_mutex_t log_buffer_mutex = PTHREAD_MUTEX_INITIALIZER;
 
 GKeyFile *igt_key_file;
+char *frame_dump_path;
 
 const char *igt_test_name(void)
 {
@@ -621,6 +626,13 @@ static int config_parse(void)
 	if (!igt_key_file)
 		return 0;
 
+	frame_dump_path = getenv("IGT_FRAME_DUMP_PATH");
+
+	if (!frame_dump_path)
+		frame_dump_path = g_key_file_get_string(igt_key_file, "Common",
+							"FrameDumpPath",
+							&error);
+
 	rc = g_key_file_get_integer(igt_key_file, "DUT", "SuspendResumeDelay",
 				    &error);
 	if (error && error->code == G_KEY_FILE_ERROR_INVALID_VALUE)
diff --git a/lib/igt_core.h b/lib/igt_core.h
index 0739ca83..1619a9d6 100644
--- a/lib/igt_core.h
+++ b/lib/igt_core.h
@@ -50,7 +50,7 @@
 extern const char* __igt_test_description __attribute__((weak));
 extern bool __igt_plain_output;
 extern GKeyFile *igt_key_file;
-
+extern char *frame_dump_path;
 
 /**
  * IGT_TEST_DESCRIPTION:
diff --git a/lib/igt_frame.c b/lib/igt_frame.c
new file mode 100644
index 00000000..dfafe53d
--- /dev/null
+++ b/lib/igt_frame.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright © 2017 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.
+ *
+ * Authors:
+ *  Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
+ */
+
+#include "config.h"
+
+#include <fcntl.h>
+#include <pixman.h>
+#include <cairo.h>
+
+#include "igt.h"
+
+/**
+ * SECTION:igt_frame
+ * @short_description: Library for frame-related tests
+ * @title: Frame
+ * @include: igt_frame.h
+ *
+ * This library contains helpers for frame-related tests. This includes common
+ * frame dumping as well as frame comparison helpers.
+ */
+
+/**
+ * igt_frame_dump_is_enabled:
+ *
+ * Get whether frame dumping is enabled.
+ *
+ * Returns: A boolean indicating whether frame dumping is enabled
+ */
+bool igt_frame_dump_is_enabled(void)
+{
+	return frame_dump_path != NULL;
+}
+
+static void igt_write_frame_to_png(cairo_surface_t *surface, int fd,
+				   const char *qualifier, const char *suffix)
+{
+	char path[PATH_MAX];
+	const char *test_name;
+	const char *subtest_name;
+	cairo_status_t status;
+	int index;
+
+	test_name = igt_test_name();
+	subtest_name = igt_subtest_name();
+
+	if (suffix)
+		snprintf(path, PATH_MAX, "%s/frame-%s-%s-%s-%s.png",
+			 frame_dump_path, test_name, subtest_name, qualifier,
+			 suffix);
+	else
+		snprintf(path, PATH_MAX, "%s/frame-%s-%s-%s.png",
+			 frame_dump_path, test_name, subtest_name, qualifier);
+
+	igt_debug("Dumping %s frame to %s...\n", qualifier, path);
+
+	status = cairo_surface_write_to_png(surface, path);
+
+	igt_assert_eq(status, CAIRO_STATUS_SUCCESS);
+
+	index = strlen(path);
+
+	if (fd >= 0 && index < (PATH_MAX - 1)) {
+		path[index++] = '\n';
+		path[index] = '\0';
+
+		write(fd, path, strlen(path));
+	}
+}
+
+/**
+ * igt_write_compared_frames_to_png:
+ * @reference: The reference cairo surface
+ * @capture: The captured cairo surface
+ * @reference_suffix: The suffix to give to the reference png file
+ * @capture_suffix: The suffix to give to the capture png file
+ *
+ * Write previously compared frames to png files.
+ */
+void igt_write_compared_frames_to_png(cairo_surface_t *reference,
+				      cairo_surface_t *capture,
+				      const char *reference_suffix,
+				      const char *capture_suffix)
+{
+	char *id;
+	const char *test_name;
+	const char *subtest_name;
+	char path[PATH_MAX];
+	int fd = -1;
+
+	if (!igt_frame_dump_is_enabled())
+		return;
+
+	id = getenv("IGT_FRAME_DUMP_ID");
+
+	test_name = igt_test_name();
+	subtest_name = igt_subtest_name();
+
+	if (id)
+		snprintf(path, PATH_MAX, "%s/frame-%s-%s-%s.txt",
+			 frame_dump_path, test_name, subtest_name, id);
+	else
+		snprintf(path, PATH_MAX, "%s/frame-%s-%s.txt",
+			 frame_dump_path, test_name, subtest_name);
+
+	fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+	igt_assert(fd >= 0);
+
+	igt_debug("Writing dump report to %s...\n", path);
+
+	igt_write_frame_to_png(reference, fd, "reference", reference_suffix);
+	igt_write_frame_to_png(capture, fd, "capture", capture_suffix);
+
+	close(fd);
+}
diff --git a/lib/igt_frame.h b/lib/igt_frame.h
new file mode 100644
index 00000000..ec6a1643
--- /dev/null
+++ b/lib/igt_frame.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright © 2017 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.
+ *
+ * Authors:
+ *  Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
+ */
+
+#ifndef IGT_FRAME_H
+#define IGT_FRAME_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "igt.h"
+#include <stdbool.h>
+
+bool igt_frame_dump_is_enabled(void);
+void igt_write_compared_frames_to_png(cairo_surface_t *reference,
+				      cairo_surface_t *capture,
+				      const char *reference_suffix,
+				      const char *capture_suffix);
+
+#endif
-- 
2.13.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH i-g-t v4 5/7] lib/igt_debugfs: Add extended helper to format crc to string
  2017-07-12 14:50 ` [PATCH i-g-t v4 0/7] CRC testing with Chamelium improvements Paul Kocialkowski
                     ` (3 preceding siblings ...)
  2017-07-12 14:50   ` [PATCH i-g-t v4 4/7] Introduce common frame dumping configuration and helpers Paul Kocialkowski
@ 2017-07-12 14:50   ` Paul Kocialkowski
  2017-07-12 14:50   ` [PATCH i-g-t v4 6/7] chamelium: Dump captured and reference frames to png on crc error Paul Kocialkowski
                     ` (3 subsequent siblings)
  8 siblings, 0 replies; 57+ messages in thread
From: Paul Kocialkowski @ 2017-07-12 14:50 UTC (permalink / raw)
  To: intel-gfx; +Cc: Lyude

This introduces a igt_crc_to_string_extended helper that allows
formatting a crc to a string with a given delimiter and size to print
per crc word.

Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
---
 lib/igt_debugfs.c | 28 ++++++++++++++++++++++++----
 lib/igt_debugfs.h |  1 +
 2 files changed, 25 insertions(+), 4 deletions(-)

diff --git a/lib/igt_debugfs.c b/lib/igt_debugfs.c
index 78c22e67..005f99b1 100644
--- a/lib/igt_debugfs.c
+++ b/lib/igt_debugfs.c
@@ -348,26 +348,46 @@ bool igt_check_crc_equal(const igt_crc_t *a, const igt_crc_t *b)
 }
 
 /**
- * igt_crc_to_string:
+ * igt_crc_to_string_extended:
  * @crc: pipe CRC value to print
+ * @delimiter: The delimiter to use between crc words
+ * @crc_size: the number of bytes to print per crc word (either 4 or 2)
  *
- * This formats @crc into a string buffer which is owned by igt_crc_to_string().
+ * This formats @crc into a string buffer, depending on @delimiter and @crc_size
+ * which is owned by igt_crc_to_string_extended().
  * The next call will override the buffer again, which makes this multithreading
  * unsafe.
  *
  * This should only ever be used for diagnostic debug output.
  */
-char *igt_crc_to_string(igt_crc_t *crc)
+char *igt_crc_to_string_extended(igt_crc_t *crc, char delimiter, int crc_size)
 {
 	int i;
 	char buf[128] = { 0 };
+	const char *format[2] = { "%08x%c", "%04x%c" };
 
 	for (i = 0; i < crc->n_words; i++)
-		sprintf(buf + strlen(buf), "%08x ", crc->crc[i]);
+		sprintf(buf + strlen(buf), format[crc_size == 2], crc->crc[i],
+			i == (crc->n_words - 1) ? '\0' : delimiter);
 
 	return strdup(buf);
 }
 
+/**
+ * igt_crc_to_string:
+ * @crc: pipe CRC value to print
+ *
+ * This formats @crc into a string buffer which is owned by igt_crc_to_string().
+ * The next call will override the buffer again, which makes this multithreading
+ * unsafe.
+ *
+ * This should only ever be used for diagnostic debug output.
+ */
+char *igt_crc_to_string(igt_crc_t *crc)
+{
+	return igt_crc_to_string_extended(crc, ' ', 4);
+}
+
 #define MAX_CRC_ENTRIES 10
 #define MAX_LINE_LEN (10 + 11 * MAX_CRC_ENTRIES + 1)
 
diff --git a/lib/igt_debugfs.h b/lib/igt_debugfs.h
index fe355919..f1a76406 100644
--- a/lib/igt_debugfs.h
+++ b/lib/igt_debugfs.h
@@ -115,6 +115,7 @@ enum intel_pipe_crc_source {
 
 void igt_assert_crc_equal(const igt_crc_t *a, const igt_crc_t *b);
 bool igt_check_crc_equal(const igt_crc_t *a, const igt_crc_t *b);
+char *igt_crc_to_string_extended(igt_crc_t *crc, char delimiter, int crc_size);
 char *igt_crc_to_string(igt_crc_t *crc);
 
 void igt_require_pipe_crc(int fd);
-- 
2.13.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH i-g-t v4 6/7] chamelium: Dump captured and reference frames to png on crc error
  2017-07-12 14:50 ` [PATCH i-g-t v4 0/7] CRC testing with Chamelium improvements Paul Kocialkowski
                     ` (4 preceding siblings ...)
  2017-07-12 14:50   ` [PATCH i-g-t v4 5/7] lib/igt_debugfs: Add extended helper to format crc to string Paul Kocialkowski
@ 2017-07-12 14:50   ` Paul Kocialkowski
  2017-07-12 14:50   ` [PATCH i-g-t v4 7/7] tests/chamelium: Merge the crc testing functions into one Paul Kocialkowski
                     ` (2 subsequent siblings)
  8 siblings, 0 replies; 57+ messages in thread
From: Paul Kocialkowski @ 2017-07-12 14:50 UTC (permalink / raw)
  To: intel-gfx; +Cc: Lyude

This adds support for dumping both the frame capture from the chamelium
and the reference frame generated by cairo when the captured crc does
not match the crc calculated from the reference, using common helpers.

Getting a dump of the frames is quite useful in order to compare them.

Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
---
 lib/igt_chamelium.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/igt_chamelium.h |  4 +++
 tests/chamelium.c   | 14 ++++++---
 3 files changed, 95 insertions(+), 4 deletions(-)

diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
index baa6399c..df49936b 100644
--- a/lib/igt_chamelium.c
+++ b/lib/igt_chamelium.c
@@ -930,6 +930,32 @@ static pixman_image_t *convert_frame_format(pixman_image_t *src,
 	return converted;
 }
 
+static cairo_surface_t *convert_frame_dump_argb32(const struct chamelium_frame_dump *dump)
+{
+	cairo_surface_t *dump_surface;
+	pixman_image_t *image_bgr;
+	pixman_image_t *image_argb;
+	int w = dump->width, h = dump->height;
+	uint32_t *bits_bgr = (uint32_t *) dump->bgr;
+	unsigned char *bits_argb;
+
+	image_bgr = pixman_image_create_bits(
+	    PIXMAN_b8g8r8, w, h, bits_bgr,
+	    PIXMAN_FORMAT_BPP(PIXMAN_b8g8r8) / 8 * w);
+	image_argb = convert_frame_format(image_bgr, PIXMAN_x8r8g8b8);
+	pixman_image_unref(image_bgr);
+
+	bits_argb = (unsigned char *) pixman_image_get_data(image_argb);
+
+	dump_surface = cairo_image_surface_create_for_data(
+	    bits_argb, CAIRO_FORMAT_ARGB32, w, h,
+	    PIXMAN_FORMAT_BPP(PIXMAN_x8r8g8b8) / 8 * w);
+
+	pixman_image_unref(image_argb);
+
+	return dump_surface;
+}
+
 /**
  * chamelium_assert_frame_eq:
  * @chamelium: The chamelium instance the frame dump belongs to
@@ -974,6 +1000,61 @@ void chamelium_assert_frame_eq(const struct chamelium *chamelium,
 }
 
 /**
+ * chamelium_assert_crc_eq_or_dump:
+ * @chamelium: The chamelium instance the frame dump belongs to
+ * @reference_crc: The CRC for the reference frame
+ * @capture_crc: The CRC for the captured frame
+ * @fb: pointer to an #igt_fb structure
+ *
+ * Asserts that the CRC provided for both the reference and the captured frame
+ * are identical. If they are not, this grabs the captured frame and saves it
+ * along with the reference to a png file.
+ */
+void chamelium_assert_crc_eq_or_dump(struct chamelium *chamelium,
+				     igt_crc_t *reference_crc,
+				     igt_crc_t *capture_crc, struct igt_fb *fb,
+				     int index)
+{
+	struct chamelium_frame_dump *frame;
+	cairo_surface_t *reference;
+	cairo_surface_t *capture;
+	char *reference_suffix;
+	char *capture_suffix;
+	bool eq;
+
+	eq = igt_check_crc_equal(reference_crc, capture_crc);
+	if (!eq && igt_frame_dump_is_enabled()) {
+		/* Grab the reference frame from framebuffer */
+		reference = igt_get_cairo_surface(chamelium->drm_fd, fb);
+
+		/* Grab the captured frame from chamelium */
+		frame = chamelium_read_captured_frame(chamelium, index);
+		igt_assert(frame);
+
+		capture = convert_frame_dump_argb32(frame);
+
+		reference_suffix = igt_crc_to_string_extended(reference_crc,
+							      '-', 2);
+		capture_suffix = igt_crc_to_string_extended(capture_crc, '-',
+							    2);
+
+		/* Write reference and capture frames to png */
+		igt_write_compared_frames_to_png(reference, capture,
+						 reference_suffix,
+						 capture_suffix);
+
+		free(reference_suffix);
+		free(capture_suffix);
+
+		chamelium_destroy_frame_dump(frame);
+
+		cairo_surface_destroy(capture);
+	}
+
+	igt_assert(eq);
+}
+
+/**
  * chamelium_get_frame_limit:
  * @chamelium: The Chamelium instance to use
  * @port: The port to check the frame limit on
diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
index 2bfbfdc7..80afcafa 100644
--- a/lib/igt_chamelium.h
+++ b/lib/igt_chamelium.h
@@ -105,6 +105,10 @@ int chamelium_get_frame_limit(struct chamelium *chamelium,
 void chamelium_assert_frame_eq(const struct chamelium *chamelium,
 			       const struct chamelium_frame_dump *dump,
 			       struct igt_fb *fb);
+void chamelium_assert_crc_eq_or_dump(struct chamelium *chamelium,
+				     igt_crc_t *reference_crc,
+				     igt_crc_t *capture_crc, struct igt_fb *fb,
+				     int index);
 void chamelium_destroy_frame_dump(struct chamelium_frame_dump *dump);
 
 #endif /* IGT_CHAMELIUM_H */
diff --git a/tests/chamelium.c b/tests/chamelium.c
index da98de47..f93ff7ee 100644
--- a/tests/chamelium.c
+++ b/tests/chamelium.c
@@ -390,7 +390,7 @@ test_display_crc_single(data_t *data, struct chamelium_port *port)
 	struct igt_fb fb;
 	drmModeModeInfo *mode;
 	drmModeConnector *connector;
-	int fb_id, i;
+	int fb_id, i, captured_frame_count;
 
 	reset_state(data, port);
 
@@ -415,11 +415,15 @@ test_display_crc_single(data_t *data, struct chamelium_port *port)
 
 		igt_debug("Testing single CRC fetch\n");
 
-		crc = chamelium_get_crc_for_area(data->chamelium, port,
-						 0, 0, 0, 0);
+		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 1);
+		crc = chamelium_read_captured_crcs(data->chamelium,
+						   &captured_frame_count);
 
 		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
 
+		chamelium_assert_crc_eq_or_dump(data->chamelium, expected_crc,
+						crc, &fb, 0);
+
 		igt_assert_crc_equal(crc, expected_crc);
 		free(expected_crc);
 		free(crc);
@@ -481,7 +485,9 @@ test_display_crc_multiple(data_t *data, struct chamelium_port *port)
 		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
 
 		for (j = 0; j < captured_frame_count; j++)
-			igt_assert_crc_equal(&crc[j], expected_crc);
+			chamelium_assert_crc_eq_or_dump(data->chamelium,
+							expected_crc, &crc[j],
+							&fb, j);
 
 		free(expected_crc);
 		free(crc);
-- 
2.13.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH i-g-t v4 7/7] tests/chamelium: Merge the crc testing functions into one
  2017-07-12 14:50 ` [PATCH i-g-t v4 0/7] CRC testing with Chamelium improvements Paul Kocialkowski
                     ` (5 preceding siblings ...)
  2017-07-12 14:50   ` [PATCH i-g-t v4 6/7] chamelium: Dump captured and reference frames to png on crc error Paul Kocialkowski
@ 2017-07-12 14:50   ` Paul Kocialkowski
  2017-07-12 14:53   ` [PATCH i-g-t v4 0/7] CRC testing with Chamelium improvements Paul Kocialkowski
  2017-07-17 17:04   ` Lyude Paul
  8 siblings, 0 replies; 57+ messages in thread
From: Paul Kocialkowski @ 2017-07-12 14:50 UTC (permalink / raw)
  To: intel-gfx; +Cc: Lyude

This merges the two test_display_crc_single and
test_display_crc_multiple functions into one, with a variable number of
frames to capture. This reduces code duplication.

Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
---
 tests/chamelium.c | 72 +++++++------------------------------------------------
 1 file changed, 8 insertions(+), 64 deletions(-)

diff --git a/tests/chamelium.c b/tests/chamelium.c
index f93ff7ee..89a3bde0 100644
--- a/tests/chamelium.c
+++ b/tests/chamelium.c
@@ -379,65 +379,7 @@ disable_output(data_t *data,
 }
 
 static void
-test_display_crc_single(data_t *data, struct chamelium_port *port)
-{
-	igt_display_t display;
-	igt_output_t *output;
-	igt_plane_t *primary;
-	igt_crc_t *crc;
-	igt_crc_t *expected_crc;
-	struct chamelium_fb_crc_async_data *fb_crc;
-	struct igt_fb fb;
-	drmModeModeInfo *mode;
-	drmModeConnector *connector;
-	int fb_id, i, captured_frame_count;
-
-	reset_state(data, port);
-
-	output = prepare_output(data, &display, port);
-	connector = chamelium_port_get_connector(data->chamelium, port, false);
-	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-	igt_assert(primary);
-
-	for (i = 0; i < connector->count_modes; i++) {
-		mode = &connector->modes[i];
-		fb_id = igt_create_color_pattern_fb(data->drm_fd,
-						    mode->hdisplay,
-						    mode->vdisplay,
-						    DRM_FORMAT_XRGB8888,
-						    LOCAL_DRM_FORMAT_MOD_NONE,
-						    0, 0, 0, &fb);
-		igt_assert(fb_id > 0);
-
-		fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd,
-								&fb);
-		enable_output(data, port, output, mode, &fb);
-
-		igt_debug("Testing single CRC fetch\n");
-
-		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 1);
-		crc = chamelium_read_captured_crcs(data->chamelium,
-						   &captured_frame_count);
-
-		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
-
-		chamelium_assert_crc_eq_or_dump(data->chamelium, expected_crc,
-						crc, &fb, 0);
-
-		igt_assert_crc_equal(crc, expected_crc);
-		free(expected_crc);
-		free(crc);
-
-		disable_output(data, port, output);
-		igt_remove_fb(data->drm_fd, &fb);
-	}
-
-	drmModeFreeConnector(connector);
-	igt_display_fini(&display);
-}
-
-static void
-test_display_crc_multiple(data_t *data, struct chamelium_port *port)
+test_display_crc(data_t *data, struct chamelium_port *port, int count)
 {
 	igt_display_t display;
 	igt_output_t *output;
@@ -476,10 +418,12 @@ test_display_crc_multiple(data_t *data, struct chamelium_port *port)
 		 * there's always the potential the driver isn't able to keep
 		 * the display running properly for very long
 		 */
-		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 3);
+		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, count);
 		crc = chamelium_read_captured_crcs(data->chamelium,
 						   &captured_frame_count);
 
+		igt_assert(captured_frame_count == count);
+
 		igt_debug("Captured %d frames\n", captured_frame_count);
 
 		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
@@ -696,10 +640,10 @@ igt_main
 							edid_id, alt_edid_id);
 
 		connector_subtest("dp-crc-single", DisplayPort)
-			test_display_crc_single(&data, port);
+			test_display_crc(&data, port, 1);
 
 		connector_subtest("dp-crc-multiple", DisplayPort)
-			test_display_crc_multiple(&data, port);
+			test_display_crc(&data, port, 3);
 
 		connector_subtest("dp-frame-dump", DisplayPort)
 			test_display_frame_dump(&data, port);
@@ -753,10 +697,10 @@ igt_main
 							edid_id, alt_edid_id);
 
 		connector_subtest("hdmi-crc-single", HDMIA)
-			test_display_crc_single(&data, port);
+			test_display_crc(&data, port, 1);
 
 		connector_subtest("hdmi-crc-multiple", HDMIA)
-			test_display_crc_multiple(&data, port);
+			test_display_crc(&data, port, 3);
 
 		connector_subtest("hdmi-frame-dump", HDMIA)
 			test_display_frame_dump(&data, port);
-- 
2.13.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* Re: [PATCH i-g-t v4 0/7] CRC testing with Chamelium improvements
  2017-07-12 14:50 ` [PATCH i-g-t v4 0/7] CRC testing with Chamelium improvements Paul Kocialkowski
                     ` (6 preceding siblings ...)
  2017-07-12 14:50   ` [PATCH i-g-t v4 7/7] tests/chamelium: Merge the crc testing functions into one Paul Kocialkowski
@ 2017-07-12 14:53   ` Paul Kocialkowski
  2017-07-17 17:04   ` Lyude Paul
  8 siblings, 0 replies; 57+ messages in thread
From: Paul Kocialkowski @ 2017-07-12 14:53 UTC (permalink / raw)
  To: intel-gfx; +Cc: Lyude

On Wed, 2017-07-12 at 17:50 +0300, Paul Kocialkowski wrote:
> Changes since v3:
> * Renamed structure used by async crc calculation for more clarity
> * Used const qualifier for untouched buffer when hashing
> * Split actual calculation to a dedicated function
> * Reworked async functions names for more clarity
> * Reworked descriptions for better accuracy
> * Exported framebuffer cairo surface and use it directly instead of
>   (unused) png dumping
> * Fix how the framebuffer cairo surface is obtained to avoid
> destroying
>   it too early

This also contains the following changes that I forgot to mention:

Changes since v3:
* Made CRC checking logic common
* Added a check for the same number of words
* Made frame dumping configuration and helpers common
* Added an extended crc to string helper
* Added a chamelium helper for crc checking and frame dumping
* Split the merging of crc functions to a separate patch
* Added support for frame dump path global variable
* Added listing the dumped images in a file, possibly identified with
  an id global variable

The latter allows having one "dump report" file per run, possibly
identified with the id global variable, that indicates which files
are the output, while keeping the possibility to have the same files
for different runs. This allows saving significant disk space when
the images are identified with e.g. their crc, so that duplicate results
only lead to duplicate dump reports and not duplicate images.

-- 
Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo, Finland
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH i-g-t v4 2/7] chamelium: Calculate CRC from framebuffer instead of hardcoding it
  2017-07-12 14:50   ` [PATCH i-g-t v4 2/7] chamelium: Calculate CRC from framebuffer instead of hardcoding it Paul Kocialkowski
@ 2017-07-17 16:29     ` Lyude Paul
  2017-07-19 11:11       ` Paul Kocialkowski
  0 siblings, 1 reply; 57+ messages in thread
From: Lyude Paul @ 2017-07-17 16:29 UTC (permalink / raw)
  To: Paul Kocialkowski, intel-gfx

On Wed, 2017-07-12 at 17:50 +0300, Paul Kocialkowski wrote:
> This introduces CRC calculation for reference frames, instead of
> using
> hardcoded values for them. The rendering of reference frames may
> differ
> from machine to machine, especially due to font rendering, and the
> frame itself may change with subsequent IGT changes.
> 
> These differences would cause the CRC checks to fail on different
> setups. This allows them to pass regardless of the setup.

Just one question before I push this since I didn't think of testing
this previously and don't have access to my chamelium at the moment.
Have you made sure that this doesn't break things with igt if a test
gets interrupted due to failure in the middle of an asynchronous CRC
calculation?

Other then that, everything here looks good.
> 
> Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
> ---
>  lib/igt_chamelium.c | 143
> ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  lib/igt_chamelium.h |   5 ++
>  tests/chamelium.c   |  77 +++++++---------------------
>  3 files changed, 167 insertions(+), 58 deletions(-)
> 
> diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
> index 93392af7..baa6399c 100644
> --- a/lib/igt_chamelium.c
> +++ b/lib/igt_chamelium.c
> @@ -94,6 +94,14 @@ struct chamelium_frame_dump {
>  	struct chamelium_port *port;
>  };
>  
> +struct chamelium_fb_crc_async_data {
> +	int fd;
> +	struct igt_fb *fb;
> +
> +	pthread_t thread_id;
> +	igt_crc_t *ret;
> +};
> +
>  struct chamelium {
>  	xmlrpc_env env;
>  	xmlrpc_client *client;
> @@ -998,6 +1006,141 @@ int chamelium_get_frame_limit(struct chamelium
> *chamelium,
>  	return ret;
>  }
>  
> +static uint32_t chamelium_xrgb_hash16(const unsigned char *buffer,
> int width,
> +				      int height, int k, int m)
> +{
> +	unsigned char r, g, b;
> +	uint64_t sum = 0;
> +	uint64_t count = 0;
> +	uint64_t value;
> +	uint32_t hash;
> +	int index;
> +	int i;
> +
> +	for (i=0; i < width * height; i++) {
> +		if ((i % m) != k)
> +			continue;
> +
> +		index = i * 4;
> +
> +		r = buffer[index + 2];
> +		g = buffer[index + 1];
> +		b = buffer[index + 0];
> +
> +		value = r | (g << 8) | (b << 16);
> +		sum += ++count * value;
> +	}
> +
> +	hash = ((sum >> 0) ^ (sum >> 16) ^ (sum >> 32) ^ (sum >>
> 48)) & 0xffff;
> +
> +	return hash;
> +}
> +
> +static void chamelium_do_calculate_fb_crc(int fd, struct igt_fb *fb,
> +					  igt_crc_t *out)
> +{
> +	unsigned char *buffer;
> +	cairo_surface_t *fb_surface;
> +	int n = 4;
> +	int w, h;
> +	int i, j;
> +
> +	/* Get the cairo surface for the framebuffer */
> +	fb_surface = igt_get_cairo_surface(fd, fb);
> +
> +	buffer = cairo_image_surface_get_data(fb_surface);
> +	w = fb->width;
> +	h = fb->height;
> +
> +	for (i = 0; i < n; i++) {
> +		j = n - i - 1;
> +		out->crc[i] = chamelium_xrgb_hash16(buffer, w, h, j,
> n);
> +	}
> +
> +	out->n_words = n;
> +}
> +
> +/**
> + * chamelium_calculate_fb_crc:
> + * @fd: The drm file descriptor
> + * @fb: The framebuffer to calculate the CRC for
> + *
> + * Calculates the CRC for the provided framebuffer, using the
> Chamelium's CRC
> + * algorithm. This calculates the CRC in a synchronous fashion.
> + *
> + * Returns: The calculated CRC
> + */
> +igt_crc_t *chamelium_calculate_fb_crc(int fd, struct igt_fb *fb)
> +{
> +	igt_crc_t *ret = calloc(1, sizeof(igt_crc_t));
> +
> +	chamelium_do_calculate_fb_crc(fd, fb, ret);
> +
> +	return ret;
> +}
> +
> +static void *chamelium_calculate_fb_crc_async_work(void *data)
> +{
> +	struct chamelium_fb_crc_async_data *fb_crc;
> +
> +	fb_crc = (struct chamelium_fb_crc_async_data *) data;
> +
> +	chamelium_do_calculate_fb_crc(fb_crc->fd, fb_crc->fb,
> fb_crc->ret);
> +
> +	return NULL;
> +}
> +
> +/**
> + * chamelium_calculate_fb_crc_launch:
> + * @fd: The drm file descriptor
> + * @fb: The framebuffer to calculate the CRC for
> + *
> + * Launches the CRC calculation for the provided framebuffer, using
> the
> + * Chamelium's CRC algorithm. This calculates the CRC in an
> asynchronous
> + * fashion.
> + *
> + * The returned structure should be passed to a subsequent call to
> + * chamelium_calculate_fb_crc_result. It should not be freed.
> + *
> + * Returns: An intermediate structure for the CRC calculation work.
> + */
> +struct chamelium_fb_crc_async_data
> *chamelium_calculate_fb_crc_async_start(int fd,
> +									
>    struct igt_fb *fb)
> +{
> +	struct chamelium_fb_crc_async_data *fb_crc;
> +
> +	fb_crc = calloc(1, sizeof(struct
> chamelium_fb_crc_async_data));
> +	fb_crc->ret = calloc(1, sizeof(igt_crc_t));
> +	fb_crc->fd = fd;
> +	fb_crc->fb = fb;
> +
> +	pthread_create(&fb_crc->thread_id, NULL,
> +		       chamelium_calculate_fb_crc_async_work,
> fb_crc);
> +
> +	return fb_crc;
> +}
> +
> +/**
> + * chamelium_calculate_fb_crc_result:
> + * @fb_crc: An intermediate structure with thread-related
> information
> + *
> + * Blocks until the asynchronous CRC calculation is finished, and
> then returns
> + * its result.
> + *
> + * Returns: The calculated CRC
> + */
> +igt_crc_t *chamelium_calculate_fb_crc_async_finish(struct
> chamelium_fb_crc_async_data *fb_crc)
> +{
> +	igt_crc_t *ret;
> +
> +	pthread_join(fb_crc->thread_id, NULL);
> +
> +	ret = fb_crc->ret;
> +	free(fb_crc);
> +
> +	return ret;
> +}
> +
>  static unsigned int chamelium_get_port_type(struct chamelium
> *chamelium,
>  					    struct chamelium_port
> *port)
>  {
> diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
> index 81322ad2..2bfbfdc7 100644
> --- a/lib/igt_chamelium.h
> +++ b/lib/igt_chamelium.h
> @@ -36,6 +36,7 @@
>  struct chamelium;
>  struct chamelium_port;
>  struct chamelium_frame_dump;
> +struct chamelium_fb_crc_async_data;
>  
>  struct chamelium *chamelium_init(int drm_fd);
>  void chamelium_deinit(struct chamelium *chamelium);
> @@ -92,6 +93,10 @@ struct chamelium_frame_dump
> *chamelium_port_dump_pixels(struct chamelium *chamel
>  							struct
> chamelium_port *port,
>  							int x, int
> y,
>  							int w, int
> h);
> +igt_crc_t *chamelium_calculate_fb_crc(int fd, struct igt_fb *fb);
> +struct chamelium_fb_crc_async_data
> *chamelium_calculate_fb_crc_async_start(int fd,
> +									
>    struct igt_fb *fb);
> +igt_crc_t *chamelium_calculate_fb_crc_async_finish(struct
> chamelium_fb_crc_async_data *fb_crc);
>  int chamelium_get_captured_frame_count(struct chamelium *chamelium);
>  int chamelium_get_frame_limit(struct chamelium *chamelium,
>  			      struct chamelium_port *port,
> diff --git a/tests/chamelium.c b/tests/chamelium.c
> index e26f0557..da98de47 100644
> --- a/tests/chamelium.c
> +++ b/tests/chamelium.c
> @@ -49,43 +49,6 @@ typedef struct {
>  #define HPD_TOGGLE_COUNT_VGA 5
>  #define HPD_TOGGLE_COUNT_DP_HDMI 15
>  
> -/* Pre-calculated CRCs for the pattern fb, for all the modes in the
> default
> - * chamelium edid
> - */
> -struct crc_entry {
> -	int width;
> -	int height;
> -	igt_crc_t crc;
> -};
> -
> -#define CRC_ENTRY(w_, h_, ...) \
> -	{ w_, h_, { .n_words = 4, .crc = { __VA_ARGS__ } } }
> -
> -static const struct crc_entry pattern_fb_crcs[] = {
> -	CRC_ENTRY(1920, 1080, 0xf859, 0xa751, 0x8c81, 0x45a1),
> -	CRC_ENTRY(1280,  720, 0xcec2, 0x4246, 0x6cfd, 0xeb43),
> -	CRC_ENTRY(1024,  768, 0x85e5, 0xf0cd, 0xafe3, 0x7f18),
> -	CRC_ENTRY( 800,  600, 0x6b39, 0x32b6, 0x831a, 0xb03e),
> -	CRC_ENTRY( 640,  480, 0xa121, 0x2473, 0xb150, 0x8c47),
> -};
> -#undef CRC_ENTRY
> -
> -static const igt_crc_t *
> -get_precalculated_crc(struct chamelium_port *port, int w, int h)
> -{
> -	int i;
> -	const struct crc_entry *entry;
> -
> -	for (i = 0; i < ARRAY_SIZE(pattern_fb_crcs); i++) {
> -		entry = &pattern_fb_crcs[i];
> -
> -		if (entry->width == w && entry->height == h)
> -			return &entry->crc;
> -	}
> -
> -	return NULL;
> -}
> -
>  static void
>  require_connector_present(data_t *data, unsigned int type)
>  {
> @@ -422,7 +385,8 @@ test_display_crc_single(data_t *data, struct
> chamelium_port *port)
>  	igt_output_t *output;
>  	igt_plane_t *primary;
>  	igt_crc_t *crc;
> -	const igt_crc_t *expected_crc;
> +	igt_crc_t *expected_crc;
> +	struct chamelium_fb_crc_async_data *fb_crc;
>  	struct igt_fb fb;
>  	drmModeModeInfo *mode;
>  	drmModeConnector *connector;
> @@ -445,24 +409,21 @@ test_display_crc_single(data_t *data, struct
> chamelium_port *port)
>  						    0, 0, 0, &fb);
>  		igt_assert(fb_id > 0);
>  
> +		fb_crc =
> chamelium_calculate_fb_crc_async_start(data->drm_fd,
> +								&fb)
> ;
>  		enable_output(data, port, output, mode, &fb);
>  
> -		expected_crc = get_precalculated_crc(port,
> -						     mode->hdisplay,
> -						     mode-
> >vdisplay);
> -		if (!expected_crc) {
> -			igt_warn("No precalculated CRC found for
> %dx%d, skipping CRC check\n",
> -				 mode->hdisplay, mode->vdisplay);
> -			goto next;
> -		}
> -
>  		igt_debug("Testing single CRC fetch\n");
> +
>  		crc = chamelium_get_crc_for_area(data->chamelium,
> port,
>  						 0, 0, 0, 0);
> +
> +		expected_crc =
> chamelium_calculate_fb_crc_async_finish(fb_crc);
> +
>  		igt_assert_crc_equal(crc, expected_crc);
> +		free(expected_crc);
>  		free(crc);
>  
> -next:
>  		disable_output(data, port, output);
>  		igt_remove_fb(data->drm_fd, &fb);
>  	}
> @@ -478,7 +439,8 @@ test_display_crc_multiple(data_t *data, struct
> chamelium_port *port)
>  	igt_output_t *output;
>  	igt_plane_t *primary;
>  	igt_crc_t *crc;
> -	const igt_crc_t *expected_crc;
> +	igt_crc_t *expected_crc;
> +	struct chamelium_fb_crc_async_data *fb_crc;
>  	struct igt_fb fb;
>  	drmModeModeInfo *mode;
>  	drmModeConnector *connector;
> @@ -501,15 +463,10 @@ test_display_crc_multiple(data_t *data, struct
> chamelium_port *port)
>  						    0, 0, 0, &fb);
>  		igt_assert(fb_id > 0);
>  
> -		enable_output(data, port, output, mode, &fb);
> +		fb_crc =
> chamelium_calculate_fb_crc_async_start(data->drm_fd,
> +								&fb)
> ;
>  
> -		expected_crc = get_precalculated_crc(port, mode-
> >hdisplay,
> -						     mode-
> >vdisplay);
> -		if (!expected_crc) {
> -			igt_warn("No precalculated CRC found for
> %dx%d, skipping CRC check\n",
> -				 mode->hdisplay, mode->vdisplay);
> -			goto next;
> -		}
> +		enable_output(data, port, output, mode, &fb);
>  
>  		/* We want to keep the display running for a little
> bit, since
>  		 * there's always the potential the driver isn't
> able to keep
> @@ -520,11 +477,15 @@ test_display_crc_multiple(data_t *data, struct
> chamelium_port *port)
>  						   &captured_frame_c
> ount);
>  
>  		igt_debug("Captured %d frames\n",
> captured_frame_count);
> +
> +		expected_crc =
> chamelium_calculate_fb_crc_async_finish(fb_crc);
> +
>  		for (j = 0; j < captured_frame_count; j++)
>  			igt_assert_crc_equal(&crc[j], expected_crc);
> +
> +		free(expected_crc);
>  		free(crc);
>  
> -next:
>  		disable_output(data, port, output);
>  		igt_remove_fb(data->drm_fd, &fb);
>  	}
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH i-g-t v4 0/7] CRC testing with Chamelium improvements
  2017-07-12 14:50 ` [PATCH i-g-t v4 0/7] CRC testing with Chamelium improvements Paul Kocialkowski
                     ` (7 preceding siblings ...)
  2017-07-12 14:53   ` [PATCH i-g-t v4 0/7] CRC testing with Chamelium improvements Paul Kocialkowski
@ 2017-07-17 17:04   ` Lyude Paul
  8 siblings, 0 replies; 57+ messages in thread
From: Lyude Paul @ 2017-07-17 17:04 UTC (permalink / raw)
  To: Paul Kocialkowski, intel-gfx

The only thing that needs changing is the thing I mentioned on patch
#2. After you make sure exiting prematurely doesn't cause the rest of
IGT to segfault or something like that, that should hopefully be the
last change that will need to be done. Afterwards I will push the whole
series at once.

Thanks for all the great work! And the changelist ;)

On Wed, 2017-07-12 at 17:50 +0300, Paul Kocialkowski wrote:
> Changes since v3:
> * Renamed structure used by async crc calculation for more clarity
> * Used const qualifier for untouched buffer when hashing
> * Split actual calculation to a dedicated function
> * Reworked async functions names for more clarity
> * Reworked descriptions for better accuracy
> * Exported framebuffer cairo surface and use it directly instead of
>   (unused) png dumping
> * Fix how the framebuffer cairo surface is obtained to avoid
> destroying
>   it too early
> 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH i-g-t v4 2/7] chamelium: Calculate CRC from framebuffer instead of hardcoding it
  2017-07-17 16:29     ` Lyude Paul
@ 2017-07-19 11:11       ` Paul Kocialkowski
  0 siblings, 0 replies; 57+ messages in thread
From: Paul Kocialkowski @ 2017-07-19 11:11 UTC (permalink / raw)
  To: Lyude Paul, intel-gfx

On Mon, 2017-07-17 at 12:29 -0400, Lyude Paul wrote:
> On Wed, 2017-07-12 at 17:50 +0300, Paul Kocialkowski wrote:
> > This introduces CRC calculation for reference frames, instead of
> > using
> > hardcoded values for them. The rendering of reference frames may
> > differ
> > from machine to machine, especially due to font rendering, and the
> > frame itself may change with subsequent IGT changes.
> > 
> > These differences would cause the CRC checks to fail on different
> > setups. This allows them to pass regardless of the setup.
> 
> Just one question before I push this since I didn't think of testing
> this previously and don't have access to my chamelium at the moment.
> Have you made sure that this doesn't break things with igt if a test
> gets interrupted due to failure in the middle of an asynchronous CRC
> calculation?

So I have now tested that a failed assert (in the main thread) in the
middle of the threaded calculation will not cause any segfault. There is
no reason why it should, because none of the ressources used for the
calculation are liberated prior to the end of the process. Everything is
really cleaned up when the process dies.

On the other hand, it may happen, due to the call to
igt_get_cairo_surface that an igt_assert fails in the calculation
thread, which definitely causes a segfault.

I will rework the patches so that the call to the function is made prior
to starting the thread, thus avoiding any possibility of hitting a
failed igt_assert in the thread itself.

> Other then that, everything here looks good.
> > 
> > Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
> > ---
> >  lib/igt_chamelium.c | 143
> > ++++++++++++++++++++++++++++++++++++++++++++++++++++
> >  lib/igt_chamelium.h |   5 ++
> >  tests/chamelium.c   |  77 +++++++---------------------
> >  3 files changed, 167 insertions(+), 58 deletions(-)
> > 
> > diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
> > index 93392af7..baa6399c 100644
> > --- a/lib/igt_chamelium.c
> > +++ b/lib/igt_chamelium.c
> > @@ -94,6 +94,14 @@ struct chamelium_frame_dump {
> >  	struct chamelium_port *port;
> >  };
> >  
> > +struct chamelium_fb_crc_async_data {
> > +	int fd;
> > +	struct igt_fb *fb;
> > +
> > +	pthread_t thread_id;
> > +	igt_crc_t *ret;
> > +};
> > +
> >  struct chamelium {
> >  	xmlrpc_env env;
> >  	xmlrpc_client *client;
> > @@ -998,6 +1006,141 @@ int chamelium_get_frame_limit(struct
> > chamelium
> > *chamelium,
> >  	return ret;
> >  }
> >  
> > +static uint32_t chamelium_xrgb_hash16(const unsigned char *buffer,
> > int width,
> > +				      int height, int k, int m)
> > +{
> > +	unsigned char r, g, b;
> > +	uint64_t sum = 0;
> > +	uint64_t count = 0;
> > +	uint64_t value;
> > +	uint32_t hash;
> > +	int index;
> > +	int i;
> > +
> > +	for (i=0; i < width * height; i++) {
> > +		if ((i % m) != k)
> > +			continue;
> > +
> > +		index = i * 4;
> > +
> > +		r = buffer[index + 2];
> > +		g = buffer[index + 1];
> > +		b = buffer[index + 0];
> > +
> > +		value = r | (g << 8) | (b << 16);
> > +		sum += ++count * value;
> > +	}
> > +
> > +	hash = ((sum >> 0) ^ (sum >> 16) ^ (sum >> 32) ^ (sum >>
> > 48)) & 0xffff;
> > +
> > +	return hash;
> > +}
> > +
> > +static void chamelium_do_calculate_fb_crc(int fd, struct igt_fb
> > *fb,
> > +					  igt_crc_t *out)
> > +{
> > +	unsigned char *buffer;
> > +	cairo_surface_t *fb_surface;
> > +	int n = 4;
> > +	int w, h;
> > +	int i, j;
> > +
> > +	/* Get the cairo surface for the framebuffer */
> > +	fb_surface = igt_get_cairo_surface(fd, fb);
> > +
> > +	buffer = cairo_image_surface_get_data(fb_surface);
> > +	w = fb->width;
> > +	h = fb->height;
> > +
> > +	for (i = 0; i < n; i++) {
> > +		j = n - i - 1;
> > +		out->crc[i] = chamelium_xrgb_hash16(buffer, w, h,
> > j,
> > n);
> > +	}
> > +
> > +	out->n_words = n;
> > +}
> > +
> > +/**
> > + * chamelium_calculate_fb_crc:
> > + * @fd: The drm file descriptor
> > + * @fb: The framebuffer to calculate the CRC for
> > + *
> > + * Calculates the CRC for the provided framebuffer, using the
> > Chamelium's CRC
> > + * algorithm. This calculates the CRC in a synchronous fashion.
> > + *
> > + * Returns: The calculated CRC
> > + */
> > +igt_crc_t *chamelium_calculate_fb_crc(int fd, struct igt_fb *fb)
> > +{
> > +	igt_crc_t *ret = calloc(1, sizeof(igt_crc_t));
> > +
> > +	chamelium_do_calculate_fb_crc(fd, fb, ret);
> > +
> > +	return ret;
> > +}
> > +
> > +static void *chamelium_calculate_fb_crc_async_work(void *data)
> > +{
> > +	struct chamelium_fb_crc_async_data *fb_crc;
> > +
> > +	fb_crc = (struct chamelium_fb_crc_async_data *) data;
> > +
> > +	chamelium_do_calculate_fb_crc(fb_crc->fd, fb_crc->fb,
> > fb_crc->ret);
> > +
> > +	return NULL;
> > +}
> > +
> > +/**
> > + * chamelium_calculate_fb_crc_launch:
> > + * @fd: The drm file descriptor
> > + * @fb: The framebuffer to calculate the CRC for
> > + *
> > + * Launches the CRC calculation for the provided framebuffer, using
> > the
> > + * Chamelium's CRC algorithm. This calculates the CRC in an
> > asynchronous
> > + * fashion.
> > + *
> > + * The returned structure should be passed to a subsequent call to
> > + * chamelium_calculate_fb_crc_result. It should not be freed.
> > + *
> > + * Returns: An intermediate structure for the CRC calculation work.
> > + */
> > +struct chamelium_fb_crc_async_data
> > *chamelium_calculate_fb_crc_async_start(int fd,
> > +									
> >    struct igt_fb *fb)
> > +{
> > +	struct chamelium_fb_crc_async_data *fb_crc;
> > +
> > +	fb_crc = calloc(1, sizeof(struct
> > chamelium_fb_crc_async_data));
> > +	fb_crc->ret = calloc(1, sizeof(igt_crc_t));
> > +	fb_crc->fd = fd;
> > +	fb_crc->fb = fb;
> > +
> > +	pthread_create(&fb_crc->thread_id, NULL,
> > +		       chamelium_calculate_fb_crc_async_work,
> > fb_crc);
> > +
> > +	return fb_crc;
> > +}
> > +
> > +/**
> > + * chamelium_calculate_fb_crc_result:
> > + * @fb_crc: An intermediate structure with thread-related
> > information
> > + *
> > + * Blocks until the asynchronous CRC calculation is finished, and
> > then returns
> > + * its result.
> > + *
> > + * Returns: The calculated CRC
> > + */
> > +igt_crc_t *chamelium_calculate_fb_crc_async_finish(struct
> > chamelium_fb_crc_async_data *fb_crc)
> > +{
> > +	igt_crc_t *ret;
> > +
> > +	pthread_join(fb_crc->thread_id, NULL);
> > +
> > +	ret = fb_crc->ret;
> > +	free(fb_crc);
> > +
> > +	return ret;
> > +}
> > +
> >  static unsigned int chamelium_get_port_type(struct chamelium
> > *chamelium,
> >  					    struct chamelium_port
> > *port)
> >  {
> > diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
> > index 81322ad2..2bfbfdc7 100644
> > --- a/lib/igt_chamelium.h
> > +++ b/lib/igt_chamelium.h
> > @@ -36,6 +36,7 @@
> >  struct chamelium;
> >  struct chamelium_port;
> >  struct chamelium_frame_dump;
> > +struct chamelium_fb_crc_async_data;
> >  
> >  struct chamelium *chamelium_init(int drm_fd);
> >  void chamelium_deinit(struct chamelium *chamelium);
> > @@ -92,6 +93,10 @@ struct chamelium_frame_dump
> > *chamelium_port_dump_pixels(struct chamelium *chamel
> >  							struct
> > chamelium_port *port,
> >  							int x, int
> > y,
> >  							int w, int
> > h);
> > +igt_crc_t *chamelium_calculate_fb_crc(int fd, struct igt_fb *fb);
> > +struct chamelium_fb_crc_async_data
> > *chamelium_calculate_fb_crc_async_start(int fd,
> > +									
> >    struct igt_fb *fb);
> > +igt_crc_t *chamelium_calculate_fb_crc_async_finish(struct
> > chamelium_fb_crc_async_data *fb_crc);
> >  int chamelium_get_captured_frame_count(struct chamelium
> > *chamelium);
> >  int chamelium_get_frame_limit(struct chamelium *chamelium,
> >  			      struct chamelium_port *port,
> > diff --git a/tests/chamelium.c b/tests/chamelium.c
> > index e26f0557..da98de47 100644
> > --- a/tests/chamelium.c
> > +++ b/tests/chamelium.c
> > @@ -49,43 +49,6 @@ typedef struct {
> >  #define HPD_TOGGLE_COUNT_VGA 5
> >  #define HPD_TOGGLE_COUNT_DP_HDMI 15
> >  
> > -/* Pre-calculated CRCs for the pattern fb, for all the modes in the
> > default
> > - * chamelium edid
> > - */
> > -struct crc_entry {
> > -	int width;
> > -	int height;
> > -	igt_crc_t crc;
> > -};
> > -
> > -#define CRC_ENTRY(w_, h_, ...) \
> > -	{ w_, h_, { .n_words = 4, .crc = { __VA_ARGS__ } } }
> > -
> > -static const struct crc_entry pattern_fb_crcs[] = {
> > -	CRC_ENTRY(1920, 1080, 0xf859, 0xa751, 0x8c81, 0x45a1),
> > -	CRC_ENTRY(1280,  720, 0xcec2, 0x4246, 0x6cfd, 0xeb43),
> > -	CRC_ENTRY(1024,  768, 0x85e5, 0xf0cd, 0xafe3, 0x7f18),
> > -	CRC_ENTRY( 800,  600, 0x6b39, 0x32b6, 0x831a, 0xb03e),
> > -	CRC_ENTRY( 640,  480, 0xa121, 0x2473, 0xb150, 0x8c47),
> > -};
> > -#undef CRC_ENTRY
> > -
> > -static const igt_crc_t *
> > -get_precalculated_crc(struct chamelium_port *port, int w, int h)
> > -{
> > -	int i;
> > -	const struct crc_entry *entry;
> > -
> > -	for (i = 0; i < ARRAY_SIZE(pattern_fb_crcs); i++) {
> > -		entry = &pattern_fb_crcs[i];
> > -
> > -		if (entry->width == w && entry->height == h)
> > -			return &entry->crc;
> > -	}
> > -
> > -	return NULL;
> > -}
> > -
> >  static void
> >  require_connector_present(data_t *data, unsigned int type)
> >  {
> > @@ -422,7 +385,8 @@ test_display_crc_single(data_t *data, struct
> > chamelium_port *port)
> >  	igt_output_t *output;
> >  	igt_plane_t *primary;
> >  	igt_crc_t *crc;
> > -	const igt_crc_t *expected_crc;
> > +	igt_crc_t *expected_crc;
> > +	struct chamelium_fb_crc_async_data *fb_crc;
> >  	struct igt_fb fb;
> >  	drmModeModeInfo *mode;
> >  	drmModeConnector *connector;
> > @@ -445,24 +409,21 @@ test_display_crc_single(data_t *data, struct
> > chamelium_port *port)
> >  						    0, 0, 0, &fb);
> >  		igt_assert(fb_id > 0);
> >  
> > +		fb_crc =
> > chamelium_calculate_fb_crc_async_start(data->drm_fd,
> > +								&fb
> > )
> > ;
> >  		enable_output(data, port, output, mode, &fb);
> >  
> > -		expected_crc = get_precalculated_crc(port,
> > -						     mode-
> > >hdisplay,
> > -						     mode-
> > > vdisplay);
> > 
> > -		if (!expected_crc) {
> > -			igt_warn("No precalculated CRC found for
> > %dx%d, skipping CRC check\n",
> > -				 mode->hdisplay, mode->vdisplay);
> > -			goto next;
> > -		}
> > -
> >  		igt_debug("Testing single CRC fetch\n");
> > +
> >  		crc = chamelium_get_crc_for_area(data->chamelium,
> > port,
> >  						 0, 0, 0, 0);
> > +
> > +		expected_crc =
> > chamelium_calculate_fb_crc_async_finish(fb_crc);
> > +
> >  		igt_assert_crc_equal(crc, expected_crc);
> > +		free(expected_crc);
> >  		free(crc);
> >  
> > -next:
> >  		disable_output(data, port, output);
> >  		igt_remove_fb(data->drm_fd, &fb);
> >  	}
> > @@ -478,7 +439,8 @@ test_display_crc_multiple(data_t *data, struct
> > chamelium_port *port)
> >  	igt_output_t *output;
> >  	igt_plane_t *primary;
> >  	igt_crc_t *crc;
> > -	const igt_crc_t *expected_crc;
> > +	igt_crc_t *expected_crc;
> > +	struct chamelium_fb_crc_async_data *fb_crc;
> >  	struct igt_fb fb;
> >  	drmModeModeInfo *mode;
> >  	drmModeConnector *connector;
> > @@ -501,15 +463,10 @@ test_display_crc_multiple(data_t *data, struct
> > chamelium_port *port)
> >  						    0, 0, 0, &fb);
> >  		igt_assert(fb_id > 0);
> >  
> > -		enable_output(data, port, output, mode, &fb);
> > +		fb_crc =
> > chamelium_calculate_fb_crc_async_start(data->drm_fd,
> > +								&fb
> > )
> > ;
> >  
> > -		expected_crc = get_precalculated_crc(port, mode-
> > > hdisplay,
> > 
> > -						     mode-
> > > vdisplay);
> > 
> > -		if (!expected_crc) {
> > -			igt_warn("No precalculated CRC found for
> > %dx%d, skipping CRC check\n",
> > -				 mode->hdisplay, mode->vdisplay);
> > -			goto next;
> > -		}
> > +		enable_output(data, port, output, mode, &fb);
> >  
> >  		/* We want to keep the display running for a little
> > bit, since
> >  		 * there's always the potential the driver isn't
> > able to keep
> > @@ -520,11 +477,15 @@ test_display_crc_multiple(data_t *data, struct
> > chamelium_port *port)
> >  						   &captured_frame_
> > c
> > ount);
> >  
> >  		igt_debug("Captured %d frames\n",
> > captured_frame_count);
> > +
> > +		expected_crc =
> > chamelium_calculate_fb_crc_async_finish(fb_crc);
> > +
> >  		for (j = 0; j < captured_frame_count; j++)
> >  			igt_assert_crc_equal(&crc[j],
> > expected_crc);
> > +
> > +		free(expected_crc);
> >  		free(crc);
> >  
> > -next:
> >  		disable_output(data, port, output);
> >  		igt_remove_fb(data->drm_fd, &fb);
> >  	}
-- 
Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo, Finland
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCH i-g-t v5 0/7] CRC testing with Chamelium improvements
  2017-07-05  8:04 [PATCH i-g-t v3 1/4] chamelium: Calculate CRC from framebuffer instead of hardcoding it Paul Kocialkowski
                   ` (4 preceding siblings ...)
  2017-07-12 14:50 ` [PATCH i-g-t v4 0/7] CRC testing with Chamelium improvements Paul Kocialkowski
@ 2017-07-19 13:46 ` Paul Kocialkowski
  2017-07-19 13:46   ` [PATCH i-g-t v5 1/7] lib/igt_fb: Export the cairo surface instead of writing to a png Paul Kocialkowski
                     ` (8 more replies)
  5 siblings, 9 replies; 57+ messages in thread
From: Paul Kocialkowski @ 2017-07-19 13:46 UTC (permalink / raw)
  To: intel-gfx

Changes since v4:
* Moved igt_get_cairo_surface out of the thread function to properly
  handle assert failure
* Rebased on top of current master

Changes since v3:
* Renamed structure used by async crc calculation for more clarity
* Used const qualifier for untouched buffer when hashing
* Split actual calculation to a dedicated function
* Reworked async functions names for more clarity
* Reworked descriptions for better accuracy
* Exported framebuffer cairo surface and use it directly instead of
  (unused) png dumping
* Fix how the framebuffer cairo surface is obtained to avoid destroying
  it too early

* Made CRC checking logic common
* Added a check for the same number of words
* Made frame dumping configuration and helpers common
* Added an extended crc to string helper
* Added a chamelium helper for crc checking and frame dumping
* Split the merging of crc functions to a separate patch
* Added support for frame dump path global variable
* Added listing the dumped images in a file, possibly identified with
  an id global variable

The latter allows having one "dump report" file per run, possibly
identified with the id global variable, that indicates which files
are the output, while keeping the possibility to have the same files
for different runs. This allows saving significant disk space when
the images are identified with e.g. their crc, so that duplicate results
only lead to duplicate dump reports and not duplicate images.

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* [PATCH i-g-t v5 1/7] lib/igt_fb: Export the cairo surface instead of writing to a png
  2017-07-19 13:46 ` [PATCH i-g-t v5 " Paul Kocialkowski
@ 2017-07-19 13:46   ` Paul Kocialkowski
  2017-07-19 13:46   ` [PATCH i-g-t v5 2/7] chamelium: Calculate CRC from framebuffer instead of hardcoding it Paul Kocialkowski
                     ` (7 subsequent siblings)
  8 siblings, 0 replies; 57+ messages in thread
From: Paul Kocialkowski @ 2017-07-19 13:46 UTC (permalink / raw)
  To: intel-gfx

This removes the igt_write_fb_to_png function (that was unused thus far)
and exports the igt_get_cairo_surface function to grab the matching
cairo surface. Writing to a png is now handled by the common frame
handling code in lib/igt_frame.

This also fixes how the surface is retreived in chamelium code,
which avoids destroying it too early.

Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
---
 lib/igt_chamelium.c |  7 +------
 lib/igt_fb.c        | 36 +++++++++++++-----------------------
 lib/igt_fb.h        |  2 +-
 3 files changed, 15 insertions(+), 30 deletions(-)

diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
index bff08c0e..93392af7 100644
--- a/lib/igt_chamelium.c
+++ b/lib/igt_chamelium.c
@@ -936,17 +936,13 @@ void chamelium_assert_frame_eq(const struct chamelium *chamelium,
 			       const struct chamelium_frame_dump *dump,
 			       struct igt_fb *fb)
 {
-	cairo_t *cr;
 	cairo_surface_t *fb_surface;
 	pixman_image_t *reference_src, *reference_bgr;
 	int w = dump->width, h = dump->height;
 	bool eq;
 
 	/* Get the cairo surface for the framebuffer */
-	cr = igt_get_cairo_ctx(chamelium->drm_fd, fb);
-	fb_surface = cairo_get_target(cr);
-	cairo_surface_reference(fb_surface);
-	cairo_destroy(cr);
+	fb_surface = igt_get_cairo_surface(chamelium->drm_fd, fb);
 
 	/*
 	 * Convert the reference image into the same format as the chamelium
@@ -964,7 +960,6 @@ void chamelium_assert_frame_eq(const struct chamelium *chamelium,
 		    dump->size) == 0;
 
 	pixman_image_unref(reference_bgr);
-	cairo_surface_destroy(fb_surface);
 
 	igt_fail_on_f(!eq,
 		      "Chamelium frame dump didn't match reference image\n");
diff --git a/lib/igt_fb.c b/lib/igt_fb.c
index d2b7e9e3..93e21c17 100644
--- a/lib/igt_fb.c
+++ b/lib/igt_fb.c
@@ -1124,7 +1124,18 @@ static void create_cairo_surface__gtt(int fd, struct igt_fb *fb)
 				    fb, destroy_cairo_surface__gtt);
 }
 
-static cairo_surface_t *get_cairo_surface(int fd, struct igt_fb *fb)
+/**
+ * igt_get_cairo_surface:
+ * @fd: open drm file descriptor
+ * @fb: pointer to an #igt_fb structure
+ *
+ * This function stores the contents of the supplied framebuffer into a cairo
+ * surface and returns it.
+ *
+ * Returns:
+ * A pointer to a cairo surface with the contents of the framebuffer.
+ */
+cairo_surface_t *igt_get_cairo_surface(int fd, struct igt_fb *fb)
 {
 	if (fb->cairo_surface == NULL) {
 		if (fb->tiling == LOCAL_I915_FORMAT_MOD_Y_TILED ||
@@ -1160,7 +1171,7 @@ cairo_t *igt_get_cairo_ctx(int fd, struct igt_fb *fb)
 	cairo_surface_t *surface;
 	cairo_t *cr;
 
-	surface = get_cairo_surface(fd, fb);
+	surface = igt_get_cairo_surface(fd, fb);
 	cr = cairo_create(surface);
 	cairo_surface_destroy(surface);
 	igt_assert(cairo_status(cr) == CAIRO_STATUS_SUCCESS);
@@ -1173,27 +1184,6 @@ cairo_t *igt_get_cairo_ctx(int fd, struct igt_fb *fb)
 }
 
 /**
- * igt_write_fb_to_png:
- * @fd: open i915 drm file descriptor
- * @fb: pointer to an #igt_fb structure
- * @filename: target name for the png image
- *
- * This function stores the contents of the supplied framebuffer into a png
- * image stored at @filename.
- */
-void igt_write_fb_to_png(int fd, struct igt_fb *fb, const char *filename)
-{
-	cairo_surface_t *surface;
-	cairo_status_t status;
-
-	surface = get_cairo_surface(fd, fb);
-	status = cairo_surface_write_to_png(surface, filename);
-	cairo_surface_destroy(surface);
-
-	igt_assert(status == CAIRO_STATUS_SUCCESS);
-}
-
-/**
  * igt_remove_fb:
  * @fd: open i915 drm file descriptor
  * @fb: pointer to an #igt_fb structure
diff --git a/lib/igt_fb.h b/lib/igt_fb.h
index 4a680cef..f8a845cc 100644
--- a/lib/igt_fb.h
+++ b/lib/igt_fb.h
@@ -132,6 +132,7 @@ int igt_create_bo_with_dimensions(int fd, int width, int height, uint32_t format
 uint64_t igt_fb_mod_to_tiling(uint64_t modifier);
 
 /* cairo-based painting */
+cairo_surface_t *igt_get_cairo_surface(int fd, struct igt_fb *fb);
 cairo_t *igt_get_cairo_ctx(int fd, struct igt_fb *fb);
 void igt_paint_color(cairo_t *cr, int x, int y, int w, int h,
 			 double r, double g, double b);
@@ -145,7 +146,6 @@ void igt_paint_color_gradient_range(cairo_t *cr, int x, int y, int w, int h,
 void igt_paint_test_pattern(cairo_t *cr, int width, int height);
 void igt_paint_image(cairo_t *cr, const char *filename,
 			 int dst_x, int dst_y, int dst_width, int dst_height);
-void igt_write_fb_to_png(int fd, struct igt_fb *fb, const char *filename);
 int igt_cairo_printf_line(cairo_t *cr, enum igt_text_align align,
 			       double yspacing, const char *fmt, ...)
 			       __attribute__((format (printf, 4, 5)));
-- 
2.13.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH i-g-t v5 2/7] chamelium: Calculate CRC from framebuffer instead of hardcoding it
  2017-07-19 13:46 ` [PATCH i-g-t v5 " Paul Kocialkowski
  2017-07-19 13:46   ` [PATCH i-g-t v5 1/7] lib/igt_fb: Export the cairo surface instead of writing to a png Paul Kocialkowski
@ 2017-07-19 13:46   ` Paul Kocialkowski
  2017-07-19 13:46   ` [PATCH i-g-t v5 3/7] lib/igt_debugfs: Introduce CRC check function, with logic made common Paul Kocialkowski
                     ` (6 subsequent siblings)
  8 siblings, 0 replies; 57+ messages in thread
From: Paul Kocialkowski @ 2017-07-19 13:46 UTC (permalink / raw)
  To: intel-gfx

This introduces CRC calculation for reference frames, instead of using
hardcoded values for them. The rendering of reference frames may differ
from machine to machine, especially due to font rendering, and the
frame itself may change with subsequent IGT changes.

These differences would cause the CRC checks to fail on different
setups. This allows them to pass regardless of the setup.

Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
---
 lib/igt_chamelium.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/igt_chamelium.h |   5 ++
 tests/chamelium.c   |  77 +++++++---------------------
 3 files changed, 167 insertions(+), 58 deletions(-)

diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
index 93392af7..abcdc522 100644
--- a/lib/igt_chamelium.c
+++ b/lib/igt_chamelium.c
@@ -94,6 +94,13 @@ struct chamelium_frame_dump {
 	struct chamelium_port *port;
 };
 
+struct chamelium_fb_crc_async_data {
+	cairo_surface_t *fb_surface;
+
+	pthread_t thread_id;
+	igt_crc_t *ret;
+};
+
 struct chamelium {
 	xmlrpc_env env;
 	xmlrpc_client *client;
@@ -998,6 +1005,142 @@ int chamelium_get_frame_limit(struct chamelium *chamelium,
 	return ret;
 }
 
+static uint32_t chamelium_xrgb_hash16(const unsigned char *buffer, int width,
+				      int height, int k, int m)
+{
+	unsigned char r, g, b;
+	uint64_t sum = 0;
+	uint64_t count = 0;
+	uint64_t value;
+	uint32_t hash;
+	int index;
+	int i;
+
+	for (i=0; i < width * height; i++) {
+		if ((i % m) != k)
+			continue;
+
+		index = i * 4;
+
+		r = buffer[index + 2];
+		g = buffer[index + 1];
+		b = buffer[index + 0];
+
+		value = r | (g << 8) | (b << 16);
+		sum += ++count * value;
+	}
+
+	hash = ((sum >> 0) ^ (sum >> 16) ^ (sum >> 32) ^ (sum >> 48)) & 0xffff;
+
+	return hash;
+}
+
+static void chamelium_do_calculate_fb_crc(cairo_surface_t *fb_surface,
+					  igt_crc_t *out)
+{
+	unsigned char *buffer;
+	int n = 4;
+	int w, h;
+	int i, j;
+
+	buffer = cairo_image_surface_get_data(fb_surface);
+	w = cairo_image_surface_get_width(fb_surface);
+	h = cairo_image_surface_get_height(fb_surface);
+
+	for (i = 0; i < n; i++) {
+		j = n - i - 1;
+		out->crc[i] = chamelium_xrgb_hash16(buffer, w, h, j, n);
+	}
+
+	out->n_words = n;
+}
+
+/**
+ * chamelium_calculate_fb_crc:
+ * @fd: The drm file descriptor
+ * @fb: The framebuffer to calculate the CRC for
+ *
+ * Calculates the CRC for the provided framebuffer, using the Chamelium's CRC
+ * algorithm. This calculates the CRC in a synchronous fashion.
+ *
+ * Returns: The calculated CRC
+ */
+igt_crc_t *chamelium_calculate_fb_crc(int fd, struct igt_fb *fb)
+{
+	igt_crc_t *ret = calloc(1, sizeof(igt_crc_t));
+	cairo_surface_t *fb_surface;
+
+	/* Get the cairo surface for the framebuffer */
+	fb_surface = igt_get_cairo_surface(fd, fb);
+
+	chamelium_do_calculate_fb_crc(fb_surface, ret);
+
+	return ret;
+}
+
+static void *chamelium_calculate_fb_crc_async_work(void *data)
+{
+	struct chamelium_fb_crc_async_data *fb_crc;
+
+	fb_crc = (struct chamelium_fb_crc_async_data *) data;
+
+	chamelium_do_calculate_fb_crc(fb_crc->fb_surface, fb_crc->ret);
+
+	return NULL;
+}
+
+/**
+ * chamelium_calculate_fb_crc_launch:
+ * @fd: The drm file descriptor
+ * @fb: The framebuffer to calculate the CRC for
+ *
+ * Launches the CRC calculation for the provided framebuffer, using the
+ * Chamelium's CRC algorithm. This calculates the CRC in an asynchronous
+ * fashion.
+ *
+ * The returned structure should be passed to a subsequent call to
+ * chamelium_calculate_fb_crc_result. It should not be freed.
+ *
+ * Returns: An intermediate structure for the CRC calculation work.
+ */
+struct chamelium_fb_crc_async_data *chamelium_calculate_fb_crc_async_start(int fd,
+									   struct igt_fb *fb)
+{
+	struct chamelium_fb_crc_async_data *fb_crc;
+
+	fb_crc = calloc(1, sizeof(struct chamelium_fb_crc_async_data));
+	fb_crc->ret = calloc(1, sizeof(igt_crc_t));
+
+	/* Get the cairo surface for the framebuffer */
+	fb_crc->fb_surface = igt_get_cairo_surface(fd, fb);
+
+	pthread_create(&fb_crc->thread_id, NULL,
+		       chamelium_calculate_fb_crc_async_work, fb_crc);
+
+	return fb_crc;
+}
+
+/**
+ * chamelium_calculate_fb_crc_result:
+ * @fb_crc: An intermediate structure with thread-related information
+ *
+ * Blocks until the asynchronous CRC calculation is finished, and then returns
+ * its result.
+ *
+ * Returns: The calculated CRC
+ */
+igt_crc_t *chamelium_calculate_fb_crc_async_finish(struct chamelium_fb_crc_async_data *fb_crc)
+{
+	igt_crc_t *ret;
+
+	pthread_join(fb_crc->thread_id, NULL);
+
+	ret = fb_crc->ret;
+	free(fb_crc);
+
+	return ret;
+}
+
 static unsigned int chamelium_get_port_type(struct chamelium *chamelium,
 					    struct chamelium_port *port)
 {
diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
index 81322ad2..2bfbfdc7 100644
--- a/lib/igt_chamelium.h
+++ b/lib/igt_chamelium.h
@@ -36,6 +36,7 @@
 struct chamelium;
 struct chamelium_port;
 struct chamelium_frame_dump;
+struct chamelium_fb_crc_async_data;
 
 struct chamelium *chamelium_init(int drm_fd);
 void chamelium_deinit(struct chamelium *chamelium);
@@ -92,6 +93,10 @@ struct chamelium_frame_dump *chamelium_port_dump_pixels(struct chamelium *chamel
 							struct chamelium_port *port,
 							int x, int y,
 							int w, int h);
+igt_crc_t *chamelium_calculate_fb_crc(int fd, struct igt_fb *fb);
+struct chamelium_fb_crc_async_data *chamelium_calculate_fb_crc_async_start(int fd,
+									   struct igt_fb *fb);
+igt_crc_t *chamelium_calculate_fb_crc_async_finish(struct chamelium_fb_crc_async_data *fb_crc);
 int chamelium_get_captured_frame_count(struct chamelium *chamelium);
 int chamelium_get_frame_limit(struct chamelium *chamelium,
 			      struct chamelium_port *port,
diff --git a/tests/chamelium.c b/tests/chamelium.c
index 0528ffb3..ecd0434c 100644
--- a/tests/chamelium.c
+++ b/tests/chamelium.c
@@ -49,43 +49,6 @@ typedef struct {
 #define HPD_TOGGLE_COUNT_VGA 5
 #define HPD_TOGGLE_COUNT_DP_HDMI 15
 
-/* Pre-calculated CRCs for the pattern fb, for all the modes in the default
- * chamelium edid
- */
-struct crc_entry {
-	int width;
-	int height;
-	igt_crc_t crc;
-};
-
-#define CRC_ENTRY(w_, h_, ...) \
-	{ w_, h_, { .n_words = 4, .crc = { __VA_ARGS__ } } }
-
-static const struct crc_entry pattern_fb_crcs[] = {
-	CRC_ENTRY(1920, 1080, 0xf859, 0xa751, 0x8c81, 0x45a1),
-	CRC_ENTRY(1280,  720, 0xcec2, 0x4246, 0x6cfd, 0xeb43),
-	CRC_ENTRY(1024,  768, 0x85e5, 0xf0cd, 0xafe3, 0x7f18),
-	CRC_ENTRY( 800,  600, 0x6b39, 0x32b6, 0x831a, 0xb03e),
-	CRC_ENTRY( 640,  480, 0xa121, 0x2473, 0xb150, 0x8c47),
-};
-#undef CRC_ENTRY
-
-static const igt_crc_t *
-get_precalculated_crc(struct chamelium_port *port, int w, int h)
-{
-	int i;
-	const struct crc_entry *entry;
-
-	for (i = 0; i < ARRAY_SIZE(pattern_fb_crcs); i++) {
-		entry = &pattern_fb_crcs[i];
-
-		if (entry->width == w && entry->height == h)
-			return &entry->crc;
-	}
-
-	return NULL;
-}
-
 static void
 get_connectors_link_status_failed(data_t *data, bool *link_status_failed)
 {
@@ -463,7 +426,8 @@ test_display_crc_single(data_t *data, struct chamelium_port *port)
 	igt_output_t *output;
 	igt_plane_t *primary;
 	igt_crc_t *crc;
-	const igt_crc_t *expected_crc;
+	igt_crc_t *expected_crc;
+	struct chamelium_fb_crc_async_data *fb_crc;
 	struct igt_fb fb;
 	drmModeModeInfo *mode;
 	drmModeConnector *connector;
@@ -486,24 +450,21 @@ test_display_crc_single(data_t *data, struct chamelium_port *port)
 						    0, 0, 0, &fb);
 		igt_assert(fb_id > 0);
 
+		fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd,
+								&fb);
 		enable_output(data, port, output, mode, &fb);
 
-		expected_crc = get_precalculated_crc(port,
-						     mode->hdisplay,
-						     mode->vdisplay);
-		if (!expected_crc) {
-			igt_warn("No precalculated CRC found for %dx%d, skipping CRC check\n",
-				 mode->hdisplay, mode->vdisplay);
-			goto next;
-		}
-
 		igt_debug("Testing single CRC fetch\n");
+
 		crc = chamelium_get_crc_for_area(data->chamelium, port,
 						 0, 0, 0, 0);
+
+		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
+
 		igt_assert_crc_equal(crc, expected_crc);
+		free(expected_crc);
 		free(crc);
 
-next:
 		disable_output(data, port, output);
 		igt_remove_fb(data->drm_fd, &fb);
 	}
@@ -519,7 +480,8 @@ test_display_crc_multiple(data_t *data, struct chamelium_port *port)
 	igt_output_t *output;
 	igt_plane_t *primary;
 	igt_crc_t *crc;
-	const igt_crc_t *expected_crc;
+	igt_crc_t *expected_crc;
+	struct chamelium_fb_crc_async_data *fb_crc;
 	struct igt_fb fb;
 	drmModeModeInfo *mode;
 	drmModeConnector *connector;
@@ -542,15 +504,10 @@ test_display_crc_multiple(data_t *data, struct chamelium_port *port)
 						    0, 0, 0, &fb);
 		igt_assert(fb_id > 0);
 
-		enable_output(data, port, output, mode, &fb);
+		fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd,
+								&fb);
 
-		expected_crc = get_precalculated_crc(port, mode->hdisplay,
-						     mode->vdisplay);
-		if (!expected_crc) {
-			igt_warn("No precalculated CRC found for %dx%d, skipping CRC check\n",
-				 mode->hdisplay, mode->vdisplay);
-			goto next;
-		}
+		enable_output(data, port, output, mode, &fb);
 
 		/* We want to keep the display running for a little bit, since
 		 * there's always the potential the driver isn't able to keep
@@ -561,11 +518,15 @@ test_display_crc_multiple(data_t *data, struct chamelium_port *port)
 						   &captured_frame_count);
 
 		igt_debug("Captured %d frames\n", captured_frame_count);
+
+		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
+
 		for (j = 0; j < captured_frame_count; j++)
 			igt_assert_crc_equal(&crc[j], expected_crc);
+
+		free(expected_crc);
 		free(crc);
 
-next:
 		disable_output(data, port, output);
 		igt_remove_fb(data->drm_fd, &fb);
 	}
-- 
2.13.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH i-g-t v5 3/7] lib/igt_debugfs: Introduce CRC check function, with logic made common
  2017-07-19 13:46 ` [PATCH i-g-t v5 " Paul Kocialkowski
  2017-07-19 13:46   ` [PATCH i-g-t v5 1/7] lib/igt_fb: Export the cairo surface instead of writing to a png Paul Kocialkowski
  2017-07-19 13:46   ` [PATCH i-g-t v5 2/7] chamelium: Calculate CRC from framebuffer instead of hardcoding it Paul Kocialkowski
@ 2017-07-19 13:46   ` Paul Kocialkowski
  2017-07-19 13:46   ` [PATCH i-g-t v5 4/7] Introduce common frame dumping configuration and helpers Paul Kocialkowski
                     ` (5 subsequent siblings)
  8 siblings, 0 replies; 57+ messages in thread
From: Paul Kocialkowski @ 2017-07-19 13:46 UTC (permalink / raw)
  To: intel-gfx

This introduces an igt_check_crc_equal function in addition to
igt_assert_crc_equal and makes the CRC comparison logic from the latter
common. In particular, an igt_find_crc_mismatch function indicates
whether there is a mistmatch and at what index, so that the calling
functions can print the diverging values.

Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
---
 lib/igt_debugfs.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++---
 lib/igt_debugfs.h |  1 +
 2 files changed, 51 insertions(+), 3 deletions(-)

diff --git a/lib/igt_debugfs.c b/lib/igt_debugfs.c
index 2702686a..ef05dc77 100644
--- a/lib/igt_debugfs.c
+++ b/lib/igt_debugfs.c
@@ -281,6 +281,26 @@ bool igt_debugfs_search(int device, const char *filename, const char *substring)
  * Pipe CRC
  */
 
+static bool igt_find_crc_mismatch(const igt_crc_t *a, const igt_crc_t *b,
+				  int *index)
+{
+	int i;
+
+	if (a->n_words != b->n_words)
+		return true;
+
+	for (i = 0; i < a->n_words; i++) {
+		if (a->crc[i] != b->crc[i]) {
+			if (index)
+				*index = i;
+
+			return true;
+		}
+	}
+
+	return false;
+}
+
 /**
  * igt_assert_crc_equal:
  * @a: first pipe CRC value
@@ -294,10 +314,37 @@ bool igt_debugfs_search(int device, const char *filename, const char *substring)
  */
 void igt_assert_crc_equal(const igt_crc_t *a, const igt_crc_t *b)
 {
-	int i;
+	int index;
+	bool mismatch;
+
+	mismatch = igt_find_crc_mismatch(a, b, &index);
+	if (mismatch)
+		igt_debug("CRC mismatch at index %d: 0x%x != 0x%x\n", index,
+			  a->crc[index], b->crc[index]);
+
+	igt_assert(!mismatch);
+}
+
+/**
+ * igt_check_crc_equal:
+ * @a: first pipe CRC value
+ * @b: second pipe CRC value
+ *
+ * Compares two CRC values and return whether they match.
+ *
+ * Returns: A boolean indicating whether the CRC values match
+ */
+bool igt_check_crc_equal(const igt_crc_t *a, const igt_crc_t *b)
+{
+	int index;
+	bool mismatch;
+
+	mismatch = igt_find_crc_mismatch(a, b, &index);
+	if (mismatch)
+		igt_debug("CRC mismatch at index %d: 0x%x != 0x%x\n", index,
+			  a->crc[index], b->crc[index]);
 
-	for (i = 0; i < a->n_words; i++)
-		igt_assert_eq_u32(a->crc[i], b->crc[i]);
+	return !mismatch;
 }
 
 /**
diff --git a/lib/igt_debugfs.h b/lib/igt_debugfs.h
index 7b846a83..fe355919 100644
--- a/lib/igt_debugfs.h
+++ b/lib/igt_debugfs.h
@@ -114,6 +114,7 @@ enum intel_pipe_crc_source {
 };
 
 void igt_assert_crc_equal(const igt_crc_t *a, const igt_crc_t *b);
+bool igt_check_crc_equal(const igt_crc_t *a, const igt_crc_t *b);
 char *igt_crc_to_string(igt_crc_t *crc);
 
 void igt_require_pipe_crc(int fd);
-- 
2.13.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH i-g-t v5 4/7] Introduce common frame dumping configuration and helpers
  2017-07-19 13:46 ` [PATCH i-g-t v5 " Paul Kocialkowski
                     ` (2 preceding siblings ...)
  2017-07-19 13:46   ` [PATCH i-g-t v5 3/7] lib/igt_debugfs: Introduce CRC check function, with logic made common Paul Kocialkowski
@ 2017-07-19 13:46   ` Paul Kocialkowski
  2017-07-20  7:24     ` Daniel Vetter
  2017-07-19 13:46   ` [PATCH i-g-t v5 5/7] lib/igt_debugfs: Add extended helper to format crc to string Paul Kocialkowski
                     ` (4 subsequent siblings)
  8 siblings, 1 reply; 57+ messages in thread
From: Paul Kocialkowski @ 2017-07-19 13:46 UTC (permalink / raw)
  To: intel-gfx

This introduces a common FrameDumpPath configuration field, as well as
helper functions in dedicated igt_frame for writing cairo surfaces
to png files.

Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
---
 lib/Makefile.sources |   2 +
 lib/igt.h            |   1 +
 lib/igt_core.c       |  12 +++++
 lib/igt_core.h       |   2 +-
 lib/igt_frame.c      | 137 +++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/igt_frame.h      |  43 ++++++++++++++++
 6 files changed, 196 insertions(+), 1 deletion(-)
 create mode 100644 lib/igt_frame.c
 create mode 100644 lib/igt_frame.h

diff --git a/lib/Makefile.sources b/lib/Makefile.sources
index 53fdb54c..c2e58809 100644
--- a/lib/Makefile.sources
+++ b/lib/Makefile.sources
@@ -83,6 +83,8 @@ lib_source_list =	 	\
 	uwildmat/uwildmat.c	\
 	igt_kmod.c		\
 	igt_kmod.h		\
+	igt_frame.c		\
+	igt_frame.h		\
 	$(NULL)
 
 .PHONY: version.h.tmp
diff --git a/lib/igt.h b/lib/igt.h
index a069deb3..d16a4991 100644
--- a/lib/igt.h
+++ b/lib/igt.h
@@ -34,6 +34,7 @@
 #include "igt_draw.h"
 #include "igt_dummyload.h"
 #include "igt_fb.h"
+#include "igt_frame.h"
 #include "igt_gt.h"
 #include "igt_kms.h"
 #include "igt_pm.h"
diff --git a/lib/igt_core.c b/lib/igt_core.c
index 1ba79361..5a3b00e8 100644
--- a/lib/igt_core.c
+++ b/lib/igt_core.c
@@ -235,6 +235,10 @@
  * An example configuration follows:
  *
  * |[<!-- language="plain" -->
+ *	# The common configuration secton follows.
+ *	[Common]
+ *	FrameDumpPath=/tmp # The path to dump frames that fail comparison checks
+ *
  *	# The following section is used for configuring the Device Under Test.
  *	# It is not mandatory and allows overriding default values.
  *	[DUT]
@@ -290,6 +294,7 @@ static struct {
 static pthread_mutex_t log_buffer_mutex = PTHREAD_MUTEX_INITIALIZER;
 
 GKeyFile *igt_key_file;
+char *frame_dump_path;
 
 const char *igt_test_name(void)
 {
@@ -621,6 +626,13 @@ static int config_parse(void)
 	if (!igt_key_file)
 		return 0;
 
+	frame_dump_path = getenv("IGT_FRAME_DUMP_PATH");
+
+	if (!frame_dump_path)
+		frame_dump_path = g_key_file_get_string(igt_key_file, "Common",
+							"FrameDumpPath",
+							&error);
+
 	rc = g_key_file_get_integer(igt_key_file, "DUT", "SuspendResumeDelay",
 				    &error);
 	if (error && error->code == G_KEY_FILE_ERROR_INVALID_VALUE)
diff --git a/lib/igt_core.h b/lib/igt_core.h
index 0739ca83..1619a9d6 100644
--- a/lib/igt_core.h
+++ b/lib/igt_core.h
@@ -50,7 +50,7 @@
 extern const char* __igt_test_description __attribute__((weak));
 extern bool __igt_plain_output;
 extern GKeyFile *igt_key_file;
-
+extern char *frame_dump_path;
 
 /**
  * IGT_TEST_DESCRIPTION:
diff --git a/lib/igt_frame.c b/lib/igt_frame.c
new file mode 100644
index 00000000..dfafe53d
--- /dev/null
+++ b/lib/igt_frame.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright © 2017 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.
+ *
+ * Authors:
+ *  Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
+ */
+
+#include "config.h"
+
+#include <fcntl.h>
+#include <pixman.h>
+#include <cairo.h>
+
+#include "igt.h"
+
+/**
+ * SECTION:igt_frame
+ * @short_description: Library for frame-related tests
+ * @title: Frame
+ * @include: igt_frame.h
+ *
+ * This library contains helpers for frame-related tests. This includes common
+ * frame dumping as well as frame comparison helpers.
+ */
+
+/**
+ * igt_frame_dump_is_enabled:
+ *
+ * Get whether frame dumping is enabled.
+ *
+ * Returns: A boolean indicating whether frame dumping is enabled
+ */
+bool igt_frame_dump_is_enabled(void)
+{
+	return frame_dump_path != NULL;
+}
+
+static void igt_write_frame_to_png(cairo_surface_t *surface, int fd,
+				   const char *qualifier, const char *suffix)
+{
+	char path[PATH_MAX];
+	const char *test_name;
+	const char *subtest_name;
+	cairo_status_t status;
+	int index;
+
+	test_name = igt_test_name();
+	subtest_name = igt_subtest_name();
+
+	if (suffix)
+		snprintf(path, PATH_MAX, "%s/frame-%s-%s-%s-%s.png",
+			 frame_dump_path, test_name, subtest_name, qualifier,
+			 suffix);
+	else
+		snprintf(path, PATH_MAX, "%s/frame-%s-%s-%s.png",
+			 frame_dump_path, test_name, subtest_name, qualifier);
+
+	igt_debug("Dumping %s frame to %s...\n", qualifier, path);
+
+	status = cairo_surface_write_to_png(surface, path);
+
+	igt_assert_eq(status, CAIRO_STATUS_SUCCESS);
+
+	index = strlen(path);
+
+	if (fd >= 0 && index < (PATH_MAX - 1)) {
+		path[index++] = '\n';
+		path[index] = '\0';
+
+		write(fd, path, strlen(path));
+	}
+}
+
+/**
+ * igt_write_compared_frames_to_png:
+ * @reference: The reference cairo surface
+ * @capture: The captured cairo surface
+ * @reference_suffix: The suffix to give to the reference png file
+ * @capture_suffix: The suffix to give to the capture png file
+ *
+ * Write previously compared frames to png files.
+ */
+void igt_write_compared_frames_to_png(cairo_surface_t *reference,
+				      cairo_surface_t *capture,
+				      const char *reference_suffix,
+				      const char *capture_suffix)
+{
+	char *id;
+	const char *test_name;
+	const char *subtest_name;
+	char path[PATH_MAX];
+	int fd = -1;
+
+	if (!igt_frame_dump_is_enabled())
+		return;
+
+	id = getenv("IGT_FRAME_DUMP_ID");
+
+	test_name = igt_test_name();
+	subtest_name = igt_subtest_name();
+
+	if (id)
+		snprintf(path, PATH_MAX, "%s/frame-%s-%s-%s.txt",
+			 frame_dump_path, test_name, subtest_name, id);
+	else
+		snprintf(path, PATH_MAX, "%s/frame-%s-%s.txt",
+			 frame_dump_path, test_name, subtest_name);
+
+	fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+	igt_assert(fd >= 0);
+
+	igt_debug("Writing dump report to %s...\n", path);
+
+	igt_write_frame_to_png(reference, fd, "reference", reference_suffix);
+	igt_write_frame_to_png(capture, fd, "capture", capture_suffix);
+
+	close(fd);
+}
diff --git a/lib/igt_frame.h b/lib/igt_frame.h
new file mode 100644
index 00000000..ec6a1643
--- /dev/null
+++ b/lib/igt_frame.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright © 2017 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.
+ *
+ * Authors:
+ *  Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
+ */
+
+#ifndef IGT_FRAME_H
+#define IGT_FRAME_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "igt.h"
+#include <stdbool.h>
+
+bool igt_frame_dump_is_enabled(void);
+void igt_write_compared_frames_to_png(cairo_surface_t *reference,
+				      cairo_surface_t *capture,
+				      const char *reference_suffix,
+				      const char *capture_suffix);
+
+#endif
-- 
2.13.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH i-g-t v5 5/7] lib/igt_debugfs: Add extended helper to format crc to string
  2017-07-19 13:46 ` [PATCH i-g-t v5 " Paul Kocialkowski
                     ` (3 preceding siblings ...)
  2017-07-19 13:46   ` [PATCH i-g-t v5 4/7] Introduce common frame dumping configuration and helpers Paul Kocialkowski
@ 2017-07-19 13:46   ` Paul Kocialkowski
  2017-07-19 13:46   ` [PATCH i-g-t v5 6/7] chamelium: Dump captured and reference frames to png on crc error Paul Kocialkowski
                     ` (3 subsequent siblings)
  8 siblings, 0 replies; 57+ messages in thread
From: Paul Kocialkowski @ 2017-07-19 13:46 UTC (permalink / raw)
  To: intel-gfx

This introduces a igt_crc_to_string_extended helper that allows
formatting a crc to a string with a given delimiter and size to print
per crc word.

Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
---
 lib/igt_debugfs.c | 27 +++++++++++++++++++++++----
 lib/igt_debugfs.h |  1 +
 2 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/lib/igt_debugfs.c b/lib/igt_debugfs.c
index ef05dc77..2aa33586 100644
--- a/lib/igt_debugfs.c
+++ b/lib/igt_debugfs.c
@@ -348,28 +348,47 @@ bool igt_check_crc_equal(const igt_crc_t *a, const igt_crc_t *b)
 }
 
 /**
- * igt_crc_to_string:
+ * igt_crc_to_string_extended:
  * @crc: pipe CRC value to print
+ * @delimiter: The delimiter to use between crc words
+ * @crc_size: the number of bytes to print per crc word (either 4 or 2)
  *
- * This function allocates a string and formats @crc into it.
+ * This function allocates a string and formats @crc into it, depending on
+ * @delimiter and @crc_size.
  * The caller is responsible for freeing the string.
  *
  * This should only ever be used for diagnostic debug output.
  */
-char *igt_crc_to_string(igt_crc_t *crc)
+char *igt_crc_to_string_extended(igt_crc_t *crc, char delimiter, int crc_size)
 {
 	int i;
 	char *buf = calloc(128, sizeof(char));
+	const char *format[2] = { "%08x%c", "%04x%c" };
 
 	if (!buf)
 		return NULL;
 
 	for (i = 0; i < crc->n_words; i++)
-		sprintf(buf + strlen(buf), "%08x ", crc->crc[i]);
+		sprintf(buf + strlen(buf), format[crc_size == 2], crc->crc[i],
+			i == (crc->n_words - 1) ? '\0' : delimiter);
 
 	return buf;
 }
 
+/**
+ * igt_crc_to_string:
+ * @crc: pipe CRC value to print
+ *
+ * This function allocates a string and formats @crc into it.
+ * The caller is responsible for freeing the string.
+ *
+ * This should only ever be used for diagnostic debug output.
+ */
+char *igt_crc_to_string(igt_crc_t *crc)
+{
+	return igt_crc_to_string_extended(crc, ' ', 4);
+}
+
 #define MAX_CRC_ENTRIES 10
 #define MAX_LINE_LEN (10 + 11 * MAX_CRC_ENTRIES + 1)
 
diff --git a/lib/igt_debugfs.h b/lib/igt_debugfs.h
index fe355919..f1a76406 100644
--- a/lib/igt_debugfs.h
+++ b/lib/igt_debugfs.h
@@ -115,6 +115,7 @@ enum intel_pipe_crc_source {
 
 void igt_assert_crc_equal(const igt_crc_t *a, const igt_crc_t *b);
 bool igt_check_crc_equal(const igt_crc_t *a, const igt_crc_t *b);
+char *igt_crc_to_string_extended(igt_crc_t *crc, char delimiter, int crc_size);
 char *igt_crc_to_string(igt_crc_t *crc);
 
 void igt_require_pipe_crc(int fd);
-- 
2.13.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH i-g-t v5 6/7] chamelium: Dump captured and reference frames to png on crc error
  2017-07-19 13:46 ` [PATCH i-g-t v5 " Paul Kocialkowski
                     ` (4 preceding siblings ...)
  2017-07-19 13:46   ` [PATCH i-g-t v5 5/7] lib/igt_debugfs: Add extended helper to format crc to string Paul Kocialkowski
@ 2017-07-19 13:46   ` Paul Kocialkowski
  2017-07-19 13:46   ` [PATCH i-g-t v5 7/7] tests/chamelium: Merge the crc testing functions into one Paul Kocialkowski
                     ` (2 subsequent siblings)
  8 siblings, 0 replies; 57+ messages in thread
From: Paul Kocialkowski @ 2017-07-19 13:46 UTC (permalink / raw)
  To: intel-gfx

This adds support for dumping both the frame capture from the chamelium
and the reference frame generated by cairo when the captured crc does
not match the crc calculated from the reference, using common helpers.

Getting a dump of the frames is quite useful in order to compare them.

Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
---
 lib/igt_chamelium.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/igt_chamelium.h |  4 +++
 tests/chamelium.c   | 14 ++++++---
 3 files changed, 95 insertions(+), 4 deletions(-)

diff --git a/lib/igt_chamelium.c b/lib/igt_chamelium.c
index abcdc522..348d2176 100644
--- a/lib/igt_chamelium.c
+++ b/lib/igt_chamelium.c
@@ -929,6 +929,32 @@ static pixman_image_t *convert_frame_format(pixman_image_t *src,
 	return converted;
 }
 
+static cairo_surface_t *convert_frame_dump_argb32(const struct chamelium_frame_dump *dump)
+{
+	cairo_surface_t *dump_surface;
+	pixman_image_t *image_bgr;
+	pixman_image_t *image_argb;
+	int w = dump->width, h = dump->height;
+	uint32_t *bits_bgr = (uint32_t *) dump->bgr;
+	unsigned char *bits_argb;
+
+	image_bgr = pixman_image_create_bits(
+	    PIXMAN_b8g8r8, w, h, bits_bgr,
+	    PIXMAN_FORMAT_BPP(PIXMAN_b8g8r8) / 8 * w);
+	image_argb = convert_frame_format(image_bgr, PIXMAN_x8r8g8b8);
+	pixman_image_unref(image_bgr);
+
+	bits_argb = (unsigned char *) pixman_image_get_data(image_argb);
+
+	dump_surface = cairo_image_surface_create_for_data(
+	    bits_argb, CAIRO_FORMAT_ARGB32, w, h,
+	    PIXMAN_FORMAT_BPP(PIXMAN_x8r8g8b8) / 8 * w);
+
+	pixman_image_unref(image_argb);
+
+	return dump_surface;
+}
+
 /**
  * chamelium_assert_frame_eq:
  * @chamelium: The chamelium instance the frame dump belongs to
@@ -973,6 +999,61 @@ void chamelium_assert_frame_eq(const struct chamelium *chamelium,
 }
 
 /**
+ * chamelium_assert_crc_eq_or_dump:
+ * @chamelium: The chamelium instance the frame dump belongs to
+ * @reference_crc: The CRC for the reference frame
+ * @capture_crc: The CRC for the captured frame
+ * @fb: pointer to an #igt_fb structure
+ *
+ * Asserts that the CRC provided for both the reference and the captured frame
+ * are identical. If they are not, this grabs the captured frame and saves it
+ * along with the reference to a png file.
+ */
+void chamelium_assert_crc_eq_or_dump(struct chamelium *chamelium,
+				     igt_crc_t *reference_crc,
+				     igt_crc_t *capture_crc, struct igt_fb *fb,
+				     int index)
+{
+	struct chamelium_frame_dump *frame;
+	cairo_surface_t *reference;
+	cairo_surface_t *capture;
+	char *reference_suffix;
+	char *capture_suffix;
+	bool eq;
+
+	eq = igt_check_crc_equal(reference_crc, capture_crc);
+	if (!eq && igt_frame_dump_is_enabled()) {
+		/* Grab the reference frame from framebuffer */
+		reference = igt_get_cairo_surface(chamelium->drm_fd, fb);
+
+		/* Grab the captured frame from chamelium */
+		frame = chamelium_read_captured_frame(chamelium, index);
+		igt_assert(frame);
+
+		capture = convert_frame_dump_argb32(frame);
+
+		reference_suffix = igt_crc_to_string_extended(reference_crc,
+							      '-', 2);
+		capture_suffix = igt_crc_to_string_extended(capture_crc, '-',
+							    2);
+
+		/* Write reference and capture frames to png */
+		igt_write_compared_frames_to_png(reference, capture,
+						 reference_suffix,
+						 capture_suffix);
+
+		free(reference_suffix);
+		free(capture_suffix);
+
+		chamelium_destroy_frame_dump(frame);
+
+		cairo_surface_destroy(capture);
+	}
+
+	igt_assert(eq);
+}
+
+/**
  * chamelium_get_frame_limit:
  * @chamelium: The Chamelium instance to use
  * @port: The port to check the frame limit on
diff --git a/lib/igt_chamelium.h b/lib/igt_chamelium.h
index 2bfbfdc7..80afcafa 100644
--- a/lib/igt_chamelium.h
+++ b/lib/igt_chamelium.h
@@ -105,6 +105,10 @@ int chamelium_get_frame_limit(struct chamelium *chamelium,
 void chamelium_assert_frame_eq(const struct chamelium *chamelium,
 			       const struct chamelium_frame_dump *dump,
 			       struct igt_fb *fb);
+void chamelium_assert_crc_eq_or_dump(struct chamelium *chamelium,
+				     igt_crc_t *reference_crc,
+				     igt_crc_t *capture_crc, struct igt_fb *fb,
+				     int index);
 void chamelium_destroy_frame_dump(struct chamelium_frame_dump *dump);
 
 #endif /* IGT_CHAMELIUM_H */
diff --git a/tests/chamelium.c b/tests/chamelium.c
index ecd0434c..1567386e 100644
--- a/tests/chamelium.c
+++ b/tests/chamelium.c
@@ -431,7 +431,7 @@ test_display_crc_single(data_t *data, struct chamelium_port *port)
 	struct igt_fb fb;
 	drmModeModeInfo *mode;
 	drmModeConnector *connector;
-	int fb_id, i;
+	int fb_id, i, captured_frame_count;
 
 	reset_state(data, port);
 
@@ -456,11 +456,15 @@ test_display_crc_single(data_t *data, struct chamelium_port *port)
 
 		igt_debug("Testing single CRC fetch\n");
 
-		crc = chamelium_get_crc_for_area(data->chamelium, port,
-						 0, 0, 0, 0);
+		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 1);
+		crc = chamelium_read_captured_crcs(data->chamelium,
+						   &captured_frame_count);
 
 		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
 
+		chamelium_assert_crc_eq_or_dump(data->chamelium, expected_crc,
+						crc, &fb, 0);
+
 		igt_assert_crc_equal(crc, expected_crc);
 		free(expected_crc);
 		free(crc);
@@ -522,7 +526,9 @@ test_display_crc_multiple(data_t *data, struct chamelium_port *port)
 		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
 
 		for (j = 0; j < captured_frame_count; j++)
-			igt_assert_crc_equal(&crc[j], expected_crc);
+			chamelium_assert_crc_eq_or_dump(data->chamelium,
+							expected_crc, &crc[j],
+							&fb, j);
 
 		free(expected_crc);
 		free(crc);
-- 
2.13.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* [PATCH i-g-t v5 7/7] tests/chamelium: Merge the crc testing functions into one
  2017-07-19 13:46 ` [PATCH i-g-t v5 " Paul Kocialkowski
                     ` (5 preceding siblings ...)
  2017-07-19 13:46   ` [PATCH i-g-t v5 6/7] chamelium: Dump captured and reference frames to png on crc error Paul Kocialkowski
@ 2017-07-19 13:46   ` Paul Kocialkowski
  2017-07-19 16:09   ` [PATCH i-g-t v5 0/7] CRC testing with Chamelium improvements Lyude Paul
  2017-07-20  9:39   ` Jani Nikula
  8 siblings, 0 replies; 57+ messages in thread
From: Paul Kocialkowski @ 2017-07-19 13:46 UTC (permalink / raw)
  To: intel-gfx

This merges the two test_display_crc_single and
test_display_crc_multiple functions into one, with a variable number of
frames to capture. This reduces code duplication.

Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
---
 tests/chamelium.c | 72 +++++++------------------------------------------------
 1 file changed, 8 insertions(+), 64 deletions(-)

diff --git a/tests/chamelium.c b/tests/chamelium.c
index 1567386e..34448152 100644
--- a/tests/chamelium.c
+++ b/tests/chamelium.c
@@ -420,65 +420,7 @@ disable_output(data_t *data,
 }
 
 static void
-test_display_crc_single(data_t *data, struct chamelium_port *port)
-{
-	igt_display_t display;
-	igt_output_t *output;
-	igt_plane_t *primary;
-	igt_crc_t *crc;
-	igt_crc_t *expected_crc;
-	struct chamelium_fb_crc_async_data *fb_crc;
-	struct igt_fb fb;
-	drmModeModeInfo *mode;
-	drmModeConnector *connector;
-	int fb_id, i, captured_frame_count;
-
-	reset_state(data, port);
-
-	output = prepare_output(data, &display, port);
-	connector = chamelium_port_get_connector(data->chamelium, port, false);
-	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
-	igt_assert(primary);
-
-	for (i = 0; i < connector->count_modes; i++) {
-		mode = &connector->modes[i];
-		fb_id = igt_create_color_pattern_fb(data->drm_fd,
-						    mode->hdisplay,
-						    mode->vdisplay,
-						    DRM_FORMAT_XRGB8888,
-						    LOCAL_DRM_FORMAT_MOD_NONE,
-						    0, 0, 0, &fb);
-		igt_assert(fb_id > 0);
-
-		fb_crc = chamelium_calculate_fb_crc_async_start(data->drm_fd,
-								&fb);
-		enable_output(data, port, output, mode, &fb);
-
-		igt_debug("Testing single CRC fetch\n");
-
-		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 1);
-		crc = chamelium_read_captured_crcs(data->chamelium,
-						   &captured_frame_count);
-
-		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
-
-		chamelium_assert_crc_eq_or_dump(data->chamelium, expected_crc,
-						crc, &fb, 0);
-
-		igt_assert_crc_equal(crc, expected_crc);
-		free(expected_crc);
-		free(crc);
-
-		disable_output(data, port, output);
-		igt_remove_fb(data->drm_fd, &fb);
-	}
-
-	drmModeFreeConnector(connector);
-	igt_display_fini(&display);
-}
-
-static void
-test_display_crc_multiple(data_t *data, struct chamelium_port *port)
+test_display_crc(data_t *data, struct chamelium_port *port, int count)
 {
 	igt_display_t display;
 	igt_output_t *output;
@@ -517,10 +459,12 @@ test_display_crc_multiple(data_t *data, struct chamelium_port *port)
 		 * there's always the potential the driver isn't able to keep
 		 * the display running properly for very long
 		 */
-		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, 3);
+		chamelium_capture(data->chamelium, port, 0, 0, 0, 0, count);
 		crc = chamelium_read_captured_crcs(data->chamelium,
 						   &captured_frame_count);
 
+		igt_assert(captured_frame_count == count);
+
 		igt_debug("Captured %d frames\n", captured_frame_count);
 
 		expected_crc = chamelium_calculate_fb_crc_async_finish(fb_crc);
@@ -737,10 +681,10 @@ igt_main
 							edid_id, alt_edid_id);
 
 		connector_subtest("dp-crc-single", DisplayPort)
-			test_display_crc_single(&data, port);
+			test_display_crc(&data, port, 1);
 
 		connector_subtest("dp-crc-multiple", DisplayPort)
-			test_display_crc_multiple(&data, port);
+			test_display_crc(&data, port, 3);
 
 		connector_subtest("dp-frame-dump", DisplayPort)
 			test_display_frame_dump(&data, port);
@@ -794,10 +738,10 @@ igt_main
 							edid_id, alt_edid_id);
 
 		connector_subtest("hdmi-crc-single", HDMIA)
-			test_display_crc_single(&data, port);
+			test_display_crc(&data, port, 1);
 
 		connector_subtest("hdmi-crc-multiple", HDMIA)
-			test_display_crc_multiple(&data, port);
+			test_display_crc(&data, port, 3);
 
 		connector_subtest("hdmi-frame-dump", HDMIA)
 			test_display_frame_dump(&data, port);
-- 
2.13.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* Re: [PATCH i-g-t v5 0/7] CRC testing with Chamelium improvements
  2017-07-19 13:46 ` [PATCH i-g-t v5 " Paul Kocialkowski
                     ` (6 preceding siblings ...)
  2017-07-19 13:46   ` [PATCH i-g-t v5 7/7] tests/chamelium: Merge the crc testing functions into one Paul Kocialkowski
@ 2017-07-19 16:09   ` Lyude Paul
  2017-07-20  9:39   ` Jani Nikula
  8 siblings, 0 replies; 57+ messages in thread
From: Lyude Paul @ 2017-07-19 16:09 UTC (permalink / raw)
  To: Paul Kocialkowski, intel-gfx

Thank you for all of the great work you're doing! This looks perfect,
so for the whole series

Reviewed-by: Lyude <lyude@redhat.com>

I've pushed everything upstream, congrats!

On Wed, 2017-07-19 at 16:46 +0300, Paul Kocialkowski wrote:
> Changes since v4:
> * Moved igt_get_cairo_surface out of the thread function to properly
>   handle assert failure
> * Rebased on top of current master
> 
> Changes since v3:
> * Renamed structure used by async crc calculation for more clarity
> * Used const qualifier for untouched buffer when hashing
> * Split actual calculation to a dedicated function
> * Reworked async functions names for more clarity
> * Reworked descriptions for better accuracy
> * Exported framebuffer cairo surface and use it directly instead of
>   (unused) png dumping
> * Fix how the framebuffer cairo surface is obtained to avoid
> destroying
>   it too early
> 
> * Made CRC checking logic common
> * Added a check for the same number of words
> * Made frame dumping configuration and helpers common
> * Added an extended crc to string helper
> * Added a chamelium helper for crc checking and frame dumping
> * Split the merging of crc functions to a separate patch
> * Added support for frame dump path global variable
> * Added listing the dumped images in a file, possibly identified with
>   an id global variable
> 
> The latter allows having one "dump report" file per run, possibly
> identified with the id global variable, that indicates which files
> are the output, while keeping the possibility to have the same files
> for different runs. This allows saving significant disk space when
> the images are identified with e.g. their crc, so that duplicate
> results
> only lead to duplicate dump reports and not duplicate images.
> 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH i-g-t v5 4/7] Introduce common frame dumping configuration and helpers
  2017-07-19 13:46   ` [PATCH i-g-t v5 4/7] Introduce common frame dumping configuration and helpers Paul Kocialkowski
@ 2017-07-20  7:24     ` Daniel Vetter
  2017-07-20 14:14       ` Paul Kocialkowski
  0 siblings, 1 reply; 57+ messages in thread
From: Daniel Vetter @ 2017-07-20  7:24 UTC (permalink / raw)
  To: Paul Kocialkowski; +Cc: intel-gfx

On Wed, Jul 19, 2017 at 04:46:07PM +0300, Paul Kocialkowski wrote:
> This introduces a common FrameDumpPath configuration field, as well as
> helper functions in dedicated igt_frame for writing cairo surfaces
> to png files.
> 
> Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
> ---
>  lib/Makefile.sources |   2 +
>  lib/igt.h            |   1 +
>  lib/igt_core.c       |  12 +++++
>  lib/igt_core.h       |   2 +-
>  lib/igt_frame.c      | 137 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  lib/igt_frame.h      |  43 ++++++++++++++++

Please make sure you pull the new docs into the docs build too. And while
doing that, please review for other stuff added in the past year and
include that too. And please build the docs and check the result.

Thanks, Daniel

>  6 files changed, 196 insertions(+), 1 deletion(-)
>  create mode 100644 lib/igt_frame.c
>  create mode 100644 lib/igt_frame.h
> 
> diff --git a/lib/Makefile.sources b/lib/Makefile.sources
> index 53fdb54c..c2e58809 100644
> --- a/lib/Makefile.sources
> +++ b/lib/Makefile.sources
> @@ -83,6 +83,8 @@ lib_source_list =	 	\
>  	uwildmat/uwildmat.c	\
>  	igt_kmod.c		\
>  	igt_kmod.h		\
> +	igt_frame.c		\
> +	igt_frame.h		\
>  	$(NULL)
>  
>  .PHONY: version.h.tmp
> diff --git a/lib/igt.h b/lib/igt.h
> index a069deb3..d16a4991 100644
> --- a/lib/igt.h
> +++ b/lib/igt.h
> @@ -34,6 +34,7 @@
>  #include "igt_draw.h"
>  #include "igt_dummyload.h"
>  #include "igt_fb.h"
> +#include "igt_frame.h"
>  #include "igt_gt.h"
>  #include "igt_kms.h"
>  #include "igt_pm.h"
> diff --git a/lib/igt_core.c b/lib/igt_core.c
> index 1ba79361..5a3b00e8 100644
> --- a/lib/igt_core.c
> +++ b/lib/igt_core.c
> @@ -235,6 +235,10 @@
>   * An example configuration follows:
>   *
>   * |[<!-- language="plain" -->
> + *	# The common configuration secton follows.
> + *	[Common]
> + *	FrameDumpPath=/tmp # The path to dump frames that fail comparison checks
> + *
>   *	# The following section is used for configuring the Device Under Test.
>   *	# It is not mandatory and allows overriding default values.
>   *	[DUT]
> @@ -290,6 +294,7 @@ static struct {
>  static pthread_mutex_t log_buffer_mutex = PTHREAD_MUTEX_INITIALIZER;
>  
>  GKeyFile *igt_key_file;
> +char *frame_dump_path;
>  
>  const char *igt_test_name(void)
>  {
> @@ -621,6 +626,13 @@ static int config_parse(void)
>  	if (!igt_key_file)
>  		return 0;
>  
> +	frame_dump_path = getenv("IGT_FRAME_DUMP_PATH");
> +
> +	if (!frame_dump_path)
> +		frame_dump_path = g_key_file_get_string(igt_key_file, "Common",
> +							"FrameDumpPath",
> +							&error);
> +
>  	rc = g_key_file_get_integer(igt_key_file, "DUT", "SuspendResumeDelay",
>  				    &error);
>  	if (error && error->code == G_KEY_FILE_ERROR_INVALID_VALUE)
> diff --git a/lib/igt_core.h b/lib/igt_core.h
> index 0739ca83..1619a9d6 100644
> --- a/lib/igt_core.h
> +++ b/lib/igt_core.h
> @@ -50,7 +50,7 @@
>  extern const char* __igt_test_description __attribute__((weak));
>  extern bool __igt_plain_output;
>  extern GKeyFile *igt_key_file;
> -
> +extern char *frame_dump_path;
>  
>  /**
>   * IGT_TEST_DESCRIPTION:
> diff --git a/lib/igt_frame.c b/lib/igt_frame.c
> new file mode 100644
> index 00000000..dfafe53d
> --- /dev/null
> +++ b/lib/igt_frame.c
> @@ -0,0 +1,137 @@
> +/*
> + * Copyright © 2017 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.
> + *
> + * Authors:
> + *  Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
> + */
> +
> +#include "config.h"
> +
> +#include <fcntl.h>
> +#include <pixman.h>
> +#include <cairo.h>
> +
> +#include "igt.h"
> +
> +/**
> + * SECTION:igt_frame
> + * @short_description: Library for frame-related tests
> + * @title: Frame
> + * @include: igt_frame.h
> + *
> + * This library contains helpers for frame-related tests. This includes common
> + * frame dumping as well as frame comparison helpers.
> + */
> +
> +/**
> + * igt_frame_dump_is_enabled:
> + *
> + * Get whether frame dumping is enabled.
> + *
> + * Returns: A boolean indicating whether frame dumping is enabled
> + */
> +bool igt_frame_dump_is_enabled(void)
> +{
> +	return frame_dump_path != NULL;
> +}
> +
> +static void igt_write_frame_to_png(cairo_surface_t *surface, int fd,
> +				   const char *qualifier, const char *suffix)
> +{
> +	char path[PATH_MAX];
> +	const char *test_name;
> +	const char *subtest_name;
> +	cairo_status_t status;
> +	int index;
> +
> +	test_name = igt_test_name();
> +	subtest_name = igt_subtest_name();
> +
> +	if (suffix)
> +		snprintf(path, PATH_MAX, "%s/frame-%s-%s-%s-%s.png",
> +			 frame_dump_path, test_name, subtest_name, qualifier,
> +			 suffix);
> +	else
> +		snprintf(path, PATH_MAX, "%s/frame-%s-%s-%s.png",
> +			 frame_dump_path, test_name, subtest_name, qualifier);
> +
> +	igt_debug("Dumping %s frame to %s...\n", qualifier, path);
> +
> +	status = cairo_surface_write_to_png(surface, path);
> +
> +	igt_assert_eq(status, CAIRO_STATUS_SUCCESS);
> +
> +	index = strlen(path);
> +
> +	if (fd >= 0 && index < (PATH_MAX - 1)) {
> +		path[index++] = '\n';
> +		path[index] = '\0';
> +
> +		write(fd, path, strlen(path));
> +	}
> +}
> +
> +/**
> + * igt_write_compared_frames_to_png:
> + * @reference: The reference cairo surface
> + * @capture: The captured cairo surface
> + * @reference_suffix: The suffix to give to the reference png file
> + * @capture_suffix: The suffix to give to the capture png file
> + *
> + * Write previously compared frames to png files.
> + */
> +void igt_write_compared_frames_to_png(cairo_surface_t *reference,
> +				      cairo_surface_t *capture,
> +				      const char *reference_suffix,
> +				      const char *capture_suffix)
> +{
> +	char *id;
> +	const char *test_name;
> +	const char *subtest_name;
> +	char path[PATH_MAX];
> +	int fd = -1;
> +
> +	if (!igt_frame_dump_is_enabled())
> +		return;
> +
> +	id = getenv("IGT_FRAME_DUMP_ID");
> +
> +	test_name = igt_test_name();
> +	subtest_name = igt_subtest_name();
> +
> +	if (id)
> +		snprintf(path, PATH_MAX, "%s/frame-%s-%s-%s.txt",
> +			 frame_dump_path, test_name, subtest_name, id);
> +	else
> +		snprintf(path, PATH_MAX, "%s/frame-%s-%s.txt",
> +			 frame_dump_path, test_name, subtest_name);
> +
> +	fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
> +	igt_assert(fd >= 0);
> +
> +	igt_debug("Writing dump report to %s...\n", path);
> +
> +	igt_write_frame_to_png(reference, fd, "reference", reference_suffix);
> +	igt_write_frame_to_png(capture, fd, "capture", capture_suffix);
> +
> +	close(fd);
> +}
> diff --git a/lib/igt_frame.h b/lib/igt_frame.h
> new file mode 100644
> index 00000000..ec6a1643
> --- /dev/null
> +++ b/lib/igt_frame.h
> @@ -0,0 +1,43 @@
> +/*
> + * Copyright © 2017 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.
> + *
> + * Authors:
> + *  Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
> + */
> +
> +#ifndef IGT_FRAME_H
> +#define IGT_FRAME_H
> +
> +#ifdef HAVE_CONFIG_H
> +#include "config.h"
> +#endif
> +
> +#include "igt.h"
> +#include <stdbool.h>
> +
> +bool igt_frame_dump_is_enabled(void);
> +void igt_write_compared_frames_to_png(cairo_surface_t *reference,
> +				      cairo_surface_t *capture,
> +				      const char *reference_suffix,
> +				      const char *capture_suffix);
> +
> +#endif
> -- 
> 2.13.2
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH i-g-t v5 0/7] CRC testing with Chamelium improvements
  2017-07-19 13:46 ` [PATCH i-g-t v5 " Paul Kocialkowski
                     ` (7 preceding siblings ...)
  2017-07-19 16:09   ` [PATCH i-g-t v5 0/7] CRC testing with Chamelium improvements Lyude Paul
@ 2017-07-20  9:39   ` Jani Nikula
  2017-07-20 11:15     ` Martin Peres
  2017-07-20 11:27     ` Paul Kocialkowski
  8 siblings, 2 replies; 57+ messages in thread
From: Jani Nikula @ 2017-07-20  9:39 UTC (permalink / raw)
  To: Paul Kocialkowski, intel-gfx


For future reference, please post new versions of the entire series as
new threads. When posting new versions of just some individual patches,
in-reply-to each patch being replaced is fine. I think this is more
clear, and also gives patchwork a better chance to apply the right
patches for testing (not that it does igt CI, but that might change).

BR,
Jani.


On Wed, 19 Jul 2017, Paul Kocialkowski <paul.kocialkowski@linux.intel.com> wrote:
> Changes since v4:
> * Moved igt_get_cairo_surface out of the thread function to properly
>   handle assert failure
> * Rebased on top of current master
>
> Changes since v3:
> * Renamed structure used by async crc calculation for more clarity
> * Used const qualifier for untouched buffer when hashing
> * Split actual calculation to a dedicated function
> * Reworked async functions names for more clarity
> * Reworked descriptions for better accuracy
> * Exported framebuffer cairo surface and use it directly instead of
>   (unused) png dumping
> * Fix how the framebuffer cairo surface is obtained to avoid destroying
>   it too early
>
> * Made CRC checking logic common
> * Added a check for the same number of words
> * Made frame dumping configuration and helpers common
> * Added an extended crc to string helper
> * Added a chamelium helper for crc checking and frame dumping
> * Split the merging of crc functions to a separate patch
> * Added support for frame dump path global variable
> * Added listing the dumped images in a file, possibly identified with
>   an id global variable
>
> The latter allows having one "dump report" file per run, possibly
> identified with the id global variable, that indicates which files
> are the output, while keeping the possibility to have the same files
> for different runs. This allows saving significant disk space when
> the images are identified with e.g. their crc, so that duplicate results
> only lead to duplicate dump reports and not duplicate images.
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Jani Nikula, Intel Open Source Technology Center
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH i-g-t v5 0/7] CRC testing with Chamelium improvements
  2017-07-20  9:39   ` Jani Nikula
@ 2017-07-20 11:15     ` Martin Peres
  2017-07-20 11:27     ` Paul Kocialkowski
  1 sibling, 0 replies; 57+ messages in thread
From: Martin Peres @ 2017-07-20 11:15 UTC (permalink / raw)
  To: Jani Nikula, Paul Kocialkowski, intel-gfx

On 20/07/17 12:39, Jani Nikula wrote:
> 
> For future reference, please post new versions of the entire series as
> new threads. When posting new versions of just some individual patches,
> in-reply-to each patch being replaced is fine. I think this is more
> clear, and also gives patchwork a better chance to apply the right
> patches for testing (not that it does igt CI, but that might change).

Spoiler: we are working on having pre-merge for IGT too
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH i-g-t v5 0/7] CRC testing with Chamelium improvements
  2017-07-20  9:39   ` Jani Nikula
  2017-07-20 11:15     ` Martin Peres
@ 2017-07-20 11:27     ` Paul Kocialkowski
  2017-07-20 12:41       ` Daniel Vetter
  1 sibling, 1 reply; 57+ messages in thread
From: Paul Kocialkowski @ 2017-07-20 11:27 UTC (permalink / raw)
  To: Jani Nikula, intel-gfx

On Thu, 2017-07-20 at 12:39 +0300, Jani Nikula wrote:
> For future reference, please post new versions of the entire series as
> new threads. When posting new versions of just some individual
> patches,
> in-reply-to each patch being replaced is fine. I think this is more
> clear, and also gives patchwork a better chance to apply the right
> patches for testing (not that it does igt CI, but that might change).

Quoting Lyude from an earlier exchange:
 * When you're doing a new revision of a patch series, it's helpful to
   keep it in the same email thread as the original v1 so it's easier
   to keep track of in people's mail clients (as well as avoiding
   accidentally reviewing older patch versions.

I actually prefer it your way (posting as new threads), so I suppose
I'll do that in the future, if Lyude doesn't have any strong objection
about it.

Cheers,

Paul

> On Wed, 19 Jul 2017, Paul Kocialkowski <paul.kocialkowski@linux.intel.
> com> wrote:
> > Changes since v4:
> > * Moved igt_get_cairo_surface out of the thread function to properly
> >   handle assert failure
> > * Rebased on top of current master
> > 
> > Changes since v3:
> > * Renamed structure used by async crc calculation for more clarity
> > * Used const qualifier for untouched buffer when hashing
> > * Split actual calculation to a dedicated function
> > * Reworked async functions names for more clarity
> > * Reworked descriptions for better accuracy
> > * Exported framebuffer cairo surface and use it directly instead of
> >   (unused) png dumping
> > * Fix how the framebuffer cairo surface is obtained to avoid
> > destroying
> >   it too early
> > 
> > * Made CRC checking logic common
> > * Added a check for the same number of words
> > * Made frame dumping configuration and helpers common
> > * Added an extended crc to string helper
> > * Added a chamelium helper for crc checking and frame dumping
> > * Split the merging of crc functions to a separate patch
> > * Added support for frame dump path global variable
> > * Added listing the dumped images in a file, possibly identified
> > with
> >   an id global variable
> > 
> > The latter allows having one "dump report" file per run, possibly
> > identified with the id global variable, that indicates which files
> > are the output, while keeping the possibility to have the same files
> > for different runs. This allows saving significant disk space when
> > the images are identified with e.g. their crc, so that duplicate
> > results
> > only lead to duplicate dump reports and not duplicate images.
> > 
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 
> 
-- 
Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo, Finland
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH i-g-t v5 0/7] CRC testing with Chamelium improvements
  2017-07-20 11:27     ` Paul Kocialkowski
@ 2017-07-20 12:41       ` Daniel Vetter
  2017-07-20 12:44         ` Paul Kocialkowski
  0 siblings, 1 reply; 57+ messages in thread
From: Daniel Vetter @ 2017-07-20 12:41 UTC (permalink / raw)
  To: Paul Kocialkowski; +Cc: intel-gfx

On Thu, Jul 20, 2017 at 1:27 PM, Paul Kocialkowski
<paul.kocialkowski@linux.intel.com> wrote:
> On Thu, 2017-07-20 at 12:39 +0300, Jani Nikula wrote:
>> For future reference, please post new versions of the entire series as
>> new threads. When posting new versions of just some individual
>> patches,
>> in-reply-to each patch being replaced is fine. I think this is more
>> clear, and also gives patchwork a better chance to apply the right
>> patches for testing (not that it does igt CI, but that might change).
>
> Quoting Lyude from an earlier exchange:
>  * When you're doing a new revision of a patch series, it's helpful to
>    keep it in the same email thread as the original v1 so it's easier
>    to keep track of in people's mail clients (as well as avoiding
>    accidentally reviewing older patch versions.
>
> I actually prefer it your way (posting as new threads), so I suppose
> I'll do that in the future, if Lyude doesn't have any strong objection
> about it.

Yeah, new patch series = new thread, otherwise patchwork doesn't pick
it up. I know that some people like to in-reply-to the previous thread
to link stuff up, but that doesn't work with patchwork and CI.

Another reason why mailing lists aren't awesome, but that's what we're
stuck with for now.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH i-g-t v5 0/7] CRC testing with Chamelium improvements
  2017-07-20 12:41       ` Daniel Vetter
@ 2017-07-20 12:44         ` Paul Kocialkowski
  0 siblings, 0 replies; 57+ messages in thread
From: Paul Kocialkowski @ 2017-07-20 12:44 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx

On Thu, 2017-07-20 at 14:41 +0200, Daniel Vetter wrote:
> On Thu, Jul 20, 2017 at 1:27 PM, Paul Kocialkowski
> <paul.kocialkowski@linux.intel.com> wrote:
> > On Thu, 2017-07-20 at 12:39 +0300, Jani Nikula wrote:
> > > For future reference, please post new versions of the entire
> > > series as
> > > new threads. When posting new versions of just some individual
> > > patches,
> > > in-reply-to each patch being replaced is fine. I think this is
> > > more
> > > clear, and also gives patchwork a better chance to apply the right
> > > patches for testing (not that it does igt CI, but that might
> > > change).
> > 
> > Quoting Lyude from an earlier exchange:
> >  * When you're doing a new revision of a patch series, it's helpful
> > to
> >    keep it in the same email thread as the original v1 so it's
> > easier
> >    to keep track of in people's mail clients (as well as avoiding
> >    accidentally reviewing older patch versions.
> > 
> > I actually prefer it your way (posting as new threads), so I suppose
> > I'll do that in the future, if Lyude doesn't have any strong
> > objection
> > about it.
> 
> Yeah, new patch series = new thread, otherwise patchwork doesn't pick
> it up. I know that some people like to in-reply-to the previous thread
> to link stuff up, but that doesn't work with patchwork and CI.

Nice, glad to hear it!

> Another reason why mailing lists aren't awesome, but that's what we're
> stuck with for now.

Frankly, I love mailing lists, in comparison to anything web-based that
basically kills my workflow and cannot be used offline.

-- 
Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo, Finland
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH i-g-t v5 4/7] Introduce common frame dumping configuration and helpers
  2017-07-20  7:24     ` Daniel Vetter
@ 2017-07-20 14:14       ` Paul Kocialkowski
  0 siblings, 0 replies; 57+ messages in thread
From: Paul Kocialkowski @ 2017-07-20 14:14 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx

On Thu, 2017-07-20 at 09:24 +0200, Daniel Vetter wrote:
> On Wed, Jul 19, 2017 at 04:46:07PM +0300, Paul Kocialkowski wrote:
> > This introduces a common FrameDumpPath configuration field, as well
> > as
> > helper functions in dedicated igt_frame for writing cairo surfaces
> > to png files.
> > 
> > Signed-off-by: Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
> > ---
> >  lib/Makefile.sources |   2 +
> >  lib/igt.h            |   1 +
> >  lib/igt_core.c       |  12 +++++
> >  lib/igt_core.h       |   2 +-
> >  lib/igt_frame.c      | 137
> > +++++++++++++++++++++++++++++++++++++++++++++++++++
> >  lib/igt_frame.h      |  43 ++++++++++++++++
> 
> Please make sure you pull the new docs into the docs build too. And
> while
> doing that, please review for other stuff added in the past year and
> include that too. And please build the docs and check the result.

I've just sent out a patch for that, thanks for pointing it out!

Cheers,

Paul

> Thanks, Daniel
> 
> >  6 files changed, 196 insertions(+), 1 deletion(-)
> >  create mode 100644 lib/igt_frame.c
> >  create mode 100644 lib/igt_frame.h
> > 
> > diff --git a/lib/Makefile.sources b/lib/Makefile.sources
> > index 53fdb54c..c2e58809 100644
> > --- a/lib/Makefile.sources
> > +++ b/lib/Makefile.sources
> > @@ -83,6 +83,8 @@ lib_source_list =	 	\
> >  	uwildmat/uwildmat.c	\
> >  	igt_kmod.c		\
> >  	igt_kmod.h		\
> > +	igt_frame.c		\
> > +	igt_frame.h		\
> >  	$(NULL)
> >  
> >  .PHONY: version.h.tmp
> > diff --git a/lib/igt.h b/lib/igt.h
> > index a069deb3..d16a4991 100644
> > --- a/lib/igt.h
> > +++ b/lib/igt.h
> > @@ -34,6 +34,7 @@
> >  #include "igt_draw.h"
> >  #include "igt_dummyload.h"
> >  #include "igt_fb.h"
> > +#include "igt_frame.h"
> >  #include "igt_gt.h"
> >  #include "igt_kms.h"
> >  #include "igt_pm.h"
> > diff --git a/lib/igt_core.c b/lib/igt_core.c
> > index 1ba79361..5a3b00e8 100644
> > --- a/lib/igt_core.c
> > +++ b/lib/igt_core.c
> > @@ -235,6 +235,10 @@
> >   * An example configuration follows:
> >   *
> >   * |[<!-- language="plain" -->
> > + *	# The common configuration secton follows.
> > + *	[Common]
> > + *	FrameDumpPath=/tmp # The path to dump frames that fail
> > comparison checks
> > + *
> >   *	# The following section is used for configuring the
> > Device Under Test.
> >   *	# It is not mandatory and allows overriding default
> > values.
> >   *	[DUT]
> > @@ -290,6 +294,7 @@ static struct {
> >  static pthread_mutex_t log_buffer_mutex =
> > PTHREAD_MUTEX_INITIALIZER;
> >  
> >  GKeyFile *igt_key_file;
> > +char *frame_dump_path;
> >  
> >  const char *igt_test_name(void)
> >  {
> > @@ -621,6 +626,13 @@ static int config_parse(void)
> >  	if (!igt_key_file)
> >  		return 0;
> >  
> > +	frame_dump_path = getenv("IGT_FRAME_DUMP_PATH");
> > +
> > +	if (!frame_dump_path)
> > +		frame_dump_path =
> > g_key_file_get_string(igt_key_file, "Common",
> > +							"FrameDumpP
> > ath",
> > +							&error);
> > +
> >  	rc = g_key_file_get_integer(igt_key_file, "DUT",
> > "SuspendResumeDelay",
> >  				    &error);
> >  	if (error && error->code == G_KEY_FILE_ERROR_INVALID_VALUE)
> > diff --git a/lib/igt_core.h b/lib/igt_core.h
> > index 0739ca83..1619a9d6 100644
> > --- a/lib/igt_core.h
> > +++ b/lib/igt_core.h
> > @@ -50,7 +50,7 @@
> >  extern const char* __igt_test_description __attribute__((weak));
> >  extern bool __igt_plain_output;
> >  extern GKeyFile *igt_key_file;
> > -
> > +extern char *frame_dump_path;
> >  
> >  /**
> >   * IGT_TEST_DESCRIPTION:
> > diff --git a/lib/igt_frame.c b/lib/igt_frame.c
> > new file mode 100644
> > index 00000000..dfafe53d
> > --- /dev/null
> > +++ b/lib/igt_frame.c
> > @@ -0,0 +1,137 @@
> > +/*
> > + * Copyright © 2017 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.
> > + *
> > + * Authors:
> > + *  Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
> > + */
> > +
> > +#include "config.h"
> > +
> > +#include <fcntl.h>
> > +#include <pixman.h>
> > +#include <cairo.h>
> > +
> > +#include "igt.h"
> > +
> > +/**
> > + * SECTION:igt_frame
> > + * @short_description: Library for frame-related tests
> > + * @title: Frame
> > + * @include: igt_frame.h
> > + *
> > + * This library contains helpers for frame-related tests. This
> > includes common
> > + * frame dumping as well as frame comparison helpers.
> > + */
> > +
> > +/**
> > + * igt_frame_dump_is_enabled:
> > + *
> > + * Get whether frame dumping is enabled.
> > + *
> > + * Returns: A boolean indicating whether frame dumping is enabled
> > + */
> > +bool igt_frame_dump_is_enabled(void)
> > +{
> > +	return frame_dump_path != NULL;
> > +}
> > +
> > +static void igt_write_frame_to_png(cairo_surface_t *surface, int
> > fd,
> > +				   const char *qualifier, const
> > char *suffix)
> > +{
> > +	char path[PATH_MAX];
> > +	const char *test_name;
> > +	const char *subtest_name;
> > +	cairo_status_t status;
> > +	int index;
> > +
> > +	test_name = igt_test_name();
> > +	subtest_name = igt_subtest_name();
> > +
> > +	if (suffix)
> > +		snprintf(path, PATH_MAX, "%s/frame-%s-%s-%s-
> > %s.png",
> > +			 frame_dump_path, test_name, subtest_name,
> > qualifier,
> > +			 suffix);
> > +	else
> > +		snprintf(path, PATH_MAX, "%s/frame-%s-%s-%s.png",
> > +			 frame_dump_path, test_name, subtest_name,
> > qualifier);
> > +
> > +	igt_debug("Dumping %s frame to %s...\n", qualifier, path);
> > +
> > +	status = cairo_surface_write_to_png(surface, path);
> > +
> > +	igt_assert_eq(status, CAIRO_STATUS_SUCCESS);
> > +
> > +	index = strlen(path);
> > +
> > +	if (fd >= 0 && index < (PATH_MAX - 1)) {
> > +		path[index++] = '\n';
> > +		path[index] = '\0';
> > +
> > +		write(fd, path, strlen(path));
> > +	}
> > +}
> > +
> > +/**
> > + * igt_write_compared_frames_to_png:
> > + * @reference: The reference cairo surface
> > + * @capture: The captured cairo surface
> > + * @reference_suffix: The suffix to give to the reference png file
> > + * @capture_suffix: The suffix to give to the capture png file
> > + *
> > + * Write previously compared frames to png files.
> > + */
> > +void igt_write_compared_frames_to_png(cairo_surface_t *reference,
> > +				      cairo_surface_t *capture,
> > +				      const char *reference_suffix,
> > +				      const char *capture_suffix)
> > +{
> > +	char *id;
> > +	const char *test_name;
> > +	const char *subtest_name;
> > +	char path[PATH_MAX];
> > +	int fd = -1;
> > +
> > +	if (!igt_frame_dump_is_enabled())
> > +		return;
> > +
> > +	id = getenv("IGT_FRAME_DUMP_ID");
> > +
> > +	test_name = igt_test_name();
> > +	subtest_name = igt_subtest_name();
> > +
> > +	if (id)
> > +		snprintf(path, PATH_MAX, "%s/frame-%s-%s-%s.txt",
> > +			 frame_dump_path, test_name, subtest_name,
> > id);
> > +	else
> > +		snprintf(path, PATH_MAX, "%s/frame-%s-%s.txt",
> > +			 frame_dump_path, test_name, subtest_name);
> > +
> > +	fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
> > +	igt_assert(fd >= 0);
> > +
> > +	igt_debug("Writing dump report to %s...\n", path);
> > +
> > +	igt_write_frame_to_png(reference, fd, "reference",
> > reference_suffix);
> > +	igt_write_frame_to_png(capture, fd, "capture",
> > capture_suffix);
> > +
> > +	close(fd);
> > +}
> > diff --git a/lib/igt_frame.h b/lib/igt_frame.h
> > new file mode 100644
> > index 00000000..ec6a1643
> > --- /dev/null
> > +++ b/lib/igt_frame.h
> > @@ -0,0 +1,43 @@
> > +/*
> > + * Copyright © 2017 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.
> > + *
> > + * Authors:
> > + *  Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
> > + */
> > +
> > +#ifndef IGT_FRAME_H
> > +#define IGT_FRAME_H
> > +
> > +#ifdef HAVE_CONFIG_H
> > +#include "config.h"
> > +#endif
> > +
> > +#include "igt.h"
> > +#include <stdbool.h>
> > +
> > +bool igt_frame_dump_is_enabled(void);
> > +void igt_write_compared_frames_to_png(cairo_surface_t *reference,
> > +				      cairo_surface_t *capture,
> > +				      const char *reference_suffix,
> > +				      const char *capture_suffix);
> > +
> > +#endif
> > -- 
> > 2.13.2
> > 
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 
> 
-- 
Paul Kocialkowski <paul.kocialkowski@linux.intel.com>
Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo, Finland
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 57+ messages in thread

end of thread, other threads:[~2017-07-20 14:14 UTC | newest]

Thread overview: 57+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-07-05  8:04 [PATCH i-g-t v3 1/4] chamelium: Calculate CRC from framebuffer instead of hardcoding it Paul Kocialkowski
2017-07-05  8:04 ` [PATCH i-g-t v3 2/4] tests/ chamelium: Remove the frame dump tests Paul Kocialkowski
2017-07-05 20:53   ` Lyude Paul
2017-07-06  7:37     ` Martin Peres
2017-07-06 13:29     ` Paul Kocialkowski
2017-07-05  8:04 ` [PATCH i-g-t v3 3/4] lib/igt_chamelium: Add support for dumping chamelium frames to a png Paul Kocialkowski
2017-07-05 21:16   ` Lyude Paul
2017-07-05  8:04 ` [PATCH i-g-t v3 4/4] chamelium: Dump obtained and reference frames to png on crc error Paul Kocialkowski
2017-07-05 21:44   ` Lyude Paul
2017-07-06  7:41     ` Martin Peres
2017-07-06 11:35       ` Paul Kocialkowski
2017-07-06 22:23         ` Lyude Paul
2017-07-10 10:12           ` Paul Kocialkowski
2017-07-06 11:31     ` Paul Kocialkowski
2017-07-06 13:33       ` Paul Kocialkowski
2017-07-06 21:57         ` Lyude Paul
2017-07-10 10:27           ` Paul Kocialkowski
2017-07-11 17:27             ` Lyude Paul
2017-07-10 10:31           ` Paul Kocialkowski
2017-07-10 10:33             ` Martin Peres
2017-07-10 12:06               ` Paul Kocialkowski
2017-07-10 13:56                 ` Martin Peres
2017-07-10 14:11                   ` Paul Kocialkowski
2017-07-10 16:02                     ` Martin Peres
2017-07-05 20:34 ` [PATCH i-g-t v3 1/4] chamelium: Calculate CRC from framebuffer instead of hardcoding it Lyude Paul
2017-07-05 20:49   ` Lyude Paul
2017-07-06  8:49   ` Paul Kocialkowski
2017-07-06 13:14   ` Paul Kocialkowski
2017-07-06 22:33     ` Lyude Paul
2017-07-12 14:50 ` [PATCH i-g-t v4 0/7] CRC testing with Chamelium improvements Paul Kocialkowski
2017-07-12 14:50   ` [PATCH i-g-t v4 1/7] lib/igt_fb: Export the cairo surface instead of writing to a png Paul Kocialkowski
2017-07-12 14:50   ` [PATCH i-g-t v4 2/7] chamelium: Calculate CRC from framebuffer instead of hardcoding it Paul Kocialkowski
2017-07-17 16:29     ` Lyude Paul
2017-07-19 11:11       ` Paul Kocialkowski
2017-07-12 14:50   ` [PATCH i-g-t v4 3/7] lib/igt_debugfs: Introduce CRC check function, with logic made common Paul Kocialkowski
2017-07-12 14:50   ` [PATCH i-g-t v4 4/7] Introduce common frame dumping configuration and helpers Paul Kocialkowski
2017-07-12 14:50   ` [PATCH i-g-t v4 5/7] lib/igt_debugfs: Add extended helper to format crc to string Paul Kocialkowski
2017-07-12 14:50   ` [PATCH i-g-t v4 6/7] chamelium: Dump captured and reference frames to png on crc error Paul Kocialkowski
2017-07-12 14:50   ` [PATCH i-g-t v4 7/7] tests/chamelium: Merge the crc testing functions into one Paul Kocialkowski
2017-07-12 14:53   ` [PATCH i-g-t v4 0/7] CRC testing with Chamelium improvements Paul Kocialkowski
2017-07-17 17:04   ` Lyude Paul
2017-07-19 13:46 ` [PATCH i-g-t v5 " Paul Kocialkowski
2017-07-19 13:46   ` [PATCH i-g-t v5 1/7] lib/igt_fb: Export the cairo surface instead of writing to a png Paul Kocialkowski
2017-07-19 13:46   ` [PATCH i-g-t v5 2/7] chamelium: Calculate CRC from framebuffer instead of hardcoding it Paul Kocialkowski
2017-07-19 13:46   ` [PATCH i-g-t v5 3/7] lib/igt_debugfs: Introduce CRC check function, with logic made common Paul Kocialkowski
2017-07-19 13:46   ` [PATCH i-g-t v5 4/7] Introduce common frame dumping configuration and helpers Paul Kocialkowski
2017-07-20  7:24     ` Daniel Vetter
2017-07-20 14:14       ` Paul Kocialkowski
2017-07-19 13:46   ` [PATCH i-g-t v5 5/7] lib/igt_debugfs: Add extended helper to format crc to string Paul Kocialkowski
2017-07-19 13:46   ` [PATCH i-g-t v5 6/7] chamelium: Dump captured and reference frames to png on crc error Paul Kocialkowski
2017-07-19 13:46   ` [PATCH i-g-t v5 7/7] tests/chamelium: Merge the crc testing functions into one Paul Kocialkowski
2017-07-19 16:09   ` [PATCH i-g-t v5 0/7] CRC testing with Chamelium improvements Lyude Paul
2017-07-20  9:39   ` Jani Nikula
2017-07-20 11:15     ` Martin Peres
2017-07-20 11:27     ` Paul Kocialkowski
2017-07-20 12:41       ` Daniel Vetter
2017-07-20 12:44         ` Paul Kocialkowski

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.