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