[PATCH i-g-t 1/2] tests/kms_vrr: New subtest for CMRR
Bhanuprakash Modem
bhanuprakash.modem at intel.com
Fri Jun 7 12:48:39 UTC 2024
CMRR is an variation of VRR where it varies Vtotal slightly
(between additional 0 and 1 Vtotal scanlines) to match content
rate exactly without frame drops using the adaptive sync framework.
This patch creates a new subtest to validate the CMRR as below:
- Request flips with the refresh_rate * 1.001
- Flips should happen at the frequency of refresh_rate.
V2:
- Tweak the clock if CMRR supported mode not found (Ankit)
- Rebase
V3:
- Read flip completion events instead of Vblank evants
Signed-off-by: Bhanuprakash Modem <bhanuprakash.modem at intel.com>
---
tests/kms_vrr.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 128 insertions(+), 2 deletions(-)
diff --git a/tests/kms_vrr.c b/tests/kms_vrr.c
index 7f64d6806..f3daa55f5 100644
--- a/tests/kms_vrr.c
+++ b/tests/kms_vrr.c
@@ -37,6 +37,11 @@
#include <signal.h>
/**
+ * SUBTEST: cmrr
+ * Description: Test to validate the content rate to exactly match with the
+ * requested rate without any frame drops.
+ * Functionality: CMRR
+ *
* SUBTEST: flip-basic
* Description: Tests that VRR is enabled and that the difference between flip
* timestamps converges to the requested rate
@@ -87,6 +92,9 @@
*/
#define TEST_DURATION_NS (5000000000ull)
+#define CMRR_PRECISION_TOLERANCE 10
+#define CMRR_MULTIPLIER 1.001
+
enum {
TEST_BASIC = 1 << 0,
TEST_DPMS = 1 << 1,
@@ -97,7 +105,8 @@ enum {
TEST_SEAMLESS_VIRTUAL_RR = 1 << 6,
TEST_FASTSET = 1 << 7,
TEST_MAXMIN = 1 << 8,
- TEST_NEGATIVE = 1 << 9,
+ TEST_CMRR = 1 << 9,
+ TEST_NEGATIVE = 1 << 10,
};
enum {
@@ -232,6 +241,21 @@ virtual_rr_vrr_range_mode(igt_output_t *output, unsigned int virtual_refresh_rat
return mode;
}
+static bool
+is_cmrr_mode(drmModeModeInfoPtr mode)
+{
+ int calculated_refresh, actual_refresh, pixel_clock_per_line;
+
+ actual_refresh = mode->vrefresh * 100;
+ pixel_clock_per_line = mode->clock * 1000 / mode->htotal;
+ calculated_refresh = pixel_clock_per_line * 100 / mode->vtotal;
+
+ if ((actual_refresh - calculated_refresh) < CMRR_PRECISION_TOLERANCE)
+ return false;
+
+ return true;
+}
+
/* Read min and max vrr range from the connector debugfs. */
static range_t
get_vrr_range(data_t *data, igt_output_t *output)
@@ -496,6 +520,57 @@ flip_and_measure(data_t *data, igt_output_t *output, enum pipe pipe,
return total_flip ? ((total_pass * 100) / total_flip) : 0;
}
+static uint32_t
+flip_and_measure_cmrr(data_t *data, igt_output_t *output, enum pipe pipe,
+ uint64_t duration_ns)
+{
+ uint64_t start_ns, last_event_ns, event_ns;
+ uint32_t total_flip = 0, total_pass = 0;
+ bool front = false;
+ drmModeModeInfoPtr mode = igt_output_get_mode(output);
+ uint64_t req_rate_ns = rate_from_refresh(mode->vrefresh * CMRR_MULTIPLIER);
+ uint64_t exp_rate_ns = rate_from_refresh(mode->vrefresh);
+ uint64_t threshold_ns = exp_rate_ns / mode->vdisplay; /* Upto 1 scan line. */
+
+ igt_info("CMRR on: requested rate: %"PRIu64" ns (%f Hz) "
+ "expected rate: %"PRIu64" ns - %"PRIu64" ns (%f-%f Hz)\n",
+ req_rate_ns, mode->vrefresh * CMRR_MULTIPLIER,
+ (exp_rate_ns - threshold_ns), (exp_rate_ns + threshold_ns),
+ (float)NSECS_PER_SEC / (exp_rate_ns + threshold_ns),
+ (float)NSECS_PER_SEC / (exp_rate_ns - threshold_ns));
+
+ do_flip(data, &data->fb[0]);
+ start_ns = last_event_ns = get_kernel_event_ns(data, DRM_EVENT_FLIP_COMPLETE);
+ do {
+ int64_t target_ns, wait_ns, diff_ns = exp_rate_ns;
+
+ front = !front;
+ do_flip(data, front ? &data->fb[1] : &data->fb[0]);
+
+ event_ns = get_kernel_event_ns(data, DRM_EVENT_FLIP_COMPLETE);
+ igt_debug("event_ns - last_event_ns: %"PRIu64" ns (%f Hz)\n",
+ event_ns - last_event_ns, (float)NSECS_PER_SEC / (event_ns - last_event_ns));
+
+ diff_ns -= event_ns - last_event_ns;
+ if (llabs(diff_ns) <= threshold_ns)
+ total_pass += 1;
+
+ last_event_ns = event_ns;
+ total_flip += 1;
+
+ diff_ns = event_ns - start_ns;
+ wait_ns = ((diff_ns + req_rate_ns - 1) / req_rate_ns) * req_rate_ns;
+ wait_ns -= diff_ns;
+ target_ns = event_ns + wait_ns;
+ while (get_time_ns() < target_ns - 10);
+ } while (event_ns - start_ns <= duration_ns);
+
+ igt_info("Completed %u flips, %u vblanks were in threshold for (%u Hz) %"PRIu64"ns.\n",
+ total_flip, total_pass, mode->vrefresh, req_rate_ns);
+
+ return total_flip ? ((total_pass * 100) / total_flip) : 0;
+}
+
/* Basic VRR flip functionality test - enable, measure, disable, measure */
static void
test_basic(data_t *data, enum pipe pipe, igt_output_t *output, uint32_t flags)
@@ -702,6 +777,49 @@ test_seamless_virtual_rr_basic(data_t *data, enum pipe pipe, igt_output_t *outpu
}
}
+static void
+test_cmrr(data_t *data, enum pipe pipe, igt_output_t *output, uint32_t flags)
+{
+ uint32_t result;
+ int i;
+ bool found = false;
+ drmModeConnectorPtr connector = output->config.connector;
+ drmModeModeInfo mode = *igt_output_get_mode(output);
+
+ igt_info("CMRR test execution on %s, PIPE_%s with VRR range: (%u-%u) Hz\n",
+ output->name, kmstest_pipe_name(pipe), data->range.min, data->range.max);
+
+ for (i = 0; i < connector->count_modes; i++) {
+ if (is_cmrr_mode(&connector->modes[i])) {
+ mode = connector->modes[i];
+
+ found = true;
+ break;
+ }
+ }
+
+ igt_info("Selected mode: ");
+ kmstest_dump_mode(&mode);
+
+ if (!found) {
+ igt_info("No CMRR mode found on %s, try to tweak the clock.\n", output->name);
+
+ mode.clock = (mode.htotal * mode.vtotal * (mode.vrefresh * CMRR_MULTIPLIER)) / 1000;
+
+ igt_info("Tweaked mode: ");
+ kmstest_dump_mode(&mode);
+ }
+
+ igt_output_override_mode(output, &mode);
+ igt_display_commit2(&data->display, COMMIT_ATOMIC);
+
+ prepare_test(data, output, pipe);
+ result = flip_and_measure_cmrr(data, output, pipe, TEST_DURATION_NS * 2);
+ igt_assert_f(result > 75,
+ "Refresh rate (%u Hz) %"PRIu64"ns: Target CMRR on threshold not reached, result was %u%%\n",
+ mode.vrefresh, rate_from_refresh(mode.vrefresh), result);
+}
+
static void test_cleanup(data_t *data, enum pipe pipe, igt_output_t *output)
{
if (vrr_capable(output))
@@ -718,7 +836,7 @@ static void test_cleanup(data_t *data, enum pipe pipe, igt_output_t *output)
static bool output_constraint(data_t *data, igt_output_t *output, uint32_t flags)
{
- if ((flags & (TEST_SEAMLESS_VRR | TEST_SEAMLESS_DRRS)) &&
+ if ((flags & (TEST_SEAMLESS_VRR | TEST_SEAMLESS_DRRS | TEST_CMRR)) &&
output->config.connector->connector_type != DRM_MODE_CONNECTOR_eDP)
return false;
@@ -906,6 +1024,14 @@ igt_main_args("drs:", long_opts, help_str, opt_handler, &data)
igt_describe("Test to switch to any custom virtual mode in VRR range without modeset.");
igt_subtest_with_dynamic("seamless-rr-switch-virtual")
run_vrr_test(&data, test_seamless_virtual_rr_basic, TEST_SEAMLESS_VIRTUAL_RR);
+
+ igt_describe("Test to validate the the content rate exactly match with the "
+ "requested rate without any frame drops.");
+ igt_subtest_with_dynamic("cmrr") {
+ igt_require(intel_display_ver(intel_get_drm_devid(data.drm_fd)) >= 20);
+
+ run_vrr_test(&data, test_cmrr, TEST_CMRR);
+ }
}
igt_fixture {
--
2.43.2
More information about the igt-dev
mailing list