[i-g-t 1/2] tests/kms_vrr: New subtest to swith RR without modeset

Bhanuprakash Modem bhanuprakash.modem at intel.com
Tue Nov 28 11:12:27 UTC 2023


V2: - Add DRRS seamless support

Signed-off-by: Bhanuprakash Modem <bhanuprakash.modem at intel.com>
---
 tests/kms_vrr.c | 185 +++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 152 insertions(+), 33 deletions(-)

diff --git a/tests/kms_vrr.c b/tests/kms_vrr.c
index 13b347631..8afdc2027 100644
--- a/tests/kms_vrr.c
+++ b/tests/kms_vrr.c
@@ -53,6 +53,10 @@
  * SUBTEST: flipline
  * Description: Make sure that flips happen at flipline decision boundary.
  *
+ * SUBTEST: seamless-rr-switch
+ * Description: Test to switch RR seamlessly without modeset.
+ * Functionality: adaptive_sync, drrs, lrr
+ *
  * SUBTEST: negative-basic
  * Description: Make sure that VRR should not be enabled on the Non-VRR panel.
  */
@@ -65,19 +69,19 @@
  */
 #define TEST_DURATION_NS (5000000000ull)
 
-#define DRM_MODE_FMT    "\"%s\": %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x"
-#define DRM_MODE_ARG(m) \
-	(m)->name, (m)->vrefresh, (m)->clock, \
-	(m)->hdisplay, (m)->hsync_start, (m)->hsync_end, (m)->htotal, \
-	(m)->vdisplay, (m)->vsync_start, (m)->vsync_end, (m)->vtotal, \
-	(m)->type, (m)->flags
+enum {
+	HIGH_RR_MODE,
+	LOW_RR_MODE,
+	RR_MODES_COUNT,
+};
 
 enum {
 	TEST_BASIC = 1 << 0,
 	TEST_DPMS = 1 << 1,
 	TEST_SUSPEND = 1 << 2,
 	TEST_FLIPLINE = 1 << 3,
-	TEST_NEGATIVE = 1 << 4,
+	TEST_SEAMLESS_RR = 1 << 4,
+	TEST_NEGATIVE = 1 << 5,
 };
 
 typedef struct range {
@@ -92,6 +96,7 @@ typedef struct data {
 	igt_fb_t fb0;
 	igt_fb_t fb1;
 	range_t range;
+	drmModeModeInfo switch_modes[RR_MODES_COUNT];
 } data_t;
 
 typedef struct vtest_ns {
@@ -162,15 +167,11 @@ output_mode_with_maxrate(igt_output_t *output, unsigned int vrr_max)
 	drmModeConnectorPtr connector = output->config.connector;
 	drmModeModeInfo mode = *igt_output_get_mode(output);
 
-	igt_debug("Default Mode " DRM_MODE_FMT "\n", DRM_MODE_ARG(&mode));
-
 	for (i = 0; i < connector->count_modes; i++)
 		if (connector->modes[i].vrefresh > mode.vrefresh &&
 		    connector->modes[i].vrefresh <= vrr_max)
 			mode = connector->modes[i];
 
-	igt_debug("Override Mode " DRM_MODE_FMT "\n", DRM_MODE_ARG(&mode));
-
 	return mode;
 }
 
@@ -238,19 +239,7 @@ static void prepare_test(data_t *data, igt_output_t *output, enum pipe pipe)
 	drmModeModeInfo mode;
 	cairo_t *cr;
 
-	/* Reset output */
-	igt_display_reset(&data->display);
-	igt_output_set_pipe(output, pipe);
-
-	/* Capture VRR range */
-	data->range = get_vrr_range(data, output);
-
-	/* Override mode with max vrefresh.
-	 *   - vrr_min range should be less than the override mode vrefresh.
-	 *   - Limit the vrr_max range with the override mode vrefresh.
-	 */
-	mode = output_mode_with_maxrate(output, data->range.max);
-	igt_require(mode.vrefresh > data->range.min);
+	mode = data->switch_modes[HIGH_RR_MODE];
 	data->range.max = mode.vrefresh;
 	igt_output_override_mode(output, &mode);
 
@@ -340,7 +329,7 @@ flip_and_measure(data_t *data, igt_output_t *output, enum pipe pipe,
 		 */
 		event_ns = get_kernel_event_ns(data, DRM_EVENT_FLIP_COMPLETE);
 
-		igt_debug("event_ns - last_event_ns: %"PRIu64"\n",
+		igt_info("event_ns - last_event_ns: %"PRIu64"\n",
 						(event_ns - last_event_ns));
 
 		/*
@@ -485,6 +474,136 @@ test_basic(data_t *data, enum pipe pipe, igt_output_t *output, uint32_t flags)
 	igt_remove_fb(data->drm_fd, &data->fb0);
 }
 
+static void
+test_seamless_rr_basic(data_t *data, enum pipe pipe, igt_output_t *output, uint32_t flags)
+{
+	uint32_t result;
+	vtest_ns_t vtest_ns;
+	range_t range;
+	uint64_t rate;
+
+	igt_info("Use HIGH_RR Mode as default: ");
+	kmstest_dump_mode(&data->switch_modes[HIGH_RR_MODE]);
+
+	prepare_test(data, output, pipe);
+	range = data->range;
+	vtest_ns = get_test_rate_ns(range);
+
+	rate = vtest_ns.max;
+	result = flip_and_measure(data, output, pipe, rate, TEST_DURATION_NS);
+	igt_info("Refresh rate (%u Hz) %"PRIu64"ns: %u%%\n", range.max, rate, result);
+
+	/* Switch to low rr mode without modeset. */
+	igt_info("Override with LOW_RR Mode: ");
+	kmstest_dump_mode(&data->switch_modes[LOW_RR_MODE]);
+	igt_output_override_mode(output, &data->switch_modes[LOW_RR_MODE]);
+	igt_assert(igt_display_try_commit_atomic(&data->display, 0, NULL) == 0);
+
+	rate = vtest_ns.min;
+	result = flip_and_measure(data, output, pipe, rate, TEST_DURATION_NS);
+	igt_info("Refresh rate (%u Hz) %"PRIu64"ns: %u%%\n", range.min, rate, result);
+
+	/* Switch back to high rr mode without modeset. */
+	igt_info("Override with HIGH_RR Mode: ");
+	kmstest_dump_mode(&data->switch_modes[HIGH_RR_MODE]);
+	igt_output_override_mode(output, &data->switch_modes[HIGH_RR_MODE]);
+	igt_assert(igt_display_try_commit_atomic(&data->display, 0, NULL) == 0);
+
+	/* Clean-up */
+	igt_plane_set_fb(data->primary, NULL);
+	igt_output_set_pipe(output, PIPE_NONE);
+	igt_output_override_mode(output, NULL);
+	igt_display_commit2(&data->display, COMMIT_ATOMIC);
+
+	igt_remove_fb(data->drm_fd, &data->fb1);
+	igt_remove_fb(data->drm_fd, &data->fb0);
+}
+
+static bool output_constraint(data_t *data, igt_output_t *output, uint32_t flags)
+{
+	/* Reset output */
+	igt_display_reset(&data->display);
+
+	/* Capture VRR range */
+	data->range = get_vrr_range(data, output);
+
+	/* Override mode with max vrefresh.
+	 *   - vrr_min range should be less than the override mode vrefresh.
+	 *   - Limit the vrr_max range with the override mode vrefresh.
+	 */
+	data->switch_modes[HIGH_RR_MODE] = output_mode_with_maxrate(output, data->range.max);
+	if (data->switch_modes[HIGH_RR_MODE].vrefresh < data->range.min)
+		return false;
+
+	if (!(flags & TEST_SEAMLESS_RR))
+		return true;
+
+	/* Search for a low refresh rate mode */
+	for_each_connector_mode(output) {
+		drmModeModeInfo mode = output->config.connector->modes[j__];
+
+		/* TODO: improve checks for downclock */
+		if (mode.hdisplay != data->switch_modes[HIGH_RR_MODE].hdisplay ||
+		    mode.vdisplay != data->switch_modes[HIGH_RR_MODE].vdisplay)
+			continue;
+
+		if (mode.vrefresh >= data->switch_modes[HIGH_RR_MODE].vrefresh ||
+		    mode.vrefresh < data->range.min)
+			continue;
+
+		memcpy(&data->switch_modes[LOW_RR_MODE], &mode, sizeof(drmModeModeInfo));
+
+		return true;
+	}
+
+	return false;
+}
+
+static bool drrs_capable(data_t *data, igt_output_t *output)
+{
+	if (output->config.connector->connector_type != DRM_MODE_CONNECTOR_eDP)
+		return false;
+
+	/*
+	 * FIXME to read the DRRS capability, currently assuming:
+	 * - Panel should contain 2 modes only
+	 * - Both modes should have the same resolution but different RR
+	 */
+	if (output->config.connector->count_modes != 2)
+		return false;
+
+	data->switch_modes[HIGH_RR_MODE] = output->config.connector->modes[0];
+	data->switch_modes[LOW_RR_MODE] = output->config.connector->modes[1];
+
+	if (data->switch_modes[HIGH_RR_MODE].hdisplay != data->switch_modes[LOW_RR_MODE].hdisplay ||
+	    data->switch_modes[HIGH_RR_MODE].vdisplay != data->switch_modes[LOW_RR_MODE].vdisplay ||
+	    data->switch_modes[HIGH_RR_MODE].vrefresh <= data->switch_modes[LOW_RR_MODE].vrefresh)
+		return false;
+
+	return true;
+}
+
+static bool config_constraint(data_t *data, igt_output_t *output, uint32_t flags)
+{
+	if (!has_vrr(output))
+		return false;
+
+	if ((flags & TEST_SEAMLESS_RR) && !vrr_capable(output))
+		return drrs_capable(data, output);
+
+	/* For Negative tests, panel should be non-vrr. */
+	if ((flags & TEST_NEGATIVE) && vrr_capable(output))
+		return false;
+
+	if (!(flags & TEST_NEGATIVE) && !vrr_capable(output))
+		return false;
+
+	if (!output_constraint(data, output, flags))
+		return false;
+
+	return true;
+}
+
 /* Runs tests on outputs that are VRR capable. */
 static void
 run_vrr_test(data_t *data, test_t test, uint32_t flags)
@@ -494,14 +613,7 @@ run_vrr_test(data_t *data, test_t test, uint32_t flags)
 	for_each_connected_output(&data->display, output) {
 		enum pipe pipe;
 
-		if (!has_vrr(output))
-			continue;
-
-		/* For Negative tests, panel should be non-vrr. */
-		if ((flags & TEST_NEGATIVE) && vrr_capable(output))
-			continue;
-
-		if ((flags & ~TEST_NEGATIVE) && !vrr_capable(output))
+		if (!config_constraint(data, output, flags))
 			continue;
 
 		for_each_pipe(&data->display, pipe) {
@@ -509,6 +621,7 @@ run_vrr_test(data_t *data, test_t test, uint32_t flags)
 				igt_display_reset(&data->display);
 
 				igt_output_set_pipe(output, pipe);
+				igt_output_override_mode(output, &data->switch_modes[HIGH_RR_MODE]);
 				if (!intel_pipe_output_combo_valid(&data->display))
 					continue;
 
@@ -558,6 +671,12 @@ igt_main
 	igt_subtest_with_dynamic("negative-basic")
 		run_vrr_test(&data, test_basic, TEST_NEGATIVE);
 
+	igt_describe("Test to switch RR seamlessly without modeset.");
+	igt_subtest_with_dynamic("seamless-rr-switch") {
+		igt_require_intel(data.drm_fd);
+		run_vrr_test(&data, test_seamless_rr_basic, TEST_SEAMLESS_RR);
+	}
+
 	igt_fixture {
 		igt_display_fini(&data.display);
 		drm_close_driver(data.drm_fd);
-- 
2.40.0



More information about the Intel-gfx-trybot mailing list