[Intel-gfx] [PATCH i-g-t 3/3] tests/kms_cursor_legacy: Rework the 2x-*-vs-cursor-* tests.

Mika Kahola mika.kahola at intel.com
Fri Dec 22 08:55:37 UTC 2017


On Thu, 2017-12-07 at 14:40 +0100, Maarten Lankhorst wrote:
> Using the fancy new DRM_CAP_CRTC_IN_VBLANK_EVENT cap I can finally
> make this test the work I originally intended to.
> 
> For the !modeset case that means performing a pageflip on both
> crtc's,
> then requeueing as soon as the event is delivered and then check the
> vblank counter against the original value, it should be advanced by
> 1.
> 
> The modeset case is slightly more complicated, ideally it's handled
> the same, but if we can't perform a modeset and pageflip at the same
> time, fall back to queueing both in a single commit, in which case
> we can say nothing about the vblank counter.
> 
> There is a small race between flip_done and hw_done, so make
> flip_nonblocking retry for a second when encountering -EBUSY.
> 
Reviewed-by: Mika Kahola <mika.kahola at intel.com>

> Signed-off-by: Maarten Lankhorst <maarten.lankhorst at linux.intel.com>
> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=101634
> ---
>  tests/kms_cursor_legacy.c | 228 +++++++++++++++++++++++++++++++-----
> ----------
>  1 file changed, 156 insertions(+), 72 deletions(-)
> 
> diff --git a/tests/kms_cursor_legacy.c b/tests/kms_cursor_legacy.c
> index 94d91e9c921a..5011e78e5c2f 100644
> --- a/tests/kms_cursor_legacy.c
> +++ b/tests/kms_cursor_legacy.c
> @@ -243,19 +243,27 @@ static enum pipe
> find_connected_pipe(igt_display_t *display, bool second)
>  	return pipe;
>  }
>  
> -static void flip_nonblocking(igt_display_t *display, enum pipe
> pipe_id, bool atomic, struct igt_fb *fb)
> +static void flip_nonblocking(igt_display_t *display, enum pipe
> pipe_id, bool atomic, struct igt_fb *fb, void *data)
>  {
>  	igt_pipe_t *pipe = &display->pipes[pipe_id];
>  	igt_plane_t *primary = igt_pipe_get_plane_type(pipe,
> DRM_PLANE_TYPE_PRIMARY);
> +	int ret;
>  
> +	igt_set_timeout(1, "Scheduling page flip\n");
>  	if (!atomic) {
>  		/* Schedule a nonblocking flip for the next vblank
> */
> -		do_or_die(drmModePageFlip(display->drm_fd, pipe-
> >crtc_id, fb->fb_id,
> -					DRM_MODE_PAGE_FLIP_EVENT,
> fb));
> +		do {
> +			ret = drmModePageFlip(display->drm_fd, pipe-
> >crtc_id, fb->fb_id,
> +					      DRM_MODE_PAGE_FLIP_EVE
> NT, data);
> +		} while (ret == -EBUSY);
>  	} else {
>  		igt_plane_set_fb(primary, fb);
> -		igt_display_commit_atomic(display,
> DRM_MODE_ATOMIC_NONBLOCK | DRM_MODE_PAGE_FLIP_EVENT, fb);
> +		do {
> +			ret = igt_display_try_commit_atomic(display,
> DRM_MODE_ATOMIC_NONBLOCK | DRM_MODE_PAGE_FLIP_EVENT, data);
> +		} while (ret == -EBUSY);
>  	}
> +	igt_assert(!ret);
> +	igt_reset_timeout();
>  }
>  
>  enum flip_test {
> @@ -424,7 +432,7 @@ static void flip(igt_display_t *display,
>  
>  			switch (mode) {
>  			default:
> -				flip_nonblocking(display, flip_pipe,
> mode >= flip_test_atomic, &fb_info);
> +				flip_nonblocking(display, flip_pipe,
> mode >= flip_test_atomic, &fb_info, NULL);
>  				break;
>  			case flip_test_atomic_transitions:
>  			case
> flip_test_atomic_transitions_varying_size:
> @@ -533,7 +541,7 @@ static void basic_flip_cursor(igt_display_t
> *display,
>  		case FLIP_BEFORE_CURSOR:
>  			switch (mode) {
>  			default:
> -				flip_nonblocking(display, pipe, mode
> >= flip_test_atomic, &fb_info);
> +				flip_nonblocking(display, pipe, mode
> >= flip_test_atomic, &fb_info, NULL);
>  				break;
>  			case flip_test_atomic_transitions:
>  			case
> flip_test_atomic_transitions_varying_size:
> @@ -555,7 +563,7 @@ static void basic_flip_cursor(igt_display_t
> *display,
>  
>  			switch (mode) {
>  			default:
> -				flip_nonblocking(display, pipe, mode
> >= flip_test_atomic, &fb_info);
> +				flip_nonblocking(display, pipe, mode
> >= flip_test_atomic, &fb_info, NULL);
>  				break;
>  			case flip_test_atomic_transitions:
>  			case
> flip_test_atomic_transitions_varying_size:
> @@ -712,7 +720,7 @@ static void flip_vs_cursor(igt_display_t
> *display, enum flip_test mode, int nloo
>  		vblank_start = get_vblank(display->drm_fd, pipe,
> DRM_VBLANK_NEXTONMISS);
>  		switch (mode) {
>  		default:
> -			flip_nonblocking(display, pipe, mode >=
> flip_test_atomic, &fb_info);
> +			flip_nonblocking(display, pipe, mode >=
> flip_test_atomic, &fb_info, NULL);
>  			break;
>  		case flip_test_atomic_transitions:
>  		case flip_test_atomic_transitions_varying_size:
> @@ -843,13 +851,26 @@ static void
> nonblocking_modeset_vs_cursor(igt_display_t *display, int loops)
>  
>  static void two_screens_flip_vs_cursor(igt_display_t *display, int
> nloops, bool modeset, bool atomic)
>  {
> -	struct drm_mode_cursor arg[2], arg2[2];
> -	struct drm_event_vblank vbl;
> +	struct drm_mode_cursor arg1[2], arg2[2];
>  	struct igt_fb fb_info, fb2_info, cursor_fb;
> -	unsigned vblank_start;
>  	enum pipe pipe = find_connected_pipe(display, false);
>  	enum pipe pipe2 = find_connected_pipe(display, true);
>  	igt_output_t *output, *output2;
> +	bool vblank_matches, enabled = false;
> +	volatile unsigned long *shared;
> +	unsigned flags = 0, vblank_start;
> +	struct drm_event_vblank vbl;
> +	int ret;
> +
> +	if (modeset) {
> +		uint64_t val;
> +
> +		igt_fail_on(!atomic);
> +		igt_require(drmGetCap(display->drm_fd,
> DRM_CAP_CRTC_IN_VBLANK_EVENT, &val) == 0);
> +	}
> +
> +	shared = mmap(NULL, 4096, PROT_WRITE, MAP_SHARED | MAP_ANON,
> -1, 0);
> +	igt_assert(shared != MAP_FAILED);
>  
>  	igt_fail_on(modeset && !atomic);
>  
> @@ -861,77 +882,140 @@ static void
> two_screens_flip_vs_cursor(igt_display_t *display, int nloops, bool
>  
>  	igt_create_color_fb(display->drm_fd, 64, 64,
> DRM_FORMAT_ARGB8888, 0, 1., 1., 1., &cursor_fb);
>  	set_cursor_on_pipe(display, pipe, &cursor_fb);
> -	populate_cursor_args(display, pipe, arg, &cursor_fb);
> +	populate_cursor_args(display, pipe, arg1, &cursor_fb);
>  
> -	arg[1].x = arg[1].y = 192;
> +	arg1[1].x = arg1[1].y = 192;
>  
>  	set_cursor_on_pipe(display, pipe2, &cursor_fb);
>  	populate_cursor_args(display, pipe2, arg2, &cursor_fb);
>  
>  	arg2[1].x = arg2[1].y = 192;
>  
> +
>  	igt_display_commit2(display, display->is_atomic ?
> COMMIT_ATOMIC : COMMIT_LEGACY);
>  
> -	vblank_start = get_vblank(display->drm_fd, pipe,
> DRM_VBLANK_NEXTONMISS);
> -	igt_assert_eq(get_vblank(display->drm_fd, pipe, 0),
> vblank_start);
> -	do_ioctl(display->drm_fd, DRM_IOCTL_MODE_CURSOR, &arg[0]);
> -	do_ioctl(display->drm_fd, DRM_IOCTL_MODE_CURSOR, &arg2[0]);
> -	igt_assert_eq(get_vblank(display->drm_fd, pipe, 0),
> vblank_start);
> +	igt_fork(child, 2) {
> +		struct drm_mode_cursor *arg = child ? arg2 : arg1;
>  
> -	while (nloops--) {
> -		/* Start with a synchronous query to align with the
> vblank */
> +		while (!shared[0])
> +			do_ioctl(display->drm_fd,
> DRM_IOCTL_MODE_CURSOR,
> +				 &arg[!shared[1]]);
> +	}
> +
> +	if (modeset) {
> +		igt_plane_t *plane =
> igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> +
> +		flags = DRM_MODE_ATOMIC_ALLOW_MODESET |
> +			DRM_MODE_ATOMIC_NONBLOCK |
> DRM_MODE_PAGE_FLIP_EVENT;
> +
> +		/* Disable pipe2 */
> +		igt_output_set_pipe(output2, PIPE_NONE);
> +		igt_display_commit_atomic(display, flags, NULL);
> +		enabled = false;
> +
> +		/*
> +		 * Try a page flip on crtc 1, if we succeed pump
> page flips and
> +		 * modesets interleaved, else do a single atomic
> commit with both.
> +		 */
>  		vblank_start = get_vblank(display->drm_fd, pipe,
> DRM_VBLANK_NEXTONMISS);
> -		do_ioctl(display->drm_fd, DRM_IOCTL_MODE_CURSOR,
> &arg[nloops & 1]);
> +		igt_plane_set_fb(plane, &fb_info);
> +		ret = igt_display_try_commit_atomic(display, flags,
> (void*)(ptrdiff_t)vblank_start);
> +		igt_assert(!ret || ret == -EBUSY);
> +
> +		if (ret == -EBUSY) {
> +			/* Force completion on both pipes, and
> generate event. */
> +			igt_display_commit_atomic(display, flags,
> NULL);
> +
> +			while (nloops--) {
> +				shared[1] = nloops & 1;
> +
> +				igt_set_timeout(35, "Stuck
> modeset");
> +				igt_assert_eq(read(display->drm_fd,
> &vbl, sizeof(vbl)), sizeof(vbl));
> +				igt_assert_eq(read(display->drm_fd,
> &vbl, sizeof(vbl)), sizeof(vbl));
> +				igt_reset_timeout();
> +
> +				if (!nloops)
> +					break;
> +
> +				/* Commit page flip and modeset
> simultaneously. */
> +				igt_plane_set_fb(plane, &fb_info);
> +				igt_output_set_pipe(output2, enabled
> ? PIPE_NONE : pipe2);
> +				enabled = !enabled;
> +
> +				igt_set_timeout(5, "Scheduling
> modeset\n");
> +				do {
> +					ret =
> igt_display_try_commit_atomic(display, flags, NULL);
> +				} while (ret == -EBUSY);
> +				igt_assert(!ret);
> +				igt_reset_timeout();
> +			}
>  
> -		if (!modeset)
> -			flip_nonblocking(display, pipe, false,
> &fb_info);
> -		else {
> -			/*
> -			 * There are 2 design issues that prevent us
> from doing
> -			 * the test we would like here:
> -			 *
> -			 * - drm_event_vblank doesn't set crtc_id,
> so if we
> -			 *   use events we don't know which pipe
> fired the event,
> -			 *   no way to distinguish.
> -			 * - Doing a modeset may add unrelated
> pipes, and fail with
> -			 *   -EBUSY if a page flip is queued on one
> of those.
> -			 *
> -			 * Work around it by not setting an event,
> but doing a synchronous
> -			 * commit to wait for completion, and queue
> the page flip and modeset
> -			 * in the same commit.
> -			 */
> -
> -			igt_plane_set_fb(igt_output_get_plane_type(o
> utput, DRM_PLANE_TYPE_PRIMARY), &fb_info);
> -			igt_output_set_pipe(output2, (nloops & 1) ?
> PIPE_NONE : pipe2);
> -			igt_display_commit_atomic(display,
> DRM_MODE_ATOMIC_ALLOW_MODESET | DRM_MODE_ATOMIC_NONBLOCK, NULL);
> +			goto done;
>  		}
> +	} else {
> +		vblank_start = get_vblank(display->drm_fd, pipe,
> DRM_VBLANK_NEXTONMISS);
> +		flip_nonblocking(display, pipe, atomic, &fb_info,
> (void*)(ptrdiff_t)vblank_start);
>  
> -		igt_assert_eq(get_vblank(display->drm_fd, pipe, 0),
> vblank_start);
> -
> -		do_ioctl(display->drm_fd, DRM_IOCTL_MODE_CURSOR,
> &arg[nloops & 1]);
> -		if (!modeset) {
> -			do_ioctl(display->drm_fd,
> DRM_IOCTL_MODE_CURSOR, &arg2[nloops & 1]);
> -			do_ioctl(display->drm_fd,
> DRM_IOCTL_MODE_CURSOR, &arg[nloops & 1]);
> -			do_ioctl(display->drm_fd,
> DRM_IOCTL_MODE_CURSOR, &arg2[nloops & 1]);
> +		vblank_start = get_vblank(display->drm_fd, pipe2,
> DRM_VBLANK_NEXTONMISS);
> +		flip_nonblocking(display, pipe2, atomic, &fb2_info,
> (void*)(ptrdiff_t)vblank_start);
> +	}
>  
> -			igt_assert_eq(get_vblank(display->drm_fd,
> pipe, 0), vblank_start);
> +	vblank_matches = false;
> +	while (nloops) {
> +		shared[1] = nloops & 1;
>  
> +		if (!modeset || nloops > 1)
>  			igt_set_timeout(1, "Stuck page flip");
> -			igt_ignore_warn(read(display->drm_fd, &vbl,
> sizeof(vbl)));
> -			igt_assert_eq(get_vblank(display->drm_fd,
> pipe, 0), vblank_start + 1);
> -			igt_reset_timeout();
> -		} else {
> -			do_ioctl(display->drm_fd,
> DRM_IOCTL_MODE_CURSOR, &arg2[nloops & 1]);
> +		else
> +			igt_set_timeout(35, "Stuck modeset");
> +		igt_assert_eq(read(display->drm_fd, &vbl,
> sizeof(vbl)), sizeof(vbl));
> +		igt_reset_timeout();
> +
> +		vblank_start = vbl.user_data;
> +		if (!modeset)
> +			igt_assert_eq(vbl.sequence, vblank_start +
> 1);
> +
> +		if (vblank_start && vbl.sequence == vblank_start +
> 1)
> +			vblank_matches = true;
> +
> +		/* Do not requeue on the last 2 events. */
> +		if (nloops <= 2) {
> +			nloops--;
> +			continue;
>  		}
>  
> -		if (modeset) {
> -			/* wait for pending modeset and page flip to
> complete, to prevent -EBUSY */
> -			igt_pipe_refresh(display, pipe, false);
> -			igt_pipe_refresh(display, pipe2, false);
> -			igt_display_commit2(display, COMMIT_ATOMIC);
> +		if (vbl.crtc_id == display->pipes[pipe].crtc_id) {
> +			vblank_start = get_vblank(display->drm_fd,
> pipe, DRM_VBLANK_NEXTONMISS);
> +			flip_nonblocking(display, pipe, atomic,
> &fb_info, (void*)(ptrdiff_t)vblank_start);
> +		} else {
> +			igt_assert(vbl.crtc_id == display-
> >pipes[pipe2].crtc_id);
> +
> +			nloops--;
> +
> +			if (!modeset) {
> +				vblank_start = get_vblank(display-
> >drm_fd, pipe2, DRM_VBLANK_NEXTONMISS);
> +				flip_nonblocking(display, pipe2,
> atomic, &fb2_info, (void*)(ptrdiff_t)vblank_start);
> +			} else {
> +				igt_output_set_pipe(output2, enabled
> ? PIPE_NONE : pipe2);
> +
> +				igt_set_timeout(1, "Scheduling
> modeset\n");
> +				do {
> +					ret =
> igt_display_try_commit_atomic(display, flags, NULL);
> +				} while (ret == -EBUSY);
> +				igt_assert(!ret);
> +				igt_reset_timeout();
> +
> +				enabled = !enabled;
> +			}
>  		}
>  	}
>  
> +	igt_assert_f(vblank_matches, "During modeset at least 1 page
> flip needs to match!\n");
> +
> +done:
> +	shared[0] = 1;
> +	igt_waitchildren();
> +
>  	igt_remove_fb(display->drm_fd, &fb_info);
>  	igt_remove_fb(display->drm_fd, &fb2_info);
>  	igt_remove_fb(display->drm_fd, &cursor_fb);
> @@ -982,7 +1066,7 @@ static void cursor_vs_flip(igt_display_t
> *display, enum flip_test mode, int nloo
>  
>  		switch (mode) {
>  		default:
> -			flip_nonblocking(display, pipe, mode >=
> flip_test_atomic, &fb_info);
> +			flip_nonblocking(display, pipe, mode >=
> flip_test_atomic, &fb_info, NULL);
>  			break;
>  		case flip_test_atomic_transitions:
>  		case flip_test_atomic_transitions_varying_size:
> @@ -993,7 +1077,7 @@ static void cursor_vs_flip(igt_display_t
> *display, enum flip_test mode, int nloo
>  		igt_assert_eq(read(display->drm_fd, &vbl,
> sizeof(vbl)), sizeof(vbl));
>  		vblank_start = vblank_last = vbl.sequence;
>  		for (int n = 0; n < vrefresh / 2; n++) {
> -			flip_nonblocking(display, pipe, mode >=
> flip_test_atomic, &fb_info);
> +			flip_nonblocking(display, pipe, mode >=
> flip_test_atomic, &fb_info, NULL);
>  
>  			igt_assert_eq(read(display->drm_fd, &vbl,
> sizeof(vbl)), sizeof(vbl));
>  			if (vbl.sequence != vblank_last + 1) {
> @@ -1083,14 +1167,14 @@ static void
> two_screens_cursor_vs_flip(igt_display_t *display, int nloops, bool
>  			shared[child] = count;
>  		}
>  
> -		flip_nonblocking(display, pipe[0], atomic,
> &fb_info[0]);
> -		flip_nonblocking(display, pipe[1], atomic,
> &fb_info[1]);
> +		flip_nonblocking(display, pipe[0], atomic,
> &fb_info[0], (void *)0UL);
> +		flip_nonblocking(display, pipe[1], atomic,
> &fb_info[1], (void *)1UL);
>  
>  		for (int n = 0; n < vrefresh[0] / 2 + vrefresh[1] /
> 2; n++) {
> -			int child;
> +			unsigned long child;
>  
>  			igt_assert_eq(read(display->drm_fd, &vbl,
> sizeof(vbl)), sizeof(vbl));
> -			child = vbl.user_data == (unsigned
> long)&fb_info[1];
> +			child = vbl.user_data;
>  
>  			if (!done[child]++)
>  				vblank_start[child] = vbl.sequence;
> @@ -1101,7 +1185,7 @@ static void
> two_screens_cursor_vs_flip(igt_display_t *display, int nloops, bool
>  			vblank_last[child] = vbl.sequence;
>  
>  			if (done[child] < vrefresh[child] / 2) {
> -				flip_nonblocking(display,
> pipe[child], atomic, &fb_info[child]);
> +				flip_nonblocking(display,
> pipe[child], atomic, &fb_info[child], (void *)child);
>  			} else {
>  				igt_assert_lte(vbl.sequence,
> vblank_start[child] + 5 * vrefresh[child] / 8);
>  
> @@ -1163,7 +1247,7 @@ static void flip_vs_cursor_crc(igt_display_t
> *display, bool atomic)
>  	for (int i = 1; i >= 0; i--) {
>  		vblank_start = get_vblank(display->drm_fd, pipe,
> DRM_VBLANK_NEXTONMISS);
>  
> -		flip_nonblocking(display, pipe, atomic, &fb_info);
> +		flip_nonblocking(display, pipe, atomic, &fb_info,
> NULL);
>  		do_ioctl(display->drm_fd, DRM_IOCTL_MODE_CURSOR,
> &arg[i]);
>  
>  		igt_assert_eq(get_vblank(display->drm_fd, pipe, 0),
> vblank_start);
> @@ -1247,7 +1331,7 @@ static void
> flip_vs_cursor_busy_crc(igt_display_t *display, bool atomic)
>  
>  		vblank_start = get_vblank(display->drm_fd, pipe,
> DRM_VBLANK_NEXTONMISS);
>  
> -		flip_nonblocking(display, pipe, atomic,
> &fb_info[1]);
> +		flip_nonblocking(display, pipe, atomic, &fb_info[1],
> NULL);
>  		do_ioctl(display->drm_fd, DRM_IOCTL_MODE_CURSOR,
> &arg[i]);
>  
>  		igt_assert_eq(get_vblank(display->drm_fd, pipe, 0),
> vblank_start);
> @@ -1347,7 +1431,7 @@ igt_main
>  		two_screens_flip_vs_cursor(&display, 8, false,
> false);
>  
>  	igt_subtest("2x-flip-vs-cursor-atomic")
> -		two_screens_flip_vs_cursor(&display, 4, false,
> true);
> +		two_screens_flip_vs_cursor(&display, 8, false,
> true);
>  
>  	igt_subtest("2x-cursor-vs-flip-legacy")
>  		two_screens_cursor_vs_flip(&display, 8, false);
> @@ -1362,13 +1446,13 @@ igt_main
>  		two_screens_cursor_vs_flip(&display, 50, false);
>  
>  	igt_subtest("2x-nonblocking-modeset-vs-cursor-atomic")
> -		two_screens_flip_vs_cursor(&display, 8, true, true);
> +		two_screens_flip_vs_cursor(&display, 4, true, true);
>  
>  	igt_subtest("2x-cursor-vs-flip-atomic")
>  		two_screens_cursor_vs_flip(&display, 8, true);
>  
>  	igt_subtest("2x-long-nonblocking-modeset-vs-cursor-atomic")
> -		two_screens_flip_vs_cursor(&display, 150, true,
> true);
> +		two_screens_flip_vs_cursor(&display, 15, true,
> true);
>  
>  	igt_subtest("2x-long-cursor-vs-flip-atomic")
>  		two_screens_cursor_vs_flip(&display, 50, true);
-- 
Mika Kahola - Intel OTC



More information about the Intel-gfx mailing list