• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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