1 /*
2 * Copyright © 2016 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 #include "igt.h"
25 #include "igt_rand.h"
26 #include "drmtest.h"
27 #include "sw_sync.h"
28 #include <errno.h>
29 #include <pthread.h>
30 #include <stdbool.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <time.h>
34 #include <poll.h>
35
36 #ifndef DRM_CAP_CURSOR_WIDTH
37 #define DRM_CAP_CURSOR_WIDTH 0x8
38 #endif
39 #ifndef DRM_CAP_CURSOR_HEIGHT
40 #define DRM_CAP_CURSOR_HEIGHT 0x9
41 #endif
42
43 struct plane_parms {
44 struct igt_fb *fb;
45 uint32_t width, height, mask;
46 };
47
48 /* globals for fence support */
49 int *timeline;
50 pthread_t *thread;
51 int *seqno;
52
53 static void
run_primary_test(igt_display_t * display,enum pipe pipe,igt_output_t * output)54 run_primary_test(igt_display_t *display, enum pipe pipe, igt_output_t *output)
55 {
56 drmModeModeInfo *mode;
57 igt_plane_t *primary;
58 igt_fb_t fb;
59 int i, ret;
60 unsigned flags = DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET;
61
62 igt_output_set_pipe(output, pipe);
63 primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
64
65 mode = igt_output_get_mode(output);
66
67 igt_plane_set_fb(primary, NULL);
68 ret = igt_display_try_commit_atomic(display, flags, NULL);
69 igt_skip_on_f(ret == -EINVAL, "Primary plane cannot be disabled separately from output\n");
70
71 igt_create_fb(display->drm_fd, mode->hdisplay, mode->vdisplay,
72 DRM_FORMAT_XRGB8888, LOCAL_DRM_FORMAT_MOD_NONE, &fb);
73
74 igt_plane_set_fb(primary, &fb);
75
76 for (i = 0; i < 4; i++) {
77 igt_display_commit2(display, COMMIT_ATOMIC);
78
79 if (!(i & 1))
80 igt_wait_for_vblank(display->drm_fd, pipe);
81
82 igt_plane_set_fb(primary, (i & 1) ? &fb : NULL);
83 igt_display_commit2(display, COMMIT_ATOMIC);
84
85 if (i & 1)
86 igt_wait_for_vblank(display->drm_fd, pipe);
87
88 igt_plane_set_fb(primary, (i & 1) ? NULL : &fb);
89 }
90
91 igt_plane_set_fb(primary, NULL);
92 igt_output_set_pipe(output, PIPE_NONE);
93 igt_remove_fb(display->drm_fd, &fb);
94 }
95
fence_inc_thread(void * arg)96 static void *fence_inc_thread(void *arg)
97 {
98 int t = *((int *) arg);
99
100 pthread_detach(pthread_self());
101
102 usleep(5000);
103 sw_sync_timeline_inc(t, 1);
104 return NULL;
105 }
106
configure_fencing(igt_plane_t * plane)107 static void configure_fencing(igt_plane_t *plane)
108 {
109 int i, fd, ret;
110
111 i = plane->index;
112
113 seqno[i]++;
114 fd = sw_sync_timeline_create_fence(timeline[i], seqno[i]);
115 igt_plane_set_fence_fd(plane, fd);
116 close(fd);
117 ret = pthread_create(&thread[i], NULL, fence_inc_thread, &timeline[i]);
118 igt_assert_eq(ret, 0);
119 }
120
121 static int
wm_setup_plane(igt_display_t * display,enum pipe pipe,uint32_t mask,struct plane_parms * parms,bool fencing)122 wm_setup_plane(igt_display_t *display, enum pipe pipe,
123 uint32_t mask, struct plane_parms *parms, bool fencing)
124 {
125 igt_plane_t *plane;
126 int planes_set_up = 0;
127
128 /*
129 * Make sure these buffers are suited for display use
130 * because most of the modeset operations must be fast
131 * later on.
132 */
133 for_each_plane_on_pipe(display, pipe, plane) {
134 int i = plane->index;
135
136 if (!mask || !(parms[i].mask & mask)) {
137 if (plane->values[IGT_PLANE_FB_ID]) {
138 igt_plane_set_fb(plane, NULL);
139 planes_set_up++;
140 }
141 continue;
142 }
143
144 if (fencing)
145 configure_fencing(plane);
146
147 igt_plane_set_fb(plane, parms[i].fb);
148 igt_fb_set_size(parms[i].fb, plane, parms[i].width, parms[i].height);
149 igt_plane_set_size(plane, parms[i].width, parms[i].height);
150
151 planes_set_up++;
152 }
153 return planes_set_up;
154 }
155
ev_page_flip(int fd,unsigned seq,unsigned tv_sec,unsigned tv_usec,void * user_data)156 static void ev_page_flip(int fd, unsigned seq, unsigned tv_sec, unsigned tv_usec, void *user_data)
157 {
158 igt_debug("Retrieved vblank seq: %u on unk\n", seq);
159 }
160
161 static drmEventContext drm_events = {
162 .version = 2,
163 .page_flip_handler = ev_page_flip
164 };
165
166 enum transition_type {
167 TRANSITION_PLANES,
168 TRANSITION_AFTER_FREE,
169 TRANSITION_MODESET,
170 TRANSITION_MODESET_FAST,
171 TRANSITION_MODESET_DISABLE,
172 };
173
set_sprite_wh(igt_display_t * display,enum pipe pipe,struct plane_parms * parms,struct igt_fb * sprite_fb,bool alpha,unsigned w,unsigned h)174 static void set_sprite_wh(igt_display_t *display, enum pipe pipe,
175 struct plane_parms *parms, struct igt_fb *sprite_fb,
176 bool alpha, unsigned w, unsigned h)
177 {
178 igt_plane_t *plane;
179
180 for_each_plane_on_pipe(display, pipe, plane) {
181 int i = plane->index;
182
183 if (plane->type == DRM_PLANE_TYPE_PRIMARY ||
184 plane->type == DRM_PLANE_TYPE_CURSOR)
185 continue;
186
187 if (!parms[i].mask)
188 continue;
189
190 parms[i].width = w;
191 parms[i].height = h;
192 }
193
194 igt_remove_fb(display->drm_fd, sprite_fb);
195 igt_create_fb(display->drm_fd, w, h,
196 alpha ? DRM_FORMAT_ARGB8888 : DRM_FORMAT_XRGB8888,
197 LOCAL_DRM_FORMAT_MOD_NONE, sprite_fb);
198 }
199
200 #define is_atomic_check_failure_errno(errno) \
201 (errno != -EINVAL && errno != 0)
202
203 #define is_atomic_check_plane_size_errno(errno) \
204 (errno == -EINVAL)
205
setup_parms(igt_display_t * display,enum pipe pipe,const drmModeModeInfo * mode,struct igt_fb * primary_fb,struct igt_fb * argb_fb,struct igt_fb * sprite_fb,struct plane_parms * parms,unsigned * iter_max)206 static void setup_parms(igt_display_t *display, enum pipe pipe,
207 const drmModeModeInfo *mode,
208 struct igt_fb *primary_fb,
209 struct igt_fb *argb_fb,
210 struct igt_fb *sprite_fb,
211 struct plane_parms *parms,
212 unsigned *iter_max)
213 {
214 uint64_t cursor_width, cursor_height;
215 unsigned sprite_width, sprite_height, prev_w, prev_h;
216 bool max_sprite_width, max_sprite_height, alpha = true;
217 uint32_t n_planes = display->pipes[pipe].n_planes;
218 uint32_t n_overlays = 0, overlays[n_planes];
219 igt_plane_t *plane;
220 uint32_t iter_mask = 3;
221
222 do_or_die(drmGetCap(display->drm_fd, DRM_CAP_CURSOR_WIDTH, &cursor_width));
223 if (cursor_width >= mode->hdisplay)
224 cursor_width = mode->hdisplay;
225
226 do_or_die(drmGetCap(display->drm_fd, DRM_CAP_CURSOR_HEIGHT, &cursor_height));
227 if (cursor_height >= mode->vdisplay)
228 cursor_height = mode->vdisplay;
229
230 for_each_plane_on_pipe(display, pipe, plane) {
231 int i = plane->index;
232
233 if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
234 parms[i].fb = primary_fb;
235 parms[i].width = mode->hdisplay;
236 parms[i].height = mode->vdisplay;
237 parms[i].mask = 1 << 0;
238 } else if (plane->type == DRM_PLANE_TYPE_CURSOR) {
239 parms[i].fb = argb_fb;
240 parms[i].width = cursor_width;
241 parms[i].height = cursor_height;
242 parms[i].mask = 1 << 1;
243 } else {
244 if (!n_overlays)
245 alpha = igt_plane_has_format_mod(plane,
246 DRM_FORMAT_ARGB8888, LOCAL_DRM_FORMAT_MOD_NONE);
247 parms[i].fb = sprite_fb;
248 parms[i].mask = 1 << 2;
249
250 iter_mask |= 1 << 2;
251
252 overlays[n_overlays++] = i;
253 }
254 }
255
256 if (n_overlays >= 2) {
257 uint32_t i;
258
259 /*
260 * Create 2 groups for overlays, make sure 1 plane is put
261 * in each then spread the rest out.
262 */
263 iter_mask |= 1 << 3;
264 parms[overlays[n_overlays - 1]].mask = 1 << 3;
265
266 for (i = 1; i < n_overlays - 1; i++) {
267 int val = hars_petruska_f54_1_random_unsafe_max(2);
268
269 parms[overlays[i]].mask = 1 << (2 + val);
270 }
271 }
272
273 igt_create_fb(display->drm_fd, cursor_width, cursor_height,
274 DRM_FORMAT_ARGB8888, LOCAL_DRM_FORMAT_MOD_NONE, argb_fb);
275
276 igt_create_fb(display->drm_fd, cursor_width, cursor_height,
277 DRM_FORMAT_ARGB8888, LOCAL_DRM_FORMAT_MOD_NONE, sprite_fb);
278
279 *iter_max = iter_mask + 1;
280 if (!n_overlays)
281 return;
282
283 /*
284 * Pre gen9 not all sizes are supported, find the biggest possible
285 * size that can be enabled on all sprite planes.
286 */
287 prev_w = sprite_width = cursor_width;
288 prev_h = sprite_height = cursor_height;
289
290 max_sprite_width = (sprite_width == mode->hdisplay);
291 max_sprite_height = (sprite_height == mode->vdisplay);
292
293 while (!max_sprite_width && !max_sprite_height) {
294 int ret;
295
296 set_sprite_wh(display, pipe, parms, sprite_fb,
297 alpha, sprite_width, sprite_height);
298
299 wm_setup_plane(display, pipe, (1 << n_planes) - 1, parms, false);
300 ret = igt_display_try_commit_atomic(display, DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
301 igt_assert(!is_atomic_check_failure_errno(ret));
302
303 if (!is_atomic_check_plane_size_errno(ret)) {
304 prev_w = sprite_width;
305 prev_h = sprite_height;
306 sprite_width *= max_sprite_width ? 1 : 2;
307 if (sprite_width >= mode->hdisplay) {
308 max_sprite_width = true;
309
310 sprite_width = mode->hdisplay;
311 }
312
313 sprite_height *= max_sprite_height ? 1 : 2;
314 if (sprite_height >= mode->vdisplay) {
315 max_sprite_height = true;
316
317 sprite_height = mode->vdisplay;
318 }
319 continue;
320 }
321
322 if (cursor_width == sprite_width &&
323 cursor_height == sprite_height) {
324 igt_plane_t *removed_plane = NULL;
325 igt_assert_f(n_planes >= 3, "No planes left to proceed with!");
326 if (n_overlays > 0) {
327 uint32_t plane_to_remove = hars_petruska_f54_1_random_unsafe_max(n_overlays);
328 removed_plane = &display->pipes[pipe].planes[overlays[plane_to_remove]];
329 igt_plane_set_fb(removed_plane, NULL);
330 while (plane_to_remove < (n_overlays - 1)) {
331 overlays[plane_to_remove] = overlays[plane_to_remove + 1];
332 plane_to_remove++;
333 }
334 n_overlays--;
335 }
336 if (removed_plane) {
337 parms[removed_plane->index].mask = 0;
338 igt_info("Removed plane %d\n", removed_plane->index);
339 }
340 n_planes--;
341 igt_info("Reduced available planes to %d\n", n_planes);
342 continue;
343 }
344
345 sprite_width = prev_w;
346 sprite_height = prev_h;
347
348 if (!max_sprite_width)
349 max_sprite_width = true;
350 else
351 max_sprite_height = true;
352 }
353
354 set_sprite_wh(display, pipe, parms, sprite_fb,
355 alpha, sprite_width, sprite_height);
356
357 igt_info("Running test on pipe %s with resolution %dx%d and sprite size %dx%d alpha %i\n",
358 kmstest_pipe_name(pipe), mode->hdisplay, mode->vdisplay,
359 sprite_width, sprite_height, alpha);
360 }
361
prepare_fencing(igt_display_t * display,enum pipe pipe)362 static void prepare_fencing(igt_display_t *display, enum pipe pipe)
363 {
364 igt_plane_t *plane;
365 int n_planes;
366
367 igt_require_sw_sync();
368
369 n_planes = display->pipes[pipe].n_planes;
370 timeline = calloc(sizeof(*timeline), n_planes);
371 igt_assert_f(timeline != NULL, "Failed to allocate memory for timelines\n");
372 thread = calloc(sizeof(*thread), n_planes);
373 igt_assert_f(thread != NULL, "Failed to allocate memory for thread\n");
374 seqno = calloc(sizeof(*seqno), n_planes);
375 igt_assert_f(seqno != NULL, "Failed to allocate memory for seqno\n");
376
377 for_each_plane_on_pipe(display, pipe, plane)
378 timeline[plane->index] = sw_sync_timeline_create();
379 }
380
unprepare_fencing(igt_display_t * display,enum pipe pipe)381 static void unprepare_fencing(igt_display_t *display, enum pipe pipe)
382 {
383 igt_plane_t *plane;
384
385 for_each_plane_on_pipe(display, pipe, plane)
386 close(timeline[plane->index]);
387
388 free(timeline);
389 free(thread);
390 free(seqno);
391 }
392
atomic_commit(igt_display_t * display,enum pipe pipe,unsigned int flags,void * data,bool fencing)393 static void atomic_commit(igt_display_t *display, enum pipe pipe, unsigned int flags, void *data, bool fencing)
394 {
395 if (fencing)
396 igt_pipe_request_out_fence(&display->pipes[pipe]);
397
398 igt_display_commit_atomic(display, flags, data);
399 }
400
fd_completed(int fd)401 static int fd_completed(int fd)
402 {
403 struct pollfd pfd = { fd, POLLIN };
404 int ret;
405
406 ret = poll(&pfd, 1, 0);
407 igt_assert(ret >= 0);
408 return ret;
409 }
410
wait_for_transition(igt_display_t * display,enum pipe pipe,bool nonblocking,bool fencing)411 static void wait_for_transition(igt_display_t *display, enum pipe pipe, bool nonblocking, bool fencing)
412 {
413 if (fencing) {
414 int fence_fd = display->pipes[pipe].out_fence_fd;
415
416 if (!nonblocking)
417 igt_assert(fd_completed(fence_fd));
418
419 igt_assert(sync_fence_wait(fence_fd, 30000) == 0);
420 } else {
421 if (!nonblocking)
422 igt_assert(fd_completed(display->drm_fd));
423
424 drmHandleEvent(display->drm_fd, &drm_events);
425 }
426 }
427
428 /*
429 * 1. Set primary plane to a known fb.
430 * 2. Make sure getcrtc returns the correct fb id.
431 * 3. Call rmfb on the fb.
432 * 4. Make sure getcrtc returns 0 fb id.
433 *
434 * RMFB is supposed to free the framebuffers from any and all planes,
435 * so test this and make sure it works.
436 */
437 static void
run_transition_test(igt_display_t * display,enum pipe pipe,igt_output_t * output,enum transition_type type,bool nonblocking,bool fencing)438 run_transition_test(igt_display_t *display, enum pipe pipe, igt_output_t *output,
439 enum transition_type type, bool nonblocking, bool fencing)
440 {
441 struct igt_fb fb, argb_fb, sprite_fb;
442 drmModeModeInfo *mode, override_mode;
443 igt_plane_t *plane;
444 igt_pipe_t *pipe_obj = &display->pipes[pipe];
445 uint32_t iter_max, i;
446 struct plane_parms parms[pipe_obj->n_planes];
447 unsigned flags = 0;
448 int ret;
449
450 if (fencing)
451 prepare_fencing(display, pipe);
452 else
453 flags |= DRM_MODE_PAGE_FLIP_EVENT;
454
455 if (nonblocking)
456 flags |= DRM_MODE_ATOMIC_NONBLOCK;
457
458 if (type >= TRANSITION_MODESET)
459 flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
460
461 mode = igt_output_get_mode(output);
462 override_mode = *mode;
463 /* try to force a modeset */
464 override_mode.flags ^= DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NHSYNC;
465
466 igt_create_fb(display->drm_fd, mode->hdisplay, mode->vdisplay,
467 DRM_FORMAT_XRGB8888, LOCAL_DRM_FORMAT_MOD_NONE, &fb);
468
469 igt_output_set_pipe(output, pipe);
470
471 wm_setup_plane(display, pipe, 0, NULL, false);
472
473 if (flags & DRM_MODE_ATOMIC_ALLOW_MODESET) {
474 igt_output_set_pipe(output, PIPE_NONE);
475
476 igt_display_commit2(display, COMMIT_ATOMIC);
477
478 igt_output_set_pipe(output, pipe);
479 }
480
481 igt_display_commit2(display, COMMIT_ATOMIC);
482
483 setup_parms(display, pipe, mode, &fb, &argb_fb, &sprite_fb, parms, &iter_max);
484
485 /*
486 * In some configurations the tests may not run to completion with all
487 * sprite planes lit up at 4k resolution, try decreasing width/size of secondary
488 * planes to fix this
489 */
490 while (1) {
491 wm_setup_plane(display, pipe, iter_max - 1, parms, false);
492
493 if (fencing)
494 igt_pipe_request_out_fence(pipe_obj);
495
496 ret = igt_display_try_commit_atomic(display, DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
497 igt_assert(!is_atomic_check_failure_errno(ret));
498
499 if (!is_atomic_check_plane_size_errno(ret) || pipe_obj->n_planes < 3)
500 break;
501
502 ret = 0;
503 for_each_plane_on_pipe(display, pipe, plane) {
504 i = plane->index;
505
506 if (plane->type == DRM_PLANE_TYPE_PRIMARY ||
507 plane->type == DRM_PLANE_TYPE_CURSOR)
508 continue;
509
510 parms[i].width /= 2;
511 ret = 1;
512 igt_info("Reducing sprite %i to %ux%u\n", i - 1, parms[i].width, parms[i].height);
513 break;
514 }
515
516 if (!ret)
517 igt_skip("Cannot run tests without proper size sprite planes\n");
518 }
519
520 igt_display_commit2(display, COMMIT_ATOMIC);
521
522 if (type == TRANSITION_AFTER_FREE) {
523 int fence_fd = -1;
524
525 wm_setup_plane(display, pipe, 0, parms, fencing);
526
527 atomic_commit(display, pipe, flags, (void *)(unsigned long)0, fencing);
528 if (fencing) {
529 fence_fd = pipe_obj->out_fence_fd;
530 pipe_obj->out_fence_fd = -1;
531 }
532
533 /* force planes to be part of commit */
534 for_each_plane_on_pipe(display, pipe, plane) {
535 if (parms[plane->index].mask)
536 igt_plane_set_position(plane, 0, 0);
537 }
538
539 igt_display_commit2(display, COMMIT_ATOMIC);
540
541 if (fence_fd != -1) {
542 igt_assert(fd_completed(fence_fd));
543 close(fence_fd);
544 } else {
545 igt_assert(fd_completed(display->drm_fd));
546 wait_for_transition(display, pipe, false, fencing);
547 }
548 goto cleanup;
549 }
550
551 for (i = 0; i < iter_max; i++) {
552 int n_enable_planes = igt_hweight(i);
553
554 if (type == TRANSITION_MODESET_FAST &&
555 n_enable_planes > 1 &&
556 n_enable_planes < pipe_obj->n_planes)
557 continue;
558
559 igt_output_set_pipe(output, pipe);
560
561 if (!wm_setup_plane(display, pipe, i, parms, fencing))
562 continue;
563
564 atomic_commit(display, pipe, flags, (void *)(unsigned long)i, fencing);
565 wait_for_transition(display, pipe, nonblocking, fencing);
566
567 if (type == TRANSITION_MODESET_DISABLE) {
568 igt_output_set_pipe(output, PIPE_NONE);
569
570 if (!wm_setup_plane(display, pipe, 0, parms, fencing))
571 continue;
572
573 atomic_commit(display, pipe, flags, (void *) 0UL, fencing);
574 wait_for_transition(display, pipe, nonblocking, fencing);
575 } else {
576 uint32_t j;
577
578 /* i -> i+1 will be done when i increases, can be skipped here */
579 for (j = iter_max - 1; j > i + 1; j--) {
580 n_enable_planes = igt_hweight(j);
581
582 if (type == TRANSITION_MODESET_FAST &&
583 n_enable_planes > 1 &&
584 n_enable_planes < pipe_obj->n_planes)
585 continue;
586
587 if (!wm_setup_plane(display, pipe, j, parms, fencing))
588 continue;
589
590 if (type >= TRANSITION_MODESET)
591 igt_output_override_mode(output, &override_mode);
592
593 atomic_commit(display, pipe, flags, (void *)(unsigned long) j, fencing);
594 wait_for_transition(display, pipe, nonblocking, fencing);
595
596 if (!wm_setup_plane(display, pipe, i, parms, fencing))
597 continue;
598
599 if (type >= TRANSITION_MODESET)
600 igt_output_override_mode(output, NULL);
601
602 atomic_commit(display, pipe, flags, (void *)(unsigned long) i, fencing);
603 wait_for_transition(display, pipe, nonblocking, fencing);
604 }
605 }
606 }
607
608 cleanup:
609 if (fencing)
610 unprepare_fencing(display, pipe);
611
612 igt_output_set_pipe(output, PIPE_NONE);
613
614 for_each_plane_on_pipe(display, pipe, plane)
615 igt_plane_set_fb(plane, NULL);
616
617 igt_display_commit2(display, COMMIT_ATOMIC);
618
619 igt_remove_fb(display->drm_fd, &fb);
620 igt_remove_fb(display->drm_fd, &argb_fb);
621 igt_remove_fb(display->drm_fd, &sprite_fb);
622 }
623
commit_display(igt_display_t * display,unsigned event_mask,bool nonblocking)624 static void commit_display(igt_display_t *display, unsigned event_mask, bool nonblocking)
625 {
626 unsigned flags;
627 int num_events = igt_hweight(event_mask);
628 ssize_t ret;
629
630 flags = DRM_MODE_ATOMIC_ALLOW_MODESET | DRM_MODE_PAGE_FLIP_EVENT;
631 if (nonblocking)
632 flags |= DRM_MODE_ATOMIC_NONBLOCK;
633
634 igt_display_commit_atomic(display, flags, NULL);
635
636 igt_debug("Event mask: %x, waiting for %i events\n", event_mask, num_events);
637
638 igt_set_timeout(30, "Waiting for events timed out\n");
639
640 while (num_events) {
641 char buf[32];
642 struct drm_event *e = (void *)buf;
643 struct drm_event_vblank *vblank = (void *)buf;
644
645 igt_set_timeout(3, "Timed out while reading drm_fd\n");
646 ret = read(display->drm_fd, buf, sizeof(buf));
647 igt_reset_timeout();
648 if (ret < 0 && (errno == EINTR || errno == EAGAIN))
649 continue;
650
651 igt_assert(ret >= 0);
652 igt_assert_eq(e->type, DRM_EVENT_FLIP_COMPLETE);
653
654 igt_debug("Retrieved vblank seq: %u on unk/unk\n", vblank->sequence);
655
656 num_events--;
657 }
658
659 igt_reset_timeout();
660 }
661
set_combinations(igt_display_t * display,unsigned mask,struct igt_fb * fb)662 static unsigned set_combinations(igt_display_t *display, unsigned mask, struct igt_fb *fb)
663 {
664 igt_output_t *output;
665 enum pipe pipe;
666 unsigned event_mask = 0;
667
668 for_each_connected_output(display, output)
669 igt_output_set_pipe(output, PIPE_NONE);
670
671 for_each_pipe(display, pipe) {
672 igt_plane_t *plane = igt_pipe_get_plane_type(&display->pipes[pipe],
673 DRM_PLANE_TYPE_PRIMARY);
674 drmModeModeInfo *mode = NULL;
675
676 if (!(mask & (1 << pipe))) {
677 if (igt_pipe_is_prop_changed(display, pipe, IGT_CRTC_ACTIVE)) {
678 event_mask |= 1 << pipe;
679 igt_plane_set_fb(plane, NULL);
680 }
681
682 continue;
683 }
684
685 event_mask |= 1 << pipe;
686
687 for_each_valid_output_on_pipe(display, pipe, output) {
688 if (output->pending_pipe != PIPE_NONE)
689 continue;
690
691 mode = igt_output_get_mode(output);
692 break;
693 }
694
695 if (!mode)
696 return 0;
697
698 igt_output_set_pipe(output, pipe);
699 igt_plane_set_fb(plane, fb);
700 igt_fb_set_size(fb, plane, mode->hdisplay, mode->vdisplay);
701 igt_plane_set_size(plane, mode->hdisplay, mode->vdisplay);
702 }
703
704 return event_mask;
705 }
706
refresh_primaries(igt_display_t * display,int mask)707 static void refresh_primaries(igt_display_t *display, int mask)
708 {
709 enum pipe pipe;
710 igt_plane_t *plane;
711
712 for_each_pipe(display, pipe) {
713 if (!((1 << pipe) & mask))
714 continue;
715
716 for_each_plane_on_pipe(display, pipe, plane)
717 if (plane->type == DRM_PLANE_TYPE_PRIMARY)
718 igt_plane_set_position(plane, 0, 0);
719 }
720 }
721
collect_crcs_mask(igt_pipe_crc_t ** pipe_crcs,unsigned mask,igt_crc_t * crcs)722 static void collect_crcs_mask(igt_pipe_crc_t **pipe_crcs, unsigned mask, igt_crc_t *crcs)
723 {
724 int i;
725
726 for (i = 0; i < IGT_MAX_PIPES; i++) {
727 if (!((1 << i) & mask))
728 continue;
729
730 if (!pipe_crcs[i])
731 continue;
732
733 igt_pipe_crc_collect_crc(pipe_crcs[i], &crcs[i]);
734 }
735 }
736
run_modeset_tests(igt_display_t * display,int howmany,bool nonblocking,bool fencing)737 static void run_modeset_tests(igt_display_t *display, int howmany, bool nonblocking, bool fencing)
738 {
739 struct igt_fb fbs[2];
740 int i, j;
741 unsigned iter_max = 1 << display->n_pipes;
742 igt_pipe_crc_t *pipe_crcs[IGT_MAX_PIPES] = { 0 };
743 igt_output_t *output;
744 unsigned width = 0, height = 0;
745
746 for_each_connected_output(display, output) {
747 drmModeModeInfo *mode = igt_output_get_mode(output);
748
749 igt_output_set_pipe(output, PIPE_NONE);
750
751 width = max(width, mode->hdisplay);
752 height = max(height, mode->vdisplay);
753 }
754
755 igt_create_pattern_fb(display->drm_fd, width, height,
756 DRM_FORMAT_XRGB8888, 0, &fbs[0]);
757 igt_create_color_pattern_fb(display->drm_fd, width, height,
758 DRM_FORMAT_XRGB8888, 0, .5, .5, .5, &fbs[1]);
759
760 for_each_pipe(display, i) {
761 igt_pipe_t *pipe = &display->pipes[i];
762 igt_plane_t *plane = igt_pipe_get_plane_type(pipe, DRM_PLANE_TYPE_PRIMARY);
763 drmModeModeInfo *mode = NULL;
764
765 if (is_i915_device(display->drm_fd))
766 pipe_crcs[i] = igt_pipe_crc_new(display->drm_fd, i, INTEL_PIPE_CRC_SOURCE_AUTO);
767
768 for_each_valid_output_on_pipe(display, i, output) {
769 if (output->pending_pipe != PIPE_NONE)
770 continue;
771
772 igt_output_set_pipe(output, i);
773 mode = igt_output_get_mode(output);
774 break;
775 }
776
777 if (mode) {
778 igt_plane_set_fb(plane, &fbs[1]);
779 igt_fb_set_size(&fbs[1], plane, mode->hdisplay, mode->vdisplay);
780 igt_plane_set_size(plane, mode->hdisplay, mode->vdisplay);
781
782 if (fencing)
783 igt_pipe_request_out_fence(&display->pipes[i]);
784 } else
785 igt_plane_set_fb(plane, NULL);
786 }
787
788 igt_display_commit2(display, COMMIT_ATOMIC);
789
790 for (i = 0; i < iter_max; i++) {
791 igt_crc_t crcs[5][IGT_MAX_PIPES];
792 unsigned event_mask;
793
794 if (igt_hweight(i) > howmany)
795 continue;
796
797 event_mask = set_combinations(display, i, &fbs[0]);
798 if (!event_mask && i)
799 continue;
800
801 commit_display(display, event_mask, nonblocking);
802
803 collect_crcs_mask(pipe_crcs, i, crcs[0]);
804
805 for (j = iter_max - 1; j > i + 1; j--) {
806 if (igt_hweight(j) > howmany)
807 continue;
808
809 if (igt_hweight(i) < howmany && igt_hweight(j) < howmany)
810 continue;
811
812 event_mask = set_combinations(display, j, &fbs[1]);
813 if (!event_mask)
814 continue;
815
816 commit_display(display, event_mask, nonblocking);
817
818 collect_crcs_mask(pipe_crcs, j, crcs[1]);
819
820 refresh_primaries(display, j);
821 commit_display(display, j, nonblocking);
822 collect_crcs_mask(pipe_crcs, j, crcs[2]);
823
824 event_mask = set_combinations(display, i, &fbs[0]);
825 if (!event_mask)
826 continue;
827
828 commit_display(display, event_mask, nonblocking);
829 collect_crcs_mask(pipe_crcs, i, crcs[3]);
830
831 refresh_primaries(display, i);
832 commit_display(display, i, nonblocking);
833 collect_crcs_mask(pipe_crcs, i, crcs[4]);
834
835 if (!is_i915_device(display->drm_fd))
836 continue;
837
838 for (int k = 0; k < IGT_MAX_PIPES; k++) {
839 if (i & (1 << k)) {
840 igt_assert_crc_equal(&crcs[0][k], &crcs[3][k]);
841 igt_assert_crc_equal(&crcs[0][k], &crcs[4][k]);
842 }
843
844 if (j & (1 << k))
845 igt_assert_crc_equal(&crcs[1][k], &crcs[2][k]);
846 }
847 }
848 }
849
850 set_combinations(display, 0, NULL);
851 igt_display_commit2(display, COMMIT_ATOMIC);
852
853 if (is_i915_device(display->drm_fd))
854 for_each_pipe(display, i)
855 igt_pipe_crc_free(pipe_crcs[i]);
856
857 igt_remove_fb(display->drm_fd, &fbs[1]);
858 igt_remove_fb(display->drm_fd, &fbs[0]);
859 }
860
run_modeset_transition(igt_display_t * display,int requested_outputs,bool nonblocking,bool fencing)861 static void run_modeset_transition(igt_display_t *display, int requested_outputs, bool nonblocking, bool fencing)
862 {
863 igt_output_t *outputs[IGT_MAX_PIPES] = {};
864 int num_outputs = 0;
865 enum pipe pipe;
866
867 for_each_pipe(display, pipe) {
868 igt_output_t *output;
869
870 for_each_valid_output_on_pipe(display, pipe, output) {
871 int i;
872
873 for (i = pipe - 1; i >= 0; i--)
874 if (outputs[i] == output)
875 break;
876
877 if (i < 0) {
878 outputs[pipe] = output;
879 num_outputs++;
880 break;
881 }
882 }
883 }
884
885 igt_require_f(num_outputs >= requested_outputs,
886 "Should have at least %i outputs, found %i\n",
887 requested_outputs, num_outputs);
888
889 run_modeset_tests(display, requested_outputs, nonblocking, fencing);
890 }
891
output_is_internal_panel(igt_output_t * output)892 static bool output_is_internal_panel(igt_output_t *output)
893 {
894 switch (output->config.connector->connector_type) {
895 case DRM_MODE_CONNECTOR_LVDS:
896 case DRM_MODE_CONNECTOR_eDP:
897 case DRM_MODE_CONNECTOR_DSI:
898 case DRM_MODE_CONNECTOR_DPI:
899 return true;
900 default:
901 return false;
902 }
903 }
904
905 igt_main
906 {
907 igt_display_t display;
908 igt_output_t *output;
909 enum pipe pipe;
910 int i;
911
912 igt_skip_on_simulation();
913
914 igt_fixture {
915 display.drm_fd = drm_open_driver_master(DRIVER_ANY);
916
917 kmstest_set_vt_graphics_mode();
918
919 igt_display_require(&display, display.drm_fd);
920 igt_require(display.is_atomic);
921
922 igt_display_require_output(&display);
923 }
924
925 igt_subtest("plane-primary-toggle-with-vblank-wait")
926 for_each_pipe_with_valid_output(&display, pipe, output)
927 run_primary_test(&display, pipe, output);
928
929 igt_subtest("plane-all-transition")
930 for_each_pipe_with_valid_output(&display, pipe, output)
931 run_transition_test(&display, pipe, output, TRANSITION_PLANES, false, false);
932
933 igt_subtest("plane-all-transition-fencing")
934 for_each_pipe_with_valid_output(&display, pipe, output)
935 run_transition_test(&display, pipe, output, TRANSITION_PLANES, false, true);
936
937 igt_subtest("plane-all-transition-nonblocking")
938 for_each_pipe_with_valid_output(&display, pipe, output)
939 run_transition_test(&display, pipe, output, TRANSITION_PLANES, true, false);
940
941 igt_subtest("plane-all-transition-nonblocking-fencing")
942 for_each_pipe_with_valid_output(&display, pipe, output)
943 run_transition_test(&display, pipe, output, TRANSITION_PLANES, true, true);
944
945 igt_subtest("plane-use-after-nonblocking-unbind")
946 for_each_pipe_with_valid_output(&display, pipe, output)
947 run_transition_test(&display, pipe, output, TRANSITION_AFTER_FREE, true, false);
948
949 igt_subtest("plane-use-after-nonblocking-unbind-fencing")
950 for_each_pipe_with_valid_output(&display, pipe, output)
951 run_transition_test(&display, pipe, output, TRANSITION_AFTER_FREE, true, true);
952
953 /*
954 * Test modeset cases on internal panels separately with a reduced
955 * number of combinations, to avoid long runtimes due to modesets on
956 * panels with long power cycle delays.
957 */
958 igt_subtest("plane-all-modeset-transition")
959 for_each_pipe_with_valid_output(&display, pipe, output) {
960 if (output_is_internal_panel(output))
961 continue;
962 run_transition_test(&display, pipe, output, TRANSITION_MODESET, false, false);
963 }
964
965 igt_subtest("plane-all-modeset-transition-fencing")
966 for_each_pipe_with_valid_output(&display, pipe, output) {
967 if (output_is_internal_panel(output))
968 continue;
969 run_transition_test(&display, pipe, output, TRANSITION_MODESET, false, true);
970 }
971
972 igt_subtest("plane-all-modeset-transition-internal-panels") {
973 int tested = 0;
974
975 for_each_pipe_with_valid_output(&display, pipe, output) {
976 if (!output_is_internal_panel(output))
977 continue;
978 run_transition_test(&display, pipe, output, TRANSITION_MODESET_FAST, false, false);
979 tested++;
980 }
981 igt_skip_on_f(!tested, "No output with internal panel found\n");
982 }
983
984 igt_subtest("plane-all-modeset-transition-fencing-internal-panels") {
985 int tested = 0;
986
987 for_each_pipe_with_valid_output(&display, pipe, output) {
988 if (!output_is_internal_panel(output))
989 continue;
990 run_transition_test(&display, pipe, output, TRANSITION_MODESET_FAST, false, true);
991 tested++;
992 }
993 igt_skip_on_f(!tested, "No output with internal panel found\n");
994 }
995
996 igt_subtest("plane-toggle-modeset-transition")
997 for_each_pipe_with_valid_output(&display, pipe, output)
998 run_transition_test(&display, pipe, output, TRANSITION_MODESET_DISABLE, false, false);
999
1000 for (i = 1; i <= IGT_MAX_PIPES; i++) {
1001 igt_subtest_f("%ix-modeset-transitions", i)
1002 run_modeset_transition(&display, i, false, false);
1003
1004 igt_subtest_f("%ix-modeset-transitions-nonblocking", i)
1005 run_modeset_transition(&display, i, true, false);
1006
1007 igt_subtest_f("%ix-modeset-transitions-fencing", i)
1008 run_modeset_transition(&display, i, false, true);
1009
1010 igt_subtest_f("%ix-modeset-transitions-nonblocking-fencing", i)
1011 run_modeset_transition(&display, i, true, true);
1012 }
1013
1014 igt_fixture {
1015 igt_display_fini(&display);
1016 }
1017 }
1018