[igt] kms_plane_crc: Add a basic CRC based planes test ala. ksm_cursor_crc

Submitted by Ville Syrjälä on Jan. 13, 2014, 3:10 p.m.

Details

Message ID 1389625851-13774-1-git-send-email-ville.syrjala@linux.intel.com
State New, archived
Headers show

Not browsing as part of any series.

Commit Message

Ville Syrjälä Jan. 13, 2014, 3:10 p.m.
From: Ville Syrjälä <ville.syrjala@linux.intel.com>

The test uses a 64x64 plane and moves it aroudn the screen corners
like kms_cursor_crc does with cursors. We alternate between black
and white framebuffers on both the crtc and plane in question.

On platforms that have scalable sprites, we also test if the crc
behaves as expected when we scale up the 64x64 image to cover the
entire screen.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 tests/Android.mk       |   1 +
 tests/Makefile.sources |   1 +
 tests/kms_plane_crc.c  | 498 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 500 insertions(+)
 create mode 100644 tests/kms_plane_crc.c

Patch hide | download patch | download mbox

diff --git a/tests/Android.mk b/tests/Android.mk
index c65f94c..c097aa6 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -96,6 +96,7 @@  skip_tests_list := \
     kms_flip \
     kms_pipe_crc_basic \
     kms_fbc_crc \
+    kms_plane_crc \
     kms_render \
     kms_setmode \
     pm_pc8 \
diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index c586bd3..cf4564e 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -58,6 +58,7 @@  TESTS_progs_M = \
 	kms_fbc_crc \
 	kms_flip \
 	kms_pipe_crc_basic \
+	kms_plane_crc \
 	kms_render \
 	kms_setmode \
 	pm_lpsp \
