[igt-dev] [PATCH i-g-t] tests/kms_atomic_multi: new test

Simon Ser simon.ser at intel.com
Fri Sep 6 14:13:52 UTC 2019


This test performs a single atomic commit on multiple CRTCs at once. The goal
is to check that a page-flip event for each CRTC is received.

I chose not to integrate this to an existing test, because kms_atomic is
basically a single function with lots of options. Integrating this test to
kms_atomic would mix up these two and make it difficult to understand the test.

Changes from RFC to v1:
- Added 1x, 3x, 4x tests
- Improve pipe allocation for outputs
- Handle multiple page-flip events for a single poll call
- Use TEST_ONLY to make sure the configuration we choose is supported

Signed-off-by: Simon Ser <simon.ser at intel.com>
Cc: Ville Syrjälä <ville.syrjala at linux.intel.com>
---
 tests/Makefile.sources   |   1 +
 tests/kms_atomic_multi.c | 206 +++++++++++++++++++++++++++++++++++++++
 tests/meson.build        |   1 +
 3 files changed, 208 insertions(+)
 create mode 100644 tests/kms_atomic_multi.c

diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index c02e4d9489f2..e08968d2b0fc 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -29,6 +29,7 @@ TESTS_progs = \
 	kms_atomic \
 	kms_atomic_interruptible \
 	kms_atomic_transition \
+	kms_atomic_multi \
 	kms_available_modes_crc \
 	kms_big_fb \
 	kms_busy \
