blob: a2fe1cc1be38f7ee4fa659345275f8bba33d1917 [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>
29
Matt Roper075d9ea2014-06-30 16:44:28 -070030
31typedef struct {
32 int drm_fd;
33 igt_display_t display;
Matt Roperb81f7db2015-07-01 15:45:21 -070034 int gen;
Matt Roper075d9ea2014-06-30 16:44:28 -070035} data_t;
36
37typedef struct {
38 data_t *data;
39 igt_pipe_crc_t *pipe_crc;
40 igt_crc_t crc_1, crc_2, crc_3, crc_4, crc_5, crc_6, crc_7, crc_8,
41 crc_9, crc_10;
42 struct igt_fb red_fb, blue_fb, black_fb, yellow_fb;
43 drmModeModeInfo *mode;
44} functional_test_t;
45
46typedef struct {
47 data_t *data;
48 drmModeResPtr moderes;
49 struct igt_fb blue_fb, oversized_fb, undersized_fb;
50} sanity_test_t;
51
52typedef struct {
53 data_t *data;
54 struct igt_fb red_fb, blue_fb;
55} pageflip_test_t;
56
Matt Roper1a593d22015-10-06 17:04:49 -070057typedef struct {
58 data_t *data;
59 int x, y;
60 int w, h;
61 struct igt_fb biggreen_fb, smallred_fb, smallblue_fb;
62} gen9_test_t;
63
Matt Roper075d9ea2014-06-30 16:44:28 -070064static void
65functional_test_init(functional_test_t *test, igt_output_t *output, enum pipe pipe)
66{
67 data_t *data = test->data;
68 drmModeModeInfo *mode;
69
70 test->pipe_crc = igt_pipe_crc_new(pipe, INTEL_PIPE_CRC_SOURCE_AUTO);
Matt Roper075d9ea2014-06-30 16:44:28 -070071
72 igt_output_set_pipe(output, pipe);
73
74 mode = igt_output_get_mode(output);
75 igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
76 DRM_FORMAT_XRGB8888,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +000077 LOCAL_DRM_FORMAT_MOD_NONE,
Matt Roper075d9ea2014-06-30 16:44:28 -070078 0.0, 0.0, 0.0,
79 &test->black_fb);
80 igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
81 DRM_FORMAT_XRGB8888,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +000082 LOCAL_DRM_FORMAT_MOD_NONE,
Matt Roper075d9ea2014-06-30 16:44:28 -070083 0.0, 0.0, 1.0,
84 &test->blue_fb);
85 igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
86 DRM_FORMAT_XRGB8888,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +000087 LOCAL_DRM_FORMAT_MOD_NONE,
Matt Roper075d9ea2014-06-30 16:44:28 -070088 1.0, 1.0, 0.0,
89 &test->yellow_fb);
90 igt_create_color_fb(data->drm_fd, 100, 100,
91 DRM_FORMAT_XRGB8888,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +000092 LOCAL_DRM_FORMAT_MOD_NONE,
Matt Roper075d9ea2014-06-30 16:44:28 -070093 1.0, 0.0, 0.0,
94 &test->red_fb);
95
96 test->mode = mode;
97}
98
99static void
100functional_test_fini(functional_test_t *test, igt_output_t *output)
101{
102 igt_pipe_crc_free(test->pipe_crc);
103
104 igt_remove_fb(test->data->drm_fd, &test->black_fb);
105 igt_remove_fb(test->data->drm_fd, &test->blue_fb);
106 igt_remove_fb(test->data->drm_fd, &test->red_fb);
107 igt_remove_fb(test->data->drm_fd, &test->yellow_fb);
108
109 igt_output_set_pipe(output, PIPE_ANY);
110 igt_display_commit2(&test->data->display, COMMIT_LEGACY);
111}
112
113/*
114 * Universal plane functional testing.
115 * - Black primary plane via traditional interfaces, red sprite, grab CRC:1.
116 * - Blue primary plane via traditional interfaces, red sprite, grab CRC:2.
117 * - Yellow primary via traditional interfaces
118 * - Blue primary plane, red sprite via universal planes, grab CRC:3 and compare
119 * with CRC:2 (should be the same)
120 * - Disable primary plane, grab CRC:4 (should be same as CRC:1)
121 * - Reenable primary, grab CRC:5 (should be same as CRC:2 and CRC:3)
122 * - Yellow primary, no sprite
123 * - Disable CRTC
124 * - Program red sprite (while CRTC off)
125 * - Program blue primary (while CRTC off)
126 * - Enable CRTC, grab CRC:6 (should be same as CRC:2)
127 */
128static void
129functional_test_pipe(data_t *data, enum pipe pipe, igt_output_t *output)
130{
131 functional_test_t test = { .data = data };
132 igt_display_t *display = &data->display;
133 igt_plane_t *primary, *sprite;
Matt Roper075d9ea2014-06-30 16:44:28 -0700134 int num_primary = 0, num_cursor = 0;
135 int i;
136
137 igt_skip_on(pipe >= display->n_pipes);
138
Daniel Vetterdd8fba42014-08-12 11:00:37 +0200139 igt_info("Testing connector %s using pipe %s\n", igt_output_name(output),
140 kmstest_pipe_name(pipe));
Matt Roper075d9ea2014-06-30 16:44:28 -0700141
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++)
Robert Foss265a3a52017-01-10 20:19:46 -0500151 if (display->pipes[pipe].planes[i].type == DRM_PLANE_TYPE_PRIMARY)
Matt Roper075d9ea2014-06-30 16:44:28 -0700152 num_primary++;
Robert Foss265a3a52017-01-10 20:19:46 -0500153 else if (display->pipes[pipe].planes[i].type == DRM_PLANE_TYPE_CURSOR)
Matt Roper075d9ea2014-06-30 16:44:28 -0700154 num_cursor++;
155
Matt Roper07be8fe2015-03-05 15:01:00 -0800156 igt_assert_eq(num_primary, 1);
157 igt_assert_lte(num_cursor, 1);
Matt Roper075d9ea2014-06-30 16:44:28 -0700158
Robert Foss265a3a52017-01-10 20:19:46 -0500159 primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
160 sprite = igt_output_get_plane_type(output, DRM_PLANE_TYPE_OVERLAY);
Matt Roper075d9ea2014-06-30 16:44:28 -0700161 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) */
Daniel Vettere3f8eb52015-02-27 16:18:40 +0100224 igt_assert(drmModeSetCrtc(data->drm_fd, output->config.crtc->crtc_id, -1,
225 0, 0, &output->config.connector->connector_id,
226 1, test.mode) == 0);
Matt Roper075d9ea2014-06-30 16:44:28 -0700227 igt_pipe_crc_collect_crc(test.pipe_crc, &test.crc_7);
228
229 /* Step 11: Disable primary plane */
230 igt_plane_set_fb(primary, NULL);
231 igt_display_commit2(display, COMMIT_UNIVERSAL);
232
233 /* Step 12: Legacy modeset to yellow FB (CRC 8) */
234 igt_plane_set_fb(primary, &test.yellow_fb);
235 igt_display_commit2(display, COMMIT_LEGACY);
236 igt_pipe_crc_collect_crc(test.pipe_crc, &test.crc_8);
237
238 /* Step 13: Legacy API', blue primary, red sprite */
239 igt_plane_set_fb(primary, &test.blue_fb);
240 igt_plane_set_fb(sprite, &test.red_fb);
241 igt_display_commit2(display, COMMIT_LEGACY);
242
243 /* Step 14: Universal API, set primary completely offscreen (CRC 9) */
Daniel Vettere3f8eb52015-02-27 16:18:40 +0100244 igt_assert(drmModeSetPlane(data->drm_fd, primary->drm_plane->plane_id,
245 output->config.crtc->crtc_id,
246 test.blue_fb.fb_id, 0,
247 9000, 9000,
248 test.mode->hdisplay,
249 test.mode->vdisplay,
250 IGT_FIXED(0,0), IGT_FIXED(0,0),
251 IGT_FIXED(test.mode->hdisplay,0),
252 IGT_FIXED(test.mode->vdisplay,0)) == 0);
Matt Roper075d9ea2014-06-30 16:44:28 -0700253 igt_pipe_crc_collect_crc(test.pipe_crc, &test.crc_9);
254
255 /*
256 * Step 15: Explicitly disable primary after it's already been
257 * implicitly disabled (CRC 10).
258 */
259 igt_plane_set_fb(primary, NULL);
260 igt_display_commit2(display, COMMIT_UNIVERSAL);
261 igt_pipe_crc_collect_crc(test.pipe_crc, &test.crc_10);
262
263 /* Step 16: Legacy API's, blue primary, red sprite */
264 igt_plane_set_fb(primary, &test.blue_fb);
265 igt_plane_set_fb(sprite, &test.red_fb);
266 igt_display_commit2(display, COMMIT_LEGACY);
267
268 /* Blue bg + red sprite should be same under both types of API's */
Daniel Vettere588f6d2015-02-27 20:37:29 +0100269 igt_assert_crc_equal(&test.crc_2, &test.crc_4);
Matt Roper075d9ea2014-06-30 16:44:28 -0700270
271 /* Disabling primary plane should be same as black primary */
Daniel Vettere588f6d2015-02-27 20:37:29 +0100272 igt_assert_crc_equal(&test.crc_1, &test.crc_5);
Matt Roper075d9ea2014-06-30 16:44:28 -0700273
274 /* Re-enabling primary should return to blue properly */
Daniel Vettere588f6d2015-02-27 20:37:29 +0100275 igt_assert_crc_equal(&test.crc_2, &test.crc_6);
Matt Roper075d9ea2014-06-30 16:44:28 -0700276
277 /*
278 * We should be able to setup plane FB's while CRTC is disabled and
279 * then have them pop up correctly when the CRTC is re-enabled.
280 */
Daniel Vettere588f6d2015-02-27 20:37:29 +0100281 igt_assert_crc_equal(&test.crc_2, &test.crc_7);
Matt Roper075d9ea2014-06-30 16:44:28 -0700282
283 /*
284 * We should be able to modeset with the primary plane off
285 * successfully
286 */
Daniel Vettere588f6d2015-02-27 20:37:29 +0100287 igt_assert_crc_equal(&test.crc_3, &test.crc_8);
Matt Roper075d9ea2014-06-30 16:44:28 -0700288
289 /*
290 * We should be able to move the primary plane completely offscreen
291 * and have it disable successfully.
292 */
Daniel Vettere588f6d2015-02-27 20:37:29 +0100293 igt_assert_crc_equal(&test.crc_5, &test.crc_9);
Matt Roper075d9ea2014-06-30 16:44:28 -0700294
295 /*
296 * We should be able to explicitly disable an already
297 * implicitly-disabled primary plane
298 */
Daniel Vettere588f6d2015-02-27 20:37:29 +0100299 igt_assert_crc_equal(&test.crc_5, &test.crc_10);
Matt Roper075d9ea2014-06-30 16:44:28 -0700300
301 igt_plane_set_fb(primary, NULL);
302 igt_plane_set_fb(sprite, NULL);
303
304 functional_test_fini(&test, output);
305}
306
307static void
308sanity_test_init(sanity_test_t *test, igt_output_t *output, enum pipe pipe)
309{
310 data_t *data = test->data;
311 drmModeModeInfo *mode;
312
313 igt_output_set_pipe(output, pipe);
314
315 mode = igt_output_get_mode(output);
316 igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
317 DRM_FORMAT_XRGB8888,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000318 LOCAL_DRM_FORMAT_MOD_NONE,
Matt Roper075d9ea2014-06-30 16:44:28 -0700319 0.0, 0.0, 1.0,
320 &test->blue_fb);
321 igt_create_color_fb(data->drm_fd,
322 mode->hdisplay + 100, mode->vdisplay + 100,
323 DRM_FORMAT_XRGB8888,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000324 LOCAL_DRM_FORMAT_MOD_NONE,
Matt Roper075d9ea2014-06-30 16:44:28 -0700325 0.0, 0.0, 1.0,
326 &test->oversized_fb);
327 igt_create_color_fb(data->drm_fd,
328 mode->hdisplay - 100, mode->vdisplay - 100,
329 DRM_FORMAT_XRGB8888,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000330 LOCAL_DRM_FORMAT_MOD_NONE,
Matt Roper075d9ea2014-06-30 16:44:28 -0700331 0.0, 0.0, 1.0,
332 &test->undersized_fb);
333
334 test->moderes = drmModeGetResources(data->drm_fd);
335}
336
337static void
338sanity_test_fini(sanity_test_t *test, igt_output_t *output)
339{
340 drmModeFreeResources(test->moderes);
341
342 igt_remove_fb(test->data->drm_fd, &test->oversized_fb);
343 igt_remove_fb(test->data->drm_fd, &test->undersized_fb);
344 igt_remove_fb(test->data->drm_fd, &test->blue_fb);
345
346 igt_output_set_pipe(output, PIPE_ANY);
347 igt_display_commit2(&test->data->display, COMMIT_LEGACY);
348}
349
350/*
351 * Universal plane sanity testing.
352 * - Primary doesn't cover CRTC
353 * - Primary plane tries to scale down
354 * - Primary plane tries to scale up
355 */
356static void
357sanity_test_pipe(data_t *data, enum pipe pipe, igt_output_t *output)
358{
359 sanity_test_t test = { .data = data };
360 igt_plane_t *primary;
361 drmModeModeInfo *mode;
Daniel Vettere3f8eb52015-02-27 16:18:40 +0100362 int i;
Matt Roperb81f7db2015-07-01 15:45:21 -0700363 int expect;
Matt Roper075d9ea2014-06-30 16:44:28 -0700364
Matt Roper89201c52015-01-26 09:23:51 -0800365 igt_skip_on(pipe >= data->display.n_pipes);
366
Matt Roper075d9ea2014-06-30 16:44:28 -0700367 igt_output_set_pipe(output, pipe);
368 mode = igt_output_get_mode(output);
369
370 sanity_test_init(&test, output, pipe);
371
Robert Foss265a3a52017-01-10 20:19:46 -0500372 primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
Matt Roper075d9ea2014-06-30 16:44:28 -0700373
374 /* Use legacy API to set a mode with a blue FB */
375 igt_plane_set_fb(primary, &test.blue_fb);
376 igt_display_commit2(&data->display, COMMIT_LEGACY);
377
378 /*
379 * Try to use universal plane API to set primary plane that
Matt Roperb81f7db2015-07-01 15:45:21 -0700380 * doesn't cover CRTC (should fail on pre-gen9 and succeed on
381 * gen9+).
Matt Roper075d9ea2014-06-30 16:44:28 -0700382 */
383 igt_plane_set_fb(primary, &test.undersized_fb);
Matt Roperb81f7db2015-07-01 15:45:21 -0700384 expect = (data->gen < 9) ? -EINVAL : 0;
385 igt_assert(igt_display_try_commit2(&data->display, COMMIT_UNIVERSAL) == expect);
Matt Roper075d9ea2014-06-30 16:44:28 -0700386
387 /* Same as above, but different plane positioning. */
388 igt_plane_set_position(primary, 100, 100);
Matt Roperb81f7db2015-07-01 15:45:21 -0700389 igt_assert(igt_display_try_commit2(&data->display, COMMIT_UNIVERSAL) == expect);
Matt Roper075d9ea2014-06-30 16:44:28 -0700390
391 igt_plane_set_position(primary, 0, 0);
392
Matt Roperb81f7db2015-07-01 15:45:21 -0700393 /* Try to use universal plane API to scale down (should fail on pre-gen9) */
394 expect = (data->gen < 9) ? -ERANGE : 0;
Daniel Vettere3f8eb52015-02-27 16:18:40 +0100395 igt_assert(drmModeSetPlane(data->drm_fd, primary->drm_plane->plane_id,
396 output->config.crtc->crtc_id,
397 test.oversized_fb.fb_id, 0,
398 0, 0,
399 mode->hdisplay + 100,
400 mode->vdisplay + 100,
401 IGT_FIXED(0,0), IGT_FIXED(0,0),
402 IGT_FIXED(mode->hdisplay,0),
Matt Roperb81f7db2015-07-01 15:45:21 -0700403 IGT_FIXED(mode->vdisplay,0)) == expect);
Matt Roper075d9ea2014-06-30 16:44:28 -0700404
Matt Roperb81f7db2015-07-01 15:45:21 -0700405 /* Try to use universal plane API to scale up (should fail on pre-gen9) */
Daniel Vettere3f8eb52015-02-27 16:18:40 +0100406 igt_assert(drmModeSetPlane(data->drm_fd, primary->drm_plane->plane_id,
407 output->config.crtc->crtc_id,
408 test.oversized_fb.fb_id, 0,
409 0, 0,
410 mode->hdisplay,
411 mode->vdisplay,
412 IGT_FIXED(0,0), IGT_FIXED(0,0),
413 IGT_FIXED(mode->hdisplay - 100,0),
Matt Roperb81f7db2015-07-01 15:45:21 -0700414 IGT_FIXED(mode->vdisplay - 100,0)) == expect);
Matt Roper075d9ea2014-06-30 16:44:28 -0700415
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) {
Daniel Vettere3f8eb52015-02-27 16:18:40 +0100419 igt_assert(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)) == -EINVAL);
Matt Roper075d9ea2014-06-30 16:44:28 -0700429 }
430
431 igt_plane_set_fb(primary, NULL);
432 sanity_test_fini(&test, output);
433}
434
435static void
436pageflip_test_init(pageflip_test_t *test, igt_output_t *output, enum pipe pipe)
437{
438 data_t *data = test->data;
439 drmModeModeInfo *mode;
440
441 igt_output_set_pipe(output, pipe);
442
443 mode = igt_output_get_mode(output);
444 igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
445 DRM_FORMAT_XRGB8888,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000446 LOCAL_DRM_FORMAT_MOD_NONE,
Matt Roper075d9ea2014-06-30 16:44:28 -0700447 1.0, 0.0, 0.0,
448 &test->red_fb);
449 igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
450 DRM_FORMAT_XRGB8888,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000451 LOCAL_DRM_FORMAT_MOD_NONE,
Matt Roper075d9ea2014-06-30 16:44:28 -0700452 0.0, 0.0, 1.0,
453 &test->blue_fb);
454}
455
456static void
457pageflip_test_fini(pageflip_test_t *test, igt_output_t *output)
458{
459 igt_remove_fb(test->data->drm_fd, &test->red_fb);
460 igt_remove_fb(test->data->drm_fd, &test->blue_fb);
461
462 igt_output_set_pipe(output, PIPE_ANY);
463 igt_display_commit2(&test->data->display, COMMIT_LEGACY);
464}
465
466static void
467pageflip_test_pipe(data_t *data, enum pipe pipe, igt_output_t *output)
468{
469 pageflip_test_t test = { .data = data };
470 igt_plane_t *primary;
471 struct timeval timeout = { .tv_sec = 0, .tv_usec = 500 };
472 drmEventContext evctx = { .version = DRM_EVENT_CONTEXT_VERSION };
473
474 fd_set fds;
475 int ret = 0;
476
Matt Roper89201c52015-01-26 09:23:51 -0800477 igt_skip_on(pipe >= data->display.n_pipes);
478
Matt Roper075d9ea2014-06-30 16:44:28 -0700479 igt_output_set_pipe(output, pipe);
480
481 pageflip_test_init(&test, output, pipe);
482
Robert Foss265a3a52017-01-10 20:19:46 -0500483 primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
Matt Roper075d9ea2014-06-30 16:44:28 -0700484
485 /* Use legacy API to set a mode with a blue FB */
486 igt_plane_set_fb(primary, &test.blue_fb);
487 igt_display_commit2(&data->display, COMMIT_LEGACY);
488
489 /* Disable the primary plane */
490 igt_plane_set_fb(primary, NULL);
491 igt_display_commit2(&data->display, COMMIT_UNIVERSAL);
492
493 /*
494 * Issue a pageflip to red FB
495 *
496 * Note that crtc->primary->fb = NULL causes flip to return EBUSY for
497 * historical reasons...
498 */
Daniel Vettere3f8eb52015-02-27 16:18:40 +0100499 igt_assert(drmModePageFlip(data->drm_fd, output->config.crtc->crtc_id,
500 test.red_fb.fb_id, 0, NULL) == -EBUSY);
Matt Roper075d9ea2014-06-30 16:44:28 -0700501
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 */
Daniel Vettere3f8eb52015-02-27 16:18:40 +0100513 igt_assert(drmModePageFlip(data->drm_fd, output->config.crtc->crtc_id,
514 test.red_fb.fb_id, DRM_MODE_PAGE_FLIP_EVENT,
515 &test) == 0);
Matt Roper075d9ea2014-06-30 16:44:28 -0700516 igt_plane_set_fb(primary, NULL);
517 igt_display_commit2(&data->display, COMMIT_UNIVERSAL);
518
519 /* Wait for pageflip completion, then consume event on fd */
520 FD_ZERO(&fds);
521 FD_SET(data->drm_fd, &fds);
522 do {
523 ret = select(data->drm_fd + 1, &fds, NULL, NULL, &timeout);
524 } while (ret < 0 && errno == EINTR);
Matt Roper07be8fe2015-03-05 15:01:00 -0800525 igt_assert_eq(ret, 1);
Daniel Vettere3f8eb52015-02-27 16:18:40 +0100526 igt_assert(drmHandleEvent(data->drm_fd, &evctx) == 0);
Matt Roper075d9ea2014-06-30 16:44:28 -0700527
528 igt_plane_set_fb(primary, NULL);
529 pageflip_test_fini(&test, output);
530}
531
532static void
Matt Roper59d8d662015-02-26 19:00:19 -0800533cursor_leak_test_fini(data_t *data,
534 igt_output_t *output,
535 struct igt_fb *bg,
536 struct igt_fb *curs)
537{
538 int i;
539
540 igt_remove_fb(data->drm_fd, bg);
541 for (i = 0; i < 10; i++)
542 igt_remove_fb(data->drm_fd, &curs[i]);
543
544 igt_output_set_pipe(output, PIPE_ANY);
545}
546
547static int
548i915_gem_fb_count(void)
549{
550 char buf[1024];
551 FILE *fp;
552 int count = 0;
553
554 fp = igt_debugfs_fopen("i915_gem_framebuffer", "r");
555 igt_require(fp);
556 while (fgets(buf, sizeof(buf), fp) != NULL)
557 count++;
558 fclose(fp);
559
560 return count;
561}
562
563static void
564cursor_leak_test_pipe(data_t *data, enum pipe pipe, igt_output_t *output)
565{
566 igt_display_t *display = &data->display;
567 igt_plane_t *primary, *cursor;
568 drmModeModeInfo *mode;
569 struct igt_fb background_fb;
570 struct igt_fb cursor_fb[10];
571 int i;
572 int r, g, b;
573 int count1, count2;
574
Matt Roper59d8d662015-02-26 19:00:19 -0800575 igt_skip_on(pipe >= display->n_pipes);
Lyude80baeb02016-12-07 19:02:04 -0500576 igt_require(display->has_cursor_plane);
Matt Roper59d8d662015-02-26 19:00:19 -0800577
578 igt_output_set_pipe(output, pipe);
579 mode = igt_output_get_mode(output);
580
581 /* Count GEM framebuffers before creating our cursor FB's */
582 count1 = i915_gem_fb_count();
583
584 /* Black background FB */
585 igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
586 DRM_FORMAT_XRGB8888,
587 false,
588 0.0, 0.0, 0.0,
589 &background_fb);
590
591 /* Random color cursors */
592 for (i = 0; i < 10; i++) {
593 r = rand() % 0xFF;
594 g = rand() % 0xFF;
595 b = rand() % 0xFF;
596 igt_create_color_fb(data->drm_fd, 64, 64,
597 DRM_FORMAT_ARGB8888,
598 false,
599 (double)r / 0xFF,
600 (double)g / 0xFF,
601 (double)b / 0xFF,
602 &cursor_fb[i]);
603 }
604
Robert Foss265a3a52017-01-10 20:19:46 -0500605 primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
606 cursor = igt_output_get_plane_type(output, DRM_PLANE_TYPE_CURSOR);
Matt Roper59d8d662015-02-26 19:00:19 -0800607 if (!primary || !cursor) {
608 cursor_leak_test_fini(data, output, &background_fb, cursor_fb);
609 igt_skip("Primary and/or cursor are unavailable\n");
610 }
611
612
613 igt_plane_set_fb(primary, &background_fb);
614 igt_display_commit2(display, COMMIT_LEGACY);
615
616 igt_plane_set_position(cursor, 100, 100);
617
618 /*
619 * Exercise both legacy and universal code paths. Note that legacy
620 * handling in the kernel redirects through universal codepaths
621 * internally, so that redirection is where we're most worried about
622 * leaking.
623 */
624 for (i = 0; i < 10; i++) {
625 igt_plane_set_fb(cursor, &cursor_fb[i]);
626 igt_display_commit2(display, COMMIT_UNIVERSAL);
627 }
628 for (i = 0; i < 10; i++) {
629 igt_plane_set_fb(cursor, &cursor_fb[i]);
630 igt_display_commit2(display, COMMIT_LEGACY);
631 }
632
633 /* Release our framebuffer handles before we take a second count */
634 igt_plane_set_fb(primary, NULL);
635 igt_plane_set_fb(cursor, NULL);
636 igt_display_commit2(display, COMMIT_LEGACY);
637 cursor_leak_test_fini(data, output, &background_fb, cursor_fb);
638
639 /* We should be back to the same framebuffer count as when we started */
640 count2 = i915_gem_fb_count();
641
Daniel Vettere3f8eb52015-02-27 16:18:40 +0100642 igt_assert_eq(count1, count2);
Matt Roper59d8d662015-02-26 19:00:19 -0800643}
644
645static void
Matt Roper1a593d22015-10-06 17:04:49 -0700646gen9_test_init(gen9_test_t *test, igt_output_t *output, enum pipe pipe)
647{
648 data_t *data = test->data;
649 drmModeModeInfo *mode;
650
651 igt_output_set_pipe(output, pipe);
652
653 mode = igt_output_get_mode(output);
654 test->w = mode->hdisplay / 2;
655 test->h = mode->vdisplay / 2;
656 test->x = mode->hdisplay / 4;
657 test->y = mode->vdisplay / 4;
658
659 /* Initial framebuffer of full CRTC size */
660 igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
661 DRM_FORMAT_XRGB8888,
662 LOCAL_DRM_FORMAT_MOD_NONE,
663 0.0, 1.0, 0.0,
664 &test->biggreen_fb);
665
666 /* Framebuffers that only cover a quarter of the CRTC size */
667 igt_create_color_fb(data->drm_fd, test->w, test->h,
668 DRM_FORMAT_XRGB8888,
669 LOCAL_DRM_FORMAT_MOD_NONE,
670 1.0, 0.0, 0.0,
671 &test->smallred_fb);
672 igt_create_color_fb(data->drm_fd, test->w, test->h,
673 DRM_FORMAT_XRGB8888,
674 LOCAL_DRM_FORMAT_MOD_NONE,
675 0.0, 0.0, 1.0,
676 &test->smallblue_fb);
677}
678
679static void
680gen9_test_fini(gen9_test_t *test, igt_output_t *output)
681{
682 igt_remove_fb(test->data->drm_fd, &test->biggreen_fb);
683 igt_remove_fb(test->data->drm_fd, &test->smallred_fb);
684 igt_remove_fb(test->data->drm_fd, &test->smallblue_fb);
685
686 igt_output_set_pipe(output, PIPE_ANY);
687 igt_display_commit2(&test->data->display, COMMIT_LEGACY);
688}
689
690/*
691 * Test features specific to gen9+ platforms (i.e., primary plane
692 * windowing)
693 */
694static void
695gen9_test_pipe(data_t *data, enum pipe pipe, igt_output_t *output)
696{
697 gen9_test_t test = { .data = data };
698 igt_plane_t *primary;
699
700 int ret = 0;
701
702 igt_skip_on(data->gen < 9);
703 igt_skip_on(pipe >= data->display.n_pipes);
704
705 igt_output_set_pipe(output, pipe);
706
707 gen9_test_init(&test, output, pipe);
708
Robert Foss265a3a52017-01-10 20:19:46 -0500709 primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
Matt Roper1a593d22015-10-06 17:04:49 -0700710
711 /* Start with a full-screen primary plane */
712 igt_plane_set_fb(primary, &test.biggreen_fb);
713 igt_display_commit2(&data->display, COMMIT_LEGACY);
714
715 /* Set primary to windowed size/position */
716 igt_plane_set_fb(primary, &test.smallblue_fb);
717 igt_plane_set_position(primary, test.x, test.y);
718 igt_plane_set_size(primary, test.w, test.h);
719 igt_display_commit2(&data->display, COMMIT_UNIVERSAL);
720
721 /*
722 * SetPlane update to another framebuffer of the same size
723 * should succeed
724 */
725 igt_plane_set_fb(primary, &test.smallred_fb);
726 igt_plane_set_position(primary, test.x, test.y);
727 igt_plane_set_size(primary, test.w, test.h);
728 igt_display_commit2(&data->display, COMMIT_UNIVERSAL);
729
730 /* PageFlip should also succeed */
731 ret = drmModePageFlip(data->drm_fd, output->config.crtc->crtc_id,
732 test.smallblue_fb.fb_id, 0, NULL);
733 igt_assert_eq(ret, 0);
734
735 igt_plane_set_fb(primary, NULL);
736 igt_plane_set_position(primary, 0, 0);
737 gen9_test_fini(&test, output);
738}
739
740static void
Matt Roper075d9ea2014-06-30 16:44:28 -0700741run_tests_for_pipe(data_t *data, enum pipe pipe)
742{
743 igt_output_t *output;
744
Maarten Lankhorstef8cff62017-01-12 16:08:30 +0100745 igt_fixture {
746 int valid_tests = 0;
747
748 igt_skip_on(pipe >= data->display.n_pipes);
749
750 for_each_valid_output_on_pipe(&data->display, pipe, output)
751 valid_tests++;
752
753 igt_require_f(valid_tests, "no valid crtc/connector combinations found\n");
754 }
755
Daniel Vetterdd8fba42014-08-12 11:00:37 +0200756 igt_subtest_f("universal-plane-pipe-%s-functional",
757 kmstest_pipe_name(pipe))
Maarten Lankhorstef8cff62017-01-12 16:08:30 +0100758 for_each_valid_output_on_pipe(&data->display, pipe, output)
Matt Roper075d9ea2014-06-30 16:44:28 -0700759 functional_test_pipe(data, pipe, output);
760
Daniel Vetterdd8fba42014-08-12 11:00:37 +0200761 igt_subtest_f("universal-plane-pipe-%s-sanity",
762 kmstest_pipe_name(pipe))
Maarten Lankhorstef8cff62017-01-12 16:08:30 +0100763 for_each_valid_output_on_pipe(&data->display, pipe, output)
Matt Roper075d9ea2014-06-30 16:44:28 -0700764 sanity_test_pipe(data, pipe, output);
765
Daniel Vetterdd8fba42014-08-12 11:00:37 +0200766 igt_subtest_f("disable-primary-vs-flip-pipe-%s",
767 kmstest_pipe_name(pipe))
Maarten Lankhorstef8cff62017-01-12 16:08:30 +0100768 for_each_valid_output_on_pipe(&data->display, pipe, output)
Matt Roper075d9ea2014-06-30 16:44:28 -0700769 pageflip_test_pipe(data, pipe, output);
Matt Roper59d8d662015-02-26 19:00:19 -0800770
771 igt_subtest_f("cursor-fb-leak-pipe-%s",
772 kmstest_pipe_name(pipe))
Maarten Lankhorstef8cff62017-01-12 16:08:30 +0100773 for_each_valid_output_on_pipe(&data->display, pipe, output)
Matt Roper59d8d662015-02-26 19:00:19 -0800774 cursor_leak_test_pipe(data, pipe, output);
Matt Roper1a593d22015-10-06 17:04:49 -0700775
776 igt_subtest_f("universal-plane-gen9-features-pipe-%s",
777 kmstest_pipe_name(pipe))
Maarten Lankhorstef8cff62017-01-12 16:08:30 +0100778 for_each_valid_output_on_pipe(&data->display, pipe, output)
Matt Roper1a593d22015-10-06 17:04:49 -0700779 gen9_test_pipe(data, pipe, output);
Matt Roper075d9ea2014-06-30 16:44:28 -0700780}
781
782static data_t data;
783
784igt_main
785{
Matt Roper075d9ea2014-06-30 16:44:28 -0700786 igt_skip_on_simulation();
787
788 igt_fixture {
Micah Fedkec81d2932015-07-22 21:54:02 +0000789 data.drm_fd = drm_open_driver_master(DRIVER_INTEL);
Matt Roperb81f7db2015-07-01 15:45:21 -0700790 data.gen = intel_gen(intel_get_drm_devid(data.drm_fd));
Matt Roper075d9ea2014-06-30 16:44:28 -0700791
Daniel Vetter33f08842014-08-12 11:23:09 +0200792 kmstest_set_vt_graphics_mode();
Matt Roper075d9ea2014-06-30 16:44:28 -0700793
794 igt_require_pipe_crc();
795 igt_display_init(&data.display, data.drm_fd);
Matt Roper075d9ea2014-06-30 16:44:28 -0700796 }
797
Maarten Lankhorstef8cff62017-01-12 16:08:30 +0100798 for (int pipe = 0; pipe < I915_MAX_PIPES; pipe++) {
799 igt_subtest_group
800 run_tests_for_pipe(&data, pipe);
801 }
Matt Roper075d9ea2014-06-30 16:44:28 -0700802
803 igt_fixture {
804 igt_display_fini(&data.display);
805 }
806}