Re: [PATCH i-g-t v1] tests/intel/kms_joiner: vblank test for joiner secondary crtc

Karthik B S <[email protected]>
Newsgroups org.freedesktop.lists.igt-dev
Message-ID <[email protected]>
Hi Santhosh,

On 8/13/2026 1:24 PM, Santhosh Reddy Guddati wrote:
> In joiner mode, add new subtests to validate vblank events are delivered
> on secondary crtc.
I've an open which I've mentioned below. If that is clarified, we could 
add more details here as to why we're adding this test.
>
> Assisted-by: Claude:claude-opus-4-8
> Signed-off-by: Santhosh Reddy Guddati <[email protected]>
> ---
>   tests/intel/kms_joiner.c | 94 ++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 94 insertions(+)
>
> diff --git a/tests/intel/kms_joiner.c b/tests/intel/kms_joiner.c
> index dfcb24004..ff33256a3 100644
> --- a/tests/intel/kms_joiner.c
> +++ b/tests/intel/kms_joiner.c
> @@ -76,6 +76,10 @@
>    * SUBTEST: basic-max-non-joiner
>    * Description: Validate basic max non-joiner modeset by selecting the max mode
>    *		supported on single pipe.
> + *
> + * SUBTEST: vblank-joiner-secondary
> + * Description: Verify that vblank interrupts are generated on all pipes in a
> + *		joiner configuration including the secondary pipe.
>    */
>   IGT_TEST_DESCRIPTION("Test joiner / force joiner");
>   
> @@ -275,6 +279,74 @@ static void switch_modeset_ultra_joiner_big_joiner(data_t *data, igt_output_t *o
>   	}
>   }
>   
> +static void test_joiner_vblank(data_t *data, bool force_joiner)
> +{
> +	int i;
> +	enum pipe pipe, master_pipe;
> +	uint32_t available_pipe_mask = BIT(data->n_pipes) - 1;
> +	igt_output_t *output;
> +	igt_plane_t *primary;
> +	igt_output_t **outputs;
> +	igt_fb_t fb;
> +	drmModeModeInfo *mode;
> +	int count;
> +	drmVBlank wait_vbl;
> +	uint32_t pipe_flag;
> +
> +	outputs = force_joiner ? data->non_big_joiner_output : data->big_joiner_output;
> +	count = force_joiner ? data->non_big_joiner_output_count : data->big_joiner_output_count;
> +	igt_display_reset(&data->display);
> +	igt_display_commit2(&data->display, COMMIT_ATOMIC);
> +
> +	for (i = 0; i < count; i++) {
> +		output = outputs[i];
> +		for (pipe = 0; pipe < data->n_pipes - 1; pipe++) {
> +			igt_crtc_t *primary_crtc, *secondary_crtc;
> +			int ret;
> +
> +			master_pipe = setup_pipe(data, output, pipe, available_pipe_mask);
> +			if (master_pipe == PIPE_NONE)
> +				continue;
> +
> +			mode = igt_output_get_mode(output);
> +			primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> +			igt_create_pattern_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
> +					      DRM_FORMAT_XRGB8888,
> +					      DRM_FORMAT_MOD_LINEAR, &fb);
> +			igt_plane_set_fb(primary, &fb);
> +			igt_display_commit2(&data->display, COMMIT_ATOMIC);
> +
> +			primary_crtc = igt_crtc_for_pipe(&data->display, master_pipe);
> +			secondary_crtc = igt_crtc_for_pipe(&data->display, master_pipe + 1);
> +
> +			/* Verify vblank works on the primary joiner pipe */
> +			igt_wait_for_vblank(primary_crtc);
> +			igt_info("Pipe %s (primary): vblank wait OK\n",
> +				 kmstest_pipe_name(master_pipe));
> +
> +			/* Verify vblank works on the secondary joiner pipe */
> +			pipe_flag = kmstest_get_vbl_flag(secondary_crtc->crtc_index);
> +			memset(&wait_vbl, 0, sizeof(wait_vbl));
> +
> +			wait_vbl.request.type = DRM_VBLANK_RELATIVE | pipe_flag;
> +			wait_vbl.request.sequence = 1;
> +			ret = drmWaitVBlank(data->drm_fd, &wait_vbl);
> +
> +			igt_assert_f(ret == 0,
> +				     "Pipe %s (joiner secondary): vblank wait timed out - "
> +				     "no vblank interrupt delivered\n",
> +				     kmstest_pipe_name(master_pipe + 1));
> +			igt_info("Pipe %s (secondary): vblank wait OK\n",
> +				 kmstest_pipe_name(master_pipe + 1));
> +
> +			igt_plane_set_fb(primary, NULL);
> +			igt_output_set_crtc(output, NULL);
> +			igt_display_commit2(&data->display, COMMIT_ATOMIC);
> +			igt_remove_fb(data->drm_fd, &fb);

This block should be ideally in a separate function outside the dynamic 
subtest scope, as if the assert hits this will not be executed.

Other than this the test itself looks good to me structurally, but one 
open I have is if the userspace actually needs to be aware of the second 
pipe vblank sequence?

@Ankit: Could you please provide your inputs on this?

Regards,
Karthik.B.S

> +		}
> +	}
> +}
> +
>   static void test_single_joiner(data_t *data, int output_count, bool force_joiner)
>   {
>   	int i;
> @@ -836,6 +908,28 @@ int igt_main()
>   			test_basic_max_non_joiner(&data);
>   	}
>   
> +	igt_describe("Verify vblank interrupts arrive on joiner secondary pipes");
> +	igt_subtest_with_dynamic("vblank-joiner-secondary") {
> +		igt_require_f(data.n_pipes >= 2, "Minimum 2 pipes required\n");
> +		igt_require_f(data.big_joiner_output_count > 0 ||
> +			      data.non_big_joiner_output_count > 0,
> +			      "No big joiner or force big joiner output found\n");
> +
> +		if (data.big_joiner_output_count > 0) {
> +			igt_dynamic_f("big-joiner") {
> +				test_joiner_vblank(&data, false);
> +			}
> +		}
> +
> +		if (data.non_big_joiner_output_count > 0) {
> +			igt_dynamic_f("force-big-joiner") {
> +				enable_force_joiner_on_all_non_big_joiner_outputs(&data);
> +				test_joiner_vblank(&data, true);
> +				igt_reset_connectors();
> +			}
> +		}
> +	}
> +
>   	igt_fixture() {
>   		igt_display_fini(&data.display);
>   		drm_close_driver(data.drm_fd);
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.