diff --git a/tests/kms_atomic_multi.c b/tests/kms_atomic_multi.c
new file mode 100644
index 000000000000..dd4dc66a9952
--- /dev/null
+++ b/tests/kms_atomic_multi.c
@@ -0,0 +1,206 @@
+/*
+ * 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: Simon Ser <simon.ser at intel.com>
+ */
+
+#include <poll.h>
+#include <drm_mode.h>
+#include <drm_fourcc.h>
+#include "igt.h"
+
+#define MAX_OUTPUTS 4
+
+struct test_connector {
+	igt_output_t *output;
+	struct igt_fb fb;
+	drmModeConnectorPtr connector;
+	enum pipe pipe;
+	bool got_page_flip;
+};
+
+struct test_data {
+	int drm_fd;
+	igt_display_t *display;
+	struct test_connector conns[MAX_OUTPUTS];
+	size_t conns_len;
+};
+
+static void create_and_set_fb(struct test_data *data,
+			      struct test_connector *conn)
+{
+	igt_plane_t *primary;
+	drmModeModeInfo *mode;
+
+	mode = igt_output_get_mode(conn->output);
+	igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
+			      DRM_FORMAT_XBGR8888, LOCAL_DRM_FORMAT_MOD_NONE,
+			      &conn->fb);
+
+	primary = igt_output_get_plane_type(conn->output, DRM_PLANE_TYPE_PRIMARY);
+	igt_assert(primary);
+
+	igt_plane_set_fb(primary, &conn->fb);
+}
+
+static void pick_n_outputs(struct test_data *data, size_t n)
+{
+	igt_output_t *output;
+	struct test_connector *conn;
+	enum pipe pipe;
+	int ret;
+
+	assert(n <= MAX_OUTPUTS);
+
+	for_each_connected_output(data->display, output)
+		igt_output_set_pipe(output, PIPE_NONE);
+
+	data->conns_len = 0;
+	for_each_pipe(data->display, pipe) {
+		for_each_valid_output_on_pipe(data->display, pipe, output) {
+			if (output->pending_pipe != PIPE_NONE)
+				continue;
+			if (data->conns_len >= n)
+				break;
+
+			conn = &data->conns[data->conns_len];
+			conn->output = output;
+			conn->pipe = pipe;
+			igt_output_set_pipe(output, conn->pipe);
+			data->conns_len++;
+			break;
+		}
+	}
+
+	igt_skip_on_f(data->conns_len < n,
+		      "Failed to find enough outputs with separate pipes: "
+		      "wanted %zu, got %zu\n",
+		      n, data->conns_len);
+	ret = igt_display_try_commit_atomic(data->display,
+					    DRM_MODE_ATOMIC_TEST_ONLY |
+					    DRM_MODE_ATOMIC_ALLOW_MODESET,
+					    NULL);
+	igt_skip_on_f(ret == -EINVAL || ret == -ERANGE,
+		      "Atomic test commit failed with %zu outputs: %d\n",
+		      n, ret);
+	igt_assert_f(ret == 0, "Atomic test commit failed: %d\n", ret);
+}
+
+static bool got_all_page_flips(struct test_data *data)
+{
+	size_t i;
+
+	for (i = 0; i < data->conns_len; i++) {
+		if (!data->conns[i].got_page_flip)
+			return false;
+	}
+
+	return true;
+}
+
+static void page_flip_handler(int fd, unsigned seq, unsigned tv_sec,
+			      unsigned tv_usec, unsigned crtc_id, void *_data)
+{
+	struct test_data *data = _data;
+	struct test_connector *conn;
+	size_t i;
+
+	igt_debug("Got page-flip event for CRTC %u\n", crtc_id);
+
+	for (i = 0; i < data->conns_len; i++) {
+		conn = &data->conns[i];
+		if (data->display->pipes[conn->pipe].crtc_id == crtc_id) {
+			igt_assert_f(!conn->got_page_flip,
+				     "Got two page-flips for CRTC %u\n",
+				     crtc_id);
+			conn->got_page_flip = true;
+			return;
+		}
+	}
+
+	igt_assert_f(false, "Got page-flip event for unexpected CRTC %u\n",
+		     crtc_id);
+}
+
+IGT_TEST_DESCRIPTION("Atomic commits on multiple CRTCs at a time");
+igt_main
+{
+	int ret;
+	struct test_data data = {0};
+	igt_display_t display;
+	struct pollfd pfd = {0};
+	drmEventContext drm_event = {0};
+	size_t n, i;
+
+	igt_fixture {
+		data.drm_fd = drm_open_driver_master(DRIVER_ANY);
+		kmstest_set_vt_graphics_mode();
+		igt_display_require(&display, data.drm_fd);
+		igt_display_reset(&display);
+		igt_require(display.is_atomic);
+		data.display = &display;
+
+		pfd.fd = data.drm_fd;
+		pfd.events = POLLIN;
+
+		drm_event.version = 3;
+		drm_event.page_flip_handler2 = page_flip_handler;
+	}
+
+	for (n = 1; n <= MAX_OUTPUTS; n++) {
+		igt_describe_f("Pick %zu outputs, perform an atomic commit "
+			       "performing a page-flip on all of them, check "
+			       "we get correct page-flip events", n);
+		igt_subtest_f("%zux-flip", n) {
+			pick_n_outputs(&data, n);
+
+			igt_display_commit_atomic(data.display,
+						  DRM_MODE_ATOMIC_ALLOW_MODESET,
+						  NULL);
+
+			for (i = 0; i < n; i++) {
+				create_and_set_fb(&data, &data.conns[i]);
+			}
+
+			igt_display_commit_atomic(data.display,
+						  DRM_MODE_ATOMIC_NONBLOCK |
+						  DRM_MODE_PAGE_FLIP_EVENT,
+						  &data);
+
+			while (!got_all_page_flips(&data)) {
+				ret = poll(&pfd, 1, 1000);
+				igt_assert(ret == 1);
+				drmHandleEvent(data.drm_fd, &drm_event);
+			}
+
+			for (i = 0; i < n; i++) {
+				igt_remove_fb(data.drm_fd, &data.conns[i].fb);
+			}
+		}
+	}
+
+	igt_fixture {
+		close(data.drm_fd);
+		kmstest_restore_vt_mode();
+		igt_display_fini(data.display);
+	}
+}
diff --git a/tests/meson.build b/tests/meson.build
index a7b2b3221304..df00ab4a2f81 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -14,6 +14,7 @@ test_progs = [
 	'kms_atomic',
 	'kms_atomic_interruptible',
 	'kms_atomic_transition',
+	'kms_atomic_multi',
 	'kms_available_modes_crc',
 	'kms_big_fb',
 	'kms_busy',
--
2.23.0



More information about the igt-dev mailing list