Instead of strictly measuring vblanks, we try to see if a page flip
is queued on the next vblank if we run legacy cursor updates to the
pipe and another pipe in the background.

Signed-off-by: Maarten Lankhorst <maarten.lankho...@linux.intel.com>
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=101634
---
 tests/kms_cursor_legacy.c | 90 ++++++++++++++++++++++++++++-------------------
 1 file changed, 54 insertions(+), 36 deletions(-)

diff --git a/tests/kms_cursor_legacy.c b/tests/kms_cursor_legacy.c
index 5720dbef90d3..b8b15b609d7f 100644
--- a/tests/kms_cursor_legacy.c
+++ b/tests/kms_cursor_legacy.c
@@ -884,14 +884,23 @@ cleanup:
 
 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 skip_test = false;
+       volatile unsigned long *shared;
+
+       if (modeset) {
+               uint64_t val;
+
+               igt_fail_on(!atomic);
+               igt_assert(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);
 
@@ -903,9 +912,9 @@ 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);
@@ -917,29 +926,29 @@ static void two_screens_flip_vs_cursor(igt_display_t 
*display, int nloops, bool
 
        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 (!shared[0])
+                       do_ioctl(display->drm_fd, DRM_IOCTL_MODE_CURSOR,
+                                &arg[!shared[1]]);
+       }
 
        while (nloops--) {
-               /* Start with a synchronous query to align with the vblank */
-               vblank_start = get_vblank(display->drm_fd, pipe, 
DRM_VBLANK_NEXTONMISS);
-               do_ioctl(display->drm_fd, DRM_IOCTL_MODE_CURSOR, &arg[nloops & 
1]);
+               unsigned vblank_start =
+                       get_vblank(display->drm_fd, pipe, 
DRM_VBLANK_NEXTONMISS);
+
+               shared[1] = nloops & 1;
+
+               if (!modeset) {
+                       flip_nonblocking(display, pipe, atomic, &fb_info);
+               } else {
+                       unsigned flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
+                       flags |= DRM_MODE_ATOMIC_NONBLOCK | 
DRM_MODE_PAGE_FLIP_EVENT;
 
-               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.
+                        * 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
@@ -948,26 +957,32 @@ static void two_screens_flip_vs_cursor(igt_display_t 
*display, int nloops, bool
 
                        igt_plane_set_fb(igt_output_get_plane_type(output, 
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);
+                       igt_display_commit_atomic(display, flags, NULL);
                }
 
-               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]);
-
-                       igt_assert_eq(get_vblank(display->drm_fd, pipe, 0), 
vblank_start);
+                       struct drm_event_vblank vbl;
 
                        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();
+                       igt_assert(vbl.crtc_id == display->pipes[pipe].crtc_id);
+                       igt_assert(vbl.sequence == vblank_start + 1);
                } else {
-                       do_ioctl(display->drm_fd, DRM_IOCTL_MODE_CURSOR, 
&arg2[nloops & 1]);
+                       struct drm_event_vblank vbl, vbl2;
+
+                       igt_set_timeout(35, "Stuck nonblocking modeset");
+
+                       igt_ignore_warn(read(display->drm_fd, &vbl, 
sizeof(vbl)));
+                       igt_ignore_warn(read(display->drm_fd, &vbl2, 
sizeof(vbl2)));
+
+                       igt_assert(vbl.crtc_id != vbl2.crtc_id);
+                       igt_assert(vbl.crtc_id == display->pipes[pipe].crtc_id 
||
+                                  vbl.crtc_id == 
display->pipes[pipe2].crtc_id);
+                       igt_assert(vbl2.crtc_id == display->pipes[pipe].crtc_id 
||
+                                  vbl2.crtc_id == 
display->pipes[pipe2].crtc_id);
                }
+               igt_reset_timeout();
 
                if (modeset) {
                        /* wait for pending modeset and page flip to complete, 
to prevent -EBUSY */
@@ -977,6 +992,9 @@ static void two_screens_flip_vs_cursor(igt_display_t 
*display, int nloops, bool
                }
        }
 
+       shared[0] = 1;
+       igt_waitchildren();
+
 cleanup:
        do_cleanup_display(display);
        igt_remove_fb(display->drm_fd, &fb_info);
-- 
2.15.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to