1 /*
2 * Copyright © 2014 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 <errno.h>
26 #include <stdbool.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <fcntl.h>
30
31
32 typedef struct {
33 int drm_fd;
34 igt_display_t display;
35 int gen;
36 } data_t;
37
38 typedef struct {
39 data_t *data;
40 igt_pipe_crc_t *pipe_crc;
41 igt_crc_t crc_1, crc_2, crc_3, crc_4, crc_5, crc_6, crc_7, crc_8,
42 crc_9, crc_10;
43 struct igt_fb red_fb, blue_fb, black_fb, yellow_fb;
44 drmModeModeInfo *mode;
45 } functional_test_t;
46
47 typedef struct {
48 data_t *data;
49 drmModeResPtr moderes;
50 struct igt_fb blue_fb, oversized_fb, undersized_fb;
51 } sanity_test_t;
52
53 typedef struct {
54 data_t *data;
55 struct igt_fb red_fb, blue_fb;
56 } pageflip_test_t;
57
58 typedef struct {
59 data_t *data;
60 int x, y;
61 int w, h;
62 struct igt_fb biggreen_fb, smallred_fb, smallblue_fb;
63 } gen9_test_t;
64
65 static void
functional_test_init(functional_test_t * test,igt_output_t * output,enum pipe pipe)66 functional_test_init(functional_test_t *test, igt_output_t *output, enum pipe pipe)
67 {
68 data_t *data = test->data;
69 drmModeModeInfo *mode;
70
71 test->pipe_crc = igt_pipe_crc_new(data->drm_fd, pipe, INTEL_PIPE_CRC_SOURCE_AUTO);
72
73 igt_output_set_pipe(output, pipe);
74
75 mode = igt_output_get_mode(output);
76 igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
77 DRM_FORMAT_XRGB8888,
78 LOCAL_DRM_FORMAT_MOD_NONE,
79 0.0, 0.0, 0.0,
80 &test->black_fb);
81 igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
82 DRM_FORMAT_XRGB8888,
83 LOCAL_DRM_FORMAT_MOD_NONE,
84 0.0, 0.0, 1.0,
85 &test->blue_fb);
86 igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
87 DRM_FORMAT_XRGB8888,
88 LOCAL_DRM_FORMAT_MOD_NONE,
89 1.0, 1.0, 0.0,
90 &test->yellow_fb);
91 igt_create_color_fb(data->drm_fd, 100, 100,
92 DRM_FORMAT_XRGB8888,
93 LOCAL_DRM_FORMAT_MOD_NONE,
94 1.0, 0.0, 0.0,
95 &test->red_fb);
96
97 test->mode = mode;
98 }
99
100 static void
functional_test_fini(functional_test_t * test,igt_output_t * output)101 functional_test_fini(functional_test_t *test, igt_output_t *output)
102 {
103 igt_pipe_crc_free(test->pipe_crc);
104
105 igt_remove_fb(test->data->drm_fd, &test->black_fb);
106 igt_remove_fb(test->data->drm_fd, &test->blue_fb);
107 igt_remove_fb(test->data->drm_fd, &test->red_fb);
108 igt_remove_fb(test->data->drm_fd, &test->yellow_fb);
109
110 igt_output_set_pipe(output, PIPE_ANY);
111 igt_display_commit2(&test->data->display, COMMIT_LEGACY);
112 }
113
114 /*
115 * Universal plane functional testing.
116 * - Black primary plane via traditional interfaces, red sprite, grab CRC:1.
117 * - Blue primary plane via traditional interfaces, red sprite, grab CRC:2.
118 * - Yellow primary via traditional interfaces
119 * - Blue primary plane, red sprite via universal planes, grab CRC:3 and compare
120 * with CRC:2 (should be the same)
121 * - Disable primary plane, grab CRC:4 (should be same as CRC:1)
122 * - Reenable primary, grab CRC:5 (should be same as CRC:2 and CRC:3)
123 * - Yellow primary, no sprite
124 * - Disable CRTC
125 * - Program red sprite (while CRTC off)
126 * - Program blue primary (while CRTC off)
127 * - Enable CRTC, grab CRC:6 (should be same as CRC:2)
128 */
129 static void
functional_test_pipe(data_t * data,enum pipe pipe,igt_output_t * output)130 functional_test_pipe(data_t *data, enum pipe pipe, igt_output_t *output)
131 {
132 functional_test_t test = { .data = data };
133 igt_display_t *display = &data->display;
134 igt_plane_t *primary, *sprite;
135 int num_primary = 0, num_cursor = 0;
136 int i;
137
138 igt_skip_on(pipe >= display->n_pipes);
139
140 igt_info("Testing connector %s using pipe %s\n", igt_output_name(output),
141 kmstest_pipe_name(pipe));
142
143 functional_test_init(&test, output, pipe);
144
145 /*
146 * Make sure we have no more than one primary or cursor plane per crtc.
147 * If the kernel accidentally calls drm_plane_init() rather than
148 * drm_universal_plane_init(), the type enum can get interpreted as a
149 * boolean and show up in userspace as the wrong type.
150 */
151 for (i = 0; i < display->pipes[pipe].n_planes; i++)
152 if (display->pipes[pipe].planes[i].type == DRM_PLANE_TYPE_PRIMARY)
153 num_primary++;
154 else if (display->pipes[pipe].planes[i].type == DRM_PLANE_TYPE_CURSOR)
155 num_cursor++;
156
157 igt_assert_eq(num_primary, 1);
158 igt_assert_lte(num_cursor, 1);
159
160 primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
161 sprite = igt_output_get_plane_type(output, DRM_PLANE_TYPE_OVERLAY);
162 if (!sprite) {
163 functional_test_fini(&test, output);
164 igt_skip("No sprite plane available\n");
165 }
166
167 igt_plane_set_position(sprite, 100, 100);
168
169 /* Step 1: Legacy API's, black primary, red sprite (CRC 1) */
170 igt_plane_set_fb(primary, &test.black_fb);
171 igt_plane_set_fb(sprite, &test.red_fb);
172 igt_display_commit2(display, COMMIT_LEGACY);
173 igt_pipe_crc_collect_crc(test.pipe_crc, &test.crc_1);
174
175 /* Step 2: Legacy API', blue primary, red sprite (CRC 2) */
176 igt_plane_set_fb(primary, &test.blue_fb);
177 igt_plane_set_fb(sprite, &test.red_fb);
178 igt_display_commit2(display, COMMIT_LEGACY);
179 igt_pipe_crc_collect_crc(test.pipe_crc, &test.crc_2);
180
181 /* Step 3: Legacy API's, yellow primary (CRC 3) */
182 igt_plane_set_fb(primary, &test.yellow_fb);
183 igt_display_commit2(display, COMMIT_LEGACY);
184 igt_pipe_crc_collect_crc(test.pipe_crc, &test.crc_3);
185
186 /* Step 4: Universal API's, blue primary, red sprite (CRC 4) */
187 igt_plane_set_fb(primary, &test.blue_fb);
188 igt_plane_set_fb(sprite, &test.red_fb);
189 igt_display_commit2(display, COMMIT_UNIVERSAL);
190 igt_pipe_crc_collect_crc(test.pipe_crc, &test.crc_4);
191
192 /* Step 5: Universal API's, disable primary plane (CRC 5) */
193 igt_plane_set_fb(primary, NULL);
194 igt_display_commit2(display, COMMIT_UNIVERSAL);
195 igt_pipe_crc_collect_crc(test.pipe_crc, &test.crc_5);
196
197 /* Step 6: Universal API's, re-enable primary with blue (CRC 6) */
198 igt_plane_set_fb(primary, &test.blue_fb);
199 igt_display_commit2(display, COMMIT_UNIVERSAL);
200 igt_pipe_crc_collect_crc(test.pipe_crc, &test.crc_6);
201
202 /* Step 7: Legacy API's, yellow primary, no sprite */
203 igt_plane_set_fb(primary, &test.yellow_fb);
204 igt_plane_set_fb(sprite, NULL);
205 igt_display_commit2(display, COMMIT_LEGACY);
206
207 /* Step 8: Disable CRTC */
208 igt_plane_set_fb(primary, NULL);
209 igt_display_commit2(display, COMMIT_LEGACY);
210
211 /* Step 9: Universal API's with crtc off:
212 * - red sprite
213 * - multiple primary fb's, ending in blue
214 */
215 igt_plane_set_fb(sprite, &test.red_fb);
216 igt_display_commit2(display, COMMIT_UNIVERSAL);
217 igt_plane_set_fb(primary, &test.yellow_fb);
218 igt_display_commit2(display, COMMIT_UNIVERSAL);
219 igt_plane_set_fb(primary, &test.black_fb);
220 igt_display_commit2(display, COMMIT_UNIVERSAL);
221 igt_plane_set_fb(primary, &test.blue_fb);
222 igt_display_commit2(display, COMMIT_UNIVERSAL);
223
224 /* Step 10: Enable crtc (fb = -1), take CRC (CRC 7) */
225 igt_assert(drmModeSetCrtc(data->drm_fd, output->config.crtc->crtc_id, -1,
226 0, 0, &output->config.connector->connector_id,
227 1, test.mode) == 0);
228 igt_pipe_crc_collect_crc(test.pipe_crc, &test.crc_7);
229
230 /* Step 11: Disable primary plane */
231 igt_plane_set_fb(primary, NULL);
232 igt_display_commit2(display, COMMIT_UNIVERSAL);
233
234 /* Step 12: Legacy modeset to yellow FB (CRC 8) */
235 igt_plane_set_fb(primary, &test.yellow_fb);
236 igt_display_commit2(display, COMMIT_LEGACY);
237 igt_pipe_crc_collect_crc(test.pipe_crc, &test.crc_8);
238
239 /* Step 13: Legacy API', blue primary, red sprite */
240 igt_plane_set_fb(primary, &test.blue_fb);
241 igt_plane_set_fb(sprite, &test.red_fb);
242 igt_display_commit2(display, COMMIT_LEGACY);
243
244 /* Step 14: Universal API, set primary completely offscreen (CRC 9) */
245 igt_assert(drmModeSetPlane(data->drm_fd, primary->drm_plane->plane_id,
246 output->config.crtc->crtc_id,
247 test.blue_fb.fb_id, 0,
248 9000, 9000,
249 test.mode->hdisplay,
250 test.mode->vdisplay,
251 IGT_FIXED(0,0), IGT_FIXED(0,0),
252 IGT_FIXED(test.mode->hdisplay,0),
253 IGT_FIXED(test.mode->vdisplay,0)) == 0);
254 igt_pipe_crc_collect_crc(test.pipe_crc, &test.crc_9);
255
256 /*
257 * Step 15: Explicitly disable primary after it's already been
258 * implicitly disabled (CRC 10).
259 */
260 igt_plane_set_fb(primary, NULL);
261 igt_display_commit2(display, COMMIT_UNIVERSAL);
262 igt_pipe_crc_collect_crc(test.pipe_crc, &test.crc_10);
263
264 /* Step 16: Legacy API's, blue primary, red sprite */
265 igt_plane_set_fb(primary, &test.blue_fb);
266 igt_plane_set_fb(sprite, &test.red_fb);
267 igt_display_commit2(display, COMMIT_LEGACY);
268
269 /* Blue bg + red sprite should be same under both types of API's */
270 igt_assert_crc_equal(&test.crc_2, &test.crc_4);
271
272 /* Disabling primary plane should be same as black primary */
273 igt_assert_crc_equal(&test.crc_1, &test.crc_5);
274
275 /* Re-enabling primary should return to blue properly */
276 igt_assert_crc_equal(&test.crc_2, &test.crc_6);
277
278 /*
279 * We should be able to setup plane FB's while CRTC is disabled and
280 * then have them pop up correctly when the CRTC is re-enabled.
281 */
282 igt_assert_crc_equal(&test.crc_2, &test.crc_7);
283
284 /*
285 * We should be able to modeset with the primary plane off
286 * successfully
287 */
288 igt_assert_crc_equal(&test.crc_3, &test.crc_8);
289
290 /*
291 * We should be able to move the primary plane completely offscreen
292 * and have it disable successfully.
293 */
294 igt_assert_crc_equal(&test.crc_5, &test.crc_9);
295
296 /*
297 * We should be able to explicitly disable an already
298 * implicitly-disabled primary plane
299 */
300 igt_assert_crc_equal(&test.crc_5, &test.crc_10);
301
302 igt_plane_set_fb(primary, NULL);
303 igt_plane_set_fb(sprite, NULL);
304
305 functional_test_fini(&test, output);
306 }
307
308 static void
sanity_test_init(sanity_test_t * test,igt_output_t * output,enum pipe pipe)309 sanity_test_init(sanity_test_t *test, igt_output_t *output, enum pipe pipe)
310 {
311 data_t *data = test->data;
312 drmModeModeInfo *mode;
313
314 igt_output_set_pipe(output, pipe);
315
316 mode = igt_output_get_mode(output);
317 igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
318 DRM_FORMAT_XRGB8888,
319 LOCAL_DRM_FORMAT_MOD_NONE,
320 0.0, 0.0, 1.0,
321 &test->blue_fb);
322 igt_create_color_fb(data->drm_fd,
323 mode->hdisplay + 100, mode->vdisplay + 100,
324 DRM_FORMAT_XRGB8888,
325 LOCAL_DRM_FORMAT_MOD_NONE,
326 0.0, 0.0, 1.0,
327 &test->oversized_fb);
328 igt_create_color_fb(data->drm_fd,
329 mode->hdisplay - 100, mode->vdisplay - 100,
330 DRM_FORMAT_XRGB8888,
331 LOCAL_DRM_FORMAT_MOD_NONE,
332 0.0, 0.0, 1.0,
333 &test->undersized_fb);
334
335 test->moderes = drmModeGetResources(data->drm_fd);
336 igt_assert(test->moderes);
337 }
338
339 static void
sanity_test_fini(sanity_test_t * test,igt_output_t * output)340 sanity_test_fini(sanity_test_t *test, igt_output_t *output)
341 {
342 drmModeFreeResources(test->moderes);
343
344 igt_remove_fb(test->data->drm_fd, &test->oversized_fb);
345 igt_remove_fb(test->data->drm_fd, &test->undersized_fb);
346 igt_remove_fb(test->data->drm_fd, &test->blue_fb);
347
348 igt_output_set_pipe(output, PIPE_ANY);
349 igt_display_commit2(&test->data->display, COMMIT_LEGACY);
350 }
351
352 /*
353 * Universal plane sanity testing.
354 * - Primary doesn't cover CRTC
355 * - Primary plane tries to scale down
356 * - Primary plane tries to scale up
357 */
358 static void
sanity_test_pipe(data_t * data,enum pipe pipe,igt_output_t * output)359 sanity_test_pipe(data_t *data, enum pipe pipe, igt_output_t *output)
360 {
361 sanity_test_t test = { .data = data };
362 igt_plane_t *primary;
363 drmModeModeInfo *mode;
364 int i;
365 int expect;
366
367 igt_skip_on(pipe >= data->display.n_pipes);
368
369 igt_output_set_pipe(output, pipe);
370 mode = igt_output_get_mode(output);
371
372 sanity_test_init(&test, output, pipe);
373
374 primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
375
376 /* Use legacy API to set a mode with a blue FB */
377 igt_plane_set_fb(primary, &test.blue_fb);
378 igt_display_commit2(&data->display, COMMIT_LEGACY);
379
380 /*
381 * Try to use universal plane API to set primary plane that
382 * doesn't cover CRTC (should fail on pre-gen9 and succeed on
383 * gen9+).
384 */
385 igt_plane_set_fb(primary, &test.undersized_fb);
386 expect = (data->gen < 9) ? -EINVAL : 0;
387 igt_assert(igt_display_try_commit2(&data->display, COMMIT_UNIVERSAL) == expect);
388
389 /* Same as above, but different plane positioning. */
390 igt_plane_set_position(primary, 100, 100);
391 igt_assert(igt_display_try_commit2(&data->display, COMMIT_UNIVERSAL) == expect);
392
393 igt_plane_set_position(primary, 0, 0);
394
395 /* Try to use universal plane API to scale down (should fail on pre-gen9) */
396 expect = (data->gen < 9) ? -ERANGE : 0;
397 igt_assert(drmModeSetPlane(data->drm_fd, primary->drm_plane->plane_id,
398 output->config.crtc->crtc_id,
399 test.oversized_fb.fb_id, 0,
400 0, 0,
401 mode->hdisplay + 100,
402 mode->vdisplay + 100,
403 IGT_FIXED(0,0), IGT_FIXED(0,0),
404 IGT_FIXED(mode->hdisplay,0),
405 IGT_FIXED(mode->vdisplay,0)) == expect);
406
407 /* Try to use universal plane API to scale up (should fail on pre-gen9) */
408 igt_assert(drmModeSetPlane(data->drm_fd, primary->drm_plane->plane_id,
409 output->config.crtc->crtc_id,
410 test.oversized_fb.fb_id, 0,
411 0, 0,
412 mode->hdisplay,
413 mode->vdisplay,
414 IGT_FIXED(0,0), IGT_FIXED(0,0),
415 IGT_FIXED(mode->hdisplay - 100,0),
416 IGT_FIXED(mode->vdisplay - 100,0)) == expect);
417
418 /* Find other crtcs and try to program our primary plane on them */
419 for (i = 0; i < test.moderes->count_crtcs; i++)
420 if (test.moderes->crtcs[i] != output->config.crtc->crtc_id) {
421 igt_assert(drmModeSetPlane(data->drm_fd,
422 primary->drm_plane->plane_id,
423 test.moderes->crtcs[i],
424 test.blue_fb.fb_id, 0,
425 0, 0,
426 mode->hdisplay,
427 mode->vdisplay,
428 IGT_FIXED(0,0), IGT_FIXED(0,0),
429 IGT_FIXED(mode->hdisplay,0),
430 IGT_FIXED(mode->vdisplay,0)) == -EINVAL);
431 }
432
433 igt_plane_set_fb(primary, NULL);
434 sanity_test_fini(&test, output);
435 }
436
437 static void
pageflip_test_init(pageflip_test_t * test,igt_output_t * output,enum pipe pipe)438 pageflip_test_init(pageflip_test_t *test, igt_output_t *output, enum pipe pipe)
439 {
440 data_t *data = test->data;
441 drmModeModeInfo *mode;
442
443 igt_output_set_pipe(output, pipe);
444
445 mode = igt_output_get_mode(output);
446 igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
447 DRM_FORMAT_XRGB8888,
448 LOCAL_DRM_FORMAT_MOD_NONE,
449 1.0, 0.0, 0.0,
450 &test->red_fb);
451 igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
452 DRM_FORMAT_XRGB8888,
453 LOCAL_DRM_FORMAT_MOD_NONE,
454 0.0, 0.0, 1.0,
455 &test->blue_fb);
456 }
457
458 static void
pageflip_test_fini(pageflip_test_t * test,igt_output_t * output)459 pageflip_test_fini(pageflip_test_t *test, igt_output_t *output)
460 {
461 igt_remove_fb(test->data->drm_fd, &test->red_fb);
462 igt_remove_fb(test->data->drm_fd, &test->blue_fb);
463
464 igt_output_set_pipe(output, PIPE_ANY);
465 igt_display_commit2(&test->data->display, COMMIT_LEGACY);
466 }
467
468 static void
pageflip_test_pipe(data_t * data,enum pipe pipe,igt_output_t * output)469 pageflip_test_pipe(data_t *data, enum pipe pipe, igt_output_t *output)
470 {
471 pageflip_test_t test = { .data = data };
472 igt_plane_t *primary;
473 struct timeval timeout = { .tv_sec = 0, .tv_usec = 500 };
474 drmEventContext evctx = { .version = 2 };
475
476 fd_set fds;
477 int ret = 0;
478
479 igt_skip_on(pipe >= data->display.n_pipes);
480
481 igt_output_set_pipe(output, pipe);
482
483 pageflip_test_init(&test, output, pipe);
484
485 primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
486
487 /* Use legacy API to set a mode with a blue FB */
488 igt_plane_set_fb(primary, &test.blue_fb);
489 igt_display_commit2(&data->display, COMMIT_LEGACY);
490
491 /* Disable the primary plane */
492 igt_plane_set_fb(primary, NULL);
493 igt_display_commit2(&data->display, COMMIT_UNIVERSAL);
494
495 /*
496 * Issue a pageflip to red FB
497 *
498 * Note that crtc->primary->fb = NULL causes flip to return EBUSY for
499 * historical reasons...
500 */
501 igt_assert(drmModePageFlip(data->drm_fd, output->config.crtc->crtc_id,
502 test.red_fb.fb_id, 0, NULL) == -EBUSY);
503
504 /* Turn primary plane back on */
505 igt_plane_set_fb(primary, &test.blue_fb);
506 igt_display_commit2(&data->display, COMMIT_UNIVERSAL);
507
508 /*
509 * Issue a pageflip to red, then immediately try to disable the primary
510 * plane, hopefully before the pageflip has a chance to complete. The
511 * plane disable operation should wind up blocking while the pageflip
512 * completes, which we don't have a good way to specifically test for,
513 * but at least we can make sure that nothing blows up.
514 */
515 igt_assert(drmModePageFlip(data->drm_fd, output->config.crtc->crtc_id,
516 test.red_fb.fb_id, DRM_MODE_PAGE_FLIP_EVENT,
517 &test) == 0);
518 igt_plane_set_fb(primary, NULL);
519 igt_display_commit2(&data->display, COMMIT_UNIVERSAL);
520
521 /* Wait for pageflip completion, then consume event on fd */
522 FD_ZERO(&fds);
523 FD_SET(data->drm_fd, &fds);
524 do {
525 ret = select(data->drm_fd + 1, &fds, NULL, NULL, &timeout);
526 } while (ret < 0 && errno == EINTR);
527 igt_assert_eq(ret, 1);
528 igt_assert(drmHandleEvent(data->drm_fd, &evctx) == 0);
529
530 igt_plane_set_fb(primary, NULL);
531 pageflip_test_fini(&test, output);
532 }
533
534 static void
cursor_leak_test_fini(data_t * data,igt_output_t * output,struct igt_fb * bg,struct igt_fb * curs)535 cursor_leak_test_fini(data_t *data,
536 igt_output_t *output,
537 struct igt_fb *bg,
538 struct igt_fb *curs)
539 {
540 int i;
541
542 igt_remove_fb(data->drm_fd, bg);
543 for (i = 0; i < 10; i++)
544 igt_remove_fb(data->drm_fd, &curs[i]);
545
546 igt_output_set_pipe(output, PIPE_ANY);
547 }
548
549 static int
i915_gem_fb_count(data_t * data)550 i915_gem_fb_count(data_t *data)
551 {
552 char buf[1024];
553 FILE *fp;
554 int fd;
555 int count = 0;
556
557 fd = igt_debugfs_open(data->drm_fd, "i915_gem_framebuffer", O_RDONLY);
558 fp = fdopen(fd, "r");
559 igt_require(fp);
560 while (fgets(buf, sizeof(buf), fp) != NULL)
561 count++;
562 fclose(fp);
563 close(fd);
564
565 return count;
566 }
567
568 static void
cursor_leak_test_pipe(data_t * data,enum pipe pipe,igt_output_t * output)569 cursor_leak_test_pipe(data_t *data, enum pipe pipe, igt_output_t *output)
570 {
571 igt_display_t *display = &data->display;
572 igt_plane_t *primary, *cursor;
573 drmModeModeInfo *mode;
574 struct igt_fb background_fb;
575 struct igt_fb cursor_fb[10];
576 int i;
577 int r, g, b;
578 int count1, count2;
579
580 igt_skip_on(pipe >= display->n_pipes);
581 igt_require(display->has_cursor_plane);
582
583 igt_output_set_pipe(output, pipe);
584 mode = igt_output_get_mode(output);
585
586 /* Count GEM framebuffers before creating our cursor FB's */
587 count1 = i915_gem_fb_count(data);
588
589 /* Black background FB */
590 igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
591 DRM_FORMAT_XRGB8888,
592 false,
593 0.0, 0.0, 0.0,
594 &background_fb);
595
596 /* Random color cursors */
597 for (i = 0; i < 10; i++) {
598 r = rand() % 0xFF;
599 g = rand() % 0xFF;
600 b = rand() % 0xFF;
601 igt_create_color_fb(data->drm_fd, 64, 64,
602 DRM_FORMAT_ARGB8888,
603 false,
604 (double)r / 0xFF,
605 (double)g / 0xFF,
606 (double)b / 0xFF,
607 &cursor_fb[i]);
608 }
609
610 primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
611 cursor = igt_output_get_plane_type(output, DRM_PLANE_TYPE_CURSOR);
612 if (!primary || !cursor) {
613 cursor_leak_test_fini(data, output, &background_fb, cursor_fb);
614 igt_skip("Primary and/or cursor are unavailable\n");
615 }
616
617
618 igt_plane_set_fb(primary, &background_fb);
619 igt_display_commit2(display, COMMIT_LEGACY);
620
621 igt_plane_set_position(cursor, 100, 100);
622
623 /*
624 * Exercise both legacy and universal code paths. Note that legacy
625 * handling in the kernel redirects through universal codepaths
626 * internally, so that redirection is where we're most worried about
627 * leaking.
628 */
629 for (i = 0; i < 10; i++) {
630 igt_plane_set_fb(cursor, &cursor_fb[i]);
631 igt_display_commit2(display, COMMIT_UNIVERSAL);
632 }
633 for (i = 0; i < 10; i++) {
634 igt_plane_set_fb(cursor, &cursor_fb[i]);
635 igt_display_commit2(display, COMMIT_LEGACY);
636 }
637
638 /* Release our framebuffer handles before we take a second count */
639 igt_plane_set_fb(primary, NULL);
640 igt_plane_set_fb(cursor, NULL);
641 igt_display_commit2(display, COMMIT_LEGACY);
642 cursor_leak_test_fini(data, output, &background_fb, cursor_fb);
643
644 /* We should be back to the same framebuffer count as when we started */
645 count2 = i915_gem_fb_count(data);
646
647 igt_assert_eq(count1, count2);
648 }
649
650 static void
gen9_test_init(gen9_test_t * test,igt_output_t * output,enum pipe pipe)651 gen9_test_init(gen9_test_t *test, igt_output_t *output, enum pipe pipe)
652 {
653 data_t *data = test->data;
654 drmModeModeInfo *mode;
655
656 igt_output_set_pipe(output, pipe);
657
658 mode = igt_output_get_mode(output);
659 test->w = mode->hdisplay / 2;
660 test->h = mode->vdisplay / 2;
661 test->x = mode->hdisplay / 4;
662 test->y = mode->vdisplay / 4;
663
664 /* Initial framebuffer of full CRTC size */
665 igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
666 DRM_FORMAT_XRGB8888,
667 LOCAL_DRM_FORMAT_MOD_NONE,
668 0.0, 1.0, 0.0,
669 &test->biggreen_fb);
670
671 /* Framebuffers that only cover a quarter of the CRTC size */
672 igt_create_color_fb(data->drm_fd, test->w, test->h,
673 DRM_FORMAT_XRGB8888,
674 LOCAL_DRM_FORMAT_MOD_NONE,
675 1.0, 0.0, 0.0,
676 &test->smallred_fb);
677 igt_create_color_fb(data->drm_fd, test->w, test->h,
678 DRM_FORMAT_XRGB8888,
679 LOCAL_DRM_FORMAT_MOD_NONE,
680 0.0, 0.0, 1.0,
681 &test->smallblue_fb);
682 }
683
684 static void
gen9_test_fini(gen9_test_t * test,igt_output_t * output)685 gen9_test_fini(gen9_test_t *test, igt_output_t *output)
686 {
687 igt_remove_fb(test->data->drm_fd, &test->biggreen_fb);
688 igt_remove_fb(test->data->drm_fd, &test->smallred_fb);
689 igt_remove_fb(test->data->drm_fd, &test->smallblue_fb);
690
691 igt_output_set_pipe(output, PIPE_ANY);
692 igt_display_commit2(&test->data->display, COMMIT_LEGACY);
693 }
694
695 /*
696 * Test features specific to gen9+ platforms (i.e., primary plane
697 * windowing)
698 */
699 static void
gen9_test_pipe(data_t * data,enum pipe pipe,igt_output_t * output)700 gen9_test_pipe(data_t *data, enum pipe pipe, igt_output_t *output)
701 {
702 gen9_test_t test = { .data = data };
703 igt_plane_t *primary;
704
705 int ret = 0;
706
707 igt_skip_on(data->gen < 9);
708 igt_skip_on(pipe >= data->display.n_pipes);
709
710 igt_output_set_pipe(output, pipe);
711
712 gen9_test_init(&test, output, pipe);
713
714 primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
715
716 /* Start with a full-screen primary plane */
717 igt_plane_set_fb(primary, &test.biggreen_fb);
718 igt_display_commit2(&data->display, COMMIT_LEGACY);
719
720 /* Set primary to windowed size/position */
721 igt_plane_set_fb(primary, &test.smallblue_fb);
722 igt_plane_set_position(primary, test.x, test.y);
723 igt_plane_set_size(primary, test.w, test.h);
724 igt_display_commit2(&data->display, COMMIT_UNIVERSAL);
725
726 /*
727 * SetPlane update to another framebuffer of the same size
728 * should succeed
729 */
730 igt_plane_set_fb(primary, &test.smallred_fb);
731 igt_plane_set_position(primary, test.x, test.y);
732 igt_plane_set_size(primary, test.w, test.h);
733 igt_display_commit2(&data->display, COMMIT_UNIVERSAL);
734
735 /* PageFlip should also succeed */
736 ret = drmModePageFlip(data->drm_fd, output->config.crtc->crtc_id,
737 test.smallblue_fb.fb_id, 0, NULL);
738 igt_assert_eq(ret, 0);
739
740 igt_plane_set_fb(primary, NULL);
741 igt_plane_set_position(primary, 0, 0);
742 gen9_test_fini(&test, output);
743 }
744
745 static void
run_tests_for_pipe(data_t * data,enum pipe pipe)746 run_tests_for_pipe(data_t *data, enum pipe pipe)
747 {
748 igt_output_t *output;
749
750 igt_fixture {
751 int valid_tests = 0;
752
753 igt_skip_on(pipe >= data->display.n_pipes);
754
755 for_each_valid_output_on_pipe(&data->display, pipe, output)
756 valid_tests++;
757
758 igt_require_f(valid_tests, "no valid crtc/connector combinations found\n");
759 }
760
761 igt_subtest_f("universal-plane-pipe-%s-functional",
762 kmstest_pipe_name(pipe))
763 for_each_valid_output_on_pipe(&data->display, pipe, output)
764 functional_test_pipe(data, pipe, output);
765
766 igt_subtest_f("universal-plane-pipe-%s-sanity",
767 kmstest_pipe_name(pipe))
768 for_each_valid_output_on_pipe(&data->display, pipe, output)
769 sanity_test_pipe(data, pipe, output);
770
771 igt_subtest_f("disable-primary-vs-flip-pipe-%s",
772 kmstest_pipe_name(pipe))
773 for_each_valid_output_on_pipe(&data->display, pipe, output)
774 pageflip_test_pipe(data, pipe, output);
775
776 igt_subtest_f("cursor-fb-leak-pipe-%s",
777 kmstest_pipe_name(pipe))
778 for_each_valid_output_on_pipe(&data->display, pipe, output)
779 cursor_leak_test_pipe(data, pipe, output);
780
781 igt_subtest_f("universal-plane-gen9-features-pipe-%s",
782 kmstest_pipe_name(pipe))
783 for_each_valid_output_on_pipe(&data->display, pipe, output)
784 gen9_test_pipe(data, pipe, output);
785 }
786
787 static data_t data;
788
789 igt_main
790 {
791 enum pipe pipe;
792
793 igt_skip_on_simulation();
794
795 igt_fixture {
796 data.drm_fd = drm_open_driver_master(DRIVER_INTEL);
797 data.gen = intel_gen(intel_get_drm_devid(data.drm_fd));
798
799 kmstest_set_vt_graphics_mode();
800
801 igt_require_pipe_crc(data.drm_fd);
802 igt_display_require(&data.display, data.drm_fd);
803 }
804
for_each_pipe_static(pipe)805 for_each_pipe_static(pipe) {
806 igt_subtest_group
807 run_tests_for_pipe(&data, pipe);
808 }
809
810 igt_fixture {
811 igt_display_fini(&data.display);
812 }
813 }
814