diff options
Diffstat (limited to 'tests/kms_cursor_legacy.c')
-rw-r--r-- | tests/kms_cursor_legacy.c | 228 |
1 files changed, 156 insertions, 72 deletions
diff --git a/tests/kms_cursor_legacy.c b/tests/kms_cursor_legacy.c index 94d91e9c..5011e78e 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_EVENT, 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(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); + 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); |