xref: /aosp_15_r20/external/igt-gpu-tools/tests/kms_plane.c (revision d83cc019efdc2edc6c4b16e9034a3ceb8d35d77c)
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