blob: 31f07804b887c5e7ae14c85d17ef51a78b230123 [file] [log] [blame]
Matt Roper075d9ea2014-06-30 16:44:28 -07001/*
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
Thomas Wood804e11f2015-08-17 17:57:43 +010024#include "igt.h"
Matt Roper075d9ea2014-06-30 16:44:28 -070025#include <errno.h>
26#include <stdbool.h>
27#include <stdio.h>
28#include <string.h>
Chris Wilsone08ed8a2017-03-24 20:52:44 +000029#include <fcntl.h>
Matt Roper075d9ea2014-06-30 16:44:28 -070030
Matt Roper075d9ea2014-06-30 16:44:28 -070031
32typedef struct {
33 int drm_fd;
34 igt_display_t display;
Matt Roperb81f7db2015-07-01 15:45:21 -070035 int gen;
Matt Roper075d9ea2014-06-30 16:44:28 -070036} data_t;
37
38typedef 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
47typedef struct {
48 data_t *data;
49 drmModeResPtr moderes;
50 struct igt_fb blue_fb, oversized_fb, undersized_fb;
51} sanity_test_t;
52
53typedef struct {
54 data_t *data;
55 struct igt_fb red_fb, blue_fb;
56} pageflip_test_t;
57
Matt Roper1a593d22015-10-06 17:04:49 -070058typedef 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
Matt Roper075d9ea2014-06-30 16:44:28 -070065static void
66functional_test_init(functional_test_t *test, igt_output_t *output, enum pipe pipe)
67{
68 data_t *data = test->data;
69 drmModeModeInfo *mode;
70
Chris Wilson83884e92017-03-21 17:16:03 +000071 test->pipe_crc = igt_pipe_crc_new(data->drm_fd, pipe, INTEL_PIPE_CRC_SOURCE_AUTO);
Matt Roper075d9ea2014-06-30 16:44:28 -070072
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,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +000078 LOCAL_DRM_FORMAT_MOD_NONE,
Matt Roper075d9ea2014-06-30 16:44:28 -070079 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,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +000083 LOCAL_DRM_FORMAT_MOD_NONE,
Matt Roper075d9ea2014-06-30 16:44:28 -070084 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,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +000088 LOCAL_DRM_FORMAT_MOD_NONE,
Matt Roper075d9ea2014-06-30 16:44:28 -070089 1.0, 1.0, 0.0,
90 &test->yellow_fb);
91 igt_create_color_fb(data->drm_fd, 100, 100,
92 DRM_FORMAT_XRGB8888,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +000093 LOCAL_DRM_FORMAT_MOD_NONE,
Matt Roper075d9ea2014-06-30 16:44:28 -070094 1.0, 0.0, 0.0,
95 &test->red_fb);
96
97 test->mode = mode;
98}
99
100static void
101functional_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 */
129static void
130functional_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;
Matt Roper075d9ea2014-06-30 16:44:28 -0700135 int num_primary = 0, num_cursor = 0;
136 int i;
137
138 igt_skip_on(pipe >= display->n_pipes);
139
Daniel Vetterdd8fba42014-08-12 11:00:37 +0200140 igt_info("Testing connector %s using pipe %s\n", igt_output_name(output),
141 kmstest_pipe_name(pipe));
Matt Roper075d9ea2014-06-30 16:44:28 -0700142
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++)
Robert Foss265a3a52017-01-10 20:19:46 -0500152 if (display->pipes[pipe].planes[i].type == DRM_PLANE_TYPE_PRIMARY)
Matt Roper075d9ea2014-06-30 16:44:28 -0700153 num_primary++;
Robert Foss265a3a52017-01-10 20:19:46 -0500154 else if (display->pipes[pipe].planes[i].type == DRM_PLANE_TYPE_CURSOR)
Matt Roper075d9ea2014-06-30 16:44:28 -0700155 num_cursor++;
156
Matt Roper07be8fe2015-03-05 15:01:00 -0800157 igt_assert_eq(num_primary, 1);
158 igt_assert_lte(num_cursor, 1);
Matt Roper075d9ea2014-06-30 16:44:28 -0700159
Robert Foss265a3a52017-01-10 20:19:46 -0500160 primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
161 sprite = igt_output_get_plane_type(output, DRM_PLANE_TYPE_OVERLAY);
Matt Roper075d9ea2014-06-30 16:44:28 -0700162 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) */
Daniel Vettere3f8eb52015-02-27 16:18:40 +0100225 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);
Matt Roper075d9ea2014-06-30 16:44:28 -0700228 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) */
Daniel Vettere3f8eb52015-02-27 16:18:40 +0100245 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);
Matt Roper075d9ea2014-06-30 16:44:28 -0700254 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 */
Daniel Vettere588f6d2015-02-27 20:37:29 +0100270 igt_assert_crc_equal(&test.crc_2, &test.crc_4);
Matt Roper075d9ea2014-06-30 16:44:28 -0700271
272 /* Disabling primary plane should be same as black primary */
Daniel Vettere588f6d2015-02-27 20:37:29 +0100273 igt_assert_crc_equal(&test.crc_1, &test.crc_5);
Matt Roper075d9ea2014-06-30 16:44:28 -0700274
275 /* Re-enabling primary should return to blue properly */
Daniel Vettere588f6d2015-02-27 20:37:29 +0100276 igt_assert_crc_equal(&test.crc_2, &test.crc_6);
Matt Roper075d9ea2014-06-30 16:44:28 -0700277
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 */
Daniel Vettere588f6d2015-02-27 20:37:29 +0100282 igt_assert_crc_equal(&test.crc_2, &test.crc_7);
Matt Roper075d9ea2014-06-30 16:44:28 -0700283
284 /*
285 * We should be able to modeset with the primary plane off
286 * successfully
287 */
Daniel Vettere588f6d2015-02-27 20:37:29 +0100288 igt_assert_crc_equal(&test.crc_3, &test.crc_8);
Matt Roper075d9ea2014-06-30 16:44:28 -0700289
290 /*
291 * We should be able to move the primary plane completely offscreen
292 * and have it disable successfully.
293 */
Daniel Vettere588f6d2015-02-27 20:37:29 +0100294 igt_assert_crc_equal(&test.crc_5, &test.crc_9);
Matt Roper075d9ea2014-06-30 16:44:28 -0700295
296 /*
297 * We should be able to explicitly disable an already
298 * implicitly-disabled primary plane
299 */
Daniel Vettere588f6d2015-02-27 20:37:29 +0100300 igt_assert_crc_equal(&test.crc_5, &test.crc_10);
Matt Roper075d9ea2014-06-30 16:44:28 -0700301
302 igt_plane_set_fb(primary, NULL);
303 igt_plane_set_fb(sprite, NULL);
304
305 functional_test_fini(&test, output);
306}
307
308static void
309sanity_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,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000319 LOCAL_DRM_FORMAT_MOD_NONE,
Matt Roper075d9ea2014-06-30 16:44:28 -0700320 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,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000325 LOCAL_DRM_FORMAT_MOD_NONE,
Matt Roper075d9ea2014-06-30 16:44:28 -0700326 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,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000331 LOCAL_DRM_FORMAT_MOD_NONE,
Matt Roper075d9ea2014-06-30 16:44:28 -0700332 0.0, 0.0, 1.0,
333 &test->undersized_fb);
334
335 test->moderes = drmModeGetResources(data->drm_fd);
336}
337
338static void
339sanity_test_fini(sanity_test_t *test, igt_output_t *output)
340{
341 drmModeFreeResources(test->moderes);
342
343 igt_remove_fb(test->data->drm_fd, &test->oversized_fb);
344 igt_remove_fb(test->data->drm_fd, &test->undersized_fb);
345 igt_remove_fb(test->data->drm_fd, &test->blue_fb);
346
347 igt_output_set_pipe(output, PIPE_ANY);
348 igt_display_commit2(&test->data->display, COMMIT_LEGACY);
349}
350
351/*
352 * Universal plane sanity testing.
353 * - Primary doesn't cover CRTC
354 * - Primary plane tries to scale down
355 * - Primary plane tries to scale up
356 */
357static void
358sanity_test_pipe(data_t *data, enum pipe pipe, igt_output_t *output)
359{
360 sanity_test_t test = { .data = data };
361 igt_plane_t *primary;
362 drmModeModeInfo *mode;
Daniel Vettere3f8eb52015-02-27 16:18:40 +0100363 int i;
Matt Roperb81f7db2015-07-01 15:45:21 -0700364 int expect;
Matt Roper075d9ea2014-06-30 16:44:28 -0700365
Matt Roper89201c52015-01-26 09:23:51 -0800366 igt_skip_on(pipe >= data->display.n_pipes);
367
Matt Roper075d9ea2014-06-30 16:44:28 -0700368 igt_output_set_pipe(output, pipe);
369 mode = igt_output_get_mode(output);
370
371 sanity_test_init(&test, output, pipe);
372
Robert Foss265a3a52017-01-10 20:19:46 -0500373 primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
Matt Roper075d9ea2014-06-30 16:44:28 -0700374
375 /* Use legacy API to set a mode with a blue FB */
376 igt_plane_set_fb(primary, &test.blue_fb);
377 igt_display_commit2(&data->display, COMMIT_LEGACY);
378
379 /*
380 * Try to use universal plane API to set primary plane that
Matt Roperb81f7db2015-07-01 15:45:21 -0700381 * doesn't cover CRTC (should fail on pre-gen9 and succeed on
382 * gen9+).
Matt Roper075d9ea2014-06-30 16:44:28 -0700383 */
384 igt_plane_set_fb(primary, &test.undersized_fb);
Matt Roperb81f7db2015-07-01 15:45:21 -0700385 expect = (data->gen < 9) ? -EINVAL : 0;
386 igt_assert(igt_display_try_commit2(&data->display, COMMIT_UNIVERSAL) == expect);
Matt Roper075d9ea2014-06-30 16:44:28 -0700387
388 /* Same as above, but different plane positioning. */
389 igt_plane_set_position(primary, 100, 100);
Matt Roperb81f7db2015-07-01 15:45:21 -0700390 igt_assert(igt_display_try_commit2(&data->display, COMMIT_UNIVERSAL) == expect);
Matt Roper075d9ea2014-06-30 16:44:28 -0700391
392 igt_plane_set_position(primary, 0, 0);
393
Matt Roperb81f7db2015-07-01 15:45:21 -0700394 /* Try to use universal plane API to scale down (should fail on pre-gen9) */
395 expect = (data->gen < 9) ? -ERANGE : 0;
Daniel Vettere3f8eb52015-02-27 16:18:40 +0100396 igt_assert(drmModeSetPlane(data->drm_fd, primary->drm_plane->plane_id,
397 output->config.crtc->crtc_id,
398 test.oversized_fb.fb_id, 0,
399 0, 0,
400 mode->hdisplay + 100,
401 mode->vdisplay + 100,
402 IGT_FIXED(0,0), IGT_FIXED(0,0),
403 IGT_FIXED(mode->hdisplay,0),
Matt Roperb81f7db2015-07-01 15:45:21 -0700404 IGT_FIXED(mode->vdisplay,0)) == expect);
Matt Roper075d9ea2014-06-30 16:44:28 -0700405
Matt Roperb81f7db2015-07-01 15:45:21 -0700406 /* Try to use universal plane API to scale up (should fail on pre-gen9) */
Daniel Vettere3f8eb52015-02-27 16:18:40 +0100407 igt_assert(drmModeSetPlane(data->drm_fd, primary->drm_plane->plane_id,
408 output->config.crtc->crtc_id,
409 test.oversized_fb.fb_id, 0,
410 0, 0,
411 mode->hdisplay,
412 mode->vdisplay,
413 IGT_FIXED(0,0), IGT_FIXED(0,0),
414 IGT_FIXED(mode->hdisplay - 100,0),
Matt Roperb81f7db2015-07-01 15:45:21 -0700415 IGT_FIXED(mode->vdisplay - 100,0)) == expect);
Matt Roper075d9ea2014-06-30 16:44:28 -0700416
417 /* Find other crtcs and try to program our primary plane on them */
418 for (i = 0; i < test.moderes->count_crtcs; i++)
419 if (test.moderes->crtcs[i] != output->config.crtc->crtc_id) {
Daniel Vettere3f8eb52015-02-27 16:18:40 +0100420 igt_assert(drmModeSetPlane(data->drm_fd,
421 primary->drm_plane->plane_id,
422 test.moderes->crtcs[i],
423 test.blue_fb.fb_id, 0,
424 0, 0,
425 mode->hdisplay,
426 mode->vdisplay,
427 IGT_FIXED(0,0), IGT_FIXED(0,0),
428 IGT_FIXED(mode->hdisplay,0),
429 IGT_FIXED(mode->vdisplay,0)) == -EINVAL);
Matt Roper075d9ea2014-06-30 16:44:28 -0700430 }
431
432 igt_plane_set_fb(primary, NULL);
433 sanity_test_fini(&test, output);
434}
435
436static void
437pageflip_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,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000447 LOCAL_DRM_FORMAT_MOD_NONE,
Matt Roper075d9ea2014-06-30 16:44:28 -0700448 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,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000452 LOCAL_DRM_FORMAT_MOD_NONE,
Matt Roper075d9ea2014-06-30 16:44:28 -0700453 0.0, 0.0, 1.0,
454 &test->blue_fb);
455}
456
457static void
458pageflip_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
467static void
468pageflip_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 };
Daniel Stoned7db79d2017-04-07 14:15:26 +0100473 drmEventContext evctx = { .version = 2 };
Matt Roper075d9ea2014-06-30 16:44:28 -0700474
475 fd_set fds;
476 int ret = 0;
477
Matt Roper89201c52015-01-26 09:23:51 -0800478 igt_skip_on(pipe >= data->display.n_pipes);
479
Matt Roper075d9ea2014-06-30 16:44:28 -0700480 igt_output_set_pipe(output, pipe);
481
482 pageflip_test_init(&test, output, pipe);
483
Robert Foss265a3a52017-01-10 20:19:46 -0500484 primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
Matt Roper075d9ea2014-06-30 16:44:28 -0700485
486 /* Use legacy API to set a mode with a blue FB */
487 igt_plane_set_fb(primary, &test.blue_fb);
488 igt_display_commit2(&data->display, COMMIT_LEGACY);
489
490 /* Disable the primary plane */
491 igt_plane_set_fb(primary, NULL);
492 igt_display_commit2(&data->display, COMMIT_UNIVERSAL);
493
494 /*
495 * Issue a pageflip to red FB
496 *
497 * Note that crtc->primary->fb = NULL causes flip to return EBUSY for
498 * historical reasons...
499 */
Daniel Vettere3f8eb52015-02-27 16:18:40 +0100500 igt_assert(drmModePageFlip(data->drm_fd, output->config.crtc->crtc_id,
501 test.red_fb.fb_id, 0, NULL) == -EBUSY);
Matt Roper075d9ea2014-06-30 16:44:28 -0700502
503 /* Turn primary plane back on */
504 igt_plane_set_fb(primary, &test.blue_fb);
505 igt_display_commit2(&data->display, COMMIT_UNIVERSAL);
506
507 /*
508 * Issue a pageflip to red, then immediately try to disable the primary
509 * plane, hopefully before the pageflip has a chance to complete. The
510 * plane disable operation should wind up blocking while the pageflip
511 * completes, which we don't have a good way to specifically test for,
512 * but at least we can make sure that nothing blows up.
513 */
Daniel Vettere3f8eb52015-02-27 16:18:40 +0100514 igt_assert(drmModePageFlip(data->drm_fd, output->config.crtc->crtc_id,
515 test.red_fb.fb_id, DRM_MODE_PAGE_FLIP_EVENT,
516 &test) == 0);
Matt Roper075d9ea2014-06-30 16:44:28 -0700517 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);
Matt Roper07be8fe2015-03-05 15:01:00 -0800526 igt_assert_eq(ret, 1);
Daniel Vettere3f8eb52015-02-27 16:18:40 +0100527 igt_assert(drmHandleEvent(data->drm_fd, &evctx) == 0);
Matt Roper075d9ea2014-06-30 16:44:28 -0700528
529 igt_plane_set_fb(primary, NULL);
530 pageflip_test_fini(&test, output);
531}
532
533static void
Matt Roper59d8d662015-02-26 19:00:19 -0800534cursor_leak_test_fini(data_t *data,
535 igt_output_t *output,
536 struct igt_fb *bg,
537 struct igt_fb *curs)
538{
539 int i;
540
541 igt_remove_fb(data->drm_fd, bg);
542 for (i = 0; i < 10; i++)
543 igt_remove_fb(data->drm_fd, &curs[i]);
544
545 igt_output_set_pipe(output, PIPE_ANY);
546}
547
548static int
Chris Wilson83884e92017-03-21 17:16:03 +0000549i915_gem_fb_count(data_t *data)
Matt Roper59d8d662015-02-26 19:00:19 -0800550{
551 char buf[1024];
552 FILE *fp;
Chris Wilsone08ed8a2017-03-24 20:52:44 +0000553 int fd;
Matt Roper59d8d662015-02-26 19:00:19 -0800554 int count = 0;
555
Chris Wilsone08ed8a2017-03-24 20:52:44 +0000556 fd = igt_debugfs_open(data->drm_fd, "i915_gem_framebuffer", O_RDONLY);
557 fp = fdopen(fd, "r");
Matt Roper59d8d662015-02-26 19:00:19 -0800558 igt_require(fp);
559 while (fgets(buf, sizeof(buf), fp) != NULL)
560 count++;
561 fclose(fp);
Chris Wilsone08ed8a2017-03-24 20:52:44 +0000562 close(fd);
Matt Roper59d8d662015-02-26 19:00:19 -0800563
564 return count;
565}
566
567static void
568cursor_leak_test_pipe(data_t *data, enum pipe pipe, igt_output_t *output)
569{
570 igt_display_t *display = &data->display;
571 igt_plane_t *primary, *cursor;
572 drmModeModeInfo *mode;
573 struct igt_fb background_fb;
574 struct igt_fb cursor_fb[10];
575 int i;
576 int r, g, b;
577 int count1, count2;
578
Matt Roper59d8d662015-02-26 19:00:19 -0800579 igt_skip_on(pipe >= display->n_pipes);
Lyude80baeb02016-12-07 19:02:04 -0500580 igt_require(display->has_cursor_plane);
Matt Roper59d8d662015-02-26 19:00:19 -0800581
582 igt_output_set_pipe(output, pipe);
583 mode = igt_output_get_mode(output);
584
585 /* Count GEM framebuffers before creating our cursor FB's */
Chris Wilson83884e92017-03-21 17:16:03 +0000586 count1 = i915_gem_fb_count(data);
Matt Roper59d8d662015-02-26 19:00:19 -0800587
588 /* Black background FB */
589 igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
590 DRM_FORMAT_XRGB8888,
591 false,
592 0.0, 0.0, 0.0,
593 &background_fb);
594
595 /* Random color cursors */
596 for (i = 0; i < 10; i++) {
597 r = rand() % 0xFF;
598 g = rand() % 0xFF;
599 b = rand() % 0xFF;
600 igt_create_color_fb(data->drm_fd, 64, 64,
601 DRM_FORMAT_ARGB8888,
602 false,
603 (double)r / 0xFF,
604 (double)g / 0xFF,
605 (double)b / 0xFF,
606 &cursor_fb[i]);
607 }
608
Robert Foss265a3a52017-01-10 20:19:46 -0500609 primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
610 cursor = igt_output_get_plane_type(output, DRM_PLANE_TYPE_CURSOR);
Matt Roper59d8d662015-02-26 19:00:19 -0800611 if (!primary || !cursor) {
612 cursor_leak_test_fini(data, output, &background_fb, cursor_fb);
613 igt_skip("Primary and/or cursor are unavailable\n");
614 }
615
616
617 igt_plane_set_fb(primary, &background_fb);
618 igt_display_commit2(display, COMMIT_LEGACY);
619
620 igt_plane_set_position(cursor, 100, 100);
621
622 /*
623 * Exercise both legacy and universal code paths. Note that legacy
624 * handling in the kernel redirects through universal codepaths
625 * internally, so that redirection is where we're most worried about
626 * leaking.
627 */
628 for (i = 0; i < 10; i++) {
629 igt_plane_set_fb(cursor, &cursor_fb[i]);
630 igt_display_commit2(display, COMMIT_UNIVERSAL);
631 }
632 for (i = 0; i < 10; i++) {
633 igt_plane_set_fb(cursor, &cursor_fb[i]);
634 igt_display_commit2(display, COMMIT_LEGACY);
635 }
636
637 /* Release our framebuffer handles before we take a second count */
638 igt_plane_set_fb(primary, NULL);
639 igt_plane_set_fb(cursor, NULL);
640 igt_display_commit2(display, COMMIT_LEGACY);
641 cursor_leak_test_fini(data, output, &background_fb, cursor_fb);
642
643 /* We should be back to the same framebuffer count as when we started */
Chris Wilson83884e92017-03-21 17:16:03 +0000644 count2 = i915_gem_fb_count(data);
Matt Roper59d8d662015-02-26 19:00:19 -0800645
Daniel Vettere3f8eb52015-02-27 16:18:40 +0100646 igt_assert_eq(count1, count2);
Matt Roper59d8d662015-02-26 19:00:19 -0800647}
648
649static void
Matt Roper1a593d22015-10-06 17:04:49 -0700650gen9_test_init(gen9_test_t *test, igt_output_t *output, enum pipe pipe)
651{
652 data_t *data = test->data;
653 drmModeModeInfo *mode;
654
655 igt_output_set_pipe(output, pipe);
656
657 mode = igt_output_get_mode(output);
658 test->w = mode->hdisplay / 2;
659 test->h = mode->vdisplay / 2;
660 test->x = mode->hdisplay / 4;
661 test->y = mode->vdisplay / 4;
662
663 /* Initial framebuffer of full CRTC size */
664 igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
665 DRM_FORMAT_XRGB8888,
666 LOCAL_DRM_FORMAT_MOD_NONE,
667 0.0, 1.0, 0.0,
668 &test->biggreen_fb);
669
670 /* Framebuffers that only cover a quarter of the CRTC size */
671 igt_create_color_fb(data->drm_fd, test->w, test->h,
672 DRM_FORMAT_XRGB8888,
673 LOCAL_DRM_FORMAT_MOD_NONE,
674 1.0, 0.0, 0.0,
675 &test->smallred_fb);
676 igt_create_color_fb(data->drm_fd, test->w, test->h,
677 DRM_FORMAT_XRGB8888,
678 LOCAL_DRM_FORMAT_MOD_NONE,
679 0.0, 0.0, 1.0,
680 &test->smallblue_fb);
681}
682
683static void
684gen9_test_fini(gen9_test_t *test, igt_output_t *output)
685{
686 igt_remove_fb(test->data->drm_fd, &test->biggreen_fb);
687 igt_remove_fb(test->data->drm_fd, &test->smallred_fb);
688 igt_remove_fb(test->data->drm_fd, &test->smallblue_fb);
689
690 igt_output_set_pipe(output, PIPE_ANY);
691 igt_display_commit2(&test->data->display, COMMIT_LEGACY);
692}
693
694/*
695 * Test features specific to gen9+ platforms (i.e., primary plane
696 * windowing)
697 */
698static void
699gen9_test_pipe(data_t *data, enum pipe pipe, igt_output_t *output)
700{
701 gen9_test_t test = { .data = data };
702 igt_plane_t *primary;
703
704 int ret = 0;
705
706 igt_skip_on(data->gen < 9);
707 igt_skip_on(pipe >= data->display.n_pipes);
708
709 igt_output_set_pipe(output, pipe);
710
711 gen9_test_init(&test, output, pipe);
712
Robert Foss265a3a52017-01-10 20:19:46 -0500713 primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
Matt Roper1a593d22015-10-06 17:04:49 -0700714
715 /* Start with a full-screen primary plane */
716 igt_plane_set_fb(primary, &test.biggreen_fb);
717 igt_display_commit2(&data->display, COMMIT_LEGACY);
718
719 /* Set primary to windowed size/position */
720 igt_plane_set_fb(primary, &test.smallblue_fb);
721 igt_plane_set_position(primary, test.x, test.y);
722 igt_plane_set_size(primary, test.w, test.h);
723 igt_display_commit2(&data->display, COMMIT_UNIVERSAL);
724
725 /*
726 * SetPlane update to another framebuffer of the same size
727 * should succeed
728 */
729 igt_plane_set_fb(primary, &test.smallred_fb);
730 igt_plane_set_position(primary, test.x, test.y);
731 igt_plane_set_size(primary, test.w, test.h);
732 igt_display_commit2(&data->display, COMMIT_UNIVERSAL);
733
734 /* PageFlip should also succeed */
735 ret = drmModePageFlip(data->drm_fd, output->config.crtc->crtc_id,
736 test.smallblue_fb.fb_id, 0, NULL);
737 igt_assert_eq(ret, 0);
738
739 igt_plane_set_fb(primary, NULL);
740 igt_plane_set_position(primary, 0, 0);
741 gen9_test_fini(&test, output);
742}
743
744static void
Matt Roper075d9ea2014-06-30 16:44:28 -0700745run_tests_for_pipe(data_t *data, enum pipe pipe)
746{
747 igt_output_t *output;
748
Maarten Lankhorstef8cff62017-01-12 16:08:30 +0100749 igt_fixture {
750 int valid_tests = 0;
751
752 igt_skip_on(pipe >= data->display.n_pipes);
753
754 for_each_valid_output_on_pipe(&data->display, pipe, output)
755 valid_tests++;
756
757 igt_require_f(valid_tests, "no valid crtc/connector combinations found\n");
758 }
759
Daniel Vetterdd8fba42014-08-12 11:00:37 +0200760 igt_subtest_f("universal-plane-pipe-%s-functional",
761 kmstest_pipe_name(pipe))
Maarten Lankhorstef8cff62017-01-12 16:08:30 +0100762 for_each_valid_output_on_pipe(&data->display, pipe, output)
Matt Roper075d9ea2014-06-30 16:44:28 -0700763 functional_test_pipe(data, pipe, output);
764
Daniel Vetterdd8fba42014-08-12 11:00:37 +0200765 igt_subtest_f("universal-plane-pipe-%s-sanity",
766 kmstest_pipe_name(pipe))
Maarten Lankhorstef8cff62017-01-12 16:08:30 +0100767 for_each_valid_output_on_pipe(&data->display, pipe, output)
Matt Roper075d9ea2014-06-30 16:44:28 -0700768 sanity_test_pipe(data, pipe, output);
769
Daniel Vetterdd8fba42014-08-12 11:00:37 +0200770 igt_subtest_f("disable-primary-vs-flip-pipe-%s",
771 kmstest_pipe_name(pipe))
Maarten Lankhorstef8cff62017-01-12 16:08:30 +0100772 for_each_valid_output_on_pipe(&data->display, pipe, output)
Matt Roper075d9ea2014-06-30 16:44:28 -0700773 pageflip_test_pipe(data, pipe, output);
Matt Roper59d8d662015-02-26 19:00:19 -0800774
775 igt_subtest_f("cursor-fb-leak-pipe-%s",
776 kmstest_pipe_name(pipe))
Maarten Lankhorstef8cff62017-01-12 16:08:30 +0100777 for_each_valid_output_on_pipe(&data->display, pipe, output)
Matt Roper59d8d662015-02-26 19:00:19 -0800778 cursor_leak_test_pipe(data, pipe, output);
Matt Roper1a593d22015-10-06 17:04:49 -0700779
780 igt_subtest_f("universal-plane-gen9-features-pipe-%s",
781 kmstest_pipe_name(pipe))
Maarten Lankhorstef8cff62017-01-12 16:08:30 +0100782 for_each_valid_output_on_pipe(&data->display, pipe, output)
Matt Roper1a593d22015-10-06 17:04:49 -0700783 gen9_test_pipe(data, pipe, output);
Matt Roper075d9ea2014-06-30 16:44:28 -0700784}
785
786static data_t data;
787
788igt_main
789{
Matt Roper075d9ea2014-06-30 16:44:28 -0700790 igt_skip_on_simulation();
791
792 igt_fixture {
Micah Fedkec81d2932015-07-22 21:54:02 +0000793 data.drm_fd = drm_open_driver_master(DRIVER_INTEL);
Matt Roperb81f7db2015-07-01 15:45:21 -0700794 data.gen = intel_gen(intel_get_drm_devid(data.drm_fd));
Matt Roper075d9ea2014-06-30 16:44:28 -0700795
Daniel Vetter33f08842014-08-12 11:23:09 +0200796 kmstest_set_vt_graphics_mode();
Matt Roper075d9ea2014-06-30 16:44:28 -0700797
Chris Wilson83884e92017-03-21 17:16:03 +0000798 igt_require_pipe_crc(data.drm_fd);
Matt Roper075d9ea2014-06-30 16:44:28 -0700799 igt_display_init(&data.display, data.drm_fd);
Matt Roper075d9ea2014-06-30 16:44:28 -0700800 }
801
Leo (Sunpeng) Lidf682172017-06-09 17:13:04 -0400802 for (int pipe = 0; pipe < IGT_MAX_PIPES; pipe++) {
Maarten Lankhorstef8cff62017-01-12 16:08:30 +0100803 igt_subtest_group
804 run_tests_for_pipe(&data, pipe);
805 }
Matt Roper075d9ea2014-06-30 16:44:28 -0700806
807 igt_fixture {
808 igt_display_fini(&data.display);
809 }
810}