[igt-dev] [PATCH i-g-t v2 2/2] add a kms_fb_stride test

Martin Peres martin.peres at linux.intel.com
Wed Feb 14 17:07:36 UTC 2018


This test checks what strides are actually supported by each plane of
each pipe. The tested strides are 4K, 8K, and 16K. The tested formats
are DRM_FORMAT_RGB565 (16 bits) and DRM_FORMAT_XRGB8888 (32 bits).

To verify that the display controler is OK with the stride, the test
uses the pipe crc and verifies that a test image blitted to a
hdisplay x vdisplay framebuffer appears the same when blitted to a
stride x vdisplay framebuffer (with stride varying from 4K to 16K).

Any thoughts?

v2:
 - SKIP when a stride/format is not supported by the kernel
 - perform a modeset at a low resolution on all pipes before running
   a test in order to be fast and provide coverage even without
   a display attached (requires a VGA or HDMI connector).
 - generate a subtest per pipe, plane, format and stride

Signed-off-by: Martin Peres <martin.peres at linux.intel.com>
---
 tests/Makefile.sources |   1 +
 tests/kms_fb_stride.c  | 312 +++++++++++++++++++++++++++++++++++++++++++++++++
 tests/meson.build      |   1 +
 3 files changed, 314 insertions(+)
 create mode 100644 tests/kms_fb_stride.c

diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index 870c9093..0e1eeb95 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -181,6 +181,7 @@ TESTS_progs = \
 	kms_cursor_legacy \
 	kms_draw_crc \
 	kms_fbcon_fbt \
+	kms_fb_stride \
 	kms_fence_pin_leak \
 	kms_flip \
 	kms_flip_event_leak \
