• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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