[Intel-gfx] [PATCH i-g-t] tests: Add kms_plane_blinker

ville.syrjala at linux.intel.com ville.syrjala at linux.intel.com
Mon Dec 12 20:35:31 UTC 2016


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

Add a test to try out all the different plane enable/disable
order permutations.

Signed-off-by: Ville Syrjälä <ville.syrjala at linux.intel.com>
---
 tests/Makefile.sources    |   1 +
 tests/kms_plane_blinker.c | 529 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 530 insertions(+)
 create mode 100644 tests/kms_plane_blinker.c

diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index 04dd2d58612f..9c60bb90335d 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -110,6 +110,7 @@ TESTS_progs_M = \
 	kms_pipe_color \
 	kms_pipe_crc_basic \
 	kms_plane \
+	kms_plane_blinker \
 	kms_plane_multiple \
 	kms_properties \
 	kms_psr_sink_crc \
diff --git a/tests/kms_plane_blinker.c b/tests/kms_plane_blinker.c
new file mode 100644
index 000000000000..c6dace1121b5
--- /dev/null
+++ b/tests/kms_plane_blinker.c
@@ -0,0 +1,529 @@
+/*
+ * Copyright © 2016 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+#include "igt.h"
+
+IGT_TEST_DESCRIPTION("Test all plane enable/disable sequence permutations.");
+
+#define __FAC_0 1
+#define __FAC_1 1
+#define __FAC_2 (2*__FAC_1)
+#define __FAC_3 (3*__FAC_2)
+#define __FAC_4 (4*__FAC_3)
+#define _FAC(n) __FAC_ ## n
+#define FAC(n) _FAC(n)
+
+#define __SUB_4_0 4
+#define __SUB_4_1 3
+#define __SUB_4_2 2
+#define __SUB_4_3 1
+#define __SUB_4_4 0
+#define _SUB(a,b) __SUB_ ## a ## _ ## b
+#define SUB(a,b) _SUB(a,b)
+
+#define C(k,n) (FAC(k) / (FAC(SUB(k, n)) * FAC(n)))
+
+/* all combinations */
+#define NUM_REF_CRCS (C(4,0) + C(4,1) + C(4,2) + C(4,3) + C(4,4))
+
+typedef struct {
+	int drm_fd;
+	igt_display_t display;
+	igt_output_t *output;
+	enum pipe pipe;
+	igt_pipe_crc_t *pipe_crc;
+	igt_crc_t ref_crc[NUM_REF_CRCS];
+	uint8_t ref_crc_active_planes[NUM_REF_CRCS];
+	int num_ref_crcs;
+	uint32_t devid;
+	unsigned int delay_us;
+	unsigned int timeout_ms;
+	struct igt_fb ref_fb;
+	struct igt_fb fb[4];
+	igt_plane_t *plane[4];
+	uint8_t num_planes;
+	uint8_t active_plane[4];
+	uint8_t num_active_planes;
+} data_t;
+
+static unsigned int gettime_ms(void)
+{
+	struct timespec ts;
+
+	clock_gettime(CLOCK_MONOTONIC, &ts);
+
+	return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
+}
+
+static const struct {
+	float r, g, b;
+} colors[] = {
+	{ 1.0f, 0.0f, 0.0f },
+	{ 0.0f, 1.0f, 0.0f },
+	{ 0.0f, 0.0f, 1.0f },
+	{ 0.0f, 1.0f, 1.0f },
+	{ 1.0f, 0.0f, 1.0f },
+	{ 1.0f, 1.0f, 0.0f },
+};
+
+static uint32_t plane_format(data_t *data, int plane)
+{
+	if (plane == data->num_planes - 1)
+		return DRM_FORMAT_ARGB8888;
+	else
+		return DRM_FORMAT_XRGB8888;
+}
+
+static int plane_x(int plane)
+{
+	return plane * 100;
+}
+
+static int plane_y(int plane)
+{
+	return plane * 100;
+}
+
+static int plane_width(data_t *data, int plane)
+{
+	drmModeModeInfo *mode = igt_output_get_mode(data->output);
+
+	if (plane == 0)
+		return mode->hdisplay;
+	else if (plane == data->num_planes - 1)
+		return 64;
+	else
+		return mode->hdisplay / 2;
+}
+
+static int plane_height(data_t *data, int plane)
+{
+	drmModeModeInfo *mode = igt_output_get_mode(data->output);
+
+	if (plane == 0)
+		return mode->vdisplay;
+	else if (plane == data->num_planes - 1)
+		return 64;
+	else
+		return mode->vdisplay / 2;
+}
+
+static igt_crc_t *find_ref_crc(data_t *data, uint8_t active_planes)
+{
+	int i;
+
+	for (i = 0; i < data->num_ref_crcs; i++) {
+		if (data->ref_crc_active_planes[i] == active_planes)
+			return &data->ref_crc[i];
+	}
+
+	return NULL;
+}
+
+static void generate_ref_crc(data_t *data, int num_active_planes)
+{
+	drmModeModeInfo *mode;
+	cairo_t *cr;
+	int i;
+
+	mode = igt_output_get_mode(data->output);
+
+	data->ref_crc_active_planes[data->num_ref_crcs] = 0;
+
+	cr = igt_get_cairo_ctx(data->drm_fd, &data->ref_fb);
+
+	igt_paint_color(cr, 0, 0, mode->hdisplay, mode->vdisplay,
+			0.0, 0.0, 0.0);
+
+	for (i = 0; i < num_active_planes; i++) {
+		int plane = data->active_plane[i];
+		int w, h;
+		int x, y;
+
+		data->ref_crc_active_planes[data->num_ref_crcs] |= 1 << plane;
+
+		x = plane_x(plane);
+		y = plane_y(plane);
+		w = plane_width(data, plane);
+		h = plane_height(data, plane);
+
+		cairo_save(cr);
+		cairo_rectangle(cr, x, y, w, h);
+		cairo_clip(cr);
+
+		igt_paint_color(cr, x, y, w, h,
+				colors[plane].r, colors[plane].g, colors[plane].b);
+		cairo_translate(cr, x, y);
+		igt_paint_test_pattern(cr, w, h);
+		cairo_restore(cr);
+	}
+
+	igt_assert(cairo_status(cr) == 0);
+	cairo_destroy(cr);
+
+	igt_wait_for_vblank(data->drm_fd, data->pipe);
+
+	igt_assert(data->num_ref_crcs < NUM_REF_CRCS);
+	igt_pipe_crc_collect_crc(data->pipe_crc, &data->ref_crc[data->num_ref_crcs]);
+	data->num_ref_crcs++;
+}
+
+static void do_combination(data_t *data, int plane, int idx,
+			   int num_active_planes)
+{
+	if (idx == num_active_planes) {
+		generate_ref_crc(data, num_active_planes);
+		return;
+	}
+
+	for (; plane < data->num_planes; plane++) {
+		data->active_plane[idx] = plane;
+		do_combination(data, plane + 1, idx + 1, num_active_planes);
+	}
+}
+
+static bool igt_crc_equal(const igt_crc_t *a, const igt_crc_t *b)
+{
+	return a->n_words == b->n_words &&
+		memcmp(a->crc, b->crc, sizeof(a->crc[0]) * a->n_words) == 0;
+}
+
+static void generate_ref_crcs(data_t *data)
+{
+	int num_active_planes, i, j;
+
+	data->num_ref_crcs = 0;
+
+	/* ref crc for 0 active planes */
+	for (num_active_planes = 0;
+	     num_active_planes <= data->num_active_planes;
+	     num_active_planes++)
+		do_combination(data, 0, 0, num_active_planes);
+
+	for (i = 0; i < data->num_ref_crcs; i++) {
+		for (j = i + 1; j < data->num_ref_crcs; j++) {
+			if (igt_crc_equal(&data->ref_crc[i], &data->ref_crc[j]))
+				break;
+		}
+		if (j < data->num_ref_crcs) {
+			igt_warn("reference CRCs not unique\n");
+			break;
+		}
+	}
+}
+
+static bool prepare_crtc(data_t *data)
+{
+	igt_display_t *display = &data->display;
+	drmModeModeInfo *mode;
+	int i;
+
+	/* select the pipe we want to use */
+	igt_output_set_pipe(data->output, data->pipe);
+	igt_display_commit(display);
+
+	if (!data->output->valid) {
+		igt_output_set_pipe(data->output, PIPE_ANY);
+		igt_display_commit(display);
+		return false;
+	}
+
+	mode = igt_output_get_mode(data->output);
+
+	igt_create_color_fb(data->drm_fd,
+			    mode->hdisplay, mode->vdisplay,
+			    DRM_FORMAT_XRGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
+			    1.0, 1.0, 1.0,
+			    &data->ref_fb);
+
+	for (i = 0; i < data->num_planes; i++) {
+		igt_create_color_pattern_fb(data->drm_fd,
+					    plane_width(data, i), plane_height(data, i),
+					    plane_format(data, i), LOCAL_DRM_FORMAT_MOD_NONE,
+					    colors[i].r, colors[i].g, colors[i].b,
+					    &data->fb[i]);
+
+		data->plane[i] = igt_output_get_plane(data->output, i);
+	}
+
+	igt_plane_set_fb(data->plane[0], &data->ref_fb);
+	igt_display_commit(display);
+
+	/* create the pipe_crc object for this pipe */
+	if (data->pipe_crc)
+		igt_pipe_crc_free(data->pipe_crc);
+	data->pipe_crc = igt_pipe_crc_new_nonblock(data->pipe,
+						   INTEL_PIPE_CRC_SOURCE_AUTO);
+
+	generate_ref_crcs(data);
+
+	igt_plane_set_fb(data->plane[0], NULL);
+	igt_display_commit2(display, COMMIT_UNIVERSAL);
+
+	igt_remove_fb(data->drm_fd, &data->ref_fb);
+
+	return true;
+}
+
+#define NCRC 10
+
+static void check_crcs(data_t *data, uint8_t active_planes,
+		       igt_crc_t *last_ref_crc,
+		       igt_crc_t *ref_crc)
+{
+	igt_crc_t *crc;
+	int i, n;
+
+	n = igt_pipe_crc_get_crcs(data->pipe_crc, NCRC, &crc);
+
+	for (i = 0; i < n; i++) {
+		if (!igt_crc_equal(&crc[i], last_ref_crc))
+			break;
+	}
+	for (; i < n; i++)
+		igt_assert_crc_equal(&crc[i], ref_crc);
+
+	free(crc);
+}
+
+static void do_test(data_t *data)
+{
+	igt_display_t *display = &data->display;
+	igt_crc_t *last_ref_crc;
+	unsigned int start;
+	int num;
+
+	igt_info(" Testing planes: none -> ");
+	for (num = 1; num < data->num_active_planes; num++) {
+		int idx;
+
+		igt_info("%d", data->active_plane[0]);
+		for (idx = 1; idx < num; idx++)
+			igt_info(",%d", data->active_plane[idx]);
+		igt_info(" -> ");
+	}
+	for (; num > 0; num--) {
+		int idx;
+
+		igt_info("%d", data->active_plane[0]);
+		for (idx = 1; idx < num; idx++)
+			igt_info(",%d", data->active_plane[idx]);
+		igt_info(" -> ");
+	}
+	igt_info("none\n");
+
+	start = gettime_ms();
+
+	last_ref_crc = find_ref_crc(data, 0);
+
+	igt_pipe_crc_start(data->pipe_crc);
+
+	do {
+		int idx;
+		uint8_t active_planes = 0;
+
+		for (idx = 0; idx < data->num_active_planes; idx++) {
+			int plane = data->active_plane[idx];
+			igt_crc_t *ref_crc;
+
+			active_planes |= 1 << plane;
+
+			ref_crc = find_ref_crc(data, active_planes);
+			igt_assert(ref_crc);
+
+			igt_plane_set_fb(data->plane[plane], &data->fb[plane]);
+			igt_plane_set_position(data->plane[plane],
+					       plane_x(plane), plane_y(plane));
+			igt_display_commit2(display, COMMIT_UNIVERSAL);
+			usleep(data->delay_us);
+
+			check_crcs(data, active_planes, last_ref_crc, ref_crc);
+			last_ref_crc = ref_crc;
+		}
+
+		igt_assert(active_planes != 0);
+
+		for (idx = data->num_active_planes - 1; idx >= 0; idx--) {
+			int plane = data->active_plane[idx];
+			igt_crc_t *ref_crc;
+
+			active_planes &= ~(1 << plane);
+
+			ref_crc = find_ref_crc(data, active_planes);
+			igt_assert(ref_crc);
+
+			igt_plane_set_fb(data->plane[plane], NULL);
+			igt_display_commit2(display, COMMIT_UNIVERSAL);
+			usleep(data->delay_us);
+
+			check_crcs(data, active_planes, last_ref_crc, ref_crc);
+			last_ref_crc = ref_crc;
+		}
+
+		igt_assert(active_planes == 0);
+	} while (data->timeout_ms > 0 &&
+		 gettime_ms() - start < data->timeout_ms);
+
+	igt_pipe_crc_stop(data->pipe_crc);
+}
+
+static void do_permutation(data_t *data,
+			   unsigned int available_planes,
+			   int idx)
+{
+	int plane;
+
+	if (idx == data->num_active_planes) {
+		do_test(data);
+		return;
+	}
+
+	for (plane = 0; plane < data->num_planes; plane++) {
+		if (!(available_planes & (1 << plane)))
+			continue;
+
+		data->active_plane[idx] = plane;
+		do_permutation(data,
+			       available_planes & ~(1 << plane),
+			       idx + 1);
+	}
+}
+
+static void test_permutations(data_t *data)
+{
+	do_permutation(data, (1 << data->num_planes) - 1, 0);
+}
+
+static void cleanup_crtc(data_t *data)
+{
+	igt_display_t *display = &data->display;
+	int i;
+
+	igt_pipe_crc_free(data->pipe_crc);
+	data->pipe_crc = NULL;
+
+	for (i = 0; i < data->num_planes; i++) {
+		igt_remove_fb(data->drm_fd, &data->fb[i]);
+		igt_plane_set_fb(data->plane[i], NULL);
+	}
+
+	igt_output_set_pipe(data->output, PIPE_ANY);
+	igt_display_commit(display);
+}
+
+static void test(data_t *data)
+{
+	igt_display_t *display = &data->display;
+	int valid_tests = 0;
+
+	igt_require(data->pipe <= display->n_pipes);
+	igt_require(data->num_active_planes <= display->pipes[data->pipe].n_planes);
+
+	data->num_planes = data->display.pipes[data->pipe].n_planes;
+
+	for_each_connected_output(display, data->output) {
+		if (!prepare_crtc(data))
+			continue;
+
+		valid_tests++;
+
+		igt_info("Beginning %s on pipe %s, connector %s\n",
+			 igt_subtest_name(),
+			 kmstest_pipe_name(data->pipe),
+			 igt_output_name(data->output));
+
+		test_permutations(data);
+
+		igt_info("\n%s on pipe %s, connector %s: PASSED\n\n",
+			 igt_subtest_name(),
+			 kmstest_pipe_name(data->pipe),
+			 igt_output_name(data->output));
+
+		cleanup_crtc(data);
+	}
+
+	igt_require_f(valid_tests, "no valid crtc/connector combinations found\n");
+}
+
+static int opt_handler(int opt, int opt_index, void *_data)
+{
+	data_t *data = _data;
+
+	switch (opt) {
+	case 'd':
+		data->delay_us = strtoull(optarg, NULL, 0) * 1000;
+		break;
+	case 't':
+		data->timeout_ms = strtoull(optarg, NULL, 0);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static data_t data;
+
+int main(int argc, char *argv[])
+{
+	static const struct option long_opts[] = {
+		{ .name = "delay", .val = 'd', .has_arg = required_argument },
+		{ .name = "timeout", .val = 't', .has_arg = required_argument },
+		{}
+	};
+        static const char *help_str =
+		"  --delay\t\tDelay (in ms) between each plane enable/disable\n"
+		"  --timeout\t\tTimeout (in ms) per connector for each subtest\n";
+
+	data.timeout_ms = 100;
+	data.delay_us = 20000;
+
+	igt_subtest_init_parse_opts(&argc, argv, "", long_opts, help_str,
+                                    opt_handler, &data);
+
+	data.drm_fd = drm_open_driver_master(DRIVER_INTEL);
+	data.devid = intel_get_drm_devid(data.drm_fd);
+
+	igt_require_pipe_crc();
+
+	kmstest_set_vt_graphics_mode();
+
+	igt_display_init(&data.display, data.drm_fd);
+	igt_require(data.display.has_universal_planes);
+
+	for (data.pipe = PIPE_A; data.pipe <= PIPE_C; data.pipe++) {
+		for (data.num_active_planes = 1;
+		     data.num_active_planes <= 4; data.num_active_planes++) {
+			igt_subtest_f("pipe-%s-%d-planes",
+				      kmstest_pipe_name(data.pipe), data.num_active_planes) {
+				test(&data);
+			}
+		}
+	}
+
+	igt_display_fini(&data.display);
+
+	igt_exit();
+}
-- 
2.7.4



More information about the Intel-gfx mailing list