diff --git a/tests/kms_plane_crc.c b/tests/kms_plane_crc.c
new file mode 100644
index 0000000..7e8aeed
--- /dev/null
+++ b/tests/kms_plane_crc.c
@@ -0,0 +1,498 @@ 
+/*
+ * Copyright © 2013 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 <errno.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "drm_fourcc.h"
+
+#include "drmtest.h"
+#include "igt_debugfs.h"
+#include "igt_kms.h"
+
+enum color {
+	WHITE,
+	BLACK,
+	NUM_COLORS,
+};
+
+enum test_mode {
+	TEST_ONSCREEN,
+	TEST_OFFSCREEN,
+	TEST_FULLSCREEN,
+};
+
+typedef struct {
+	struct kmstest_connector_config config;
+	drmModeModeInfo mode;
+	struct kmstest_fb fb;
+} connector_t;
+
+typedef struct {
+	int drm_fd;
+	igt_debugfs_t debugfs;
+	drmModeRes *resources;
+	drmModePlaneRes *plane_resources;
+	FILE *ctl;
+	uint32_t fb_id[NUM_COLORS];
+	struct kmstest_fb fb[NUM_COLORS];
+	igt_crc_t ref_crc[NUM_COLORS];
+	igt_pipe_crc_t **pipe_crc;
+} data_t;
+
+typedef struct {
+	data_t *data;
+	uint32_t crtc_id;
+	int crtc_idx;
+	uint32_t plane_id;
+	int plane_idx;
+	bool crc_must_match;
+	int left, right, top, bottom;
+	int pipe_w, pipe_h;
+	uint32_t fb_id;
+	igt_crc_t *ref_crc;
+	enum color crtc_color, plane_color;
+} test_data_t;
+
+static const char *color_str(enum color color)
+{
+	static const char * const colors[] = {
+		"white",
+		"black",
+	};
+
+	return colors[color];
+}
+
+static const char *test_mode_str(enum test_mode mode)
+{
+	static const char * const test_modes[] = {
+		"onscreen",
+		"offscreen",
+		"fullscreen",
+	};
+
+	return test_modes[mode];
+}
+
+static uint32_t create_fb(data_t *data,
+			  int w, int h,
+			  double r, double g, double b,
+			  struct kmstest_fb *fb)
+{
+	cairo_t *cr;
+	uint32_t fb_id;
+
+	fb_id = kmstest_create_fb2(data->drm_fd, w, h,
+				   DRM_FORMAT_XRGB8888, false, fb);
+	igt_assert(fb_id);
+
+	cr = kmstest_get_cairo_ctx(data->drm_fd, fb);
+	kmstest_paint_color(cr, 0, 0, w, h, r, g, b);
+	igt_assert(cairo_status(cr) == 0);
+
+	return fb_id;
+}
+
+static bool
+connector_set_mode(data_t *data, connector_t *connector, drmModeModeInfo *mode,
+		   enum color crtc_color)
+{
+	struct kmstest_connector_config *config = &connector->config;
+	unsigned int fb_id;
+	int ret;
+
+	if (crtc_color == WHITE)
+		fb_id = create_fb(data, mode->hdisplay, mode->vdisplay,
+				  1.0, 1.0, 1.0, &connector->fb);
+	else
+		fb_id = create_fb(data, mode->hdisplay, mode->vdisplay,
+				  0.0, 0.0, 0.0, &connector->fb);
+	igt_assert(fb_id);
+
+#if 0
+	fprintf(stdout, "Using pipe %c, %dx%d\n", pipe_name(config->pipe),
+		mode->hdisplay, mode->vdisplay);
+#endif
+
+	ret = drmModeSetCrtc(data->drm_fd,
+			     config->crtc->crtc_id,
+			     connector->fb.fb_id,
+			     0, 0, /* x, y */
+			     &config->connector->connector_id,
+			     1,
+			     mode);
+	igt_assert(ret == 0);
+
+	return 0;
+}
+
+static igt_pipe_crc_t *create_crc(data_t *data, int crtc_idx)
+{
+	igt_pipe_crc_t *crc;
+
+	crc = igt_pipe_crc_new(&data->debugfs, data->drm_fd, crtc_idx,
+			       INTEL_PIPE_CRC_SOURCE_AUTO);
+	return crc;
+}
+
+static void display_init(data_t *data)
+{
+	data->resources = drmModeGetResources(data->drm_fd);
+	igt_assert(data->resources);
+
+	data->plane_resources = drmModeGetPlaneResources(data->drm_fd);
+	igt_assert(data->plane_resources);
+
+	data->pipe_crc = calloc(data->resources->count_crtcs, sizeof(data->pipe_crc[0]));
+}
+
+static void display_fini(data_t *data)
+{
+	free(data->pipe_crc);
+
+	drmModeFreePlaneResources(data->plane_resources);
+	drmModeFreeResources(data->resources);
+}
+
+static void do_single_test(test_data_t *test_data, int x, int y)
+{
+	data_t *data = test_data->data;
+	igt_pipe_crc_t *pipe_crc = data->pipe_crc[test_data->crtc_idx];
+	igt_crc_t *crcs = NULL;
+
+	printf("."); fflush(stdout);
+
+	igt_assert(drmModeSetPlane(data->drm_fd, test_data->plane_id,
+				   test_data->crtc_id, test_data->fb_id, 0,
+				   x, y, 64, 64,
+				   0, 0, 64 << 16, 64 << 16) == 0);
+	igt_wait_for_vblank(data->drm_fd, test_data->crtc_idx);
+
+	igt_pipe_crc_start(pipe_crc);
+	igt_pipe_crc_get_crcs(pipe_crc, 1, &crcs);
+	igt_pipe_crc_stop(pipe_crc);
+	if (test_data->crc_must_match)
+		igt_assert(igt_crc_equal(&crcs[0], test_data->ref_crc));
+	else
+		igt_assert(!igt_crc_equal(&crcs[0], test_data->ref_crc));
+	free(crcs);
+}
+
+static void do_fs_test(test_data_t *test_data)
+{
+	data_t *data = test_data->data;
+	igt_pipe_crc_t *pipe_crc = data->pipe_crc[test_data->crtc_idx];
+	igt_crc_t *crcs = NULL;
+
+	printf("."); fflush(stdout);
+
+	igt_assert(drmModeSetPlane(data->drm_fd, test_data->plane_id,
+				   test_data->crtc_id, test_data->fb_id, 0,
+				   0, 0, test_data->pipe_w, test_data->pipe_h,
+				   0, 0, 64 << 16, 64 << 16) == 0);
+	igt_wait_for_vblank(data->drm_fd, test_data->crtc_idx);
+
+	igt_pipe_crc_start(pipe_crc);
+	igt_pipe_crc_get_crcs(pipe_crc, 1, &crcs);
+	igt_pipe_crc_stop(pipe_crc);
+	if (test_data->crc_must_match)
+		igt_assert(igt_crc_equal(&crcs[0], test_data->ref_crc));
+	else
+		igt_assert(!igt_crc_equal(&crcs[0], test_data->ref_crc));
+	free(crcs);
+}
+
+static void do_test(test_data_t *test_data,
+		    int left, int right, int top, int bottom)
+{
+	do_single_test(test_data, left, top);
+	do_single_test(test_data, right, top);
+	do_single_test(test_data, right, bottom);
+	do_single_test(test_data, left, bottom);
+}
+
+static void test_crc(test_data_t *test_data, enum test_mode mode)
+{
+	data_t *data = test_data->data;
+	int left = test_data->left;
+	int right = test_data->right;
+	int top = test_data->top;
+	int bottom = test_data->bottom;
+
+	if (mode == TEST_FULLSCREEN) {
+		/* plane fullscreen, crc should match plane color */
+		test_data->crc_must_match = true;
+		test_data->ref_crc = &data->ref_crc[test_data->plane_color];
+
+		/* fullscreen  */
+		do_fs_test(test_data);
+	} else if (mode == TEST_ONSCREEN) {
+		/* plane onscreen, crc should match if crtc and plane are the same color */
+		test_data->crc_must_match =
+			test_data->plane_color == test_data->crtc_color;
+		test_data->ref_crc = &data->ref_crc[test_data->crtc_color];
+
+		/* fully inside  */
+		do_test(test_data, left, right, top, bottom);
+
+		/* 2 pixels inside */
+		do_test(test_data, left - 62, right + 62, top     , bottom     );
+		do_test(test_data, left     , right     , top - 62, bottom + 62);
+		do_test(test_data, left - 62, right + 62, top - 62, bottom + 62);
+
+		/* 1 pixel inside */
+		do_test(test_data, left - 63, right + 63, top     , bottom     );
+		do_test(test_data, left     , right     , top - 63, bottom + 63);
+		do_test(test_data, left - 63, right + 63, top - 63, bottom + 63);
+	} else if (mode == TEST_OFFSCREEN) {
+		/* plane offscreen, crc should always match */
+		test_data->crc_must_match = true;
+		test_data->ref_crc = &data->ref_crc[test_data->crtc_color];
+
+		/* fully outside */
+		do_test(test_data, left - 64, right + 64, top     , bottom     );
+		do_test(test_data, left     , right     , top - 64, bottom + 64);
+		do_test(test_data, left - 64, right + 64, top - 64, bottom + 64);
+
+		/* fully outside by 1 extra pixels */
+		do_test(test_data, left - 65, right + 65, top     , bottom     );
+		do_test(test_data, left     , right     , top - 65, bottom + 65);
+		do_test(test_data, left - 65, right + 65, top - 65, bottom + 65);
+
+		/* fully outside by 2 extra pixels */
+		do_test(test_data, left - 66, right + 66, top     , bottom     );
+		do_test(test_data, left     , right     , top - 66, bottom + 66);
+		do_test(test_data, left - 66, right + 66, top - 66, bottom + 66);
+
+		/* fully outside by a lot of extra pixels */
+		do_test(test_data, left - 512, right + 512, top      , bottom      );
+		do_test(test_data, left      , right      , top - 512, bottom + 512);
+		do_test(test_data, left - 512, right + 512, top - 512, bottom + 512);
+
+		/* go nuts */
+		do_test(test_data, INT_MIN, INT_MAX-64, INT_MIN, INT_MAX-64);
+	}
+
+	/* disable plane again */
+	igt_assert(drmModeSetPlane(data->drm_fd, test_data->plane_id,
+				   0, 0, 0,
+				   0, 0, 0, 0,
+				   0, 0, 0, 0) == 0);
+}
+
+static bool prepare_crtc(test_data_t *test_data, uint32_t connector_id)
+{
+	connector_t connector;
+	data_t *data = test_data->data;
+	igt_pipe_crc_t *pipe_crc;
+        igt_crc_t *crcs = NULL;
+	int ret;
+
+	ret = kmstest_get_connector_config(data->drm_fd,
+					   connector_id,
+					   1 << test_data->crtc_idx,
+					   &connector.config);
+	if (ret)
+		return false;
+
+	connector_set_mode(data, &connector, &connector.config.default_mode, WHITE);
+
+	igt_pipe_crc_free(data->pipe_crc[test_data->crtc_idx]);
+	data->pipe_crc[test_data->crtc_idx] = NULL;
+
+	pipe_crc = create_crc(data, test_data->crtc_idx);
+	if (!pipe_crc) {
+		printf("auto crc not supported on this connector with crtc %i\n",
+		       test_data->crtc_idx);
+		return false;
+	}
+
+	data->pipe_crc[test_data->crtc_idx] = pipe_crc;
+
+	/* get reference crc for white color */
+	igt_pipe_crc_start(pipe_crc);
+	igt_pipe_crc_get_crcs(pipe_crc, 1, &crcs);
+	data->ref_crc[WHITE] = crcs[0];
+	igt_pipe_crc_stop(pipe_crc);
+	free(crcs);
+
+	connector_set_mode(data, &connector, &connector.config.default_mode, BLACK);
+
+	/* get reference crc for black color */
+	igt_pipe_crc_start(pipe_crc);
+	igt_pipe_crc_get_crcs(pipe_crc, 1, &crcs);
+	data->ref_crc[BLACK] = crcs[0];
+	igt_pipe_crc_stop(pipe_crc);
+	free(crcs);
+
+	connector_set_mode(data, &connector, &connector.config.default_mode,
+			   test_data->crtc_color);
+
+	/* x/y position where the plane is still fully visible */
+	test_data->left = 0;
+	test_data->right = connector.config.default_mode.hdisplay - 64;
+	test_data->top = 0;
+	test_data->bottom = connector.config.default_mode.vdisplay - 64;
+
+	test_data->pipe_w = connector.config.default_mode.hdisplay;
+	test_data->pipe_h = connector.config.default_mode.vdisplay;
+
+	test_data->fb_id = data->fb_id[test_data->plane_color];
+
+	kmstest_free_connector_config(&connector.config);
+
+	return true;
+}
+
+static void disable_planes(data_t *data)
+{
+	int p;
+
+	for (p = 0; p < data->plane_resources->count_planes; p++) {
+		uint32_t plane_id = data->plane_resources->planes[p];
+
+		igt_assert(drmModeSetPlane(data->drm_fd, plane_id,
+					   0, 0, 0,
+					   0, 0, 0, 0,
+					   0, 0, 0, 0) == 0);
+	}
+}
+
+static void run_test(data_t *data, enum color crtc_color,
+		     enum color plane_color, enum test_mode mode)
+{
+	test_data_t test_data = {
+		.data = data,
+		.crtc_color = crtc_color,
+		.plane_color = plane_color,
+	};
+	int i, n, p;
+	int valid_tests = 0;
+
+	disable_planes(data);
+
+	for (i = 0; i < data->resources->count_connectors; i++) {
+		uint32_t connector_id = data->resources->connectors[i];
+
+		for (n = 0; n < data->resources->count_crtcs; n++) {
+			test_data.crtc_idx = n;
+			test_data.crtc_id = data->resources->crtcs[n];
+
+			if (!prepare_crtc(&test_data, connector_id))
+				continue;
+
+			for (p = 0; p < data->plane_resources->count_planes; p++) {
+				drmModePlanePtr plane;
+				uint32_t possible_crtcs;
+
+				test_data.plane_idx = p;
+				test_data.plane_id = data->plane_resources->planes[p];
+
+				plane = drmModeGetPlane(data->drm_fd, test_data.plane_id);
+				igt_assert(plane);
+				possible_crtcs = plane->possible_crtcs;
+				drmModeFreePlane(plane);
+
+				if (!(possible_crtcs & (1 << n)))
+					continue;
+
+				valid_tests++;
+
+				fprintf(stdout, "Beginning %s on plane %d, crtc %d, connector %d\n",
+					igt_subtest_name(), test_data.plane_id,
+					test_data.crtc_id, connector_id);
+				test_crc(&test_data, mode);
+
+				fprintf(stdout, "\n%s on plane %d, crtc %d, connector %d: PASSED\n\n",
+					igt_subtest_name(), test_data.plane_id,
+					test_data.crtc_id, connector_id);
+			}
+
+			igt_pipe_crc_free(data->pipe_crc[test_data.crtc_idx]);
+			data->pipe_crc[test_data.crtc_idx] = NULL;
+		}
+	}
+
+	igt_require_f(valid_tests, "no valid crtc/connector combinations found\n");
+}
+
+static bool has_plane_scaler(uint32_t devid)
+{
+	/* scalable planes in ilk/snb/ivb only */
+	return IS_GEN5(devid) || IS_GEN6(devid) || IS_IVYBRIDGE(devid);
+}
+
+int main(int argc, char **argv)
+{
+	data_t data = {};
+	uint32_t devid = 0;
+	enum color crtc_color, plane_color;
+	enum test_mode mode;
+
+	igt_skip_on_simulation();
+
+	igt_fixture {
+		data.drm_fd = drm_open_any();
+
+		igt_set_vt_graphics_mode();
+
+		devid = intel_get_drm_devid(data.drm_fd);
+
+		igt_debugfs_init(&data.debugfs);
+		igt_pipe_crc_check(&data.debugfs);
+
+		display_init(&data);
+
+		igt_require_f(data.plane_resources->count_planes > 0,
+			      "Planes not supported on this platform\n");
+
+		data.fb_id[WHITE] = create_fb(&data, 64, 64,
+					      1.0, 1.0, 1.0,
+					      &data.fb[WHITE]);
+		data.fb_id[BLACK] = create_fb(&data, 64, 64,
+					      0.0, 0.0, 0.0,
+					      &data.fb[BLACK]);
+	}
+
+	for (crtc_color = WHITE; crtc_color <= BLACK; crtc_color++) {
+		for (plane_color = WHITE; plane_color <= BLACK; plane_color++) {
+			for (mode = TEST_ONSCREEN; mode <= TEST_FULLSCREEN; mode++) {
+				igt_subtest_f("plane-%s-on-%s-%s",
+					      color_str(crtc_color),
+					      color_str(plane_color),
+					      test_mode_str(mode)) {
+				  igt_skip_on(mode == TEST_FULLSCREEN && !has_plane_scaler(devid));
+				  run_test(&data, crtc_color, plane_color, mode);
+				}
+			}
+		}
+	}
+
+	igt_fixture
+		display_fini(&data);
+}