diff --git a/tests/kms_fb_stride.c b/tests/kms_fb_stride.c
new file mode 100644
index 00000000..a86d68dd
--- /dev/null
+++ b/tests/kms_fb_stride.c
@@ -0,0 +1,312 @@
+/*
+ * Copyright © 2018 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:
+ *   Martin Peres <martin.peres at linux.intel.com>
+ */
+
+#include "igt.h"
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+typedef enum {
+	TEST_STRIDE_CRTC = 0,
+	TEST_STRIDE_2K = 2,
+	TEST_STRIDE_4K = 4,
+	TEST_STRIDE_8K = 8,
+	TEST_STRIDE_16K = 16,
+	TEST_STRIDE_32K = 32,
+} stride_t;
+
+typedef struct {
+	int drm_fd;
+	igt_display_t display;
+	igt_pipe_crc_t *pipe_crc;
+} data_t;
+
+static drmModeModeInfo
+get_lowres_mode(int drmfd, int max_hdisplay)
+{
+	drmModeRes *mode_resources = drmModeGetResources(drmfd);
+	drmModeModeInfo mode;
+	drmModeModeInfo std_1024_mode = {
+		.clock = 65000,
+		.hdisplay = 1024,
+		.hsync_start = 1048,
+		.hsync_end = 1184,
+		.htotal = 1344,
+		.hskew = 0,
+		.vdisplay = 768,
+		.vsync_start = 771,
+		.vsync_end = 777,
+		.vtotal = 806,
+		.vscan = 0,
+		.vrefresh = 60,
+		.flags = 0xA,
+		.type = 0x40,
+		.name = "Custom 1024x768",
+	};
+	bool found;
+	int i, j;
+
+	if (!mode_resources) {
+		igt_warn("drmModeGetResources failed: %s\n", strerror(errno));
+		return std_1024_mode;
+	}
+
+	found = false;
+	for (i = 0; i < mode_resources->count_connectors; i++) {
+		drmModeConnector *connector;
+
+		connector = drmModeGetConnectorCurrent(drmfd,
+						       mode_resources->connectors[i]);
+		if (!connector) {
+			igt_warn("could not get connector %i: %s\n",
+				 mode_resources->connectors[i], strerror(errno));
+			continue;
+		}
+
+		if (!connector->count_modes)
+			continue;
+
+		for (j = 0; j < connector->count_modes; j++) {
+			mode = connector->modes[j];
+			if (mode.hdisplay < max_hdisplay) {
+				found = true;
+				break;
+			}
+		}
+
+		drmModeFreeConnector(connector);
+	}
+
+	drmModeFreeResources(mode_resources);
+
+	if (!found)
+		return std_1024_mode;
+
+	return mode;
+}
+
+static void test_cleanup(data_t *data, igt_plane_t *plane, struct igt_fb *fb) {
+	igt_plane_set_fb(plane, NULL);
+	igt_display_commit2(&data->display, COMMIT_UNIVERSAL);
+	igt_remove_fb(data->drm_fd, fb);
+}
+
+static void test_format_plane_get_crc(data_t *data, igt_output_t *output,
+				      igt_plane_t *plane, uint32_t format,
+				      stride_t stride,
+				      igt_crc_t *crc /* out */) {
+	drmModeModeInfo *mode;
+	struct igt_fb fb;
+	cairo_t *cr;
+	int width, ret;
+
+	mode = igt_output_get_mode(output);
+
+	width = (stride == TEST_STRIDE_CRTC ? mode->hdisplay : stride * 1024);
+
+	igt_skip_on(__igt_create_fb(data->drm_fd, width, mode->vdisplay,
+		                    format, LOCAL_DRM_FORMAT_MOD_NONE, &fb,
+		                    NULL));
+
+	cr = igt_get_cairo_ctx(data->drm_fd, &fb);
+	igt_paint_test_pattern(cr, mode->hdisplay, mode->vdisplay);
+	igt_assert(cairo_status(cr) == 0);
+	cairo_destroy(cr);
+
+	/* set the fb with the wanted stride. If the stride is negative, we want
+	 * to fail because it means the pipe does not support the resolution of
+	 * the screen. If the stride is positive, this means we are testing an
+	 * increased stride and we want to skip if the kernel considers the mode
+	 * invalid.
+	 */
+	igt_plane_set_fb(plane, &fb);
+
+	ret = igt_display_try_commit2(&data->display, COMMIT_UNIVERSAL);
+	if (ret) {
+		/* reset the state and free the framebuffer */
+		test_cleanup(data, plane, &fb);
+
+		igt_skip("The kernel rejected setting a %ix%i framebuffer\n",
+		         width, mode->vdisplay);
+	}
+
+	igt_pipe_crc_collect_crc(data->pipe_crc, crc);
+
+	/* reset the state and free the framebuffer */
+	test_cleanup(data, plane, &fb);
+}
+
+static void test_format_plane(data_t *data, enum pipe pipe,
+			      igt_output_t *output, igt_plane_t *plane,
+			      uint32_t format, stride_t stride)
+{
+	drmModeModeInfo mode;
+	igt_crc_t crc_ref, crc;
+
+	mode = get_lowres_mode(data->drm_fd, 1025);
+	igt_output_override_mode(output, &mode);
+	igt_output_set_pipe(output, pipe);
+	igt_display_commit2(&data->display, data->display.is_atomic ? COMMIT_ATOMIC : COMMIT_LEGACY);
+
+	data->pipe_crc = igt_pipe_crc_new(data->drm_fd, pipe,
+						INTEL_PIPE_CRC_SOURCE_AUTO);
+
+	test_format_plane_get_crc(data, output, plane, format,
+	                          TEST_STRIDE_CRTC, &crc_ref);
+	test_format_plane_get_crc(data, output, plane, format,
+	                          stride, &crc);
+	igt_assert_crc_equal(&crc_ref, &crc);
+
+	igt_pipe_crc_stop(data->pipe_crc);
+	igt_pipe_crc_free(data->pipe_crc);
+
+	igt_output_set_pipe(output, PIPE_ANY);
+}
+
+
+static igt_output_t *
+find_suitable_connector(data_t *data, enum pipe pipe) {
+	igt_output_t *output;
+	drmModeRes *res;
+
+	/* make sure all connectors are free for our testing */
+	res = drmModeGetResources(data->drm_fd);
+	igt_assert(res);
+	kmstest_unset_all_crtcs(data->drm_fd, res);
+
+	/* find a connector that supports mode injection */
+	for_each_valid_output_on_pipe(&data->display, pipe, output) {
+		drmModeConnector *c;
+
+		/* find the first VGA or HDMI connector, since they are fast to
+		 * do a modeset for, and we can force a mode on them.
+		 */
+		c = output->config.connector;
+		if (!c || (c->connector_type != DRM_MODE_CONNECTOR_VGA &&
+			   c->connector_type != DRM_MODE_CONNECTOR_HDMIA &&
+			   c->connector_type != DRM_MODE_CONNECTOR_HDMIB))
+			continue;
+
+		return output;
+	}
+
+	igt_skip("No acceptable connector found on pipe %s\n",
+		 kmstest_pipe_name(pipe));
+}
+
+static igt_plane_t *
+find_plane(data_t *data, enum pipe pipe, int plane_id) {
+	igt_plane_t *plane;
+
+	for_each_plane_on_pipe(&data->display, pipe, plane)
+		if (plane->index == plane_id) {
+			if (plane->type == DRM_PLANE_TYPE_CURSOR)
+				igt_skip("The plane %s.%d is a cursor plane\n",
+					 kmstest_pipe_name(pipe), plane->index);
+			return plane;
+		}
+
+	igt_skip("The plane %s.%d could not be found\n",
+		    kmstest_pipe_name(pipe), plane->index);
+
+	return NULL;
+}
+
+static void
+setup_test(data_t *data, enum pipe pipe, stride_t stride, int plane_id, uint32_t format) {
+	igt_output_t *output;
+	igt_plane_t *plane;
+
+	/* make sure to skip early if the plane or format is not available */
+	igt_skip_on(plane_id >= data->display.pipes[pipe].n_planes);
+	igt_skip_on(!igt_fb_supported_format(format));
+
+	/* get all the specified resources */
+	output = find_suitable_connector(data, pipe);
+	plane = find_plane(data, pipe, plane_id);
+
+	test_format_plane(data, pipe, output, plane, format, stride);
+}
+
+/* formats and strides that will be tested on all pipes and all non-cursor
+ * planes
+ */
+stride_t strides[] = { TEST_STRIDE_4K, TEST_STRIDE_8K, TEST_STRIDE_16K };
+uint32_t formats[] = { DRM_FORMAT_RGB565, DRM_FORMAT_XRGB8888 };
+#define N_PLANES_MAX 4
+
+static void
+run_tests_for_pipe(data_t *data, enum pipe pipe)
+{
+	stride_t stride;
+	uint32_t format;
+	int plane_id, s, f;
+
+	igt_fixture {
+		igt_skip_on(pipe >= data->display.n_pipes);
+		igt_require(data->display.pipes[pipe].n_planes > 0);
+	}
+
+	for (plane_id = 0; plane_id < N_PLANES_MAX; plane_id++) {
+		for (f = 0; f < ARRAY_SIZE(formats); f++) {
+			format = formats[f];
+
+			for (s = 0; s < ARRAY_SIZE(strides); s++) {
+				stride = strides[s];
+
+				igt_subtest_f("pipe-%s-plane-%d-%c%c%c%c-stride-%dK",
+					kmstest_pipe_name(pipe), plane_id, format,
+					format >> 8, format >> 16, format >> 24,
+					stride)
+					setup_test(data, pipe, stride, plane_id, format);
+			}
+		}
+	}
+}
+
+static data_t data;
+
+igt_main
+{
+	enum pipe pipe;
+
+	igt_fixture {
+		data.drm_fd = drm_open_driver_master(DRIVER_INTEL);
+
+		kmstest_set_vt_graphics_mode();
+
+		igt_require_pipe_crc(data.drm_fd);
+		igt_display_init(&data.display, data.drm_fd);
+	}
+
+	for_each_pipe_static(pipe)
+		run_tests_for_pipe(&data, pipe);
+
+	igt_fixture {
+		igt_display_fini(&data.display);
+	}
+}
diff --git a/tests/meson.build b/tests/meson.build
index 521a4c42..8b048300 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -159,6 +159,7 @@ test_progs = [
 	'kms_cursor_legacy',
 	'kms_draw_crc',
 	'kms_fbcon_fbt',
+	'kms_fb_stride',
 	'kms_fence_pin_leak',
 	'kms_flip',
 	'kms_flip_event_leak',
-- 
2.16.1



More information about the igt-dev mailing list