From: "Borah, Chaitanya Kumar" <chaitanya.kumar.borah@intel.com>
To: Naladala Ramanaidu <ramanaidu.naladala@intel.com>,
<igt-dev@lists.freedesktop.org>
Cc: <mitulkumar.ajitkumar.golani@intel.com>, <karthik.b.s@intel.com>
Subject: Re: [PATCH i-g-t v6 3/3] tests/kms_vrr: Add CMRR fixed and video mode subtests
Date: Thu, 10 Sep 2026 15:55:29 +0530 [thread overview]
Message-ID: <e7bc3094-7254-4482-a17b-de4487b1cdf4@intel.com> (raw)
In-Reply-To: <20260907174836.3159214-4-ramanaidu.naladala@intel.com>
On 9/7/2026 11:18 PM, Naladala Ramanaidu wrote:
> Add test coverage to validate Content Match Refresh Rate (CMRR)
> behavior across both fixed and video timing display modes.
>
> This introduces a shared helper library to support refresh-rate
> mode selection and parsing, along with two new test cases covering
> fixed-mode and video-mode scenarios.
>
> The new tests measure actual display refresh timing during CMRR
> operation and compare it against the expected target rate to
> verify correctness. Video mode coverage validates behavior across
> standard video timing rates, while fixed mode coverage targets
> display modes that fall outside the standard video timing set.
>
> Each test cycles through the relevant refresh configurations,
> applying and resetting the appropriate settings between
> measurement passes to ensure consistent and isolated test results.
>
> v2: Fix test issue.
> v3: Address review comments. (Mitul)
> v4: Fix test issue.
> v5: Address below review comments:
> - Rename CMRR fixed/non-video mode references to desktop
> mode. (Chaitanya)
> - Factor out vblank timestamp/sequence retrieval into
> helper. (Chaitanya)
> - Simplify CMRR tests by extracting common mode logic. (Chaitanya,
> Mitul)
> - Refactor CMRR refresh-rate verification and frame filtering.
> v6: Address below review comments:
> - Document skipped vblank intervals and fix seq_delta
> format. (Chaitanya)
> - Fix minor style issues in CMRR tests. (Chaitanya, Mitul)
> - Add mode existence checks for CMRR test paths. (Chaitanya)
>
> Assisted-by: GitHub Copilot:Claude Opus 4.6
> Signed-off-by: Naladala Ramanaidu <ramanaidu.naladala@intel.com>
> ---
> tests/kms_vrr.c | 240 ++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 240 insertions(+)
>
> diff --git a/tests/kms_vrr.c b/tests/kms_vrr.c
> index 27f18e8d0..109b4629d 100644
> --- a/tests/kms_vrr.c
> +++ b/tests/kms_vrr.c
> @@ -32,6 +32,7 @@
> #include "igt_pm.h"
> #include "igt_psr.h"
> #include "i915/intel_drrs.h"
> +#include "igt_vrr.h"
> #include "sw_sync.h"
> #include <fcntl.h>
> #include <signal.h>
> @@ -80,9 +81,22 @@
> *
> * SUBTEST: lobf-dc3co
> * Description: Test DC3CO entry during LOBF.
> + *
> + * SUBTEST: cmrr-desktop-mode
> + * Description: Test to set a desktop mode CMRR target refresh rate and verify
> + * it is correctly applied.
> + *
> + * SUBTEST: cmrr-video-mode
> + * Description: Test to set standard video timing refresh rates via CMRR
> + * and verify each target rate is correctly applied.
> */
>
> #define NSECS_PER_SEC (1000000000ull)
> +#define CMRR_NUMERATOR 1000ULL
> +#define CMRR_DENOMINATOR 1000ULL
> +#define CMRR_VIDEO_MODE_DENOMINATOR 1001ULL
> +#define TARGET_RR_SAMP_COUNT 100
> +#define CMRR_RR_TOLERANCE_HZ 0.02
>
> /*
> * Each test measurement step runs for ~5 seconds.
> @@ -103,6 +117,14 @@ enum {
> TEST_LINK_OFF = 1 << 10,
> TEST_NEGATIVE = 1 << 11,
> TEST_FORCE_RR = 1 << 12,
> + TEST_CMRR_DESKTOP_MODE = 1 << 13,
> + TEST_CMRR_VIDEO_MODE = 1 << 14,
> +};
> +
> +enum {
> + CMRR_VIDEO_MODE,
> + CMRR_DESKTOP_MODE,
> + CMRR_DISABLE,
> };
>
> enum {
> @@ -221,6 +243,38 @@ output_mode_with_maxrate(igt_output_t *output, unsigned int vrr_max)
> return mode;
> }
>
> +/**
> + * get_mode_with_video_timing:
> + * @output: Display output containing connector mode list
> + * @fps: Requested integer refresh rate in Hz
> + * @matched_mode: Returned mode that matches @fps
> + *
> + * Find and return a connector mode that matches the requested
> + * video timing refresh rate in Hz.
> + *
> + * Returns: true when a mode is found, false otherwise
> + */
> +
> +static bool
> +get_mode_with_video_timing(igt_output_t *output, uint32_t fps,
> + drmModeModeInfo *matched_mode)
> +{
> + drmModeConnectorPtr connector;
> +
> + connector = output->config.connector;
> + if (!connector)
> + return false;
> +
> + for (int i = 0; i < connector->count_modes; i++) {
> + if (connector->modes[i].vrefresh == fps) {
> + *matched_mode = connector->modes[i];
> + return true;
> + }
> + }
> +
> + return false;
> +}
> +
> static drmModeModeInfo
> low_rr_mode_with_same_res(igt_output_t *output, unsigned int vrr_min)
> {
> @@ -580,6 +634,177 @@ flip_and_measure(data_t *data, igt_output_t *output,
> return 0;
> }
>
> +/* Measure and verify the effective refresh rate against the expected CMRR target rate. */
> +static void
> +flip_and_measure_target_rr(data_t *data, igt_crtc_t *crtc,
> + double vrefresh, uint32_t cmrr_mode)
> +{
> + uint64_t last_vblank_ns, vblank_ns, frame_time_ns;
> + uint64_t total_frame_time_ns = 0;
> + uint32_t last_seq, seq, seq_delta;
> + uint32_t err_frames = 0, valid_frames;
> + double avg_frame_time_ns, avg_refresh_rate;
> + double expected_rr = 0;
double space.
> + bool front = false;
> + uint32_t i;
> +
> + switch (cmrr_mode) {
> + case CMRR_VIDEO_MODE:
> + expected_rr = (vrefresh * CMRR_NUMERATOR) /
> + (double)CMRR_VIDEO_MODE_DENOMINATOR;
> + break;
> + case CMRR_DESKTOP_MODE:
> + expected_rr = (vrefresh * CMRR_NUMERATOR) /
> + (double)CMRR_DENOMINATOR;
> + break;
> + case CMRR_DISABLE:
> + expected_rr = vrefresh;
> + break;
> + default:
> + igt_assert_f(0, "Invalid CMRR mode %u\n", cmrr_mode);
> + }
> +
> + do_flip(data, &data->fb[0]);
> + (void)get_kernel_event_ns(data, DRM_EVENT_FLIP_COMPLETE);
> + igt_wait_for_vblank_ts_seq(crtc, &last_vblank_ns, &last_seq);
> +
> + for (i = 0; i < TARGET_RR_SAMP_COUNT; i++) {
> + front = !front;
> +
> + do_flip(data, front ? &data->fb[1] : &data->fb[0]);
> + igt_wait_for_vblank_ts_seq(crtc, &vblank_ns, &seq);
> + (void)get_kernel_event_ns(data, DRM_EVENT_FLIP_COMPLETE);
> +
> + frame_time_ns = vblank_ns - last_vblank_ns;
> + seq_delta = seq - last_seq;
> +
> + last_vblank_ns = vblank_ns;
> + last_seq = seq;
> +
> + /*
> + * Use only single-frame intervals. If delta > 1, one or
> + * more vblanks were missed, so the interval is not valid
> + * for calculating the average frame time.
> + */
> + if (seq_delta != 1) {
> + igt_debug("vblank seq delta = %u\n", seq_delta);
> + err_frames++;
> + continue;
> + }
> +
> + total_frame_time_ns += frame_time_ns;
> + }
> +
> + valid_frames = TARGET_RR_SAMP_COUNT - err_frames;
> +
> + igt_assert_f(valid_frames >= 90,
> + "Valid frames below threshold (90): valid_frames=%u, err_frames=%u\n",
> + valid_frames, err_frames);
> +
> + avg_frame_time_ns = (double)total_frame_time_ns / valid_frames;
> + avg_refresh_rate = (double)NSECS_PER_SEC / avg_frame_time_ns;
> +
> + igt_assert_f(fabs(avg_refresh_rate - expected_rr) <= CMRR_RR_TOLERANCE_HZ,
> + "CMRR refresh rate mismatch: measured avg_rr = %.3f Hz, "
> + "expected_rr = %.3f Hz\n",
> + avg_refresh_rate, expected_rr);
> +
> + igt_info("Average RR (Hz): %.2f, Expected RR (Hz): %.2f, error frames = %u\n",
> + avg_refresh_rate, expected_rr, err_frames);
> +}
> +
> +/**
Did you intend it to be a doc style comment?
> + * Programs the requested CMRR target refresh rate for @mode, verifies that the measured
> + * refresh rate matches the expected CMRR behavior,then disables CMRR and verifies that
nit: behaviour, then
> + * the refresh rate returns to the mode's nominal refresh rate. The function asserts that
> + * all target refresh rate programming operations succeed.
> + */
> +static void
> +run_cmrr(data_t *data, igt_crtc_t *crtc, igt_output_t *output,
> + const drmModeModeInfo *mode, uint32_t cmrr_mode)
> +{
> + uint32_t numerator, denominator;
> + bool ret;
> + double rr_from_mode = igt_vrr_mode_line_refresh_hz(mode);
> +
> + switch (cmrr_mode) {
> + case CMRR_VIDEO_MODE:
> + numerator = mode->vrefresh * CMRR_NUMERATOR;
> + denominator = CMRR_VIDEO_MODE_DENOMINATOR;
> + break;
> + case CMRR_DESKTOP_MODE:
> + numerator = mode->vrefresh * CMRR_NUMERATOR;
> + denominator = CMRR_DENOMINATOR;
> + break;
> + default:
> + igt_assert_f(0, "Unsupported CMRR mode %u\n",
> + cmrr_mode);
> + }
> +
> + igt_output_override_mode(output, mode);
> + igt_info("Override mode:");
> + kmstest_dump_mode((drmModeModeInfo *)mode);
> + igt_display_commit2(&data->display, COMMIT_ATOMIC);
> +
> + ret = igt_vrr_target_rr_debugfs_write(data->drm_fd,
> + crtc->crtc_index,
> + numerator,
> + denominator);
> + igt_assert_f(ret, "Failed to program CMRR target RR (%u/%u)\n",
> + numerator, denominator);
> +
> + flip_and_measure_target_rr(data, crtc, mode->vrefresh, cmrr_mode);
> +
> + ret = igt_vrr_target_rr_debugfs_write(data->drm_fd, crtc->crtc_index, 0, 0);
> +
> + igt_assert_f(ret, "Failed to disable CMRR target RR\n");
> +
> + flip_and_measure_target_rr(data, crtc, rr_from_mode, CMRR_DISABLE);
> +}
> +
> +/* Validate CMRR behavior for supported video and desktop display modes. */
> +static
> +void test_cmrr(data_t *data, igt_crtc_t *crtc,
> + igt_output_t *output, uint32_t flags)
> +{
> + drmModeModeInfo mode;
> + bool found = false;
> + drmModeConnectorPtr connector = output->config.connector;
> + uint32_t j;
> +
> + igt_require_f(igt_vrr_target_refresh_rate_supported(data->drm_fd, crtc->crtc_index),
> + "CMRR not supported\n");
> + prepare_test(data, output, crtc);
> + set_vrr_on_crtc(data, crtc, true, false);
> +
> + if (flags & TEST_CMRR_VIDEO_MODE) {
> + found = false;
> + for (j = 0; j < igt_vrr_standard_video_timing_fps_count; j++) {
> + if (!get_mode_with_video_timing(output,
> + igt_vrr_standard_video_timing_fps[j],
> + &mode))
> + continue;
> +
> + found = true;
> + run_cmrr(data, crtc, output, &mode, CMRR_VIDEO_MODE);
> + }
> + igt_require_f(found, "No video mode found.\n");
> + }
> +
> + if (flags & TEST_CMRR_DESKTOP_MODE) {
> + found = false;
> + for (j = 0; j < connector->count_modes; j++) {
> + mode = connector->modes[j];
> + if (igt_vrr_mode_line_refresh_hz(&mode) - mode.vrefresh <= 0.04)
> + continue;
> +
> + found = true;
> + run_cmrr(data, crtc, output, &mode, CMRR_DESKTOP_MODE);
> + }
> + igt_require_f(found, "No desktop mode found.\n");
> + }
> +}
> +
> /* Basic VRR flip functionality test - enable, measure, disable, measure */
> static void
> test_basic(data_t *data, igt_crtc_t *crtc, igt_output_t *output,
> @@ -591,6 +816,7 @@ test_basic(data_t *data, igt_crtc_t *crtc, igt_output_t *output,
> uint64_t rate[] = {0};
>
> prepare_test(data, output, crtc);
> +
unintentional new line.
With these LGTM
Reviewed-by: Chaitanya Kumar Borah <chaitanya.kumar.borah@intel.com>v
> range = data->range;
> vtest_ns = data->vtest_ns;
> rate[0] = vtest_ns.rate_ns;
> @@ -1147,6 +1373,20 @@ int igt_main_args("drs:", long_opts, help_str, opt_handler, &data)
> }
> }
>
> + igt_subtest_group() {
> + igt_fixture()
> + igt_require_intel(data.drm_fd);
> +
> + igt_describe("Test to validate CMRR in desktop mode.");
> + igt_subtest_with_dynamic("cmrr-desktop-mode") {
> + run_vrr_test(&data, test_cmrr, TEST_CMRR_DESKTOP_MODE);
> + }
> +
> + igt_describe("Test to validate CMRR in video mode.");
> + igt_subtest_with_dynamic("cmrr-video-mode") {
> + run_vrr_test(&data, test_cmrr, TEST_CMRR_VIDEO_MODE);
> + }
> + }
> igt_fixture() {
> close(data.debugfs_fd);
> igt_display_fini(&data.display);
next prev parent reply other threads:[~2026-09-10 10:33 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-07 17:48 [PATCH i-g-t v6 0/3] Add CMRR subtests Naladala Ramanaidu
2026-09-07 17:48 ` [PATCH i-g-t v6 1/3] lib/igt_vrr: Add VRR helper library for display refresh rate testing Naladala Ramanaidu
2026-09-09 16:33 ` Golani, Mitulkumar Ajitkumar
2026-09-10 10:14 ` Borah, Chaitanya Kumar
2026-09-07 17:48 ` [PATCH i-g-t v6 2/3] lib/igt_kms: Add helper to return vblank timestamp and sequence Naladala Ramanaidu
2026-09-09 16:22 ` Golani, Mitulkumar Ajitkumar
2026-09-07 17:48 ` [PATCH i-g-t v6 3/3] tests/kms_vrr: Add CMRR fixed and video mode subtests Naladala Ramanaidu
2026-09-10 8:46 ` Golani, Mitulkumar Ajitkumar
2026-09-10 10:25 ` Borah, Chaitanya Kumar [this message]
2026-09-12 19:52 ` Naladala, Ramanaidu
2026-09-07 20:28 ` ✓ Xe.CI.BAT: success for Add CMRR subtests (rev6) Patchwork
2026-09-07 20:42 ` ✓ i915.CI.BAT: " Patchwork
2026-09-08 0:58 ` ✗ Xe.CI.FULL: failure " Patchwork
2026-09-08 7:42 ` ✗ i915.CI.Full: " Patchwork
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=e7bc3094-7254-4482-a17b-de4487b1cdf4@intel.com \
--to=chaitanya.kumar.borah@intel.com \
--cc=igt-dev@lists.freedesktop.org \
--cc=karthik.b.s@intel.com \
--cc=mitulkumar.ajitkumar.golani@intel.com \
--cc=ramanaidu.naladala@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox