kms_universal_plane: Don't assert outside of fixtures/subtests
[platform/upstream/intel-gpu-tools.git] / tests / kms_universal_plane.c
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 <errno.h>
25 #include <stdbool.h>
26 #include <stdio.h>
27 #include <string.h>
28
29 #include "drmtest.h"
30 #include "igt_debugfs.h"
31 #include "igt_kms.h"
32
33 typedef struct {
34         int drm_fd;
35         igt_display_t display;
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 static void
59 functional_test_init(functional_test_t *test, igt_output_t *output, enum pipe pipe)
60 {
61         data_t *data = test->data;
62         drmModeModeInfo *mode;
63
64         test->pipe_crc = igt_pipe_crc_new(pipe, INTEL_PIPE_CRC_SOURCE_AUTO);
65         if (!test->pipe_crc)
66                 igt_skip("auto crc not supported on this connector with pipe %i\n",
67                        pipe);
68
69
70         igt_output_set_pipe(output, pipe);
71
72         mode = igt_output_get_mode(output);
73         igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
74                                 DRM_FORMAT_XRGB8888,
75                                 false, /* tiled */
76                                 0.0, 0.0, 0.0,
77                                 &test->black_fb);
78         igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
79                                 DRM_FORMAT_XRGB8888,
80                                 false, /* tiled */
81                                 0.0, 0.0, 1.0,
82                                 &test->blue_fb);
83         igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
84                                 DRM_FORMAT_XRGB8888,
85                                 false, /* tiled */
86                                 1.0, 1.0, 0.0,
87                                 &test->yellow_fb);
88         igt_create_color_fb(data->drm_fd, 100, 100,
89                                 DRM_FORMAT_XRGB8888,
90                                 false, /* tiled */
91                                 1.0, 0.0, 0.0,
92                                 &test->red_fb);
93
94         test->mode = mode;
95 }
96
97 static void
98 functional_test_fini(functional_test_t *test, igt_output_t *output)
99 {
100         igt_pipe_crc_free(test->pipe_crc);
101
102         igt_remove_fb(test->data->drm_fd, &test->black_fb);
103         igt_remove_fb(test->data->drm_fd, &test->blue_fb);
104         igt_remove_fb(test->data->drm_fd, &test->red_fb);
105         igt_remove_fb(test->data->drm_fd, &test->yellow_fb);
106
107         igt_output_set_pipe(output, PIPE_ANY);
108         igt_display_commit2(&test->data->display, COMMIT_LEGACY);
109 }
110
111 /*
112  * Universal plane functional testing.
113  *   - Black primary plane via traditional interfaces, red sprite, grab CRC:1.
114  *   - Blue primary plane via traditional interfaces, red sprite, grab CRC:2.
115  *   - Yellow primary via traditional interfaces
116  *   - Blue primary plane, red sprite via universal planes, grab CRC:3 and compare
117  *     with CRC:2 (should be the same)
118  *   - Disable primary plane, grab CRC:4 (should be same as CRC:1)
119  *   - Reenable primary, grab CRC:5 (should be same as CRC:2 and CRC:3)
120  *   - Yellow primary, no sprite
121  *   - Disable CRTC
122  *   - Program red sprite (while CRTC off)
123  *   - Program blue primary (while CRTC off)
124  *   - Enable CRTC, grab CRC:6 (should be same as CRC:2)
125  */
126 static void
127 functional_test_pipe(data_t *data, enum pipe pipe, igt_output_t *output)
128 {
129         functional_test_t test = { .data = data };
130         igt_display_t *display = &data->display;
131         igt_plane_t *primary, *sprite;
132         int ret;
133         int num_primary = 0, num_cursor = 0;
134         int i;
135
136         igt_assert(data->display.has_universal_planes);
137         igt_skip_on(pipe >= display->n_pipes);
138
139         fprintf(stdout, "Testing connector %s using pipe %c\n",
140                 igt_output_name(output), pipe_name(pipe));
141
142         functional_test_init(&test, output, pipe);
143
144         /*
145          * Make sure we have no more than one primary or cursor plane per crtc.
146          * If the kernel accidentally calls drm_plane_init() rather than
147          * drm_universal_plane_init(), the type enum can get interpreted as a
148          * boolean and show up in userspace as the wrong type.
149          */
150         for (i = 0; i < display->pipes[pipe].n_planes; i++)
151                 if (display->pipes[pipe].planes[i].is_primary)
152                         num_primary++;
153                 else if (display->pipes[pipe].planes[i].is_cursor)
154                         num_cursor++;
155
156         igt_assert(num_primary == 1);
157         igt_assert(num_cursor <= 1);
158
159         primary = igt_output_get_plane(output, IGT_PLANE_PRIMARY);
160         sprite = igt_output_get_plane(output, IGT_PLANE_2);
161         if (!sprite) {
162                 functional_test_fini(&test, output);
163                 igt_skip("No sprite plane available\n");
164         }
165
166         igt_plane_set_position(sprite, 100, 100);
167
168         /* Step 1: Legacy API's, black primary, red sprite (CRC 1) */
169         igt_plane_set_fb(primary, &test.black_fb);
170         igt_plane_set_fb(sprite, &test.red_fb);
171         igt_display_commit2(display, COMMIT_LEGACY);
172         igt_pipe_crc_collect_crc(test.pipe_crc, &test.crc_1);
173
174         /* Step 2: Legacy API', blue primary, red sprite (CRC 2) */
175         igt_plane_set_fb(primary, &test.blue_fb);
176         igt_plane_set_fb(sprite, &test.red_fb);
177         igt_display_commit2(display, COMMIT_LEGACY);
178         igt_pipe_crc_collect_crc(test.pipe_crc, &test.crc_2);
179
180         /* Step 3: Legacy API's, yellow primary (CRC 3) */
181         igt_plane_set_fb(primary, &test.yellow_fb);
182         igt_display_commit2(display, COMMIT_LEGACY);
183         igt_pipe_crc_collect_crc(test.pipe_crc, &test.crc_3);
184
185         /* Step 4: Universal API's, blue primary, red sprite (CRC 4) */
186         igt_plane_set_fb(primary, &test.blue_fb);
187         igt_plane_set_fb(sprite, &test.red_fb);
188         igt_display_commit2(display, COMMIT_UNIVERSAL);
189         igt_pipe_crc_collect_crc(test.pipe_crc, &test.crc_4);
190
191         /* Step 5: Universal API's, disable primary plane (CRC 5) */
192         igt_plane_set_fb(primary, NULL);
193         igt_display_commit2(display, COMMIT_UNIVERSAL);
194         igt_pipe_crc_collect_crc(test.pipe_crc, &test.crc_5);
195
196         /* Step 6: Universal API's, re-enable primary with blue (CRC 6) */
197         igt_plane_set_fb(primary, &test.blue_fb);
198         igt_display_commit2(display, COMMIT_UNIVERSAL);
199         igt_pipe_crc_collect_crc(test.pipe_crc, &test.crc_6);
200
201         /* Step 7: Legacy API's, yellow primary, no sprite */
202         igt_plane_set_fb(primary, &test.yellow_fb);
203         igt_plane_set_fb(sprite, NULL);
204         igt_display_commit2(display, COMMIT_LEGACY);
205
206         /* Step 8: Disable CRTC */
207         igt_plane_set_fb(primary, NULL);
208         igt_display_commit2(display, COMMIT_LEGACY);
209
210         /* Step 9: Universal API's with crtc off:
211          *  - red sprite
212          *  - multiple primary fb's, ending in blue
213          */
214         igt_plane_set_fb(sprite, &test.red_fb);
215         igt_display_commit2(display, COMMIT_UNIVERSAL);
216         igt_plane_set_fb(primary, &test.yellow_fb);
217         igt_display_commit2(display, COMMIT_UNIVERSAL);
218         igt_plane_set_fb(primary, &test.black_fb);
219         igt_display_commit2(display, COMMIT_UNIVERSAL);
220         igt_plane_set_fb(primary, &test.blue_fb);
221         igt_display_commit2(display, COMMIT_UNIVERSAL);
222
223         /* Step 10: Enable crtc (fb = -1), take CRC (CRC 7) */
224         ret = drmModeSetCrtc(data->drm_fd, output->config.crtc->crtc_id, -1,
225                              0, 0, &output->config.connector->connector_id,
226                              1, test.mode);
227         igt_assert(ret == 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         ret = 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));
254         igt_assert(ret == 0);
255         igt_pipe_crc_collect_crc(test.pipe_crc, &test.crc_9);
256
257         /*
258          * Step 15: Explicitly disable primary after it's already been
259          * implicitly disabled (CRC 10).
260          */
261         igt_plane_set_fb(primary, NULL);
262         igt_display_commit2(display, COMMIT_UNIVERSAL);
263         igt_pipe_crc_collect_crc(test.pipe_crc, &test.crc_10);
264
265         /* Step 16: Legacy API's, blue primary, red sprite */
266         igt_plane_set_fb(primary, &test.blue_fb);
267         igt_plane_set_fb(sprite, &test.red_fb);
268         igt_display_commit2(display, COMMIT_LEGACY);
269
270         /* Blue bg + red sprite should be same under both types of API's */
271         igt_assert(igt_crc_equal(&test.crc_2, &test.crc_4));
272
273         /* Disabling primary plane should be same as black primary */
274         igt_assert(igt_crc_equal(&test.crc_1, &test.crc_5));
275
276         /* Re-enabling primary should return to blue properly */
277         igt_assert(igt_crc_equal(&test.crc_2, &test.crc_6));
278
279         /*
280          * We should be able to setup plane FB's while CRTC is disabled and
281          * then have them pop up correctly when the CRTC is re-enabled.
282          */
283         igt_assert(igt_crc_equal(&test.crc_2, &test.crc_7));
284
285         /*
286          * We should be able to modeset with the primary plane off
287          * successfully
288          */
289         igt_assert(igt_crc_equal(&test.crc_3, &test.crc_8));
290
291         /*
292          * We should be able to move the primary plane completely offscreen
293          * and have it disable successfully.
294          */
295         igt_assert(igt_crc_equal(&test.crc_5, &test.crc_9));
296
297         /*
298          * We should be able to explicitly disable an already
299          * implicitly-disabled primary plane
300          */
301         igt_assert(igt_crc_equal(&test.crc_5, &test.crc_10));
302
303         igt_plane_set_fb(primary, NULL);
304         igt_plane_set_fb(sprite, NULL);
305
306         functional_test_fini(&test, output);
307 }
308
309 static void
310 sanity_test_init(sanity_test_t *test, igt_output_t *output, enum pipe pipe)
311 {
312         data_t *data = test->data;
313         drmModeModeInfo *mode;
314
315         igt_output_set_pipe(output, pipe);
316
317         mode = igt_output_get_mode(output);
318         igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
319                             DRM_FORMAT_XRGB8888,
320                             false, /* tiled */
321                             0.0, 0.0, 1.0,
322                             &test->blue_fb);
323         igt_create_color_fb(data->drm_fd,
324                             mode->hdisplay + 100, mode->vdisplay + 100,
325                             DRM_FORMAT_XRGB8888,
326                             false, /* tiled */
327                             0.0, 0.0, 1.0,
328                             &test->oversized_fb);
329         igt_create_color_fb(data->drm_fd,
330                             mode->hdisplay - 100, mode->vdisplay - 100,
331                             DRM_FORMAT_XRGB8888,
332                             false, /* tiled */
333                             0.0, 0.0, 1.0,
334                             &test->undersized_fb);
335
336         test->moderes = drmModeGetResources(data->drm_fd);
337 }
338
339 static void
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
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, ret = 0;
365
366         igt_output_set_pipe(output, pipe);
367         mode = igt_output_get_mode(output);
368
369         sanity_test_init(&test, output, pipe);
370
371         primary = igt_output_get_plane(output, IGT_PLANE_PRIMARY);
372
373         /* Use legacy API to set a mode with a blue FB */
374         igt_plane_set_fb(primary, &test.blue_fb);
375         igt_display_commit2(&data->display, COMMIT_LEGACY);
376
377         /*
378          * Try to use universal plane API to set primary plane that
379          * doesn't cover CRTC (should fail).
380          */
381         igt_plane_set_fb(primary, &test.undersized_fb);
382         ret = igt_display_try_commit2(&data->display, COMMIT_UNIVERSAL);
383         igt_assert(ret == -EINVAL);
384
385         /* Same as above, but different plane positioning. */
386         igt_plane_set_position(primary, 100, 100);
387         ret = igt_display_try_commit2(&data->display, COMMIT_UNIVERSAL);
388         igt_assert(ret == -EINVAL);
389
390         igt_plane_set_position(primary, 0, 0);
391
392         /* Try to use universal plane API to scale down (should fail) */
393         ret = drmModeSetPlane(data->drm_fd, primary->drm_plane->plane_id,
394                               output->config.crtc->crtc_id,
395                               test.oversized_fb.fb_id, 0,
396                               0, 0,
397                               mode->hdisplay + 100,
398                               mode->vdisplay + 100,
399                               IGT_FIXED(0,0), IGT_FIXED(0,0),
400                               IGT_FIXED(mode->hdisplay,0),
401                               IGT_FIXED(mode->vdisplay,0));
402         igt_assert(ret == -ERANGE);
403
404         /* Try to use universal plane API to scale up (should fail) */
405         ret = drmModeSetPlane(data->drm_fd, primary->drm_plane->plane_id,
406                               output->config.crtc->crtc_id,
407                               test.oversized_fb.fb_id, 0,
408                               0, 0,
409                               mode->hdisplay,
410                               mode->vdisplay,
411                               IGT_FIXED(0,0), IGT_FIXED(0,0),
412                               IGT_FIXED(mode->hdisplay - 100,0),
413                               IGT_FIXED(mode->vdisplay - 100,0));
414         igt_assert(ret == -ERANGE);
415
416         /* Find other crtcs and try to program our primary plane on them */
417         for (i = 0; i < test.moderes->count_crtcs; i++)
418                 if (test.moderes->crtcs[i] != output->config.crtc->crtc_id) {
419                         ret = drmModeSetPlane(data->drm_fd,
420                                               primary->drm_plane->plane_id,
421                                               test.moderes->crtcs[i],
422                                               test.blue_fb.fb_id, 0,
423                                               0, 0,
424                                               mode->hdisplay,
425                                               mode->vdisplay,
426                                               IGT_FIXED(0,0), IGT_FIXED(0,0),
427                                               IGT_FIXED(mode->hdisplay,0),
428                                               IGT_FIXED(mode->vdisplay,0));
429                         igt_assert(ret == -EINVAL);
430                 }
431
432         igt_plane_set_fb(primary, NULL);
433         sanity_test_fini(&test, output);
434 }
435
436 static void
437 pageflip_test_init(pageflip_test_t *test, igt_output_t *output, enum pipe pipe)
438 {
439         data_t *data = test->data;
440         drmModeModeInfo *mode;
441
442         igt_output_set_pipe(output, pipe);
443
444         mode = igt_output_get_mode(output);
445         igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
446                             DRM_FORMAT_XRGB8888,
447                             false, /* tiled */
448                             1.0, 0.0, 0.0,
449                             &test->red_fb);
450         igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
451                             DRM_FORMAT_XRGB8888,
452                             false, /* tiled */
453                             0.0, 0.0, 1.0,
454                             &test->blue_fb);
455 }
456
457 static void
458 pageflip_test_fini(pageflip_test_t *test, igt_output_t *output)
459 {
460         igt_remove_fb(test->data->drm_fd, &test->red_fb);
461         igt_remove_fb(test->data->drm_fd, &test->blue_fb);
462
463         igt_output_set_pipe(output, PIPE_ANY);
464         igt_display_commit2(&test->data->display, COMMIT_LEGACY);
465 }
466
467 static void
468 pageflip_test_pipe(data_t *data, enum pipe pipe, igt_output_t *output)
469 {
470         pageflip_test_t test = { .data = data };
471         igt_plane_t *primary;
472         struct timeval timeout = { .tv_sec = 0, .tv_usec = 500 };
473         drmEventContext evctx = { .version = DRM_EVENT_CONTEXT_VERSION };
474
475         fd_set fds;
476         int ret = 0;
477
478         igt_output_set_pipe(output, pipe);
479
480         pageflip_test_init(&test, output, pipe);
481
482         primary = igt_output_get_plane(output, IGT_PLANE_PRIMARY);
483
484         /* Use legacy API to set a mode with a blue FB */
485         igt_plane_set_fb(primary, &test.blue_fb);
486         igt_display_commit2(&data->display, COMMIT_LEGACY);
487
488         /* Disable the primary plane */
489         igt_plane_set_fb(primary, NULL);
490         igt_display_commit2(&data->display, COMMIT_UNIVERSAL);
491
492         /*
493          * Issue a pageflip to red FB
494          *
495          * Note that crtc->primary->fb = NULL causes flip to return EBUSY for
496          * historical reasons...
497          */
498         ret = drmModePageFlip(data->drm_fd, output->config.crtc->crtc_id,
499                               test.red_fb.fb_id, 0, NULL);
500         igt_assert(ret == -EBUSY);
501
502         /* Turn primary plane back on */
503         igt_plane_set_fb(primary, &test.blue_fb);
504         igt_display_commit2(&data->display, COMMIT_UNIVERSAL);
505
506         /*
507          * Issue a pageflip to red, then immediately try to disable the primary
508          * plane, hopefully before the pageflip has a chance to complete.  The
509          * plane disable operation should wind up blocking while the pageflip
510          * completes, which we don't have a good way to specifically test for,
511          * but at least we can make sure that nothing blows up.
512          */
513         ret = drmModePageFlip(data->drm_fd, output->config.crtc->crtc_id,
514                               test.red_fb.fb_id, DRM_MODE_PAGE_FLIP_EVENT,
515                               &test);
516         igt_assert(ret == 0);
517         igt_plane_set_fb(primary, NULL);
518         igt_display_commit2(&data->display, COMMIT_UNIVERSAL);
519
520         /* Wait for pageflip completion, then consume event on fd */
521         FD_ZERO(&fds);
522         FD_SET(data->drm_fd, &fds);
523         do {
524                 ret = select(data->drm_fd + 1, &fds, NULL, NULL, &timeout);
525         } while (ret < 0 && errno == EINTR);
526         igt_assert(ret == 1);
527         ret = drmHandleEvent(data->drm_fd, &evctx);
528         igt_assert(ret == 0);
529
530         igt_plane_set_fb(primary, NULL);
531         pageflip_test_fini(&test, output);
532 }
533
534 static void
535 run_tests_for_pipe(data_t *data, enum pipe pipe)
536 {
537         igt_output_t *output;
538
539         igt_subtest_f("universal-plane-pipe-%c-functional", pipe_name(pipe))
540                 for_each_connected_output(&data->display, output)
541                         functional_test_pipe(data, pipe, output);
542
543         igt_subtest_f("universal-plane-pipe-%c-sanity", pipe_name(pipe))
544                 for_each_connected_output(&data->display, output)
545                         sanity_test_pipe(data, pipe, output);
546
547         igt_subtest_f("disable-primary-vs-flip-pipe-%c", pipe_name(pipe))
548                 for_each_connected_output(&data->display, output)
549                         pageflip_test_pipe(data, pipe, output);
550 }
551
552 static data_t data;
553
554 igt_main
555 {
556
557         igt_skip_on_simulation();
558
559         igt_fixture {
560                 data.drm_fd = drm_open_any();
561
562                 igt_set_vt_graphics_mode();
563
564                 igt_require_pipe_crc();
565                 igt_display_init(&data.display, data.drm_fd);
566
567                 igt_require(data.display.has_universal_planes);
568         }
569
570         for (int pipe = 0; pipe < 3; pipe++)
571                 run_tests_for_pipe(&data, pipe);
572
573         igt_fixture {
574                 igt_display_fini(&data.display);
575         }
576 }