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 * Authors:
24 * Damien Lespiau <[email protected]>
25 */
26
27 #include "igt.h"
28 #include <errno.h>
29 #include <stdbool.h>
30 #include <stdio.h>
31 #include <string.h>
32
33 /*
34 * Throw away enough lsbs in pixel formats tests
35 * to get a match despite some differences between
36 * the software and hardware YCbCr<->RGB conversion
37 * routines.
38 */
39 #define LUT_MASK 0xf800
40
41 typedef struct {
42 float red;
43 float green;
44 float blue;
45 } color_t;
46
47 typedef struct {
48 int drm_fd;
49 igt_display_t display;
50 igt_pipe_crc_t *pipe_crc;
51 uint32_t crop;
52 } data_t;
53
54 static color_t red = { 1.0f, 0.0f, 0.0f };
55 static color_t green = { 0.0f, 1.0f, 0.0f };
56 static color_t blue = { 0.0f, 0.0f, 1.0f };
57
58 /*
59 * Common code across all tests, acting on data_t
60 */
test_init(data_t * data,enum pipe pipe)61 static void test_init(data_t *data, enum pipe pipe)
62 {
63 #if defined (USE_CRC)
64 data->pipe_crc = igt_pipe_crc_new(data->drm_fd, pipe, INTEL_PIPE_CRC_SOURCE_AUTO);
65 #endif
66 }
67
test_fini(data_t * data)68 static void test_fini(data_t *data)
69 {
70 #if defined (USE_CRC)
71 igt_pipe_crc_free(data->pipe_crc);
72 #endif
73 }
74
75 static void
test_grab_crc(data_t * data,igt_output_t * output,enum pipe pipe,color_t * fb_color,igt_crc_t * crc)76 test_grab_crc(data_t *data, igt_output_t *output, enum pipe pipe,
77 color_t *fb_color, igt_crc_t *crc /* out */)
78 {
79 struct igt_fb fb;
80 drmModeModeInfo *mode;
81 igt_plane_t *primary;
82 char *crc_str;
83 int ret;
84
85 igt_output_set_pipe(output, pipe);
86
87 primary = igt_output_get_plane(output, 0);
88
89 mode = igt_output_get_mode(output);
90 igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
91 DRM_FORMAT_XRGB8888,
92 LOCAL_DRM_FORMAT_MOD_NONE,
93 fb_color->red, fb_color->green, fb_color->blue,
94 &fb);
95 igt_plane_set_fb(primary, &fb);
96
97 ret = igt_display_try_commit2(&data->display, COMMIT_LEGACY);
98 igt_skip_on(ret != 0);
99
100 #if defined (USE_CRC)
101 igt_pipe_crc_collect_crc(data->pipe_crc, crc);
102 #endif
103
104 igt_plane_set_fb(primary, NULL);
105 igt_display_commit(&data->display);
106
107 igt_remove_fb(data->drm_fd, &fb);
108
109 #if defined (USE_CRC)
110 crc_str = igt_crc_to_string(crc);
111 igt_debug("CRC for a (%.02f,%.02f,%.02f) fb: %s\n", fb_color->red,
112 fb_color->green, fb_color->blue, crc_str);
113 free(crc_str);
114 #endif
115 }
116
117 /*
118 * Plane position test.
119 * - We start by grabbing a reference CRC of a full green fb being scanned
120 * out on the primary plane
121 * - Then we scannout 2 planes:
122 * - the primary plane uses a green fb with a black rectangle
123 * - a plane, on top of the primary plane, with a green fb that is set-up
124 * to cover the black rectangle of the primary plane fb
125 * The resulting CRC should be identical to the reference CRC
126 */
127
128 typedef struct {
129 data_t *data;
130 igt_crc_t reference_crc;
131 } test_position_t;
132
133 /*
134 * create a green fb with a black rectangle at (rect_x,rect_y) and of size
135 * (rect_w,rect_h)
136 */
137 static void
create_fb_for_mode__position(data_t * data,drmModeModeInfo * mode,double rect_x,double rect_y,double rect_w,double rect_h,struct igt_fb * fb)138 create_fb_for_mode__position(data_t *data, drmModeModeInfo *mode,
139 double rect_x, double rect_y,
140 double rect_w, double rect_h,
141 struct igt_fb *fb /* out */)
142 {
143 unsigned int fb_id;
144 cairo_t *cr;
145
146 fb_id = igt_create_fb(data->drm_fd,
147 mode->hdisplay, mode->vdisplay,
148 DRM_FORMAT_XRGB8888,
149 LOCAL_DRM_FORMAT_MOD_NONE,
150 fb);
151 igt_assert(fb_id);
152
153 cr = igt_get_cairo_ctx(data->drm_fd, fb);
154 igt_paint_color(cr, 0, 0, mode->hdisplay, mode->vdisplay,
155 0.0, 1.0, 0.0);
156 igt_paint_color(cr, rect_x, rect_y, rect_w, rect_h, 0.0, 0.0, 0.0);
157 igt_put_cairo_ctx(data->drm_fd, fb, cr);
158 }
159
160 enum {
161 TEST_POSITION_FULLY_COVERED = 1 << 0,
162 TEST_DPMS = 1 << 1,
163 };
164
165 static void
test_plane_position_with_output(data_t * data,enum pipe pipe,int plane,igt_output_t * output,igt_crc_t * reference_crc,unsigned int flags)166 test_plane_position_with_output(data_t *data,
167 enum pipe pipe,
168 int plane,
169 igt_output_t *output,
170 igt_crc_t *reference_crc,
171 unsigned int flags)
172 {
173 igt_plane_t *primary, *sprite;
174 struct igt_fb primary_fb, sprite_fb;
175 drmModeModeInfo *mode;
176 igt_crc_t crc, crc2;
177
178 igt_info("Testing connector %s using pipe %s plane %d\n",
179 igt_output_name(output), kmstest_pipe_name(pipe), plane);
180
181 igt_output_set_pipe(output, pipe);
182
183 mode = igt_output_get_mode(output);
184 primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
185 sprite = igt_output_get_plane(output, plane);
186
187 /* Primary planes can't be windowed when using a legacy commit */
188 if (sprite->type == DRM_PLANE_TYPE_PRIMARY) {
189 return;
190 }
191
192 create_fb_for_mode__position(data, mode, 100, 100, 64, 64,
193 &primary_fb);
194 igt_plane_set_fb(primary, &primary_fb);
195
196 igt_create_color_fb(data->drm_fd,
197 64, 64, /* width, height */
198 DRM_FORMAT_XRGB8888,
199 LOCAL_DRM_FORMAT_MOD_NONE,
200 0.0, 1.0, 0.0,
201 &sprite_fb);
202 igt_plane_set_fb(sprite, &sprite_fb);
203
204 if (flags & TEST_POSITION_FULLY_COVERED)
205 igt_plane_set_position(sprite, 100, 100);
206 else
207 igt_plane_set_position(sprite, 132, 132);
208
209 igt_display_commit(&data->display);
210
211 #if defined (USE_CRC)
212 igt_pipe_crc_collect_crc(data->pipe_crc, &crc);
213 #endif
214
215 if (flags & TEST_DPMS) {
216 kmstest_set_connector_dpms(data->drm_fd,
217 output->config.connector,
218 DRM_MODE_DPMS_OFF);
219 kmstest_set_connector_dpms(data->drm_fd,
220 output->config.connector,
221 DRM_MODE_DPMS_ON);
222 }
223
224 #if defined (USE_CRC)
225 igt_pipe_crc_collect_crc(data->pipe_crc, &crc2);
226
227 if (flags & TEST_POSITION_FULLY_COVERED)
228 igt_assert_crc_equal(reference_crc, &crc);
229 else {
230 ;/* FIXME: missing reference CRCs */
231 }
232
233 igt_assert_crc_equal(&crc, &crc2);
234 #endif
235
236 igt_plane_set_fb(primary, NULL);
237 igt_plane_set_fb(sprite, NULL);
238
239 /* reset the constraint on the pipe */
240 igt_output_set_pipe(output, PIPE_ANY);
241 }
242
243 static void
test_plane_position(data_t * data,enum pipe pipe,unsigned int flags)244 test_plane_position(data_t *data, enum pipe pipe, unsigned int flags)
245 {
246 int n_planes = data->display.pipes[pipe].n_planes;
247 igt_output_t *output;
248 igt_crc_t reference_crc;
249
250 output = igt_get_single_output_for_pipe(&data->display, pipe);
251 igt_require(output);
252
253 test_init(data, pipe);
254
255 test_grab_crc(data, output, pipe, &green, &reference_crc);
256
257 for (int plane = 1; plane < n_planes; plane++)
258 test_plane_position_with_output(data, pipe, plane,
259 output, &reference_crc,
260 flags);
261
262 test_fini(data);
263 }
264
265 /*
266 * Plane panning test.
267 * - We start by grabbing reference CRCs of a full red and a full blue fb
268 * being scanned out on the primary plane
269 * - Then we create a big fb, sized (2 * hdisplay, 2 * vdisplay) and:
270 * - fill the top left quarter with red
271 * - fill the bottom right quarter with blue
272 * - The TEST_PANNING_TOP_LEFT test makes sure that with panning at (0, 0)
273 * we do get the same CRC than the full red fb.
274 * - The TEST_PANNING_BOTTOM_RIGHT test makes sure that with panning at
275 * (vdisplay, hdisplay) we do get the same CRC than the full blue fb.
276 */
277 static void
create_fb_for_mode__panning(data_t * data,drmModeModeInfo * mode,struct igt_fb * fb)278 create_fb_for_mode__panning(data_t *data, drmModeModeInfo *mode,
279 struct igt_fb *fb /* out */)
280 {
281 unsigned int fb_id;
282 cairo_t *cr;
283
284 fb_id = igt_create_fb(data->drm_fd,
285 mode->hdisplay * 2, mode->vdisplay * 2,
286 DRM_FORMAT_XRGB8888,
287 LOCAL_DRM_FORMAT_MOD_NONE,
288 fb);
289 igt_assert(fb_id);
290
291 cr = igt_get_cairo_ctx(data->drm_fd, fb);
292
293 igt_paint_color(cr, 0, 0, mode->hdisplay, mode->vdisplay,
294 1.0, 0.0, 0.0);
295
296 igt_paint_color(cr,
297 mode->hdisplay, mode->vdisplay,
298 mode->hdisplay, mode->vdisplay,
299 0.0, 0.0, 1.0);
300
301 igt_put_cairo_ctx(data->drm_fd, fb, cr);
302 }
303
304 enum {
305 TEST_PANNING_TOP_LEFT = 1 << 0,
306 TEST_PANNING_BOTTOM_RIGHT = 1 << 1,
307 TEST_SUSPEND_RESUME = 1 << 2,
308 };
309
310 static void
test_plane_panning_with_output(data_t * data,enum pipe pipe,int plane,igt_output_t * output,igt_crc_t * red_crc,igt_crc_t * blue_crc,unsigned int flags)311 test_plane_panning_with_output(data_t *data,
312 enum pipe pipe,
313 int plane,
314 igt_output_t *output,
315 igt_crc_t *red_crc, igt_crc_t *blue_crc,
316 unsigned int flags)
317 {
318 igt_plane_t *primary;
319 struct igt_fb primary_fb;
320 drmModeModeInfo *mode;
321 igt_crc_t crc;
322
323 igt_info("Testing connector %s using pipe %s plane %d\n",
324 igt_output_name(output), kmstest_pipe_name(pipe), plane);
325
326 igt_output_set_pipe(output, pipe);
327
328 mode = igt_output_get_mode(output);
329 primary = igt_output_get_plane(output, 0);
330
331 create_fb_for_mode__panning(data, mode, &primary_fb);
332 igt_plane_set_fb(primary, &primary_fb);
333
334 if (flags & TEST_PANNING_TOP_LEFT)
335 igt_fb_set_position(&primary_fb, primary, 0, 0);
336 else
337 igt_fb_set_position(&primary_fb, primary, mode->hdisplay, mode->vdisplay);
338
339 igt_display_commit(&data->display);
340
341 if (flags & TEST_SUSPEND_RESUME)
342 igt_system_suspend_autoresume(SUSPEND_STATE_MEM,
343 SUSPEND_TEST_NONE);
344
345 #if defined (USE_CRC)
346 igt_pipe_crc_collect_crc(data->pipe_crc, &crc);
347
348 if (flags & TEST_PANNING_TOP_LEFT)
349 igt_assert_crc_equal(red_crc, &crc);
350 else
351 igt_assert_crc_equal(blue_crc, &crc);
352 #endif
353
354 igt_plane_set_fb(primary, NULL);
355
356 /* reset states to neutral values, assumed by other tests */
357 igt_output_set_pipe(output, PIPE_ANY);
358 igt_fb_set_position(&primary_fb, primary, 0, 0);
359 }
360
361 static void
test_plane_panning(data_t * data,enum pipe pipe,unsigned int flags)362 test_plane_panning(data_t *data, enum pipe pipe, unsigned int flags)
363 {
364 int n_planes = data->display.pipes[pipe].n_planes;
365 igt_output_t *output;
366 igt_crc_t red_crc;
367 igt_crc_t blue_crc;
368
369 output = igt_get_single_output_for_pipe(&data->display, pipe);
370 igt_require(output);
371
372 test_init(data, pipe);
373
374 test_grab_crc(data, output, pipe, &red, &red_crc);
375 test_grab_crc(data, output, pipe, &blue, &blue_crc);
376
377 for (int plane = 1; plane < n_planes; plane++)
378 test_plane_panning_with_output(data, pipe, plane, output,
379 &red_crc, &blue_crc, flags);
380
381 test_fini(data);
382 }
383
384 static const color_t colors[] = {
385 { 1.0f, 0.0f, 0.0f, },
386 { 0.0f, 1.0f, 0.0f, },
387 { 0.0f, 0.0f, 1.0f, },
388 { 1.0f, 1.0f, 1.0f, },
389 { 0.0f, 0.0f, 0.0f, },
390 { 0.0f, 1.0f, 1.0f, },
391 { 1.0f, 0.0f, 1.0f, },
392 { 1.0f, 1.0f, 0.0f, },
393 };
394
set_legacy_lut(data_t * data,enum pipe pipe,uint16_t mask)395 static void set_legacy_lut(data_t *data, enum pipe pipe,
396 uint16_t mask)
397 {
398 igt_pipe_t *pipe_obj = &data->display.pipes[pipe];
399 drmModeCrtc *crtc;
400 uint16_t *lut;
401 int i, lut_size, ret;
402
403 crtc = drmModeGetCrtc(data->drm_fd, pipe_obj->crtc_id);
404 lut_size = crtc->gamma_size;
405 drmModeFreeCrtc(crtc);
406
407 lut = malloc(sizeof(uint16_t) * lut_size);
408
409 for (i = 0; i < lut_size; i++)
410 lut[i] = (i * 0xffff / (lut_size - 1)) & mask;
411
412 /* DRM driver might not implemented this and return ENOSYS .*/
413 ret = drmModeCrtcSetGamma(data->drm_fd, pipe_obj->crtc_id,
414 lut_size, lut, lut, lut);
415 igt_assert(ret == 0 || ret == -ENOSYS);
416
417 free(lut);
418 }
419
set_c8_legacy_lut(data_t * data,enum pipe pipe,uint16_t mask)420 static bool set_c8_legacy_lut(data_t *data, enum pipe pipe,
421 uint16_t mask)
422 {
423 igt_pipe_t *pipe_obj = &data->display.pipes[pipe];
424 drmModeCrtc *crtc;
425 uint16_t *r, *g, *b;
426 int i, lut_size;
427
428 crtc = drmModeGetCrtc(data->drm_fd, pipe_obj->crtc_id);
429 lut_size = crtc->gamma_size;
430 drmModeFreeCrtc(crtc);
431
432 if (lut_size != 256)
433 return false;
434
435 r = malloc(sizeof(uint16_t) * 3 * lut_size);
436 g = r + lut_size;
437 b = g + lut_size;
438
439 /* igt_fb uses RGB332 for C8 */
440 for (i = 0; i < lut_size; i++) {
441 r[i] = (((i & 0xe0) >> 5) * 0xffff / 0x7) & mask;
442 g[i] = (((i & 0x1c) >> 2) * 0xffff / 0x7) & mask;
443 b[i] = (((i & 0x03) >> 0) * 0xffff / 0x3) & mask;
444 }
445
446 igt_assert_eq(drmModeCrtcSetGamma(data->drm_fd, pipe_obj->crtc_id,
447 lut_size, r, g, b), 0);
448
449 free(r);
450
451 return true;
452 }
453
test_format_plane_color(data_t * data,enum pipe pipe,igt_plane_t * plane,uint32_t format,uint64_t modifier,int width,int height,enum igt_color_encoding color_encoding,enum igt_color_range color_range,int color,igt_crc_t * crc,struct igt_fb * fb)454 static void test_format_plane_color(data_t *data, enum pipe pipe,
455 igt_plane_t *plane,
456 uint32_t format, uint64_t modifier,
457 int width, int height,
458 enum igt_color_encoding color_encoding,
459 enum igt_color_range color_range,
460 int color, igt_crc_t *crc, struct igt_fb *fb)
461 {
462 const color_t *c = &colors[color];
463 struct igt_fb old_fb = *fb;
464 cairo_t *cr;
465
466 if (data->crop == 0 || format == DRM_FORMAT_XRGB8888) {
467 igt_create_fb_with_bo_size(data->drm_fd, width, height,
468 format, modifier, color_encoding,
469 color_range, fb, 0, 0);
470
471 cr = igt_get_cairo_ctx(data->drm_fd, fb);
472
473 igt_paint_color(cr, 0, 0, width, height,
474 c->red, c->green, c->blue);
475
476 igt_put_cairo_ctx(data->drm_fd, fb, cr);
477 } else {
478 igt_create_fb_with_bo_size(data->drm_fd,
479 width + data->crop * 2,
480 height + data->crop * 2,
481 format, modifier, color_encoding,
482 color_range, fb, 0, 0);
483
484 /*
485 * paint border in inverted color, then visible area in middle
486 * with correct color for clamping test
487 */
488 cr = igt_get_cairo_ctx(data->drm_fd, fb);
489
490 igt_paint_color(cr, 0, 0,
491 width + data->crop * 2,
492 height + data->crop * 2,
493 1.0f - c->red,
494 1.0f - c->green,
495 1.0f - c->blue);
496
497 igt_paint_color(cr, data->crop, data->crop,
498 width, height,
499 c->red, c->green, c->blue);
500
501 igt_put_cairo_ctx(data->drm_fd, fb, cr);
502 }
503
504 igt_plane_set_fb(plane, fb);
505
506 /*
507 * if clamping test. DRM_FORMAT_XRGB8888 is used for reference color.
508 */
509 if (data->crop != 0 && format != DRM_FORMAT_XRGB8888) {
510 igt_fb_set_position(fb, plane, data->crop, data->crop);
511 igt_fb_set_size(fb, plane, width, height);
512 igt_plane_set_size(plane, width, height);
513 }
514
515 igt_display_commit2(&data->display, data->display.is_atomic ? COMMIT_ATOMIC : COMMIT_UNIVERSAL);
516 #if defined (USE_CRC)
517 igt_pipe_crc_get_current(data->display.drm_fd, data->pipe_crc, crc);
518 #endif
519
520 igt_remove_fb(data->drm_fd, &old_fb);
521 }
522
523 #if defined (USE_CRC)
num_unique_crcs(const igt_crc_t crc[],int num_crc)524 static int num_unique_crcs(const igt_crc_t crc[], int num_crc)
525 {
526 int num_unique_crc = 0;
527
528 for (int i = 0; i < num_crc; i++) {
529 int j;
530
531 for (j = i + 1; j < num_crc; j++) {
532 if (igt_check_crc_equal(&crc[i], &crc[j]))
533 break;
534 }
535
536 if (j == num_crc)
537 num_unique_crc++;
538 }
539
540 return num_unique_crc;
541 }
542 #endif
543
test_format_plane_colors(data_t * data,enum pipe pipe,igt_plane_t * plane,uint32_t format,uint64_t modifier,int width,int height,enum igt_color_encoding encoding,enum igt_color_range range,igt_crc_t ref_crc[ARRAY_SIZE (colors)],struct igt_fb * fb)544 static bool test_format_plane_colors(data_t *data, enum pipe pipe,
545 igt_plane_t *plane,
546 uint32_t format, uint64_t modifier,
547 int width, int height,
548 enum igt_color_encoding encoding,
549 enum igt_color_range range,
550 igt_crc_t ref_crc[ARRAY_SIZE(colors)],
551 struct igt_fb *fb)
552 {
553 int crc_mismatch_count = 0;
554 unsigned int crc_mismatch_mask = 0;
555 bool result = true;
556
557 for (int i = 0; i < ARRAY_SIZE(colors); i++) {
558 igt_crc_t crc;
559
560 test_format_plane_color(data, pipe, plane,
561 format, modifier,
562 width, height,
563 encoding, range,
564 i, &crc, fb);
565
566 #if defined (USE_CRC)
567 if (!igt_check_crc_equal(&crc, &ref_crc[i])) {
568 crc_mismatch_count++;
569 crc_mismatch_mask |= (1 << i);
570 result = false;
571 }
572 #endif
573 }
574
575 if (crc_mismatch_count)
576 igt_warn("CRC mismatches with format " IGT_FORMAT_FMT " on %s.%u with %d/%d solid colors tested (0x%X)\n",
577 IGT_FORMAT_ARGS(format), kmstest_pipe_name(pipe),
578 plane->index, crc_mismatch_count, (int)ARRAY_SIZE(colors), crc_mismatch_mask);
579
580 return result;
581 }
582
test_format_plane_rgb(data_t * data,enum pipe pipe,igt_plane_t * plane,uint32_t format,uint64_t modifier,int width,int height,igt_crc_t ref_crc[ARRAY_SIZE (colors)],struct igt_fb * fb)583 static bool test_format_plane_rgb(data_t *data, enum pipe pipe,
584 igt_plane_t *plane,
585 uint32_t format, uint64_t modifier,
586 int width, int height,
587 igt_crc_t ref_crc[ARRAY_SIZE(colors)],
588 struct igt_fb *fb)
589 {
590 igt_info("Testing format " IGT_FORMAT_FMT " / modifier 0x%" PRIx64 " on %s.%u\n",
591 IGT_FORMAT_ARGS(format), modifier,
592 kmstest_pipe_name(pipe), plane->index);
593
594 return test_format_plane_colors(data, pipe, plane,
595 format, modifier,
596 width, height,
597 IGT_COLOR_YCBCR_BT601,
598 IGT_COLOR_YCBCR_LIMITED_RANGE,
599 ref_crc, fb);
600 }
601
test_format_plane_yuv(data_t * data,enum pipe pipe,igt_plane_t * plane,uint32_t format,uint64_t modifier,int width,int height,igt_crc_t ref_crc[ARRAY_SIZE (colors)],struct igt_fb * fb)602 static bool test_format_plane_yuv(data_t *data, enum pipe pipe,
603 igt_plane_t *plane,
604 uint32_t format, uint64_t modifier,
605 int width, int height,
606 igt_crc_t ref_crc[ARRAY_SIZE(colors)],
607 struct igt_fb *fb)
608 {
609 bool result = true;
610
611 if (!igt_plane_has_prop(plane, IGT_PLANE_COLOR_ENCODING))
612 return true;
613 if (!igt_plane_has_prop(plane, IGT_PLANE_COLOR_RANGE))
614 return true;
615
616 for (enum igt_color_encoding e = 0; e < IGT_NUM_COLOR_ENCODINGS; e++) {
617 if (!igt_plane_try_prop_enum(plane,
618 IGT_PLANE_COLOR_ENCODING,
619 igt_color_encoding_to_str(e)))
620 continue;
621
622 for (enum igt_color_range r = 0; r < IGT_NUM_COLOR_RANGES; r++) {
623 if (!igt_plane_try_prop_enum(plane,
624 IGT_PLANE_COLOR_RANGE,
625 igt_color_range_to_str(r)))
626 continue;
627
628 igt_info("Testing format " IGT_FORMAT_FMT " / modifier 0x%" PRIx64 " (%s, %s) on %s.%u\n",
629 IGT_FORMAT_ARGS(format), modifier,
630 igt_color_encoding_to_str(e),
631 igt_color_range_to_str(r),
632 kmstest_pipe_name(pipe), plane->index);
633
634 result &= test_format_plane_colors(data, pipe, plane,
635 format, modifier,
636 width, height,
637 e, r, ref_crc, fb);
638 }
639 }
640
641 return result;
642 }
643
test_format_plane(data_t * data,enum pipe pipe,igt_output_t * output,igt_plane_t * plane)644 static bool test_format_plane(data_t *data, enum pipe pipe,
645 igt_output_t *output, igt_plane_t *plane)
646 {
647 struct igt_fb fb = {};
648 drmModeModeInfo *mode;
649 uint32_t format, ref_format;
650 uint64_t modifier, ref_modifier;
651 uint64_t width, height;
652 igt_crc_t ref_crc[ARRAY_SIZE(colors)];
653 bool result = true;
654
655 /*
656 * No clamping test for cursor plane
657 */
658 if (data->crop != 0 && plane->type == DRM_PLANE_TYPE_CURSOR)
659 return true;
660
661 mode = igt_output_get_mode(output);
662 if (plane->type != DRM_PLANE_TYPE_CURSOR) {
663 width = mode->hdisplay;
664 height = mode->vdisplay;
665 ref_format = format = DRM_FORMAT_XRGB8888;
666 ref_modifier = modifier = DRM_FORMAT_MOD_NONE;
667 } else {
668 if (!plane->drm_plane) {
669 igt_debug("Only legacy cursor ioctl supported, skipping cursor plane\n");
670 return true;
671 }
672 do_or_die(drmGetCap(data->drm_fd, DRM_CAP_CURSOR_WIDTH, &width));
673 do_or_die(drmGetCap(data->drm_fd, DRM_CAP_CURSOR_HEIGHT, &height));
674 ref_format = format = DRM_FORMAT_ARGB8888;
675 ref_modifier = modifier = DRM_FORMAT_MOD_NONE;
676 }
677
678 igt_debug("Testing connector %s on %s plane %s.%u\n",
679 igt_output_name(output), kmstest_plane_type_name(plane->type),
680 kmstest_pipe_name(pipe), plane->index);
681
682 #if defined (USE_CRC)
683 igt_pipe_crc_start(data->pipe_crc);
684 #endif
685
686 igt_info("Testing format " IGT_FORMAT_FMT " / modifier 0x%" PRIx64 " on %s.%u\n",
687 IGT_FORMAT_ARGS(format), modifier,
688 kmstest_pipe_name(pipe), plane->index);
689
690 if (data->display.is_atomic) {
691 struct igt_fb test_fb;
692 int ret;
693
694 igt_create_fb(data->drm_fd, 64, 64, format,
695 LOCAL_DRM_FORMAT_MOD_NONE, &test_fb);
696
697 igt_plane_set_fb(plane, &test_fb);
698
699 ret = igt_display_try_commit_atomic(&data->display, DRM_MODE_ATOMIC_TEST_ONLY, NULL);
700
701 if (!ret) {
702 width = test_fb.width;
703 height = test_fb.height;
704 }
705
706 igt_plane_set_fb(plane, NULL);
707
708 igt_remove_fb(data->drm_fd, &test_fb);
709 }
710
711 for (int i = 0; i < ARRAY_SIZE(colors); i++) {
712 test_format_plane_color(data, pipe, plane,
713 format, modifier,
714 width, height,
715 IGT_COLOR_YCBCR_BT709,
716 IGT_COLOR_YCBCR_LIMITED_RANGE,
717 i, &ref_crc[i], &fb);
718 }
719
720 /*
721 * Make sure we have some difference between the colors. This
722 * at least avoids claiming success when everything is just
723 * black all the time (eg. if the plane is never even on).
724 */
725 #if defined (USE_CRC)
726 igt_require(num_unique_crcs(ref_crc, ARRAY_SIZE(colors)) > 1);
727 #endif
728
729 for (int i = 0; i < plane->format_mod_count; i++) {
730 format = plane->formats[i];
731 modifier = plane->modifiers[i];
732
733 if (format == ref_format &&
734 modifier == ref_modifier)
735 continue;
736
737 if (format == DRM_FORMAT_C8) {
738 if (!set_c8_legacy_lut(data, pipe, LUT_MASK))
739 continue;
740 } else {
741 if (!igt_fb_supported_format(format))
742 continue;
743 }
744
745 if (igt_format_is_yuv(format))
746 result &= test_format_plane_yuv(data, pipe, plane,
747 format, modifier,
748 width, height,
749 ref_crc, &fb);
750 else
751 result &= test_format_plane_rgb(data, pipe, plane,
752 format, modifier,
753 width, height,
754 ref_crc, &fb);
755
756 if (format == DRM_FORMAT_C8)
757 set_legacy_lut(data, pipe, LUT_MASK);
758 }
759
760 #if defined (USE_CRC)
761 igt_pipe_crc_stop(data->pipe_crc);
762 #endif
763
764 igt_plane_set_fb(plane, NULL);
765 igt_remove_fb(data->drm_fd, &fb);
766
767 return result;
768 }
769
770 static void
test_pixel_formats(data_t * data,enum pipe pipe)771 test_pixel_formats(data_t *data, enum pipe pipe)
772 {
773 struct igt_fb primary_fb;
774 igt_plane_t *primary;
775 drmModeModeInfo *mode;
776 bool result;
777 igt_output_t *output;
778 igt_plane_t *plane;
779
780 output = igt_get_single_output_for_pipe(&data->display, pipe);
781 igt_require(output);
782
783 mode = igt_output_get_mode(output);
784
785 igt_create_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
786 DRM_FORMAT_XRGB8888, LOCAL_DRM_FORMAT_MOD_NONE, &primary_fb);
787
788 igt_output_set_pipe(output, pipe);
789 primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
790 igt_plane_set_fb(primary, &primary_fb);
791
792 igt_display_commit2(&data->display, data->display.is_atomic ? COMMIT_ATOMIC : COMMIT_LEGACY);
793
794 set_legacy_lut(data, pipe, LUT_MASK);
795
796 test_init(data, pipe);
797
798 result = true;
799 for_each_plane_on_pipe(&data->display, pipe, plane)
800 result &= test_format_plane(data, pipe, output, plane);
801
802 test_fini(data);
803
804 set_legacy_lut(data, pipe, 0xffff);
805
806 igt_plane_set_fb(primary, NULL);
807 igt_output_set_pipe(output, PIPE_NONE);
808 igt_display_commit2(&data->display, data->display.is_atomic ? COMMIT_ATOMIC : COMMIT_LEGACY);
809
810 igt_remove_fb(data->drm_fd, &primary_fb);
811
812 igt_assert_f(result, "At least one CRC mismatch happened\n");
813 }
814
815 static void
run_tests_for_pipe_plane(data_t * data,enum pipe pipe)816 run_tests_for_pipe_plane(data_t *data, enum pipe pipe)
817 {
818 igt_fixture {
819 igt_skip_on(pipe >= data->display.n_pipes);
820 igt_require(data->display.pipes[pipe].n_planes > 0);
821 }
822
823 igt_subtest_f("pixel-format-pipe-%s-planes",
824 kmstest_pipe_name(pipe))
825 test_pixel_formats(data, pipe);
826
827 igt_subtest_f("pixel-format-pipe-%s-planes-source-clamping",
828 kmstest_pipe_name(pipe)) {
829 data->crop = 4;
830 test_pixel_formats(data, pipe);
831 }
832
833 data->crop = 0;
834 igt_subtest_f("plane-position-covered-pipe-%s-planes",
835 kmstest_pipe_name(pipe))
836 test_plane_position(data, pipe, TEST_POSITION_FULLY_COVERED);
837
838 igt_subtest_f("plane-position-hole-pipe-%s-planes",
839 kmstest_pipe_name(pipe))
840 test_plane_position(data, pipe, 0);
841
842 igt_subtest_f("plane-position-hole-dpms-pipe-%s-planes",
843 kmstest_pipe_name(pipe))
844 test_plane_position(data, pipe, TEST_DPMS);
845
846 igt_subtest_f("plane-panning-top-left-pipe-%s-planes",
847 kmstest_pipe_name(pipe))
848 test_plane_panning(data, pipe, TEST_PANNING_TOP_LEFT);
849
850 igt_subtest_f("plane-panning-bottom-right-pipe-%s-planes",
851 kmstest_pipe_name(pipe))
852 test_plane_panning(data, pipe, TEST_PANNING_BOTTOM_RIGHT);
853
854 igt_subtest_f("plane-panning-bottom-right-suspend-pipe-%s-planes",
855 kmstest_pipe_name(pipe))
856 test_plane_panning(data, pipe, TEST_PANNING_BOTTOM_RIGHT |
857 TEST_SUSPEND_RESUME);
858 }
859
860
861 static data_t data;
862
863 igt_main
864 {
865 enum pipe pipe;
866
867 igt_skip_on_simulation();
868
869 igt_fixture {
870 data.drm_fd = drm_open_driver_master(DRIVER_ANY);
871
872 kmstest_set_vt_graphics_mode();
873
874 #if defined (USE_CRC)
875 igt_require_pipe_crc(data.drm_fd);
876 #endif
877 igt_display_require(&data.display, data.drm_fd);
878 }
879
880 for_each_pipe_static(pipe)
881 run_tests_for_pipe_plane(&data, pipe);
882
883 igt_fixture {
884 igt_display_fini(&data.display);
885 }
886 }
887