1 /*
2  * Copyright © 2013,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  * 	Daniel Vetter <daniel.vetter@ffwll.ch>
25  * 	Damien Lespiau <damien.lespiau@intel.com>
26  */
27 
28 #include <stdio.h>
29 #include <math.h>
30 #include <wchar.h>
31 #include <inttypes.h>
32 
33 #if defined(USE_CAIRO_PIXMAN)
34 #include <pixman.h>
35 #endif
36 
37 #include "drmtest.h"
38 #include "igt_aux.h"
39 #include "igt_color_encoding.h"
40 #include "igt_fb.h"
41 #include "igt_halffloat.h"
42 #include "igt_kms.h"
43 #include "igt_matrix.h"
44 #if defined(USE_VC4)
45 #include "igt_vc4.h"
46 #endif
47 #include "igt_amd.h"
48 #include "igt_x86.h"
49 #include "ioctl_wrappers.h"
50 #include "intel_batchbuffer.h"
51 #include "intel_chipset.h"
52 #include "i915/gem_mman.h"
53 
54 /**
55  * SECTION:igt_fb
56  * @short_description: Framebuffer handling and drawing library
57  * @title: Framebuffer
58  * @include: igt.h
59  *
60  * This library contains helper functions for handling kms framebuffer objects
61  * using #igt_fb structures to track all the metadata.  igt_create_fb() creates
62  * a basic framebuffer and igt_remove_fb() cleans everything up again.
63  *
64  * It also supports drawing using the cairo library and provides some simplified
65  * helper functions to easily draw test patterns. The main function to create a
66  * cairo drawing context for a framebuffer object is igt_get_cairo_ctx().
67  *
68  * Finally it also pulls in the drm fourcc headers and provides some helper
69  * functions to work with these pixel format codes.
70  */
71 
72 #if defined(USE_CAIRO_PIXMAN)
73 #define PIXMAN_invalid	0
74 
75 #if CAIRO_VERSION < CAIRO_VERSION_ENCODE(1, 17, 2)
76 /*
77  * We need cairo 1.17.2 to use HDR formats, but the only thing added is a value
78  * to cairo_format_t.
79  *
80  * To prevent going outside the enum, make cairo_format_t an int and define
81  * ourselves.
82  */
83 
84 #define CAIRO_FORMAT_RGB96F (6)
85 #define CAIRO_FORMAT_RGBA128F (7)
86 #define cairo_format_t int
87 #endif
88 #endif /*defined(USE_CAIRO_PIXMAN)*/
89 
90 /* drm fourcc/cairo format maps */
91 static const struct format_desc_struct {
92 	const char *name;
93 	uint32_t drm_id;
94 #if defined(USE_CAIRO_PIXMAN)
95 	cairo_format_t cairo_id;
96 	pixman_format_code_t pixman_id;
97 #endif
98 	int depth;
99 	int num_planes;
100 	int plane_bpp[4];
101 	uint8_t hsub;
102 	uint8_t vsub;
103 } format_desc[] = {
104 	{ .name = "ARGB1555", .depth = -1, .drm_id = DRM_FORMAT_ARGB1555,
105 #if defined(USE_CAIRO_PIXMAN)
106 	  .cairo_id = CAIRO_FORMAT_INVALID,
107 	  .pixman_id = PIXMAN_a1r5g5b5,
108 #endif
109 	  .num_planes = 1, .plane_bpp = { 16, },
110 	  .hsub = 1, .vsub = 1,
111 	},
112 	{ .name = "C8", .depth = -1, .drm_id = DRM_FORMAT_C8,
113 #if defined(USE_CAIRO_PIXMAN)
114 	  .cairo_id = CAIRO_FORMAT_INVALID,
115 	  .pixman_id = PIXMAN_r3g3b2,
116 #endif
117 	  .num_planes = 1, .plane_bpp = { 8, },
118 	  .hsub = 1, .vsub = 1,
119 	},
120 	{ .name = "XRGB1555", .depth = -1, .drm_id = DRM_FORMAT_XRGB1555,
121 #if defined(USE_CAIRO_PIXMAN)
122 	  .cairo_id = CAIRO_FORMAT_INVALID,
123 	  .pixman_id = PIXMAN_x1r5g5b5,
124 #endif
125 	  .num_planes = 1, .plane_bpp = { 16, },
126 	  .hsub = 1, .vsub = 1,
127 	},
128 	{ .name = "RGB565", .depth = 16, .drm_id = DRM_FORMAT_RGB565,
129 #if defined(USE_CAIRO_PIXMAN)
130 	  .cairo_id = CAIRO_FORMAT_RGB16_565,
131 	  .pixman_id = PIXMAN_r5g6b5,
132 #endif
133 	  .num_planes = 1, .plane_bpp = { 16, },
134 	  .hsub = 1, .vsub = 1,
135 	},
136 	{ .name = "BGR565", .depth = -1, .drm_id = DRM_FORMAT_BGR565,
137 #if defined(USE_CAIRO_PIXMAN)
138 	  .cairo_id = CAIRO_FORMAT_INVALID,
139 	  .pixman_id = PIXMAN_b5g6r5,
140 #endif
141 	  .num_planes = 1, .plane_bpp = { 16, },
142 	  .hsub = 1, .vsub = 1,
143 	},
144 	{ .name = "BGR888", .depth = -1, .drm_id = DRM_FORMAT_BGR888,
145 #if defined(USE_CAIRO_PIXMAN)
146 	  .cairo_id = CAIRO_FORMAT_INVALID,
147 	  .pixman_id = PIXMAN_b8g8r8,
148 #endif
149 	  .num_planes = 1, .plane_bpp = { 24, },
150 	  .hsub = 1, .vsub = 1,
151 	},
152 	{ .name = "RGB888", .depth = -1, .drm_id = DRM_FORMAT_RGB888,
153 #if defined(USE_CAIRO_PIXMAN)
154 	  .cairo_id = CAIRO_FORMAT_INVALID,
155 	  .pixman_id = PIXMAN_r8g8b8,
156 #endif
157 	  .num_planes = 1, .plane_bpp = { 24, },
158 	  .hsub = 1, .vsub = 1,
159 	},
160 	{ .name = "XYUV8888", .depth = -1, .drm_id = DRM_FORMAT_XYUV8888,
161 #if defined(USE_CAIRO_PIXMAN)
162 	  .cairo_id = CAIRO_FORMAT_RGB24,
163 	  .num_planes = 1, .plane_bpp = { 32, },
164 #endif
165 	  .hsub = 1, .vsub = 1,
166 	},
167 	{ .name = "XRGB8888", .depth = 24, .drm_id = DRM_FORMAT_XRGB8888,
168 #if defined(USE_CAIRO_PIXMAN)
169 	  .cairo_id = CAIRO_FORMAT_RGB24,
170 	  .pixman_id = PIXMAN_x8r8g8b8,
171 #endif
172 	  .num_planes = 1, .plane_bpp = { 32, },
173 	  .hsub = 1, .vsub = 1,
174 	},
175 	{ .name = "XBGR8888", .depth = -1, .drm_id = DRM_FORMAT_XBGR8888,
176 #if defined(USE_CAIRO_PIXMAN)
177 	  .cairo_id = CAIRO_FORMAT_INVALID,
178 	  .pixman_id = PIXMAN_x8b8g8r8,
179 #endif
180 	  .num_planes = 1, .plane_bpp = { 32, },
181 	  .hsub = 1, .vsub = 1,
182 	},
183 	{ .name = "XRGB2101010", .depth = 30, .drm_id = DRM_FORMAT_XRGB2101010,
184 #if defined(USE_CAIRO_PIXMAN)
185 	  .cairo_id = CAIRO_FORMAT_RGB30,
186 	  .pixman_id = PIXMAN_x2r10g10b10,
187 #endif
188 	  .num_planes = 1, .plane_bpp = { 32, },
189 	  .hsub = 1, .vsub = 1,
190 	},
191 	{ .name = "ARGB8888", .depth = 32, .drm_id = DRM_FORMAT_ARGB8888,
192 #if defined(USE_CAIRO_PIXMAN)
193 	  .cairo_id = CAIRO_FORMAT_ARGB32,
194 	  .pixman_id = PIXMAN_a8r8g8b8,
195 #endif
196 	  .num_planes = 1, .plane_bpp = { 32, },
197 	  .hsub = 1, .vsub = 1,
198 	},
199 	{ .name = "ABGR8888", .depth = -1, .drm_id = DRM_FORMAT_ABGR8888,
200 #if defined(USE_CAIRO_PIXMAN)
201 	  .cairo_id = CAIRO_FORMAT_INVALID,
202 	  .pixman_id = PIXMAN_a8b8g8r8,
203 #endif
204 	  .num_planes = 1, .plane_bpp = { 32, },
205 	  .hsub = 1, .vsub = 1,
206 	},
207 	{ .name = "XRGB16161616F", .depth = -1, .drm_id = DRM_FORMAT_XRGB16161616F,
208 #if defined(USE_CAIRO_PIXMAN)
209 	  .cairo_id = CAIRO_FORMAT_RGBA128F,
210 #endif
211 	  .num_planes = 1, .plane_bpp = { 64, },
212 	},
213 	{ .name = "ARGB16161616F", .depth = -1, .drm_id = DRM_FORMAT_ARGB16161616F,
214 #if defined(USE_CAIRO_PIXMAN)
215 	  .cairo_id = CAIRO_FORMAT_RGBA128F,
216 #endif
217 	  .num_planes = 1, .plane_bpp = { 64, },
218 	},
219 	{ .name = "XBGR16161616F", .depth = -1, .drm_id = DRM_FORMAT_XBGR16161616F,
220 #if defined(USE_CAIRO_PIXMAN)
221 	  .cairo_id = CAIRO_FORMAT_RGBA128F,
222 #endif
223 	  .num_planes = 1, .plane_bpp = { 64, },
224 	},
225 	{ .name = "ABGR16161616F", .depth = -1, .drm_id = DRM_FORMAT_ABGR16161616F,
226 #if defined(USE_CAIRO_PIXMAN)
227 	  .cairo_id = CAIRO_FORMAT_RGBA128F,
228 #endif
229 	  .num_planes = 1, .plane_bpp = { 64, },
230 	},
231 	{ .name = "NV12", .depth = -1, .drm_id = DRM_FORMAT_NV12,
232 #if defined(USE_CAIRO_PIXMAN)
233 	  .cairo_id = CAIRO_FORMAT_RGB24,
234 #endif
235 	  .num_planes = 2, .plane_bpp = { 8, 16, },
236 	  .hsub = 2, .vsub = 2,
237 	},
238 	{ .name = "NV16", .depth = -1, .drm_id = DRM_FORMAT_NV16,
239 #if defined(USE_CAIRO_PIXMAN)
240 	  .cairo_id = CAIRO_FORMAT_RGB24,
241 #endif
242 	  .num_planes = 2, .plane_bpp = { 8, 16, },
243 	  .hsub = 2, .vsub = 1,
244 	},
245 	{ .name = "NV21", .depth = -1, .drm_id = DRM_FORMAT_NV21,
246 #if defined(USE_CAIRO_PIXMAN)
247 	  .cairo_id = CAIRO_FORMAT_RGB24,
248 #endif
249 	  .num_planes = 2, .plane_bpp = { 8, 16, },
250 	  .hsub = 2, .vsub = 2,
251 	},
252 	{ .name = "NV61", .depth = -1, .drm_id = DRM_FORMAT_NV61,
253 #if defined(USE_CAIRO_PIXMAN)
254 	  .cairo_id = CAIRO_FORMAT_RGB24,
255 #endif
256 	  .num_planes = 2, .plane_bpp = { 8, 16, },
257 	  .hsub = 2, .vsub = 1,
258 	},
259 	{ .name = "YUYV", .depth = -1, .drm_id = DRM_FORMAT_YUYV,
260 #if defined(USE_CAIRO_PIXMAN)
261 	  .cairo_id = CAIRO_FORMAT_RGB24,
262 #endif
263 	  .num_planes = 1, .plane_bpp = { 16, },
264 	  .hsub = 2, .vsub = 1,
265 	},
266 	{ .name = "YVYU", .depth = -1, .drm_id = DRM_FORMAT_YVYU,
267 #if defined(USE_CAIRO_PIXMAN)
268 	  .cairo_id = CAIRO_FORMAT_RGB24,
269 #endif
270 	  .num_planes = 1, .plane_bpp = { 16, },
271 	  .hsub = 2, .vsub = 1,
272 	},
273 	{ .name = "UYVY", .depth = -1, .drm_id = DRM_FORMAT_UYVY,
274 #if defined(USE_CAIRO_PIXMAN)
275 	  .cairo_id = CAIRO_FORMAT_RGB24,
276 #endif
277 	  .num_planes = 1, .plane_bpp = { 16, },
278 	  .hsub = 2, .vsub = 1,
279 	},
280 	{ .name = "VYUY", .depth = -1, .drm_id = DRM_FORMAT_VYUY,
281 #if defined(USE_CAIRO_PIXMAN)
282 	  .cairo_id = CAIRO_FORMAT_RGB24,
283 #endif
284 	  .num_planes = 1, .plane_bpp = { 16, },
285 	  .hsub = 2, .vsub = 1,
286 	},
287 	{ .name = "YU12", .depth = -1, .drm_id = DRM_FORMAT_YUV420,
288 #if defined(USE_CAIRO_PIXMAN)
289 	  .cairo_id = CAIRO_FORMAT_RGB24,
290 #endif
291 	  .num_planes = 3, .plane_bpp = { 8, 8, 8, },
292 	  .hsub = 2, .vsub = 2,
293 	},
294 	{ .name = "YU16", .depth = -1, .drm_id = DRM_FORMAT_YUV422,
295 #if defined(USE_CAIRO_PIXMAN)
296 	  .cairo_id = CAIRO_FORMAT_RGB24,
297 #endif
298 	  .num_planes = 3, .plane_bpp = { 8, 8, 8, },
299 	  .hsub = 2, .vsub = 1,
300 	},
301 	{ .name = "YV12", .depth = -1, .drm_id = DRM_FORMAT_YVU420,
302 #if defined(USE_CAIRO_PIXMAN)
303 	  .cairo_id = CAIRO_FORMAT_RGB24,
304 #endif
305 	  .num_planes = 3, .plane_bpp = { 8, 8, 8, },
306 	  .hsub = 2, .vsub = 2,
307 	},
308 	{ .name = "YV16", .depth = -1, .drm_id = DRM_FORMAT_YVU422,
309 #if defined(USE_CAIRO_PIXMAN)
310 	  .cairo_id = CAIRO_FORMAT_RGB24,
311 #endif
312 	  .num_planes = 3, .plane_bpp = { 8, 8, 8, },
313 	  .hsub = 2, .vsub = 1,
314 	},
315 	{ .name = "Y410", .depth = -1, .drm_id = DRM_FORMAT_Y410,
316 #if defined(USE_CAIRO_PIXMAN)
317 	  .cairo_id = CAIRO_FORMAT_RGBA128F,
318 #endif
319 	  .num_planes = 1, .plane_bpp = { 32, },
320 	  .hsub = 1, .vsub = 1,
321 	},
322 	{ .name = "Y412", .depth = -1, .drm_id = DRM_FORMAT_Y412,
323 #if defined(USE_CAIRO_PIXMAN)
324 	  .cairo_id = CAIRO_FORMAT_RGBA128F,
325 #endif
326 	  .num_planes = 1, .plane_bpp = { 64, },
327 	  .hsub = 1, .vsub = 1,
328 	},
329 	{ .name = "Y416", .depth = -1, .drm_id = DRM_FORMAT_Y416,
330 #if defined(USE_CAIRO_PIXMAN)
331 	  .cairo_id = CAIRO_FORMAT_RGBA128F,
332 #endif
333 	  .num_planes = 1, .plane_bpp = { 64, },
334 	  .hsub = 1, .vsub = 1,
335 	},
336 	{ .name = "XV30", .depth = -1, .drm_id = DRM_FORMAT_XVYU2101010,
337 #if defined(USE_CAIRO_PIXMAN)
338 	  .cairo_id = CAIRO_FORMAT_RGB96F,
339 #endif
340 	  .num_planes = 1, .plane_bpp = { 32, },
341 	  .hsub = 1, .vsub = 1,
342 	},
343 	{ .name = "XV36", .depth = -1, .drm_id = DRM_FORMAT_XVYU12_16161616,
344 #if defined(USE_CAIRO_PIXMAN)
345 	  .cairo_id = CAIRO_FORMAT_RGB96F,
346 #endif
347 	  .num_planes = 1, .plane_bpp = { 64, },
348 	  .hsub = 1, .vsub = 1,
349 	},
350 	{ .name = "XV48", .depth = -1, .drm_id = DRM_FORMAT_XVYU16161616,
351 #if defined(USE_CAIRO_PIXMAN)
352 	  .cairo_id = CAIRO_FORMAT_RGB96F,
353 #endif
354 	  .num_planes = 1, .plane_bpp = { 64, },
355 	  .hsub = 1, .vsub = 1,
356 	},
357 	{ .name = "P010", .depth = -1, .drm_id = DRM_FORMAT_P010,
358 #if defined(USE_CAIRO_PIXMAN)
359 	  .cairo_id = CAIRO_FORMAT_RGB96F,
360 #endif
361 	  .num_planes = 2, .plane_bpp = { 16, 32 },
362 	  .vsub = 2, .hsub = 2,
363 	},
364 	{ .name = "P012", .depth = -1, .drm_id = DRM_FORMAT_P012,
365 #if defined(USE_CAIRO_PIXMAN)
366 	  .cairo_id = CAIRO_FORMAT_RGB96F,
367 #endif
368 	  .num_planes = 2, .plane_bpp = { 16, 32 },
369 	  .vsub = 2, .hsub = 2,
370 	},
371 	{ .name = "P016", .depth = -1, .drm_id = DRM_FORMAT_P016,
372 #if defined(USE_CAIRO_PIXMAN)
373 	  .cairo_id = CAIRO_FORMAT_RGB96F,
374 #endif
375 	  .num_planes = 2, .plane_bpp = { 16, 32 },
376 	  .vsub = 2, .hsub = 2,
377 	},
378 	{ .name = "Y210", .depth = -1, .drm_id = DRM_FORMAT_Y210,
379 #if defined(USE_CAIRO_PIXMAN)
380 	  .cairo_id = CAIRO_FORMAT_RGB96F,
381 #endif
382 	  .num_planes = 1, .plane_bpp = { 32, },
383 	  .hsub = 2, .vsub = 1,
384 	},
385 	{ .name = "Y212", .depth = -1, .drm_id = DRM_FORMAT_Y212,
386 #if defined(USE_CAIRO_PIXMAN)
387 	  .cairo_id = CAIRO_FORMAT_RGB96F,
388 #endif
389 	  .num_planes = 1, .plane_bpp = { 32, },
390 	  .hsub = 2, .vsub = 1,
391 	},
392 	{ .name = "Y216", .depth = -1, .drm_id = DRM_FORMAT_Y216,
393 #if defined(USE_CAIRO_PIXMAN)
394 	  .cairo_id = CAIRO_FORMAT_RGB96F,
395 #endif
396 	  .num_planes = 1, .plane_bpp = { 32, },
397 	  .hsub = 2, .vsub = 1,
398 	},
399 	{ .name = "IGT-FLOAT", .depth = -1, .drm_id = IGT_FORMAT_FLOAT,
400 #if defined(USE_CAIRO_PIXMAN)
401 	  .cairo_id = CAIRO_FORMAT_INVALID,
402 #endif
403 	  .num_planes = 1, .plane_bpp = { 128 },
404 	},
405 };
406 #define for_each_format(f)	\
407 	for (f = format_desc; f - format_desc < ARRAY_SIZE(format_desc); f++)
408 
lookup_drm_format(uint32_t drm_format)409 static const struct format_desc_struct *lookup_drm_format(uint32_t drm_format)
410 {
411 	const struct format_desc_struct *format;
412 
413 	for_each_format(format) {
414 		if (format->drm_id != drm_format)
415 			continue;
416 
417 		return format;
418 	}
419 
420 	return NULL;
421 }
422 
423 /**
424  * igt_get_fb_tile_size:
425  * @fd: the DRM file descriptor
426  * @modifier: tiling layout of the framebuffer (as framebuffer modifier)
427  * @fb_bpp: bits per pixel of the framebuffer
428  * @width_ret: width of the tile in bytes
429  * @height_ret: height of the tile in lines
430  *
431  * This function returns width and height of a tile based on the given tiling
432  * format.
433  */
igt_get_fb_tile_size(int fd,uint64_t modifier,int fb_bpp,unsigned * width_ret,unsigned * height_ret)434 void igt_get_fb_tile_size(int fd, uint64_t modifier, int fb_bpp,
435 			  unsigned *width_ret, unsigned *height_ret)
436 {
437 	uint32_t vc4_modifier_param = 0;
438 
439 	if (is_vc4_device(fd)) {
440 		vc4_modifier_param = fourcc_mod_broadcom_param(modifier);
441 		modifier = fourcc_mod_broadcom_mod(modifier);
442 	}
443 
444 	switch (modifier) {
445 	case LOCAL_DRM_FORMAT_MOD_NONE:
446 		if (is_i915_device(fd))
447 			*width_ret = 64;
448 		else
449 			*width_ret = 1;
450 
451 		*height_ret = 1;
452 		break;
453 #if defined(USE_INTEL)
454 	case LOCAL_I915_FORMAT_MOD_X_TILED:
455 		igt_require_intel(fd);
456 		if (intel_gen(intel_get_drm_devid(fd)) == 2) {
457 			*width_ret = 128;
458 			*height_ret = 16;
459 		} else {
460 			*width_ret = 512;
461 			*height_ret = 8;
462 		}
463 		break;
464 	case LOCAL_I915_FORMAT_MOD_Y_TILED:
465 	case LOCAL_I915_FORMAT_MOD_Y_TILED_CCS:
466 		igt_require_intel(fd);
467 		if (intel_gen(intel_get_drm_devid(fd)) == 2) {
468 			*width_ret = 128;
469 			*height_ret = 16;
470 		} else if (IS_915(intel_get_drm_devid(fd))) {
471 			*width_ret = 512;
472 			*height_ret = 8;
473 		} else {
474 			*width_ret = 128;
475 			*height_ret = 32;
476 		}
477 		break;
478 	case LOCAL_I915_FORMAT_MOD_Yf_TILED:
479 	case LOCAL_I915_FORMAT_MOD_Yf_TILED_CCS:
480 		igt_require_intel(fd);
481 		switch (fb_bpp) {
482 		case 8:
483 			*width_ret = 64;
484 			*height_ret = 64;
485 			break;
486 		case 16:
487 		case 32:
488 			*width_ret = 128;
489 			*height_ret = 32;
490 			break;
491 		case 64:
492 		case 128:
493 			*width_ret = 256;
494 			*height_ret = 16;
495 			break;
496 		default:
497 			igt_assert(false);
498 		}
499 		break;
500 #endif
501 #if defined(USE_VC4)
502 	case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
503 		igt_require_vc4(fd);
504 		*width_ret = 128;
505 		*height_ret = 32;
506 		break;
507 	case DRM_FORMAT_MOD_BROADCOM_SAND32:
508 		igt_require_vc4(fd);
509 		*width_ret = 32;
510 		*height_ret = vc4_modifier_param;
511 		break;
512 	case DRM_FORMAT_MOD_BROADCOM_SAND64:
513 		igt_require_vc4(fd);
514 		*width_ret = 64;
515 		*height_ret = vc4_modifier_param;
516 		break;
517 	case DRM_FORMAT_MOD_BROADCOM_SAND128:
518 		igt_require_vc4(fd);
519 		*width_ret = 128;
520 		*height_ret = vc4_modifier_param;
521 		break;
522 	case DRM_FORMAT_MOD_BROADCOM_SAND256:
523 		igt_require_vc4(fd);
524 		*width_ret = 256;
525 		*height_ret = vc4_modifier_param;
526 		break;
527 #endif
528 	default:
529 		igt_assert(false);
530 	}
531 }
532 
is_ccs_modifier(uint64_t modifier)533 static bool is_ccs_modifier(uint64_t modifier)
534 {
535 	return modifier == LOCAL_I915_FORMAT_MOD_Y_TILED_CCS ||
536 		modifier == LOCAL_I915_FORMAT_MOD_Yf_TILED_CCS;
537 }
538 
fb_plane_width(const struct igt_fb * fb,int plane)539 static unsigned fb_plane_width(const struct igt_fb *fb, int plane)
540 {
541 	const struct format_desc_struct *format = lookup_drm_format(fb->drm_format);
542 
543 	if (is_ccs_modifier(fb->modifier) && plane == 1)
544 		return DIV_ROUND_UP(fb->width, 1024) * 128;
545 
546 	if (plane == 0)
547 		return fb->width;
548 
549 	return DIV_ROUND_UP(fb->width, format->hsub);
550 }
551 
fb_plane_bpp(const struct igt_fb * fb,int plane)552 static unsigned fb_plane_bpp(const struct igt_fb *fb, int plane)
553 {
554 	const struct format_desc_struct *format = lookup_drm_format(fb->drm_format);
555 
556 	if (is_ccs_modifier(fb->modifier) && plane == 1)
557 		return 8;
558 	else
559 		return format->plane_bpp[plane];
560 }
561 
fb_plane_height(const struct igt_fb * fb,int plane)562 static unsigned fb_plane_height(const struct igt_fb *fb, int plane)
563 {
564 	const struct format_desc_struct *format = lookup_drm_format(fb->drm_format);
565 
566 	if (is_ccs_modifier(fb->modifier) && plane == 1)
567 		return DIV_ROUND_UP(fb->height, 512) * 32;
568 
569 	if (plane == 0)
570 		return fb->height;
571 
572 	return DIV_ROUND_UP(fb->height, format->vsub);
573 }
574 
fb_num_planes(const struct igt_fb * fb)575 static int fb_num_planes(const struct igt_fb *fb)
576 {
577 	const struct format_desc_struct *format = lookup_drm_format(fb->drm_format);
578 
579 	if (is_ccs_modifier(fb->modifier))
580 		return 2;
581 	else
582 		return format->num_planes;
583 }
584 
igt_init_fb(struct igt_fb * fb,int fd,int width,int height,uint32_t drm_format,uint64_t modifier,enum igt_color_encoding color_encoding,enum igt_color_range color_range)585 void igt_init_fb(struct igt_fb *fb, int fd, int width, int height,
586 		 uint32_t drm_format, uint64_t modifier,
587 		 enum igt_color_encoding color_encoding,
588 		 enum igt_color_range color_range)
589 {
590 	const struct format_desc_struct *f = lookup_drm_format(drm_format);
591 
592 	igt_assert_f(f, "DRM format %08x not found\n", drm_format);
593 
594 	memset(fb, 0, sizeof(*fb));
595 
596 	fb->width = width;
597 	fb->height = height;
598 	fb->modifier = modifier;
599 	fb->drm_format = drm_format;
600 	fb->fd = fd;
601 	fb->num_planes = fb_num_planes(fb);
602 	fb->color_encoding = color_encoding;
603 	fb->color_range = color_range;
604 
605 	for (int i = 0; i < fb->num_planes; i++) {
606 		fb->plane_bpp[i] = fb_plane_bpp(fb, i);
607 		fb->plane_height[i] = fb_plane_height(fb, i);
608 		fb->plane_width[i] = fb_plane_width(fb, i);
609 	}
610 }
611 
calc_plane_stride(struct igt_fb * fb,int plane)612 static uint32_t calc_plane_stride(struct igt_fb *fb, int plane)
613 {
614 	uint32_t min_stride = fb->plane_width[plane] *
615 		(fb->plane_bpp[plane] / 8);
616 
617 	if (fb->modifier != LOCAL_DRM_FORMAT_MOD_NONE &&
618 	    is_i915_device(fb->fd) &&
619 	    intel_gen(intel_get_drm_devid(fb->fd)) <= 3) {
620 		uint32_t stride;
621 
622 		/* Round the tiling up to the next power-of-two and the region
623 		 * up to the next pot fence size so that this works on all
624 		 * generations.
625 		 *
626 		 * This can still fail if the framebuffer is too large to be
627 		 * tiled. But then that failure is expected.
628 		 */
629 
630 		stride = max(min_stride, 512);
631 		stride = roundup_power_of_two(stride);
632 
633 		return stride;
634 	} else if (igt_format_is_yuv(fb->drm_format) && is_amdgpu_device(fb->fd)) {
635 		/*
636 		 * Chroma address needs to be aligned to 256 bytes on AMDGPU
637 		 * so the easiest way is to align the luma stride to 256.
638 		 */
639 		return ALIGN(min_stride, 256);
640 	} else {
641 		unsigned int tile_width, tile_height;
642 
643 		igt_get_fb_tile_size(fb->fd, fb->modifier, fb->plane_bpp[plane],
644 				     &tile_width, &tile_height);
645 
646 		return ALIGN(min_stride, tile_width);
647 	}
648 }
649 
calc_plane_size(struct igt_fb * fb,int plane)650 static uint64_t calc_plane_size(struct igt_fb *fb, int plane)
651 {
652 	if (fb->modifier != LOCAL_DRM_FORMAT_MOD_NONE &&
653 	    is_i915_device(fb->fd) &&
654 	    intel_gen(intel_get_drm_devid(fb->fd)) <= 3) {
655 		uint64_t min_size = (uint64_t) fb->strides[plane] *
656 			fb->plane_height[plane];
657 		uint64_t size;
658 
659 		/* Round the tiling up to the next power-of-two and the region
660 		 * up to the next pot fence size so that this works on all
661 		 * generations.
662 		 *
663 		 * This can still fail if the framebuffer is too large to be
664 		 * tiled. But then that failure is expected.
665 		 */
666 
667 		size = max(min_size, 1024*1024);
668 		size = roundup_power_of_two(size);
669 
670 		return size;
671 	} else {
672 		unsigned int tile_width, tile_height;
673 
674 		igt_get_fb_tile_size(fb->fd, fb->modifier, fb->plane_bpp[plane],
675 				     &tile_width, &tile_height);
676 
677 		/* Special case where the "tile height" represents a
678 		 * height-based stride, such as with VC4 SAND tiling modes.
679 		 */
680 
681 		if (tile_height > fb->plane_height[plane])
682 			return fb->strides[plane] * tile_height;
683 
684 		return (uint64_t) fb->strides[plane] *
685 			ALIGN(fb->plane_height[plane], tile_height);
686 	}
687 }
688 
calc_fb_size(struct igt_fb * fb)689 static uint64_t calc_fb_size(struct igt_fb *fb)
690 {
691 	uint64_t size = 0;
692 	int plane;
693 
694 	for (plane = 0; plane < fb->num_planes; plane++) {
695 		/* respect the stride requested by the caller */
696 		if (!fb->strides[plane])
697 			fb->strides[plane] = calc_plane_stride(fb, plane);
698 
699 		fb->offsets[plane] = size;
700 
701 		size += calc_plane_size(fb, plane);
702 	}
703 
704 	return size;
705 }
706 
707 /**
708  * igt_calc_fb_size:
709  * @fd: the DRM file descriptor
710  * @width: width of the framebuffer in pixels
711  * @height: height of the framebuffer in pixels
712  * @format: drm fourcc pixel format code
713  * @modifier: tiling layout of the framebuffer (as framebuffer modifier)
714  * @size_ret: returned size for the framebuffer
715  * @stride_ret: returned stride for the framebuffer
716  *
717  * This function returns valid stride and size values for a framebuffer with the
718  * specified parameters.
719  */
igt_calc_fb_size(int fd,int width,int height,uint32_t drm_format,uint64_t modifier,uint64_t * size_ret,unsigned * stride_ret)720 void igt_calc_fb_size(int fd, int width, int height, uint32_t drm_format, uint64_t modifier,
721 		      uint64_t *size_ret, unsigned *stride_ret)
722 {
723 	struct igt_fb fb;
724 
725 	igt_init_fb(&fb, fd, width, height, drm_format, modifier,
726 		    IGT_COLOR_YCBCR_BT709, IGT_COLOR_YCBCR_LIMITED_RANGE);
727 
728 	fb.size = calc_fb_size(&fb);
729 
730 	if (size_ret)
731 		*size_ret = fb.size;
732 	if (stride_ret)
733 		*stride_ret = fb.strides[0];
734 }
735 
736 /**
737  * igt_fb_mod_to_tiling:
738  * @modifier: DRM framebuffer modifier
739  *
740  * This function converts a DRM framebuffer modifier to its corresponding
741  * tiling constant.
742  *
743  * Returns:
744  * A tiling constant
745  */
igt_fb_mod_to_tiling(uint64_t modifier)746 uint64_t igt_fb_mod_to_tiling(uint64_t modifier)
747 {
748 	switch (modifier) {
749 	case LOCAL_DRM_FORMAT_MOD_NONE:
750 		return I915_TILING_NONE;
751 	case LOCAL_I915_FORMAT_MOD_X_TILED:
752 		return I915_TILING_X;
753 	case LOCAL_I915_FORMAT_MOD_Y_TILED:
754 	case LOCAL_I915_FORMAT_MOD_Y_TILED_CCS:
755 		return I915_TILING_Y;
756 	case LOCAL_I915_FORMAT_MOD_Yf_TILED:
757 	case LOCAL_I915_FORMAT_MOD_Yf_TILED_CCS:
758 		return I915_TILING_Yf;
759 	default:
760 		igt_assert(0);
761 	}
762 }
763 
764 /**
765  * igt_fb_tiling_to_mod:
766  * @tiling: DRM framebuffer tiling
767  *
768  * This function converts a DRM framebuffer tiling to its corresponding
769  * modifier constant.
770  *
771  * Returns:
772  * A modifier constant
773  */
igt_fb_tiling_to_mod(uint64_t tiling)774 uint64_t igt_fb_tiling_to_mod(uint64_t tiling)
775 {
776 	switch (tiling) {
777 	case I915_TILING_NONE:
778 		return LOCAL_DRM_FORMAT_MOD_NONE;
779 	case I915_TILING_X:
780 		return LOCAL_I915_FORMAT_MOD_X_TILED;
781 	case I915_TILING_Y:
782 		return LOCAL_I915_FORMAT_MOD_Y_TILED;
783 	case I915_TILING_Yf:
784 		return LOCAL_I915_FORMAT_MOD_Yf_TILED;
785 	default:
786 		igt_assert(0);
787 	}
788 }
789 
memset64(uint64_t * s,uint64_t c,size_t n)790 static void memset64(uint64_t *s, uint64_t c, size_t n)
791 {
792 	for (int i = 0; i < n; i++)
793 		s[i] = c;
794 }
795 
clear_yuv_buffer(struct igt_fb * fb)796 static void clear_yuv_buffer(struct igt_fb *fb)
797 {
798 	bool full_range = fb->color_range == IGT_COLOR_YCBCR_FULL_RANGE;
799 	uint8_t *ptr;
800 
801 	igt_assert(igt_format_is_yuv(fb->drm_format));
802 
803 	/* Ensure the framebuffer is preallocated */
804 	ptr = igt_fb_map_buffer(fb->fd, fb);
805 	igt_assert(*(uint32_t *)ptr == 0);
806 
807 	switch (fb->drm_format) {
808 	case DRM_FORMAT_NV12:
809 		memset(ptr + fb->offsets[0],
810 		       full_range ? 0x00 : 0x10,
811 		       fb->strides[0] * fb->plane_height[0]);
812 		memset(ptr + fb->offsets[1],
813 		       0x80,
814 		       fb->strides[1] * fb->plane_height[1]);
815 		break;
816 	case DRM_FORMAT_XYUV8888:
817 		wmemset((wchar_t*)(ptr + fb->offsets[0]), full_range ? 0x00008080 : 0x00108080,
818 			fb->strides[0] * fb->plane_height[0] / sizeof(wchar_t));
819 		break;
820 	case DRM_FORMAT_YUYV:
821 	case DRM_FORMAT_YVYU:
822 		wmemset((wchar_t*)(ptr + fb->offsets[0]),
823 			full_range ? 0x80008000 : 0x80108010,
824 			fb->strides[0] * fb->plane_height[0] / sizeof(wchar_t));
825 		break;
826 	case DRM_FORMAT_UYVY:
827 	case DRM_FORMAT_VYUY:
828 		wmemset((wchar_t*)(ptr + fb->offsets[0]),
829 			full_range ? 0x00800080 : 0x10801080,
830 			fb->strides[0] * fb->plane_height[0] / sizeof(wchar_t));
831 		break;
832 	case DRM_FORMAT_P010:
833 	case DRM_FORMAT_P012:
834 	case DRM_FORMAT_P016:
835 		wmemset((wchar_t*)ptr, full_range ? 0 : 0x10001000,
836 			fb->offsets[1] / sizeof(wchar_t));
837 		wmemset((wchar_t*)(ptr + fb->offsets[1]), 0x80008000,
838 			fb->strides[1] * fb->plane_height[1] / sizeof(wchar_t));
839 		break;
840 	case DRM_FORMAT_Y210:
841 	case DRM_FORMAT_Y212:
842 	case DRM_FORMAT_Y216:
843 		wmemset((wchar_t*)(ptr + fb->offsets[0]),
844 			full_range ? 0x80000000 : 0x80001000,
845 			fb->strides[0] * fb->plane_height[0] / sizeof(wchar_t));
846 		break;
847 
848 	case DRM_FORMAT_XVYU2101010:
849 	case DRM_FORMAT_Y410:
850 		wmemset((wchar_t*)(ptr + fb->offsets[0]),
851 			full_range ? 0x20000200 : 0x20010200,
852 		fb->strides[0] * fb->plane_height[0] / sizeof(wchar_t));
853 		break;
854 
855 	case DRM_FORMAT_XVYU12_16161616:
856 	case DRM_FORMAT_XVYU16161616:
857 	case DRM_FORMAT_Y412:
858 	case DRM_FORMAT_Y416:
859 		memset64((uint64_t*)(ptr + fb->offsets[0]),
860 			 full_range ? 0x800000008000ULL : 0x800010008000ULL,
861 			 fb->strides[0] * fb->plane_height[0] / sizeof(uint64_t));
862 		break;
863 	}
864 
865 	igt_fb_unmap_buffer(fb, ptr);
866 }
867 
868 /* helpers to create nice-looking framebuffers */
create_bo_for_fb(struct igt_fb * fb)869 static int create_bo_for_fb(struct igt_fb *fb)
870 {
871 	const struct format_desc_struct *fmt = lookup_drm_format(fb->drm_format);
872 	unsigned int bpp = 0;
873 	unsigned int plane;
874 	unsigned *strides = &fb->strides[0];
875 	bool device_bo = false;
876 	int fd = fb->fd;
877 	uint64_t size;
878 
879 	/*
880 	 * The current dumb buffer allocation API doesn't really allow to
881 	 * specify a custom size or stride. Yet the caller is free to specify
882 	 * them, so we need to make sure to use a device BO then.
883 	 */
884 	if (fb->modifier || fb->size || fb->strides[0] ||
885 	    (is_i915_device(fd) && igt_format_is_yuv(fb->drm_format)) ||
886 	    (is_i915_device(fd) && igt_format_is_fp16(fb->drm_format)) ||
887 	    (is_amdgpu_device(fd) && igt_format_is_yuv(fb->drm_format)))
888 		device_bo = true;
889 
890 	/* Sets offets and stride if necessary. */
891 	size = calc_fb_size(fb);
892 
893 	/* Respect the size requested by the caller. */
894 	if (fb->size == 0)
895 		fb->size = size;
896 
897 	if (device_bo) {
898 		fb->is_dumb = false;
899 
900 		if (is_i915_device(fd)) {
901 			fb->gem_handle = gem_create(fd, fb->size);
902 			gem_set_tiling(fd, fb->gem_handle,
903 				       igt_fb_mod_to_tiling(fb->modifier),
904 				       fb->strides[0]);
905 #if defined(USE_VC4)
906 		} else if (is_vc4_device(fd)) {
907 			fb->gem_handle = igt_vc4_create_bo(fd, fb->size);
908 
909 			if (fb->modifier == DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED)
910 				igt_vc4_set_tiling(fd, fb->gem_handle,
911 						   fb->modifier);
912 #endif
913 #if defined(USE_AMD)
914 		} else if (is_amdgpu_device(fd)) {
915 			fb->gem_handle = igt_amd_create_bo(fd, fb->size);
916 #endif
917 		} else {
918 			igt_assert(false);
919 		}
920 
921 		goto out;
922 	}
923 
924 	for (plane = 0; plane < fb->num_planes; plane++)
925 		bpp += DIV_ROUND_UP(fb->plane_bpp[plane],
926 				    plane ? fmt->hsub * fmt->vsub : 1);
927 
928 	fb->is_dumb = true;
929 
930 	/*
931 	 * We can't really pass the stride array here since the dumb
932 	 * buffer allocation is assuming that it operates on one
933 	 * plane, and therefore will calculate the stride as if each
934 	 * pixel was stored on a single plane.
935 	 *
936 	 * This might cause issues at some point on drivers that would
937 	 * change the stride of YUV buffers, but we haven't
938 	 * encountered any yet.
939 	 */
940 	if (fb->num_planes > 1)
941 		strides = NULL;
942 
943 	fb->gem_handle = kmstest_dumb_create(fd, fb->width, fb->height,
944 					     bpp, strides, &fb->size);
945 
946 out:
947 	if (igt_format_is_yuv(fb->drm_format))
948 		clear_yuv_buffer(fb);
949 
950 	return fb->gem_handle;
951 }
952 
igt_create_bo_for_fb(int fd,int width,int height,uint32_t format,uint64_t modifier,struct igt_fb * fb)953 void igt_create_bo_for_fb(int fd, int width, int height,
954 			  uint32_t format, uint64_t modifier,
955 			  struct igt_fb *fb /* out */)
956 {
957 	igt_init_fb(fb, fd, width, height, format, modifier,
958 		    IGT_COLOR_YCBCR_BT709, IGT_COLOR_YCBCR_LIMITED_RANGE);
959 	create_bo_for_fb(fb);
960 }
961 
962 /**
963  * igt_create_bo_with_dimensions:
964  * @fd: open drm file descriptor
965  * @width: width of the buffer object in pixels
966  * @height: height of the buffer object in pixels
967  * @format: drm fourcc pixel format code
968  * @modifier: modifier corresponding to the tiling layout of the buffer object
969  * @stride: stride of the buffer object in bytes (0 for automatic stride)
970  * @size_ret: size of the buffer object as created by the kernel
971  * @stride_ret: stride of the buffer object as created by the kernel
972  * @is_dumb: whether the created buffer object is a dumb buffer or not
973  *
974  * This function allocates a gem buffer object matching the requested
975  * properties.
976  *
977  * Returns:
978  * The kms id of the created buffer object.
979  */
igt_create_bo_with_dimensions(int fd,int width,int height,uint32_t format,uint64_t modifier,unsigned stride,uint64_t * size_ret,unsigned * stride_ret,bool * is_dumb)980 int igt_create_bo_with_dimensions(int fd, int width, int height,
981 				  uint32_t format, uint64_t modifier,
982 				  unsigned stride, uint64_t *size_ret,
983 				  unsigned *stride_ret, bool *is_dumb)
984 {
985 	struct igt_fb fb;
986 
987 	igt_init_fb(&fb, fd, width, height, format, modifier,
988 		    IGT_COLOR_YCBCR_BT709, IGT_COLOR_YCBCR_LIMITED_RANGE);
989 
990 	for (int i = 0; i < fb.num_planes; i++)
991 		fb.strides[i] = stride;
992 
993 	create_bo_for_fb(&fb);
994 
995 	if (size_ret)
996 		*size_ret = fb.size;
997 	if (stride_ret)
998 		*stride_ret = fb.strides[0];
999 	if (is_dumb)
1000 		*is_dumb = fb.is_dumb;
1001 
1002 	return fb.gem_handle;
1003 }
1004 
1005 #define get_u16_bit(x, n) 	((x & (1 << n)) >> n )
1006 #define set_u16_bit(x, n, val)	((x & ~(1 << n)) | (val << n))
1007 /*
1008  * update_crc16_dp:
1009  * @crc_old: old 16-bit CRC value to be updated
1010  * @d: input 16-bit data on which to calculate 16-bit CRC
1011  *
1012  * CRC algorithm implementation described in DP 1.4 spec Appendix J
1013  * the 16-bit CRC IBM is applied, with the following polynomial:
1014  *
1015  *       f(x) = x ^ 16 + x ^ 15 + x ^ 2 + 1
1016  *
1017  * the MSB is shifted in first, for any color format that is less than 16 bits
1018  * per component, the LSB is zero-padded.
1019  *
1020  * The following implementation is based on the hardware parallel 16-bit CRC
1021  * generation and ported to C code.
1022  *
1023  * Reference: VESA DisplayPort Standard v1.4, appendix J
1024  *
1025  * Returns:
1026  * updated 16-bit CRC value.
1027  */
update_crc16_dp(uint16_t crc_old,uint16_t d)1028 static uint16_t update_crc16_dp(uint16_t crc_old, uint16_t d)
1029 {
1030 	uint16_t crc_new = 0;	/* 16-bit CRC output */
1031 
1032 	/* internal use */
1033 	uint16_t b = crc_old;
1034 	uint8_t val;
1035 
1036 	/* b[15] */
1037 	val = get_u16_bit(b, 0) ^ get_u16_bit(b, 1) ^ get_u16_bit(b, 2) ^
1038 	      get_u16_bit(b, 3) ^ get_u16_bit(b, 4) ^ get_u16_bit(b, 5) ^
1039 	      get_u16_bit(b, 6) ^ get_u16_bit(b, 7) ^ get_u16_bit(b, 8) ^
1040 	      get_u16_bit(b, 9) ^ get_u16_bit(b, 10) ^ get_u16_bit(b, 11) ^
1041 	      get_u16_bit(b, 12) ^ get_u16_bit(b, 14) ^ get_u16_bit(b, 15) ^
1042 	      get_u16_bit(d, 0) ^ get_u16_bit(d, 1) ^ get_u16_bit(d, 2) ^
1043 	      get_u16_bit(d, 3) ^ get_u16_bit(d, 4) ^ get_u16_bit(d, 5) ^
1044 	      get_u16_bit(d, 6) ^ get_u16_bit(d, 7) ^ get_u16_bit(d, 8) ^
1045 	      get_u16_bit(d, 9) ^ get_u16_bit(d, 10) ^ get_u16_bit(d, 11) ^
1046 	      get_u16_bit(d, 12) ^ get_u16_bit(d, 14) ^ get_u16_bit(d, 15);
1047 	crc_new = set_u16_bit(crc_new, 15, val);
1048 
1049 	/* b[14] */
1050 	val = get_u16_bit(b, 12) ^ get_u16_bit(b, 13) ^
1051 	      get_u16_bit(d, 12) ^ get_u16_bit(d, 13);
1052 	crc_new = set_u16_bit(crc_new, 14, val);
1053 
1054 	/* b[13] */
1055 	val = get_u16_bit(b, 11) ^ get_u16_bit(b, 12) ^
1056 	      get_u16_bit(d, 11) ^ get_u16_bit(d, 12);
1057 	crc_new = set_u16_bit(crc_new, 13, val);
1058 
1059 	/* b[12] */
1060 	val = get_u16_bit(b, 10) ^ get_u16_bit(b, 11) ^
1061 	      get_u16_bit(d, 10) ^ get_u16_bit(d, 11);
1062 	crc_new = set_u16_bit(crc_new, 12, val);
1063 
1064 	/* b[11] */
1065 	val = get_u16_bit(b, 9) ^ get_u16_bit(b, 10) ^
1066 	      get_u16_bit(d, 9) ^ get_u16_bit(d, 10);
1067 	crc_new = set_u16_bit(crc_new, 11, val);
1068 
1069 	/* b[10] */
1070 	val = get_u16_bit(b, 8) ^ get_u16_bit(b, 9) ^
1071 	      get_u16_bit(d, 8) ^ get_u16_bit(d, 9);
1072 	crc_new = set_u16_bit(crc_new, 10, val);
1073 
1074 	/* b[9] */
1075 	val = get_u16_bit(b, 7) ^ get_u16_bit(b, 8) ^
1076 	      get_u16_bit(d, 7) ^ get_u16_bit(d, 8);
1077 	crc_new = set_u16_bit(crc_new, 9, val);
1078 
1079 	/* b[8] */
1080 	val = get_u16_bit(b, 6) ^ get_u16_bit(b, 7) ^
1081 	      get_u16_bit(d, 6) ^ get_u16_bit(d, 7);
1082 	crc_new = set_u16_bit(crc_new, 8, val);
1083 
1084 	/* b[7] */
1085 	val = get_u16_bit(b, 5) ^ get_u16_bit(b, 6) ^
1086 	      get_u16_bit(d, 5) ^ get_u16_bit(d, 6);
1087 	crc_new = set_u16_bit(crc_new, 7, val);
1088 
1089 	/* b[6] */
1090 	val = get_u16_bit(b, 4) ^ get_u16_bit(b, 5) ^
1091 	      get_u16_bit(d, 4) ^ get_u16_bit(d, 5);
1092 	crc_new = set_u16_bit(crc_new, 6, val);
1093 
1094 	/* b[5] */
1095 	val = get_u16_bit(b, 3) ^ get_u16_bit(b, 4) ^
1096 	      get_u16_bit(d, 3) ^ get_u16_bit(d, 4);
1097 	crc_new = set_u16_bit(crc_new, 5, val);
1098 
1099 	/* b[4] */
1100 	val = get_u16_bit(b, 2) ^ get_u16_bit(b, 3) ^
1101 	      get_u16_bit(d, 2) ^ get_u16_bit(d, 3);
1102 	crc_new = set_u16_bit(crc_new, 4, val);
1103 
1104 	/* b[3] */
1105 	val = get_u16_bit(b, 1) ^ get_u16_bit(b, 2) ^ get_u16_bit(b, 15) ^
1106 	      get_u16_bit(d, 1) ^ get_u16_bit(d, 2) ^ get_u16_bit(d, 15);
1107 	crc_new = set_u16_bit(crc_new, 3, val);
1108 
1109 	/* b[2] */
1110 	val = get_u16_bit(b, 0) ^ get_u16_bit(b, 1) ^ get_u16_bit(b, 14) ^
1111 	      get_u16_bit(d, 0) ^ get_u16_bit(d, 1) ^ get_u16_bit(d, 14);
1112 	crc_new = set_u16_bit(crc_new, 2, val);
1113 
1114 	/* b[1] */
1115 	val = get_u16_bit(b, 1) ^ get_u16_bit(b, 2) ^ get_u16_bit(b, 3) ^
1116 	      get_u16_bit(b, 4) ^ get_u16_bit(b, 5) ^ get_u16_bit(b, 6) ^
1117 	      get_u16_bit(b, 7) ^ get_u16_bit(b, 8) ^ get_u16_bit(b, 9) ^
1118 	      get_u16_bit(b, 10) ^ get_u16_bit(b, 11) ^ get_u16_bit(b, 12) ^
1119 	      get_u16_bit(b, 13) ^ get_u16_bit(b, 14) ^
1120 	      get_u16_bit(d, 1) ^ get_u16_bit(d, 2) ^ get_u16_bit(d, 3) ^
1121 	      get_u16_bit(d, 4) ^ get_u16_bit(d, 5) ^ get_u16_bit(d, 6) ^
1122 	      get_u16_bit(d, 7) ^ get_u16_bit(d, 8) ^ get_u16_bit(d, 9) ^
1123 	      get_u16_bit(d, 10) ^ get_u16_bit(d, 11) ^ get_u16_bit(d, 12) ^
1124 	      get_u16_bit(d, 13) ^ get_u16_bit(d, 14);
1125 	crc_new = set_u16_bit(crc_new, 1, val);
1126 
1127 	/* b[0] */
1128 	val = get_u16_bit(b, 0) ^ get_u16_bit(b, 1) ^ get_u16_bit(b, 2) ^
1129 	      get_u16_bit(b, 3) ^ get_u16_bit(b, 4) ^ get_u16_bit(b, 5) ^
1130 	      get_u16_bit(b, 6) ^ get_u16_bit(b, 7) ^ get_u16_bit(b, 8) ^
1131 	      get_u16_bit(b, 9) ^ get_u16_bit(b, 10) ^ get_u16_bit(b, 11) ^
1132 	      get_u16_bit(b, 12) ^ get_u16_bit(b, 13) ^ get_u16_bit(b, 15) ^
1133 	      get_u16_bit(d, 0) ^ get_u16_bit(d, 1) ^ get_u16_bit(d, 2) ^
1134 	      get_u16_bit(d, 3) ^ get_u16_bit(d, 4) ^ get_u16_bit(d, 5) ^
1135 	      get_u16_bit(d, 6) ^ get_u16_bit(d, 7) ^ get_u16_bit(d, 8) ^
1136 	      get_u16_bit(d, 9) ^ get_u16_bit(d, 10) ^ get_u16_bit(d, 11) ^
1137 	      get_u16_bit(d, 12) ^ get_u16_bit(d, 13) ^ get_u16_bit(d, 15);
1138 	crc_new = set_u16_bit(crc_new, 0, val);
1139 
1140 	return crc_new;
1141 }
1142 
1143 /**
1144  * igt_fb_calc_crc:
1145  * @fb: pointer to an #igt_fb structure
1146  * @crc: pointer to an #igt_crc_t structure
1147  *
1148  * This function calculate the 16-bit frame CRC of RGB components over all
1149  * the active pixels.
1150  */
igt_fb_calc_crc(struct igt_fb * fb,igt_crc_t * crc)1151 void igt_fb_calc_crc(struct igt_fb *fb, igt_crc_t *crc)
1152 {
1153 	int x, y, i;
1154 	uint8_t *ptr;
1155 	uint8_t *data;
1156 	uint16_t din;
1157 
1158 	igt_assert(fb && crc);
1159 
1160 	ptr = igt_fb_map_buffer(fb->fd, fb);
1161 	igt_assert(ptr);
1162 
1163 	/* set for later CRC comparison */
1164 	crc->has_valid_frame = true;
1165 	crc->frame = 0;
1166 	crc->n_words = 3;
1167 	crc->crc[0] = 0;	/* R */
1168 	crc->crc[1] = 0;	/* G */
1169 	crc->crc[2] = 0;	/* B */
1170 
1171 	data = ptr + fb->offsets[0];
1172 	for (y = 0; y < fb->height; ++y) {
1173 		for (x = 0; x < fb->width; ++x) {
1174 			switch (fb->drm_format) {
1175 			case DRM_FORMAT_XRGB8888:
1176 				i = x * 4 + y * fb->strides[0];
1177 
1178 				din = data[i + 2] << 8; /* padding-zeros */
1179 				crc->crc[0] = update_crc16_dp(crc->crc[0], din);
1180 
1181 				/* Green-component */
1182 				din = data[i + 1] << 8;
1183 				crc->crc[1] = update_crc16_dp(crc->crc[1], din);
1184 
1185 				/* Blue-component */
1186 				din = data[i] << 8;
1187 				crc->crc[2] = update_crc16_dp(crc->crc[2], din);
1188 				break;
1189 			default:
1190 				igt_assert_f(0, "DRM Format Invalid");
1191 				break;
1192 			}
1193 		}
1194 	}
1195 
1196 	igt_fb_unmap_buffer(fb, ptr);
1197 }
1198 
1199 #if defined(USE_CAIRO_PIXMAN)
1200 /**
1201  * igt_paint_color:
1202  * @cr: cairo drawing context
1203  * @x: pixel x-coordination of the fill rectangle
1204  * @y: pixel y-coordination of the fill rectangle
1205  * @w: width of the fill rectangle
1206  * @h: height of the fill rectangle
1207  * @r: red value to use as fill color
1208  * @g: green value to use as fill color
1209  * @b: blue value to use as fill color
1210  *
1211  * This functions draws a solid rectangle with the given color using the drawing
1212  * context @cr.
1213  */
igt_paint_color(cairo_t * cr,int x,int y,int w,int h,double r,double g,double b)1214 void igt_paint_color(cairo_t *cr, int x, int y, int w, int h,
1215 		     double r, double g, double b)
1216 {
1217 	cairo_rectangle(cr, x, y, w, h);
1218 	cairo_set_source_rgb(cr, r, g, b);
1219 	cairo_fill(cr);
1220 }
1221 
1222 /**
1223  * igt_paint_color_alpha:
1224  * @cr: cairo drawing context
1225  * @x: pixel x-coordination of the fill rectangle
1226  * @y: pixel y-coordination of the fill rectangle
1227  * @w: width of the fill rectangle
1228  * @h: height of the fill rectangle
1229  * @r: red value to use as fill color
1230  * @g: green value to use as fill color
1231  * @b: blue value to use as fill color
1232  * @a: alpha value to use as fill color
1233  *
1234  * This functions draws a rectangle with the given color and alpha values using
1235  * the drawing context @cr.
1236  */
igt_paint_color_alpha(cairo_t * cr,int x,int y,int w,int h,double r,double g,double b,double a)1237 void igt_paint_color_alpha(cairo_t *cr, int x, int y, int w, int h,
1238 			   double r, double g, double b, double a)
1239 {
1240 	cairo_rectangle(cr, x, y, w, h);
1241 	cairo_set_source_rgba(cr, r, g, b, a);
1242 	cairo_fill(cr);
1243 }
1244 
1245 /**
1246  * igt_paint_color_gradient:
1247  * @cr: cairo drawing context
1248  * @x: pixel x-coordination of the fill rectangle
1249  * @y: pixel y-coordination of the fill rectangle
1250  * @w: width of the fill rectangle
1251  * @h: height of the fill rectangle
1252  * @r: red value to use as fill color
1253  * @g: green value to use as fill color
1254  * @b: blue value to use as fill color
1255  *
1256  * This functions draws a gradient into the rectangle which fades in from black
1257  * to the given values using the drawing context @cr.
1258  */
1259 void
igt_paint_color_gradient(cairo_t * cr,int x,int y,int w,int h,int r,int g,int b)1260 igt_paint_color_gradient(cairo_t *cr, int x, int y, int w, int h,
1261 			 int r, int g, int b)
1262 {
1263 	cairo_pattern_t *pat;
1264 
1265 	pat = cairo_pattern_create_linear(x, y, x + w, y + h);
1266 	cairo_pattern_add_color_stop_rgba(pat, 1, 0, 0, 0, 1);
1267 	cairo_pattern_add_color_stop_rgba(pat, 0, r, g, b, 1);
1268 
1269 	cairo_rectangle(cr, x, y, w, h);
1270 	cairo_set_source(cr, pat);
1271 	cairo_fill(cr);
1272 	cairo_pattern_destroy(pat);
1273 }
1274 
1275 /**
1276  * igt_paint_color_gradient_range:
1277  * @cr: cairo drawing context
1278  * @x: pixel x-coordination of the fill rectangle
1279  * @y: pixel y-coordination of the fill rectangle
1280  * @w: width of the fill rectangle
1281  * @h: height of the fill rectangle
1282  * @sr: red value to use as start gradient color
1283  * @sg: green value to use as start gradient color
1284  * @sb: blue value to use as start gradient color
1285  * @er: red value to use as end gradient color
1286  * @eg: green value to use as end gradient color
1287  * @eb: blue value to use as end gradient color
1288  *
1289  * This functions draws a gradient into the rectangle which fades in
1290  * from one color to the other using the drawing context @cr.
1291  */
1292 void
igt_paint_color_gradient_range(cairo_t * cr,int x,int y,int w,int h,double sr,double sg,double sb,double er,double eg,double eb)1293 igt_paint_color_gradient_range(cairo_t *cr, int x, int y, int w, int h,
1294 			       double sr, double sg, double sb,
1295 			       double er, double eg, double eb)
1296 {
1297 	cairo_pattern_t *pat;
1298 
1299 	pat = cairo_pattern_create_linear(x, y, x + w, y + h);
1300 	cairo_pattern_add_color_stop_rgba(pat, 1, sr, sg, sb, 1);
1301 	cairo_pattern_add_color_stop_rgba(pat, 0, er, eg, eb, 1);
1302 
1303 	cairo_rectangle(cr, x, y, w, h);
1304 	cairo_set_source(cr, pat);
1305 	cairo_fill(cr);
1306 	cairo_pattern_destroy(pat);
1307 }
1308 
1309 static void
paint_test_patterns(cairo_t * cr,int width,int height)1310 paint_test_patterns(cairo_t *cr, int width, int height)
1311 {
1312 	double gr_height, gr_width;
1313 	int x, y;
1314 
1315 	y = height * 0.10;
1316 	gr_width = width * 0.75;
1317 	gr_height = height * 0.08;
1318 	x = (width / 2) - (gr_width / 2);
1319 
1320 	igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 1, 0, 0);
1321 
1322 	y += gr_height;
1323 	igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 0, 1, 0);
1324 
1325 	y += gr_height;
1326 	igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 0, 0, 1);
1327 
1328 	y += gr_height;
1329 	igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 1, 1, 1);
1330 }
1331 
1332 /**
1333  * igt_cairo_printf_line:
1334  * @cr: cairo drawing context
1335  * @align: text alignment
1336  * @yspacing: additional y-direction feed after this line
1337  * @fmt: format string
1338  * @...: optional arguments used in the format string
1339  *
1340  * This is a little helper to draw text onto framebuffers. All the initial setup
1341  * (like setting the font size and the moving to the starting position) still
1342  * needs to be done manually with explicit cairo calls on @cr.
1343  *
1344  * Returns:
1345  * The width of the drawn text.
1346  */
igt_cairo_printf_line(cairo_t * cr,enum igt_text_align align,double yspacing,const char * fmt,...)1347 int igt_cairo_printf_line(cairo_t *cr, enum igt_text_align align,
1348 				double yspacing, const char *fmt, ...)
1349 {
1350 	double x, y, xofs, yofs;
1351 	cairo_text_extents_t extents;
1352 	char *text;
1353 	va_list ap;
1354 	int ret;
1355 
1356 	va_start(ap, fmt);
1357 	ret = vasprintf(&text, fmt, ap);
1358 	igt_assert(ret >= 0);
1359 	va_end(ap);
1360 
1361 	cairo_text_extents(cr, text, &extents);
1362 
1363 	xofs = yofs = 0;
1364 	if (align & align_right)
1365 		xofs = -extents.width;
1366 	else if (align & align_hcenter)
1367 		xofs = -extents.width / 2;
1368 
1369 	if (align & align_top)
1370 		yofs = extents.height;
1371 	else if (align & align_vcenter)
1372 		yofs = extents.height / 2;
1373 
1374 	cairo_get_current_point(cr, &x, &y);
1375 	if (xofs || yofs)
1376 		cairo_rel_move_to(cr, xofs, yofs);
1377 
1378 	cairo_text_path(cr, text);
1379 	cairo_set_source_rgb(cr, 0, 0, 0);
1380 	cairo_stroke_preserve(cr);
1381 	cairo_set_source_rgb(cr, 1, 1, 1);
1382 	cairo_fill(cr);
1383 
1384 	cairo_move_to(cr, x, y + extents.height + yspacing);
1385 
1386 	free(text);
1387 
1388 	return extents.width;
1389 }
1390 
1391 static void
paint_marker(cairo_t * cr,int x,int y)1392 paint_marker(cairo_t *cr, int x, int y)
1393 {
1394 	enum igt_text_align align;
1395 	int xoff, yoff;
1396 
1397 	cairo_move_to(cr, x, y - 20);
1398 	cairo_line_to(cr, x, y + 20);
1399 	cairo_move_to(cr, x - 20, y);
1400 	cairo_line_to(cr, x + 20, y);
1401 	cairo_new_sub_path(cr);
1402 	cairo_arc(cr, x, y, 10, 0, M_PI * 2);
1403 	cairo_set_line_width(cr, 4);
1404 	cairo_set_source_rgb(cr, 0, 0, 0);
1405 	cairo_stroke_preserve(cr);
1406 	cairo_set_source_rgb(cr, 1, 1, 1);
1407 	cairo_set_line_width(cr, 2);
1408 	cairo_stroke(cr);
1409 
1410 	xoff = x ? -20 : 20;
1411 	align = x ? align_right : align_left;
1412 
1413 	yoff = y ? -20 : 20;
1414 	align |= y ? align_bottom : align_top;
1415 
1416 	cairo_move_to(cr, x + xoff, y + yoff);
1417 	cairo_set_font_size(cr, 18);
1418 	igt_cairo_printf_line(cr, align, 0, "(%d, %d)", x, y);
1419 }
1420 
1421 /**
1422  * igt_paint_test_pattern:
1423  * @cr: cairo drawing context
1424  * @width: width of the visible area
1425  * @height: height of the visible area
1426  *
1427  * This functions draws an entire set of test patterns for the given visible
1428  * area using the drawing context @cr. This is useful for manual visual
1429  * inspection of displayed framebuffers.
1430  *
1431  * The test patterns include
1432  *  - corner markers to check for over/underscan and
1433  *  - a set of color and b/w gradients.
1434  */
igt_paint_test_pattern(cairo_t * cr,int width,int height)1435 void igt_paint_test_pattern(cairo_t *cr, int width, int height)
1436 {
1437 	paint_test_patterns(cr, width, height);
1438 
1439 	cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
1440 
1441 	/* Paint corner markers */
1442 	paint_marker(cr, 0, 0);
1443 	paint_marker(cr, width, 0);
1444 	paint_marker(cr, 0, height);
1445 	paint_marker(cr, width, height);
1446 
1447 	igt_assert(!cairo_status(cr));
1448 }
1449 
1450 static cairo_status_t
stdio_read_func(void * closure,unsigned char * data,unsigned int size)1451 stdio_read_func(void *closure, unsigned char* data, unsigned int size)
1452 {
1453 	if (fread(data, 1, size, (FILE*)closure) != size)
1454 		return CAIRO_STATUS_READ_ERROR;
1455 
1456 	return CAIRO_STATUS_SUCCESS;
1457 }
1458 
igt_cairo_image_surface_create_from_png(const char * filename)1459 cairo_surface_t *igt_cairo_image_surface_create_from_png(const char *filename)
1460 {
1461 	cairo_surface_t *image;
1462 	FILE *f;
1463 
1464 	f = igt_fopen_data(filename);
1465 	image = cairo_image_surface_create_from_png_stream(&stdio_read_func, f);
1466 	fclose(f);
1467 
1468 	return image;
1469 }
1470 
1471 /**
1472  * igt_paint_image:
1473  * @cr: cairo drawing context
1474  * @filename: filename of the png image to draw
1475  * @dst_x: pixel x-coordination of the destination rectangle
1476  * @dst_y: pixel y-coordination of the destination rectangle
1477  * @dst_width: width of the destination rectangle
1478  * @dst_height: height of the destination rectangle
1479  *
1480  * This function can be used to draw a scaled version of the supplied png image,
1481  * which is loaded from the package data directory.
1482  */
igt_paint_image(cairo_t * cr,const char * filename,int dst_x,int dst_y,int dst_width,int dst_height)1483 void igt_paint_image(cairo_t *cr, const char *filename,
1484 		     int dst_x, int dst_y, int dst_width, int dst_height)
1485 {
1486 	cairo_surface_t *image;
1487 	int img_width, img_height;
1488 	double scale_x, scale_y;
1489 
1490 	image = igt_cairo_image_surface_create_from_png(filename);
1491 	igt_assert(cairo_surface_status(image) == CAIRO_STATUS_SUCCESS);
1492 
1493 	img_width = cairo_image_surface_get_width(image);
1494 	img_height = cairo_image_surface_get_height(image);
1495 
1496 	scale_x = (double)dst_width / img_width;
1497 	scale_y = (double)dst_height / img_height;
1498 
1499 	cairo_save(cr);
1500 
1501 	cairo_translate(cr, dst_x, dst_y);
1502 	cairo_scale(cr, scale_x, scale_y);
1503 	cairo_set_source_surface(cr, image, 0, 0);
1504 	cairo_paint(cr);
1505 
1506 	cairo_surface_destroy(image);
1507 
1508 	cairo_restore(cr);
1509 }
1510 #endif /*defined(USE_CAIRO_PIXMAN)*/
1511 
1512 /**
1513  * igt_create_fb_with_bo_size:
1514  * @fd: open i915 drm file descriptor
1515  * @width: width of the framebuffer in pixel
1516  * @height: height of the framebuffer in pixel
1517  * @format: drm fourcc pixel format code
1518  * @modifier: tiling layout of the framebuffer (as framebuffer modifier)
1519  * @color_encoding: color encoding for YCbCr formats (ignored otherwise)
1520  * @color_range: color range for YCbCr formats (ignored otherwise)
1521  * @fb: pointer to an #igt_fb structure
1522  * @bo_size: size of the backing bo (0 for automatic size)
1523  * @bo_stride: stride of the backing bo (0 for automatic stride)
1524  *
1525  * This function allocates a gem buffer object suitable to back a framebuffer
1526  * with the requested properties and then wraps it up in a drm framebuffer
1527  * object of the requested size. All metadata is stored in @fb.
1528  *
1529  * The backing storage of the framebuffer is filled with all zeros, i.e. black
1530  * for rgb pixel formats.
1531  *
1532  * Returns:
1533  * The kms id of the created framebuffer.
1534  */
1535 unsigned int
igt_create_fb_with_bo_size(int fd,int width,int height,uint32_t format,uint64_t modifier,enum igt_color_encoding color_encoding,enum igt_color_range color_range,struct igt_fb * fb,uint64_t bo_size,unsigned bo_stride)1536 igt_create_fb_with_bo_size(int fd, int width, int height,
1537 			   uint32_t format, uint64_t modifier,
1538 			   enum igt_color_encoding color_encoding,
1539 			   enum igt_color_range color_range,
1540 			   struct igt_fb *fb, uint64_t bo_size,
1541 			   unsigned bo_stride)
1542 {
1543 	uint32_t flags = 0;
1544 
1545 	igt_init_fb(fb, fd, width, height, format, modifier,
1546 		    color_encoding, color_range);
1547 
1548 	for (int i = 0; i < fb->num_planes; i++)
1549 		fb->strides[i] = bo_stride;
1550 
1551 	fb->size = bo_size;
1552 
1553 	igt_debug("%s(width=%d, height=%d, format=" IGT_FORMAT_FMT
1554 		  ", modifier=0x%"PRIx64", size=%"PRIu64")\n",
1555 		  __func__, width, height, IGT_FORMAT_ARGS(format), modifier,
1556 		  bo_size);
1557 
1558 	create_bo_for_fb(fb);
1559 	igt_assert(fb->gem_handle > 0);
1560 
1561 	igt_debug("%s(handle=%d, pitch=%d)\n",
1562 		  __func__, fb->gem_handle, fb->strides[0]);
1563 
1564 	if (fb->modifier || igt_has_fb_modifiers(fd))
1565 		flags = LOCAL_DRM_MODE_FB_MODIFIERS;
1566 
1567 	do_or_die(__kms_addfb(fb->fd, fb->gem_handle,
1568 			      fb->width, fb->height,
1569 			      fb->drm_format, fb->modifier,
1570 			      fb->strides, fb->offsets, fb->num_planes, flags,
1571 			      &fb->fb_id));
1572 
1573 	return fb->fb_id;
1574 }
1575 
1576 /**
1577  * igt_create_fb:
1578  * @fd: open i915 drm file descriptor
1579  * @width: width of the framebuffer in pixel
1580  * @height: height of the framebuffer in pixel
1581  * @format: drm fourcc pixel format code
1582  * @modifier: tiling layout of the framebuffer
1583  * @fb: pointer to an #igt_fb structure
1584  *
1585  * This function allocates a gem buffer object suitable to back a framebuffer
1586  * with the requested properties and then wraps it up in a drm framebuffer
1587  * object. All metadata is stored in @fb.
1588  *
1589  * The backing storage of the framebuffer is filled with all zeros, i.e. black
1590  * for rgb pixel formats.
1591  *
1592  * Returns:
1593  * The kms id of the created framebuffer.
1594  */
igt_create_fb(int fd,int width,int height,uint32_t format,uint64_t modifier,struct igt_fb * fb)1595 unsigned int igt_create_fb(int fd, int width, int height, uint32_t format,
1596 			   uint64_t modifier, struct igt_fb *fb)
1597 {
1598 	return igt_create_fb_with_bo_size(fd, width, height, format, modifier,
1599 					  IGT_COLOR_YCBCR_BT709,
1600 					  IGT_COLOR_YCBCR_LIMITED_RANGE,
1601 					  fb, 0, 0);
1602 }
1603 
1604 /**
1605  * igt_create_color_fb:
1606  * @fd: open i915 drm file descriptor
1607  * @width: width of the framebuffer in pixel
1608  * @height: height of the framebuffer in pixel
1609  * @format: drm fourcc pixel format code
1610  * @modifier: tiling layout of the framebuffer
1611  * @r: red value to use as fill color
1612  * @g: green value to use as fill color
1613  * @b: blue value to use as fill color
1614  * @fb: pointer to an #igt_fb structure
1615  *
1616  * This function allocates a gem buffer object suitable to back a framebuffer
1617  * with the requested properties and then wraps it up in a drm framebuffer
1618  * object. All metadata is stored in @fb.
1619  *
1620  * Compared to igt_create_fb() this function also fills the entire framebuffer
1621  * with the given color, which is useful for some simple pipe crc based tests.
1622  *
1623  * Returns:
1624  * The kms id of the created framebuffer on success or a negative error code on
1625  * failure.
1626  */
igt_create_color_fb(int fd,int width,int height,uint32_t format,uint64_t modifier,double r,double g,double b,struct igt_fb * fb)1627 unsigned int igt_create_color_fb(int fd, int width, int height,
1628 				 uint32_t format, uint64_t modifier,
1629 				 double r, double g, double b,
1630 				 struct igt_fb *fb /* out */)
1631 {
1632 	unsigned int fb_id;
1633 	cairo_t *cr;
1634 
1635 	fb_id = igt_create_fb(fd, width, height, format, modifier, fb);
1636 	igt_assert(fb_id);
1637 
1638 #if defined(USE_CAIRO_PIXMAN)
1639 	cr = igt_get_cairo_ctx(fd, fb);
1640 	igt_paint_color(cr, 0, 0, width, height, r, g, b);
1641 	igt_put_cairo_ctx(fd, fb, cr);
1642 #endif
1643 
1644 	return fb_id;
1645 }
1646 
1647 /**
1648  * igt_create_pattern_fb:
1649  * @fd: open i915 drm file descriptor
1650  * @width: width of the framebuffer in pixel
1651  * @height: height of the framebuffer in pixel
1652  * @format: drm fourcc pixel format code
1653  * @modifier: tiling layout of the framebuffer
1654  * @fb: pointer to an #igt_fb structure
1655  *
1656  * This function allocates a gem buffer object suitable to back a framebuffer
1657  * with the requested properties and then wraps it up in a drm framebuffer
1658  * object. All metadata is stored in @fb.
1659  *
1660  * Compared to igt_create_fb() this function also draws the standard test pattern
1661  * into the framebuffer.
1662  *
1663  * Returns:
1664  * The kms id of the created framebuffer on success or a negative error code on
1665  * failure.
1666  */
igt_create_pattern_fb(int fd,int width,int height,uint32_t format,uint64_t modifier,struct igt_fb * fb)1667 unsigned int igt_create_pattern_fb(int fd, int width, int height,
1668 				   uint32_t format, uint64_t modifier,
1669 				   struct igt_fb *fb /* out */)
1670 {
1671 	unsigned int fb_id;
1672 	cairo_t *cr;
1673 
1674 	fb_id = igt_create_fb(fd, width, height, format, modifier, fb);
1675 	igt_assert(fb_id);
1676 
1677 #if defined(USE_CAIRO_PIXMAN)
1678 	cr = igt_get_cairo_ctx(fd, fb);
1679 	igt_paint_test_pattern(cr, width, height);
1680 	igt_put_cairo_ctx(fd, fb, cr);
1681 #endif
1682 
1683 	return fb_id;
1684 }
1685 
1686 /**
1687  * igt_create_color_pattern_fb:
1688  * @fd: open i915 drm file descriptor
1689  * @width: width of the framebuffer in pixel
1690  * @height: height of the framebuffer in pixel
1691  * @format: drm fourcc pixel format code
1692  * @modifier: tiling layout of the framebuffer
1693  * @r: red value to use as fill color
1694  * @g: green value to use as fill color
1695  * @b: blue value to use as fill color
1696  * @fb: pointer to an #igt_fb structure
1697  *
1698  * This function allocates a gem buffer object suitable to back a framebuffer
1699  * with the requested properties and then wraps it up in a drm framebuffer
1700  * object. All metadata is stored in @fb.
1701  *
1702  * Compared to igt_create_fb() this function also fills the entire framebuffer
1703  * with the given color, and then draws the standard test pattern into the
1704  * framebuffer.
1705  *
1706  * Returns:
1707  * The kms id of the created framebuffer on success or a negative error code on
1708  * failure.
1709  */
igt_create_color_pattern_fb(int fd,int width,int height,uint32_t format,uint64_t modifier,double r,double g,double b,struct igt_fb * fb)1710 unsigned int igt_create_color_pattern_fb(int fd, int width, int height,
1711 					 uint32_t format, uint64_t modifier,
1712 					 double r, double g, double b,
1713 					 struct igt_fb *fb /* out */)
1714 {
1715 	unsigned int fb_id;
1716 	cairo_t *cr;
1717 
1718 	fb_id = igt_create_fb(fd, width, height, format, modifier, fb);
1719 	igt_assert(fb_id);
1720 
1721 #if defined(USE_CAIRO_PIXMAN)
1722 	cr = igt_get_cairo_ctx(fd, fb);
1723 	igt_paint_color(cr, 0, 0, width, height, r, g, b);
1724 	igt_paint_test_pattern(cr, width, height);
1725 	igt_put_cairo_ctx(fd, fb, cr);
1726 #endif
1727 
1728 	return fb_id;
1729 }
1730 
1731 #if defined(USE_CAIRO_PIXMAN)
1732 /**
1733  * igt_create_image_fb:
1734  * @drm_fd: open i915 drm file descriptor
1735  * @width: width of the framebuffer in pixel or 0
1736  * @height: height of the framebuffer in pixel or 0
1737  * @format: drm fourcc pixel format code
1738  * @modifier: tiling layout of the framebuffer
1739  * @filename: filename of the png image to draw
1740  * @fb: pointer to an #igt_fb structure
1741  *
1742  * Create a framebuffer with the specified image. If @width is zero the
1743  * image width will be used. If @height is zero the image height will be used.
1744  *
1745  * Returns:
1746  * The kms id of the created framebuffer on success or a negative error code on
1747  * failure.
1748  */
igt_create_image_fb(int fd,int width,int height,uint32_t format,uint64_t modifier,const char * filename,struct igt_fb * fb)1749 unsigned int igt_create_image_fb(int fd, int width, int height,
1750 				 uint32_t format, uint64_t modifier,
1751 				 const char *filename,
1752 				 struct igt_fb *fb /* out */)
1753 {
1754 	cairo_surface_t *image;
1755 	uint32_t fb_id;
1756 	cairo_t *cr;
1757 
1758 	image = igt_cairo_image_surface_create_from_png(filename);
1759 	igt_assert(cairo_surface_status(image) == CAIRO_STATUS_SUCCESS);
1760 	if (width == 0)
1761 		width = cairo_image_surface_get_width(image);
1762 	if (height == 0)
1763 		height = cairo_image_surface_get_height(image);
1764 	cairo_surface_destroy(image);
1765 
1766 	fb_id = igt_create_fb(fd, width, height, format, modifier, fb);
1767 
1768 	cr = igt_get_cairo_ctx(fd, fb);
1769 	igt_paint_image(cr, filename, 0, 0, width, height);
1770 	igt_put_cairo_ctx(fd, fb, cr);
1771 
1772 	return fb_id;
1773 }
1774 #endif
1775 
1776 struct box {
1777 	int x, y, width, height;
1778 };
1779 
1780 struct stereo_fb_layout {
1781 	int fb_width, fb_height;
1782 	struct box left, right;
1783 };
1784 
box_init(struct box * box,int x,int y,int bwidth,int bheight)1785 static void box_init(struct box *box, int x, int y, int bwidth, int bheight)
1786 {
1787 	box->x = x;
1788 	box->y = y;
1789 	box->width = bwidth;
1790 	box->height = bheight;
1791 }
1792 
1793 
stereo_fb_layout_from_mode(struct stereo_fb_layout * layout,drmModeModeInfo * mode)1794 static void stereo_fb_layout_from_mode(struct stereo_fb_layout *layout,
1795 				       drmModeModeInfo *mode)
1796 {
1797 	unsigned int format = mode->flags & DRM_MODE_FLAG_3D_MASK;
1798 	const int hdisplay = mode->hdisplay, vdisplay = mode->vdisplay;
1799 	int middle;
1800 
1801 	switch (format) {
1802 	case DRM_MODE_FLAG_3D_TOP_AND_BOTTOM:
1803 		layout->fb_width = hdisplay;
1804 		layout->fb_height = vdisplay;
1805 
1806 		middle = vdisplay / 2;
1807 		box_init(&layout->left, 0, 0, hdisplay, middle);
1808 		box_init(&layout->right,
1809 			 0, middle, hdisplay, vdisplay - middle);
1810 		break;
1811 	case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF:
1812 		layout->fb_width = hdisplay;
1813 		layout->fb_height = vdisplay;
1814 
1815 		middle = hdisplay / 2;
1816 		box_init(&layout->left, 0, 0, middle, vdisplay);
1817 		box_init(&layout->right,
1818 			 middle, 0, hdisplay - middle, vdisplay);
1819 		break;
1820 	case DRM_MODE_FLAG_3D_FRAME_PACKING:
1821 	{
1822 		int vactive_space = mode->vtotal - vdisplay;
1823 
1824 		layout->fb_width = hdisplay;
1825 		layout->fb_height = 2 * vdisplay + vactive_space;
1826 
1827 		box_init(&layout->left,
1828 			 0, 0, hdisplay, vdisplay);
1829 		box_init(&layout->right,
1830 			 0, vdisplay + vactive_space, hdisplay, vdisplay);
1831 		break;
1832 	}
1833 	default:
1834 		igt_assert(0);
1835 	}
1836 }
1837 
1838 /**
1839  * igt_create_stereo_fb:
1840  * @drm_fd: open i915 drm file descriptor
1841  * @mode: A stereo 3D mode.
1842  * @format: drm fourcc pixel format code
1843  * @modifier: tiling layout of the framebuffer
1844  *
1845  * Create a framebuffer for use with the stereo 3D mode specified by @mode.
1846  *
1847  * Returns:
1848  * The kms id of the created framebuffer on success or a negative error code on
1849  * failure.
1850  */
igt_create_stereo_fb(int drm_fd,drmModeModeInfo * mode,uint32_t format,uint64_t modifier)1851 unsigned int igt_create_stereo_fb(int drm_fd, drmModeModeInfo *mode,
1852 				  uint32_t format, uint64_t modifier)
1853 {
1854 	struct stereo_fb_layout layout;
1855 	cairo_t *cr;
1856 	uint32_t fb_id;
1857 	struct igt_fb fb;
1858 
1859 	stereo_fb_layout_from_mode(&layout, mode);
1860 	fb_id = igt_create_fb(drm_fd, layout.fb_width, layout.fb_height, format,
1861 			      modifier, &fb);
1862 	cr = igt_get_cairo_ctx(drm_fd, &fb);
1863 
1864 	igt_paint_image(cr, "1080p-left.png",
1865 			layout.left.x, layout.left.y,
1866 			layout.left.width, layout.left.height);
1867 	igt_paint_image(cr, "1080p-right.png",
1868 			layout.right.x, layout.right.y,
1869 			layout.right.width, layout.right.height);
1870 
1871 	igt_put_cairo_ctx(drm_fd, &fb, cr);
1872 
1873 	return fb_id;
1874 }
1875 
1876 #if defined(USE_CAIRO_PIXMAN)
drm_format_to_pixman(uint32_t drm_format)1877 static pixman_format_code_t drm_format_to_pixman(uint32_t drm_format)
1878 {
1879 	const struct format_desc_struct *f;
1880 
1881 	for_each_format(f)
1882 		if (f->drm_id == drm_format)
1883 			return f->pixman_id;
1884 
1885 	igt_assert_f(0, "can't find a pixman format for %08x (%s)\n",
1886 		     drm_format, igt_format_str(drm_format));
1887 }
1888 
drm_format_to_cairo(uint32_t drm_format)1889 static cairo_format_t drm_format_to_cairo(uint32_t drm_format)
1890 {
1891 	const struct format_desc_struct *f;
1892 
1893 	for_each_format(f)
1894 		if (f->drm_id == drm_format)
1895 			return f->cairo_id;
1896 
1897 	igt_assert_f(0, "can't find a cairo format for %08x (%s)\n",
1898 		     drm_format, igt_format_str(drm_format));
1899 }
1900 #endif
1901 
1902 struct fb_blit_linear {
1903 	struct igt_fb fb;
1904 	uint8_t *map;
1905 };
1906 
1907 struct fb_blit_upload {
1908 	int fd;
1909 	struct igt_fb *fb;
1910 	struct fb_blit_linear linear;
1911 	drm_intel_bufmgr *bufmgr;
1912 	struct intel_batchbuffer *batch;
1913 };
1914 
1915 #if defined(USE_CAIRO_PIXMAN)
blitter_ok(const struct igt_fb * fb)1916 static bool blitter_ok(const struct igt_fb *fb)
1917 {
1918 	for (int i = 0; i < fb->num_planes; i++) {
1919 		/*
1920 		 * gen4+ stride limit is 4x this with tiling,
1921 		 * but since our blits are always between tiled
1922 		 * and linear surfaces (and we do this check just
1923 		 * for the tiled surface) we must use the lower
1924 		 * linear stride limit here.
1925 		 */
1926 		if (fb->plane_width[i] > 32767 ||
1927 		    fb->plane_height[i] > 32767 ||
1928 		    fb->strides[i] > 32767)
1929 			return false;
1930 	}
1931 
1932 	return true;
1933 }
1934 
use_rendercopy(const struct igt_fb * fb)1935 static bool use_rendercopy(const struct igt_fb *fb)
1936 {
1937 	return is_ccs_modifier(fb->modifier) ||
1938 		(fb->modifier == I915_FORMAT_MOD_Yf_TILED &&
1939 		 !blitter_ok(fb));
1940 }
1941 
use_blitter(const struct igt_fb * fb)1942 static bool use_blitter(const struct igt_fb *fb)
1943 {
1944 	return (fb->modifier == I915_FORMAT_MOD_Y_TILED ||
1945 		fb->modifier == I915_FORMAT_MOD_Yf_TILED) &&
1946 		blitter_ok(fb);
1947 }
1948 
init_buf(struct fb_blit_upload * blit,struct igt_buf * buf,const struct igt_fb * fb,const char * name)1949 static void init_buf(struct fb_blit_upload *blit,
1950 		     struct igt_buf *buf,
1951 		     const struct igt_fb *fb,
1952 		     const char *name)
1953 {
1954 	igt_assert_eq(fb->offsets[0], 0);
1955 
1956 	buf->bo = gem_handle_to_libdrm_bo(blit->bufmgr, blit->fd,
1957 					  name, fb->gem_handle);
1958 	buf->tiling = igt_fb_mod_to_tiling(fb->modifier);
1959 	buf->stride = fb->strides[0];
1960 	buf->bpp = fb->plane_bpp[0];
1961 	buf->size = fb->size;
1962 
1963 	if (is_ccs_modifier(fb->modifier)) {
1964 		igt_assert_eq(fb->strides[0] & 127, 0);
1965 		igt_assert_eq(fb->strides[1] & 127, 0);
1966 
1967 		buf->aux.offset = fb->offsets[1];
1968 		buf->aux.stride = fb->strides[1];
1969 	}
1970 }
1971 
fini_buf(struct igt_buf * buf)1972 static void fini_buf(struct igt_buf *buf)
1973 {
1974 	drm_intel_bo_unreference(buf->bo);
1975 }
1976 
rendercopy(struct fb_blit_upload * blit,const struct igt_fb * dst_fb,const struct igt_fb * src_fb)1977 static void rendercopy(struct fb_blit_upload *blit,
1978 		       const struct igt_fb *dst_fb,
1979 		       const struct igt_fb *src_fb)
1980 {
1981 	struct igt_buf src = {}, dst = {};
1982 	igt_render_copyfunc_t render_copy =
1983 		igt_get_render_copyfunc(intel_get_drm_devid(blit->fd));
1984 
1985 	igt_require(render_copy);
1986 
1987 	igt_assert_eq(dst_fb->offsets[0], 0);
1988 	igt_assert_eq(src_fb->offsets[0], 0);
1989 
1990 	init_buf(blit, &src, src_fb, "cairo rendercopy src");
1991 	init_buf(blit, &dst, dst_fb, "cairo rendercopy dst");
1992 
1993 	render_copy(blit->batch, NULL,
1994 		    &src, 0, 0, dst_fb->plane_width[0], dst_fb->plane_height[0],
1995 		    &dst, 0, 0);
1996 
1997 	fini_buf(&dst);
1998 	fini_buf(&src);
1999 }
2000 
blitcopy(const struct igt_fb * dst_fb,const struct igt_fb * src_fb)2001 static void blitcopy(const struct igt_fb *dst_fb,
2002 		     const struct igt_fb *src_fb)
2003 {
2004 	igt_assert_eq(dst_fb->fd, src_fb->fd);
2005 	igt_assert_eq(dst_fb->num_planes, src_fb->num_planes);
2006 
2007 	for (int i = 0; i < dst_fb->num_planes; i++) {
2008 		igt_assert_eq(dst_fb->plane_bpp[i], src_fb->plane_bpp[i]);
2009 		igt_assert_eq(dst_fb->plane_width[i], src_fb->plane_width[i]);
2010 		igt_assert_eq(dst_fb->plane_height[i], src_fb->plane_height[i]);
2011 
2012 		igt_blitter_fast_copy__raw(dst_fb->fd,
2013 					   src_fb->gem_handle,
2014 					   src_fb->offsets[i],
2015 					   src_fb->strides[i],
2016 					   igt_fb_mod_to_tiling(src_fb->modifier),
2017 					   0, 0, /* src_x, src_y */
2018 					   dst_fb->plane_width[i], dst_fb->plane_height[i],
2019 					   dst_fb->plane_bpp[i],
2020 					   dst_fb->gem_handle,
2021 					   dst_fb->offsets[i],
2022 					   dst_fb->strides[i],
2023 					   igt_fb_mod_to_tiling(dst_fb->modifier),
2024 					   0, 0 /* dst_x, dst_y */);
2025 	}
2026 }
2027 
free_linear_mapping(struct fb_blit_upload * blit)2028 static void free_linear_mapping(struct fb_blit_upload *blit)
2029 {
2030 	int fd = blit->fd;
2031 	struct igt_fb *fb = blit->fb;
2032 	struct fb_blit_linear *linear = &blit->linear;
2033 
2034 	if (igt_vc4_is_tiled(fb->modifier)) {
2035 		void *map = igt_vc4_mmap_bo(fd, fb->gem_handle, fb->size, PROT_WRITE);
2036 
2037 		vc4_fb_convert_plane_to_tiled(fb, map, &linear->fb, &linear->map);
2038 
2039 		munmap(map, fb->size);
2040 	} else {
2041 		gem_munmap(linear->map, linear->fb.size);
2042 		gem_set_domain(fd, linear->fb.gem_handle,
2043 			I915_GEM_DOMAIN_GTT, 0);
2044 
2045 		if (blit->batch)
2046 			rendercopy(blit, fb, &linear->fb);
2047 		else
2048 			blitcopy(fb, &linear->fb);
2049 
2050 		gem_sync(fd, linear->fb.gem_handle);
2051 		gem_close(fd, linear->fb.gem_handle);
2052 	}
2053 
2054 	if (blit->batch) {
2055 		intel_batchbuffer_free(blit->batch);
2056 		drm_intel_bufmgr_destroy(blit->bufmgr);
2057 	}
2058 }
2059 
destroy_cairo_surface__gpu(void * arg)2060 static void destroy_cairo_surface__gpu(void *arg)
2061 {
2062 	struct fb_blit_upload *blit = arg;
2063 
2064 	blit->fb->cairo_surface = NULL;
2065 
2066 	free_linear_mapping(blit);
2067 
2068 	free(blit);
2069 }
2070 
setup_linear_mapping(struct fb_blit_upload * blit)2071 static void setup_linear_mapping(struct fb_blit_upload *blit)
2072 {
2073 	int fd = blit->fd;
2074 	struct igt_fb *fb = blit->fb;
2075 	struct fb_blit_linear *linear = &blit->linear;
2076 
2077 	if (!igt_vc4_is_tiled(fb->modifier) && use_rendercopy(fb)) {
2078 		blit->bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
2079 		blit->batch = intel_batchbuffer_alloc(blit->bufmgr,
2080 						      intel_get_drm_devid(fd));
2081 	}
2082 
2083 	/*
2084 	 * We create a linear BO that we'll map for the CPU to write to (using
2085 	 * cairo). This linear bo will be then blitted to its final
2086 	 * destination, tiling it at the same time.
2087 	 */
2088 
2089 	igt_init_fb(&linear->fb, fb->fd, fb->width, fb->height,
2090 		    fb->drm_format, LOCAL_DRM_FORMAT_MOD_NONE,
2091 		    fb->color_encoding, fb->color_range);
2092 
2093 	create_bo_for_fb(&linear->fb);
2094 
2095 	igt_assert(linear->fb.gem_handle > 0);
2096 
2097 	if (igt_vc4_is_tiled(fb->modifier)) {
2098 		void *map = igt_vc4_mmap_bo(fd, fb->gem_handle, fb->size, PROT_READ);
2099 
2100 		linear->map = igt_vc4_mmap_bo(fd, linear->fb.gem_handle,
2101 					      linear->fb.size,
2102 					      PROT_READ | PROT_WRITE);
2103 
2104 		vc4_fb_convert_plane_from_tiled(&linear->fb, &linear->map, fb, map);
2105 
2106 		munmap(map, fb->size);
2107 	} else {
2108 		/* Copy fb content to linear BO */
2109 		gem_set_domain(fd, linear->fb.gem_handle,
2110 				I915_GEM_DOMAIN_GTT, 0);
2111 
2112 		if (blit->batch)
2113 			rendercopy(blit, &linear->fb, fb);
2114 		else
2115 			blitcopy(&linear->fb, fb);
2116 
2117 		gem_sync(fd, linear->fb.gem_handle);
2118 
2119 		gem_set_domain(fd, linear->fb.gem_handle,
2120 			I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
2121 
2122 		/* Setup cairo context */
2123 		linear->map = gem_mmap__cpu(fd, linear->fb.gem_handle,
2124 					0, linear->fb.size, PROT_READ | PROT_WRITE);
2125 	}
2126 }
2127 
create_cairo_surface__gpu(int fd,struct igt_fb * fb)2128 static void create_cairo_surface__gpu(int fd, struct igt_fb *fb)
2129 {
2130 	struct fb_blit_upload *blit;
2131 	cairo_format_t cairo_format;
2132 
2133 	blit = calloc(1, sizeof(*blit));
2134 	igt_assert(blit);
2135 
2136 	blit->fd = fd;
2137 	blit->fb = fb;
2138 	setup_linear_mapping(blit);
2139 
2140 	cairo_format = drm_format_to_cairo(fb->drm_format);
2141 	fb->cairo_surface =
2142 		cairo_image_surface_create_for_data(blit->linear.map,
2143 						    cairo_format,
2144 						    fb->width, fb->height,
2145 						    blit->linear.fb.strides[0]);
2146 	fb->domain = I915_GEM_DOMAIN_GTT;
2147 
2148 	cairo_surface_set_user_data(fb->cairo_surface,
2149 				    (cairo_user_data_key_t *)create_cairo_surface__gpu,
2150 				    blit, destroy_cairo_surface__gpu);
2151 }
2152 #endif /*defined(USE_CAIRO_PIXMAN)*/
2153 
2154 /**
2155  * igt_dirty_fb:
2156  * @fd: open drm file descriptor
2157  * @fb: pointer to an #igt_fb structure
2158  *
2159  * Flushes out the whole framebuffer.
2160  *
2161  * Returns: 0 upon success.
2162  */
igt_dirty_fb(int fd,struct igt_fb * fb)2163 int igt_dirty_fb(int fd, struct igt_fb *fb)
2164 {
2165 	return drmModeDirtyFB(fb->fd, fb->fb_id, NULL, 0);
2166 }
2167 
unmap_bo(struct igt_fb * fb,void * ptr)2168 static void unmap_bo(struct igt_fb *fb, void *ptr)
2169 {
2170 	gem_munmap(ptr, fb->size);
2171 
2172 	if (fb->is_dumb)
2173 		igt_dirty_fb(fb->fd, fb);
2174 }
2175 
2176 #if defined(USE_CAIRO_PIXMAN)
destroy_cairo_surface__gtt(void * arg)2177 static void destroy_cairo_surface__gtt(void *arg)
2178 {
2179 	struct igt_fb *fb = arg;
2180 
2181 	unmap_bo(fb, cairo_image_surface_get_data(fb->cairo_surface));
2182 	fb->cairo_surface = NULL;
2183 }
2184 #endif
2185 
map_bo(int fd,struct igt_fb * fb)2186 static void *map_bo(int fd, struct igt_fb *fb)
2187 {
2188 	void *ptr;
2189 
2190 	if (is_i915_device(fd))
2191 		gem_set_domain(fd, fb->gem_handle,
2192 			       I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
2193 
2194 	if (fb->is_dumb)
2195 		ptr = kmstest_dumb_map_buffer(fd, fb->gem_handle, fb->size,
2196 					      PROT_READ | PROT_WRITE);
2197 	else if (is_i915_device(fd))
2198 		ptr = gem_mmap__gtt(fd, fb->gem_handle, fb->size,
2199 				    PROT_READ | PROT_WRITE);
2200 #if defined(USE_VC4)
2201 	else if (is_vc4_device(fd))
2202 		ptr = igt_vc4_mmap_bo(fd, fb->gem_handle, fb->size,
2203 				      PROT_READ | PROT_WRITE);
2204 #endif
2205 #if defined(USE_AMD)
2206 	else if (is_amdgpu_device(fd))
2207 		ptr = igt_amd_mmap_bo(fd, fb->gem_handle, fb->size,
2208 				      PROT_READ | PROT_WRITE);
2209 #endif
2210 	else
2211 		igt_assert(false);
2212 
2213 	return ptr;
2214 }
2215 
2216 #if defined(USE_CAIRO_PIXMAN)
create_cairo_surface__gtt(int fd,struct igt_fb * fb)2217 static void create_cairo_surface__gtt(int fd, struct igt_fb *fb)
2218 {
2219 	void *ptr = map_bo(fd, fb);
2220 
2221 	fb->cairo_surface =
2222 		cairo_image_surface_create_for_data(ptr,
2223 						    drm_format_to_cairo(fb->drm_format),
2224 						    fb->width, fb->height, fb->strides[0]);
2225 	igt_require_f(cairo_surface_status(fb->cairo_surface) == CAIRO_STATUS_SUCCESS,
2226 		      "Unable to create a cairo surface: %s\n",
2227 		      cairo_status_to_string(cairo_surface_status(fb->cairo_surface)));
2228 
2229 	fb->domain = I915_GEM_DOMAIN_GTT;
2230 
2231 	cairo_surface_set_user_data(fb->cairo_surface,
2232 				    (cairo_user_data_key_t *)create_cairo_surface__gtt,
2233 				    fb, destroy_cairo_surface__gtt);
2234 }
2235 #endif
2236 
2237 struct fb_convert_blit_upload {
2238 	struct fb_blit_upload base;
2239 
2240 	struct igt_fb shadow_fb;
2241 	uint8_t *shadow_ptr;
2242 };
2243 
2244 #if defined(USE_CAIRO_PIXMAN)
igt_fb_create_cairo_shadow_buffer(int fd,unsigned drm_format,unsigned int width,unsigned int height,struct igt_fb * shadow)2245 static void *igt_fb_create_cairo_shadow_buffer(int fd,
2246 					       unsigned drm_format,
2247 					       unsigned int width,
2248 					       unsigned int height,
2249 					       struct igt_fb *shadow)
2250 {
2251 	void *ptr;
2252 
2253 	igt_assert(shadow);
2254 
2255 	igt_init_fb(shadow, fd, width, height,
2256 		    drm_format, LOCAL_DRM_FORMAT_MOD_NONE,
2257 		    IGT_COLOR_YCBCR_BT709, IGT_COLOR_YCBCR_LIMITED_RANGE);
2258 
2259 	shadow->strides[0] = ALIGN(width * (shadow->plane_bpp[0] / 8), 16);
2260 	shadow->size = ALIGN((uint64_t)shadow->strides[0] * height,
2261 			     sysconf(_SC_PAGESIZE));
2262 	ptr = mmap(NULL, shadow->size, PROT_READ | PROT_WRITE,
2263 		   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
2264 	igt_assert(ptr != MAP_FAILED);
2265 
2266 	return ptr;
2267 }
2268 
igt_fb_destroy_cairo_shadow_buffer(struct igt_fb * shadow,void * ptr)2269 static void igt_fb_destroy_cairo_shadow_buffer(struct igt_fb *shadow,
2270 					       void *ptr)
2271 {
2272 	munmap(ptr, shadow->size);
2273 }
2274 
clamprgb(float val)2275 static uint8_t clamprgb(float val)
2276 {
2277 	return clamp((int)(val + 0.5f), 0, 255);
2278 }
2279 
read_rgb(struct igt_vec4 * rgb,const uint8_t * rgb24)2280 static void read_rgb(struct igt_vec4 *rgb, const uint8_t *rgb24)
2281 {
2282 	rgb->d[0] = rgb24[2];
2283 	rgb->d[1] = rgb24[1];
2284 	rgb->d[2] = rgb24[0];
2285 	rgb->d[3] = 1.0f;
2286 }
2287 
write_rgb(uint8_t * rgb24,const struct igt_vec4 * rgb)2288 static void write_rgb(uint8_t *rgb24, const struct igt_vec4 *rgb)
2289 {
2290 	rgb24[2] = clamprgb(rgb->d[0]);
2291 	rgb24[1] = clamprgb(rgb->d[1]);
2292 	rgb24[0] = clamprgb(rgb->d[2]);
2293 }
2294 
2295 struct fb_convert_buf {
2296 	void			*ptr;
2297 	struct igt_fb		*fb;
2298 	bool                     slow_reads;
2299 };
2300 
2301 struct fb_convert {
2302 	struct fb_convert_buf	dst;
2303 	struct fb_convert_buf	src;
2304 };
2305 
convert_src_get(const struct fb_convert * cvt)2306 static void *convert_src_get(const struct fb_convert *cvt)
2307 {
2308 	void *buf;
2309 
2310 	if (!cvt->src.slow_reads)
2311 		return cvt->src.ptr;
2312 
2313 	/*
2314 	 * Reading from the BO is awfully slow because of lack of read caching,
2315 	 * it's faster to copy the whole BO to a temporary buffer and convert
2316 	 * from there.
2317 	 */
2318 	buf = malloc(cvt->src.fb->size);
2319 	if (!buf)
2320 		return cvt->src.ptr;
2321 
2322 	igt_memcpy_from_wc(buf, cvt->src.ptr, cvt->src.fb->size);
2323 
2324 	return buf;
2325 }
2326 
convert_src_put(const struct fb_convert * cvt,void * src_buf)2327 static void convert_src_put(const struct fb_convert *cvt,
2328 			    void *src_buf)
2329 {
2330 	if (src_buf != cvt->src.ptr)
2331 		free(src_buf);
2332 }
2333 
2334 struct yuv_parameters {
2335 	unsigned	ay_inc;
2336 	unsigned	uv_inc;
2337 	unsigned	ay_stride;
2338 	unsigned	uv_stride;
2339 	unsigned	a_offset;
2340 	unsigned	y_offset;
2341 	unsigned	u_offset;
2342 	unsigned	v_offset;
2343 };
2344 
get_yuv_parameters(struct igt_fb * fb,struct yuv_parameters * params)2345 static void get_yuv_parameters(struct igt_fb *fb, struct yuv_parameters *params)
2346 {
2347 	igt_assert(igt_format_is_yuv(fb->drm_format));
2348 
2349 	switch (fb->drm_format) {
2350 	case DRM_FORMAT_NV12:
2351 	case DRM_FORMAT_NV16:
2352 	case DRM_FORMAT_NV21:
2353 	case DRM_FORMAT_NV61:
2354 	case DRM_FORMAT_P010:
2355 	case DRM_FORMAT_P012:
2356 	case DRM_FORMAT_P016:
2357 		params->ay_inc = 1;
2358 		params->uv_inc = 2;
2359 		break;
2360 
2361 	case DRM_FORMAT_YUV420:
2362 	case DRM_FORMAT_YUV422:
2363 	case DRM_FORMAT_YVU420:
2364 	case DRM_FORMAT_YVU422:
2365 		params->ay_inc = 1;
2366 		params->uv_inc = 1;
2367 		break;
2368 
2369 	case DRM_FORMAT_YUYV:
2370 	case DRM_FORMAT_YVYU:
2371 	case DRM_FORMAT_UYVY:
2372 	case DRM_FORMAT_VYUY:
2373 	case DRM_FORMAT_Y210:
2374 	case DRM_FORMAT_Y212:
2375 	case DRM_FORMAT_Y216:
2376 		params->ay_inc = 2;
2377 		params->uv_inc = 4;
2378 		break;
2379 
2380 	case DRM_FORMAT_XVYU12_16161616:
2381 	case DRM_FORMAT_XVYU16161616:
2382 	case DRM_FORMAT_Y412:
2383 	case DRM_FORMAT_Y416:
2384 	case DRM_FORMAT_XYUV8888:
2385 		params->ay_inc = 4;
2386 		params->uv_inc = 4;
2387 		break;
2388 	}
2389 
2390 	switch (fb->drm_format) {
2391 	case DRM_FORMAT_NV12:
2392 	case DRM_FORMAT_NV16:
2393 	case DRM_FORMAT_NV21:
2394 	case DRM_FORMAT_NV61:
2395 	case DRM_FORMAT_YUV420:
2396 	case DRM_FORMAT_YUV422:
2397 	case DRM_FORMAT_YVU420:
2398 	case DRM_FORMAT_YVU422:
2399 	case DRM_FORMAT_P010:
2400 	case DRM_FORMAT_P012:
2401 	case DRM_FORMAT_P016:
2402 		params->ay_stride = fb->strides[0];
2403 		params->uv_stride = fb->strides[1];
2404 		break;
2405 
2406 	case DRM_FORMAT_YUYV:
2407 	case DRM_FORMAT_YVYU:
2408 	case DRM_FORMAT_UYVY:
2409 	case DRM_FORMAT_VYUY:
2410 	case DRM_FORMAT_Y210:
2411 	case DRM_FORMAT_Y212:
2412 	case DRM_FORMAT_Y216:
2413 	case DRM_FORMAT_XYUV8888:
2414 	case DRM_FORMAT_XVYU12_16161616:
2415 	case DRM_FORMAT_XVYU16161616:
2416 	case DRM_FORMAT_Y412:
2417 	case DRM_FORMAT_Y416:
2418 		params->ay_stride = fb->strides[0];
2419 		params->uv_stride = fb->strides[0];
2420 		break;
2421 	}
2422 
2423 	switch (fb->drm_format) {
2424 	case DRM_FORMAT_NV12:
2425 	case DRM_FORMAT_NV16:
2426 		params->y_offset = fb->offsets[0];
2427 		params->u_offset = fb->offsets[1];
2428 		params->v_offset = fb->offsets[1] + 1;
2429 		break;
2430 
2431 	case DRM_FORMAT_NV21:
2432 	case DRM_FORMAT_NV61:
2433 		params->y_offset = fb->offsets[0];
2434 		params->u_offset = fb->offsets[1] + 1;
2435 		params->v_offset = fb->offsets[1];
2436 		break;
2437 
2438 	case DRM_FORMAT_YUV420:
2439 	case DRM_FORMAT_YUV422:
2440 		params->y_offset = fb->offsets[0];
2441 		params->u_offset = fb->offsets[1];
2442 		params->v_offset = fb->offsets[2];
2443 		break;
2444 
2445 	case DRM_FORMAT_YVU420:
2446 	case DRM_FORMAT_YVU422:
2447 		params->y_offset = fb->offsets[0];
2448 		params->u_offset = fb->offsets[2];
2449 		params->v_offset = fb->offsets[1];
2450 		break;
2451 
2452 	case DRM_FORMAT_P010:
2453 	case DRM_FORMAT_P012:
2454 	case DRM_FORMAT_P016:
2455 		params->y_offset = fb->offsets[0];
2456 		params->u_offset = fb->offsets[1];
2457 		params->v_offset = fb->offsets[1] + 2;
2458 		break;
2459 
2460 	case DRM_FORMAT_YUYV:
2461 		params->y_offset = fb->offsets[0];
2462 		params->u_offset = fb->offsets[0] + 1;
2463 		params->v_offset = fb->offsets[0] + 3;
2464 		break;
2465 
2466 	case DRM_FORMAT_YVYU:
2467 		params->y_offset = fb->offsets[0];
2468 		params->u_offset = fb->offsets[0] + 3;
2469 		params->v_offset = fb->offsets[0] + 1;
2470 		break;
2471 
2472 	case DRM_FORMAT_UYVY:
2473 		params->y_offset = fb->offsets[0] + 1;
2474 		params->u_offset = fb->offsets[0];
2475 		params->v_offset = fb->offsets[0] + 2;
2476 		break;
2477 
2478 	case DRM_FORMAT_VYUY:
2479 		params->y_offset = fb->offsets[0] + 1;
2480 		params->u_offset = fb->offsets[0] + 2;
2481 		params->v_offset = fb->offsets[0];
2482 		break;
2483 
2484 	case DRM_FORMAT_Y210:
2485 	case DRM_FORMAT_Y212:
2486 	case DRM_FORMAT_Y216:
2487 		params->y_offset = fb->offsets[0];
2488 		params->u_offset = fb->offsets[0] + 2;
2489 		params->v_offset = fb->offsets[0] + 6;
2490 		break;
2491 
2492 	case DRM_FORMAT_XVYU12_16161616:
2493 	case DRM_FORMAT_XVYU16161616:
2494 	case DRM_FORMAT_Y412:
2495 	case DRM_FORMAT_Y416:
2496 		params->a_offset = fb->offsets[0] + 6;
2497 		params->y_offset = fb->offsets[0] + 2;
2498 		params->u_offset = fb->offsets[0];
2499 		params->v_offset = fb->offsets[0] + 4;
2500 		break;
2501 
2502 	case DRM_FORMAT_XYUV8888:
2503 		params->y_offset = fb->offsets[0] + 1;
2504 		params->u_offset = fb->offsets[0] + 2;
2505 		params->v_offset = fb->offsets[0] + 3;
2506 		break;
2507 	}
2508 }
2509 
convert_yuv_to_rgb24(struct fb_convert * cvt)2510 static void convert_yuv_to_rgb24(struct fb_convert *cvt)
2511 {
2512 	const struct format_desc_struct *src_fmt =
2513 		lookup_drm_format(cvt->src.fb->drm_format);
2514 	int i, j;
2515 	uint8_t bpp = 4;
2516 	uint8_t *y, *u, *v;
2517 	uint8_t *rgb24 = cvt->dst.ptr;
2518 	unsigned int rgb24_stride = cvt->dst.fb->strides[0];
2519 	struct igt_mat4 m = igt_ycbcr_to_rgb_matrix(cvt->src.fb->drm_format,
2520 						    cvt->dst.fb->drm_format,
2521 						    cvt->src.fb->color_encoding,
2522 						    cvt->src.fb->color_range);
2523 	uint8_t *buf;
2524 	struct yuv_parameters params = { };
2525 
2526 	igt_assert(cvt->dst.fb->drm_format == DRM_FORMAT_XRGB8888 &&
2527 		   igt_format_is_yuv(cvt->src.fb->drm_format));
2528 
2529 	buf = convert_src_get(cvt);
2530 	get_yuv_parameters(cvt->src.fb, &params);
2531 	y = buf + params.y_offset;
2532 	u = buf + params.u_offset;
2533 	v = buf + params.v_offset;
2534 
2535 	for (i = 0; i < cvt->dst.fb->height; i++) {
2536 		const uint8_t *y_tmp = y;
2537 		const uint8_t *u_tmp = u;
2538 		const uint8_t *v_tmp = v;
2539 		uint8_t *rgb_tmp = rgb24;
2540 
2541 		for (j = 0; j < cvt->dst.fb->width; j++) {
2542 			struct igt_vec4 rgb, yuv;
2543 
2544 			yuv.d[0] = *y_tmp;
2545 			yuv.d[1] = *u_tmp;
2546 			yuv.d[2] = *v_tmp;
2547 			yuv.d[3] = 1.0f;
2548 
2549 			rgb = igt_matrix_transform(&m, &yuv);
2550 			write_rgb(rgb_tmp, &rgb);
2551 
2552 			rgb_tmp += bpp;
2553 			y_tmp += params.ay_inc;
2554 
2555 			if ((src_fmt->hsub == 1) || (j % src_fmt->hsub)) {
2556 				u_tmp += params.uv_inc;
2557 				v_tmp += params.uv_inc;
2558 			}
2559 		}
2560 
2561 		rgb24 += rgb24_stride;
2562 		y += params.ay_stride;
2563 
2564 		if ((src_fmt->vsub == 1) || (i % src_fmt->vsub)) {
2565 			u += params.uv_stride;
2566 			v += params.uv_stride;
2567 		}
2568 	}
2569 
2570 	convert_src_put(cvt, buf);
2571 }
2572 
convert_rgb24_to_yuv(struct fb_convert * cvt)2573 static void convert_rgb24_to_yuv(struct fb_convert *cvt)
2574 {
2575 	const struct format_desc_struct *dst_fmt =
2576 		lookup_drm_format(cvt->dst.fb->drm_format);
2577 	int i, j;
2578 	uint8_t *y, *u, *v;
2579 	const uint8_t *rgb24 = cvt->src.ptr;
2580 	uint8_t bpp = 4;
2581 	unsigned rgb24_stride = cvt->src.fb->strides[0];
2582 	struct igt_mat4 m = igt_rgb_to_ycbcr_matrix(cvt->src.fb->drm_format,
2583 						    cvt->dst.fb->drm_format,
2584 						    cvt->dst.fb->color_encoding,
2585 						    cvt->dst.fb->color_range);
2586 	struct yuv_parameters params = { };
2587 
2588 	igt_assert(cvt->src.fb->drm_format == DRM_FORMAT_XRGB8888 &&
2589 		   igt_format_is_yuv(cvt->dst.fb->drm_format));
2590 
2591 	get_yuv_parameters(cvt->dst.fb, &params);
2592 	y = (uint8_t*)cvt->dst.ptr + params.y_offset;
2593 	u = (uint8_t*)cvt->dst.ptr + params.u_offset;
2594 	v = (uint8_t*)cvt->dst.ptr + params.v_offset;
2595 
2596 	for (i = 0; i < cvt->dst.fb->height; i++) {
2597 		const uint8_t *rgb_tmp = rgb24;
2598 		uint8_t *y_tmp = y;
2599 		uint8_t *u_tmp = u;
2600 		uint8_t *v_tmp = v;
2601 
2602 		for (j = 0; j < cvt->dst.fb->width; j++) {
2603 			const uint8_t *pair_rgb24 = rgb_tmp;
2604 			struct igt_vec4 pair_rgb, rgb;
2605 			struct igt_vec4 pair_yuv, yuv;
2606 
2607 			read_rgb(&rgb, rgb_tmp);
2608 			yuv = igt_matrix_transform(&m, &rgb);
2609 
2610 			rgb_tmp += bpp;
2611 
2612 			*y_tmp = yuv.d[0];
2613 			y_tmp += params.ay_inc;
2614 
2615 			if ((i % dst_fmt->vsub) || (j % dst_fmt->hsub))
2616 				continue;
2617 
2618 			/*
2619 			 * We assume the MPEG2 chroma siting convention, where
2620 			 * pixel center for Cb'Cr' is between the left top and
2621 			 * bottom pixel in a 2x2 block, so take the average.
2622 			 *
2623 			 * Therefore, if we use subsampling, we only really care
2624 			 * about two pixels all the time, either the two
2625 			 * subsequent pixels horizontally, vertically, or the
2626 			 * two corners in a 2x2 block.
2627 			 *
2628 			 * The only corner case is when we have an odd number of
2629 			 * pixels, but this can be handled pretty easily by not
2630 			 * incrementing the paired pixel pointer in the
2631 			 * direction it's odd in.
2632 			 */
2633 			if (j != (cvt->dst.fb->width - 1))
2634 				pair_rgb24 += (dst_fmt->hsub - 1) * bpp;
2635 
2636 			if (i != (cvt->dst.fb->height - 1))
2637 				pair_rgb24 += rgb24_stride * (dst_fmt->vsub - 1);
2638 
2639 			read_rgb(&pair_rgb, pair_rgb24);
2640 			pair_yuv = igt_matrix_transform(&m, &pair_rgb);
2641 
2642 			*u_tmp = (yuv.d[1] + pair_yuv.d[1]) / 2.0f;
2643 			*v_tmp = (yuv.d[2] + pair_yuv.d[2]) / 2.0f;
2644 
2645 			u_tmp += params.uv_inc;
2646 			v_tmp += params.uv_inc;
2647 		}
2648 
2649 		rgb24 += rgb24_stride;
2650 		y += params.ay_stride;
2651 
2652 		if ((i % dst_fmt->vsub) == (dst_fmt->vsub - 1)) {
2653 			u += params.uv_stride;
2654 			v += params.uv_stride;
2655 		}
2656 	}
2657 }
2658 
read_rgbf(struct igt_vec4 * rgb,const float * rgb24)2659 static void read_rgbf(struct igt_vec4 *rgb, const float *rgb24)
2660 {
2661 	rgb->d[0] = rgb24[0];
2662 	rgb->d[1] = rgb24[1];
2663 	rgb->d[2] = rgb24[2];
2664 	rgb->d[3] = 1.0f;
2665 }
2666 
write_rgbf(float * rgb24,const struct igt_vec4 * rgb)2667 static void write_rgbf(float *rgb24, const struct igt_vec4 *rgb)
2668 {
2669 	rgb24[0] = rgb->d[0];
2670 	rgb24[1] = rgb->d[1];
2671 	rgb24[2] = rgb->d[2];
2672 }
2673 
convert_yuv16_to_float(struct fb_convert * cvt,bool alpha)2674 static void convert_yuv16_to_float(struct fb_convert *cvt, bool alpha)
2675 {
2676 	const struct format_desc_struct *src_fmt =
2677 		lookup_drm_format(cvt->src.fb->drm_format);
2678 	int i, j;
2679 	uint8_t fpp = alpha ? 4 : 3;
2680 	uint16_t *a, *y, *u, *v;
2681 	float *ptr = cvt->dst.ptr;
2682 	unsigned int float_stride = cvt->dst.fb->strides[0] / sizeof(*ptr);
2683 	struct igt_mat4 m = igt_ycbcr_to_rgb_matrix(cvt->src.fb->drm_format,
2684 						    cvt->dst.fb->drm_format,
2685 						    cvt->src.fb->color_encoding,
2686 						    cvt->src.fb->color_range);
2687 	uint16_t *buf;
2688 	struct yuv_parameters params = { };
2689 
2690 	igt_assert(cvt->dst.fb->drm_format == IGT_FORMAT_FLOAT &&
2691 		   igt_format_is_yuv(cvt->src.fb->drm_format));
2692 
2693 	buf = convert_src_get(cvt);
2694 	get_yuv_parameters(cvt->src.fb, &params);
2695 	igt_assert(!(params.y_offset % sizeof(*buf)) &&
2696 		   !(params.u_offset % sizeof(*buf)) &&
2697 		   !(params.v_offset % sizeof(*buf)));
2698 
2699 	a = buf + params.a_offset / sizeof(*buf);
2700 	y = buf + params.y_offset / sizeof(*buf);
2701 	u = buf + params.u_offset / sizeof(*buf);
2702 	v = buf + params.v_offset / sizeof(*buf);
2703 
2704 	for (i = 0; i < cvt->dst.fb->height; i++) {
2705 		const uint16_t *a_tmp = a;
2706 		const uint16_t *y_tmp = y;
2707 		const uint16_t *u_tmp = u;
2708 		const uint16_t *v_tmp = v;
2709 		float *rgb_tmp = ptr;
2710 
2711 		for (j = 0; j < cvt->dst.fb->width; j++) {
2712 			struct igt_vec4 rgb, yuv;
2713 
2714 			yuv.d[0] = *y_tmp;
2715 			yuv.d[1] = *u_tmp;
2716 			yuv.d[2] = *v_tmp;
2717 			yuv.d[3] = 1.0f;
2718 
2719 			rgb = igt_matrix_transform(&m, &yuv);
2720 			write_rgbf(rgb_tmp, &rgb);
2721 
2722 			if (alpha) {
2723 				rgb_tmp[3] = ((float)*a_tmp) / 65535.f;
2724 				a_tmp += params.ay_inc;
2725 			}
2726 
2727 			rgb_tmp += fpp;
2728 			y_tmp += params.ay_inc;
2729 
2730 			if ((src_fmt->hsub == 1) || (j % src_fmt->hsub)) {
2731 				u_tmp += params.uv_inc;
2732 				v_tmp += params.uv_inc;
2733 			}
2734 		}
2735 
2736 		ptr += float_stride;
2737 
2738 		a += params.ay_stride / sizeof(*a);
2739 		y += params.ay_stride / sizeof(*y);
2740 
2741 		if ((src_fmt->vsub == 1) || (i % src_fmt->vsub)) {
2742 			u += params.uv_stride / sizeof(*u);
2743 			v += params.uv_stride / sizeof(*v);
2744 		}
2745 	}
2746 
2747 	convert_src_put(cvt, buf);
2748 }
2749 
convert_float_to_yuv16(struct fb_convert * cvt,bool alpha)2750 static void convert_float_to_yuv16(struct fb_convert *cvt, bool alpha)
2751 {
2752 	const struct format_desc_struct *dst_fmt =
2753 		lookup_drm_format(cvt->dst.fb->drm_format);
2754 	int i, j;
2755 	uint16_t *a, *y, *u, *v;
2756 	const float *ptr = cvt->src.ptr;
2757 	uint8_t fpp = alpha ? 4 : 3;
2758 	unsigned float_stride = cvt->src.fb->strides[0] / sizeof(*ptr);
2759 	struct igt_mat4 m = igt_rgb_to_ycbcr_matrix(cvt->src.fb->drm_format,
2760 						    cvt->dst.fb->drm_format,
2761 						    cvt->dst.fb->color_encoding,
2762 						    cvt->dst.fb->color_range);
2763 	struct yuv_parameters params = { };
2764 
2765 	igt_assert(cvt->src.fb->drm_format == IGT_FORMAT_FLOAT &&
2766 		   igt_format_is_yuv(cvt->dst.fb->drm_format));
2767 
2768 	get_yuv_parameters(cvt->dst.fb, &params);
2769 	igt_assert(!(params.a_offset % sizeof(*a)) &&
2770 		   !(params.y_offset % sizeof(*y)) &&
2771 		   !(params.u_offset % sizeof(*u)) &&
2772 		   !(params.v_offset % sizeof(*v)));
2773 
2774 	a = (uint16_t*)((uint8_t*)cvt->dst.ptr + params.a_offset);
2775 	y = (uint16_t*)((uint8_t*)cvt->dst.ptr + params.y_offset);
2776 	u = (uint16_t*)((uint8_t*)cvt->dst.ptr + params.u_offset);
2777 	v = (uint16_t*)((uint8_t*)cvt->dst.ptr + params.v_offset);
2778 
2779 	for (i = 0; i < cvt->dst.fb->height; i++) {
2780 		const float *rgb_tmp = ptr;
2781 		uint16_t *a_tmp = a;
2782 		uint16_t *y_tmp = y;
2783 		uint16_t *u_tmp = u;
2784 		uint16_t *v_tmp = v;
2785 
2786 		for (j = 0; j < cvt->dst.fb->width; j++) {
2787 			const float *pair_float = rgb_tmp;
2788 			struct igt_vec4 pair_rgb, rgb;
2789 			struct igt_vec4 pair_yuv, yuv;
2790 
2791 			read_rgbf(&rgb, rgb_tmp);
2792 			yuv = igt_matrix_transform(&m, &rgb);
2793 
2794 			if (alpha) {
2795 				*a_tmp = rgb_tmp[3] * 65535.f + .5f;
2796 				a_tmp += params.ay_inc;
2797 			}
2798 
2799 			rgb_tmp += fpp;
2800 
2801 			*y_tmp = yuv.d[0];
2802 			y_tmp += params.ay_inc;
2803 
2804 			if ((i % dst_fmt->vsub) || (j % dst_fmt->hsub))
2805 				continue;
2806 
2807 			/*
2808 			 * We assume the MPEG2 chroma siting convention, where
2809 			 * pixel center for Cb'Cr' is between the left top and
2810 			 * bottom pixel in a 2x2 block, so take the average.
2811 			 *
2812 			 * Therefore, if we use subsampling, we only really care
2813 			 * about two pixels all the time, either the two
2814 			 * subsequent pixels horizontally, vertically, or the
2815 			 * two corners in a 2x2 block.
2816 			 *
2817 			 * The only corner case is when we have an odd number of
2818 			 * pixels, but this can be handled pretty easily by not
2819 			 * incrementing the paired pixel pointer in the
2820 			 * direction it's odd in.
2821 			 */
2822 			if (j != (cvt->dst.fb->width - 1))
2823 				pair_float += (dst_fmt->hsub - 1) * fpp;
2824 
2825 			if (i != (cvt->dst.fb->height - 1))
2826 				pair_float += float_stride * (dst_fmt->vsub - 1);
2827 
2828 			read_rgbf(&pair_rgb, pair_float);
2829 			pair_yuv = igt_matrix_transform(&m, &pair_rgb);
2830 
2831 			*u_tmp = (yuv.d[1] + pair_yuv.d[1]) / 2.0f;
2832 			*v_tmp = (yuv.d[2] + pair_yuv.d[2]) / 2.0f;
2833 
2834 			u_tmp += params.uv_inc;
2835 			v_tmp += params.uv_inc;
2836 		}
2837 
2838 		ptr += float_stride;
2839 		a += params.ay_stride / sizeof(*a);
2840 		y += params.ay_stride / sizeof(*y);
2841 
2842 		if ((i % dst_fmt->vsub) == (dst_fmt->vsub - 1)) {
2843 			u += params.uv_stride / sizeof(*u);
2844 			v += params.uv_stride / sizeof(*v);
2845 		}
2846 	}
2847 }
2848 
convert_Y410_to_float(struct fb_convert * cvt,bool alpha)2849 static void convert_Y410_to_float(struct fb_convert *cvt, bool alpha)
2850 {
2851 	int i, j;
2852 	const uint32_t *uyv;
2853 	uint32_t *buf;
2854 	float *ptr = cvt->dst.ptr;
2855 	unsigned int float_stride = cvt->dst.fb->strides[0] / sizeof(*ptr);
2856 	unsigned int uyv_stride = cvt->src.fb->strides[0] / sizeof(*uyv);
2857 	struct igt_mat4 m = igt_ycbcr_to_rgb_matrix(cvt->src.fb->drm_format,
2858 						    cvt->dst.fb->drm_format,
2859 						    cvt->src.fb->color_encoding,
2860 						    cvt->src.fb->color_range);
2861 	unsigned bpp = alpha ? 4 : 3;
2862 
2863 	igt_assert((cvt->src.fb->drm_format == DRM_FORMAT_Y410 ||
2864 		    cvt->src.fb->drm_format == DRM_FORMAT_XVYU2101010) &&
2865 		   cvt->dst.fb->drm_format == IGT_FORMAT_FLOAT);
2866 
2867 	uyv = buf = convert_src_get(cvt);
2868 
2869 	for (i = 0; i < cvt->dst.fb->height; i++) {
2870 		for (j = 0; j < cvt->dst.fb->width; j++) {
2871 			/* Convert 2x1 pixel blocks */
2872 			struct igt_vec4 yuv;
2873 			struct igt_vec4 rgb;
2874 
2875 			yuv.d[0] = (uyv[j] >> 10) & 0x3ff;
2876 			yuv.d[1] = uyv[j] & 0x3ff;
2877 			yuv.d[2] = (uyv[j] >> 20) & 0x3ff;
2878 			yuv.d[3] = 1.f;
2879 
2880 			rgb = igt_matrix_transform(&m, &yuv);
2881 
2882 			write_rgbf(&ptr[j * bpp], &rgb);
2883 			if (alpha)
2884 				ptr[j * bpp + 3] = (float)(uyv[j] >> 30) / 3.f;
2885 		}
2886 
2887 		ptr += float_stride;
2888 		uyv += uyv_stride;
2889 	}
2890 
2891 	convert_src_put(cvt, buf);
2892 }
2893 
convert_float_to_Y410(struct fb_convert * cvt,bool alpha)2894 static void convert_float_to_Y410(struct fb_convert *cvt, bool alpha)
2895 {
2896 	int i, j;
2897 	uint32_t *uyv = cvt->dst.ptr;
2898 	const float *ptr = cvt->src.ptr;
2899 	unsigned float_stride = cvt->src.fb->strides[0] / sizeof(*ptr);
2900 	unsigned uyv_stride = cvt->dst.fb->strides[0] / sizeof(*uyv);
2901 	struct igt_mat4 m = igt_rgb_to_ycbcr_matrix(cvt->src.fb->drm_format,
2902 						    cvt->dst.fb->drm_format,
2903 						    cvt->dst.fb->color_encoding,
2904 						    cvt->dst.fb->color_range);
2905 	unsigned bpp = alpha ? 4 : 3;
2906 
2907 	igt_assert(cvt->src.fb->drm_format == IGT_FORMAT_FLOAT &&
2908 		   (cvt->dst.fb->drm_format == DRM_FORMAT_Y410 ||
2909 		    cvt->dst.fb->drm_format == DRM_FORMAT_XVYU2101010));
2910 
2911 	for (i = 0; i < cvt->dst.fb->height; i++) {
2912 		for (j = 0; j < cvt->dst.fb->width; j++) {
2913 			struct igt_vec4 rgb;
2914 			struct igt_vec4 yuv;
2915 			uint8_t a = 0;
2916 			uint16_t y, cb, cr;
2917 
2918 			read_rgbf(&rgb, &ptr[j * bpp]);
2919 			if (alpha)
2920 				 a = ptr[j * bpp + 3] * 3.f + .5f;
2921 
2922 			yuv = igt_matrix_transform(&m, &rgb);
2923 			y = yuv.d[0];
2924 			cb = yuv.d[1];
2925 			cr = yuv.d[2];
2926 
2927 			uyv[j] = ((cb & 0x3ff) << 0) |
2928 				  ((y & 0x3ff) << 10) |
2929 				  ((cr & 0x3ff) << 20) |
2930 				  (a << 30);
2931 		}
2932 
2933 		ptr += float_stride;
2934 		uyv += uyv_stride;
2935 	}
2936 }
2937 
2938 /* { R, G, B, X } */
2939 static const unsigned char swizzle_rgbx[] = { 0, 1, 2, 3 };
2940 static const unsigned char swizzle_bgrx[] = { 2, 1, 0, 3 };
2941 
rgbx_swizzle(uint32_t format)2942 static const unsigned char *rgbx_swizzle(uint32_t format)
2943 {
2944 	switch (format) {
2945 	default:
2946 	case DRM_FORMAT_XRGB16161616F:
2947 	case DRM_FORMAT_ARGB16161616F:
2948 		return swizzle_bgrx;
2949 	case DRM_FORMAT_XBGR16161616F:
2950 	case DRM_FORMAT_ABGR16161616F:
2951 		return swizzle_rgbx;
2952 	}
2953 }
2954 
convert_fp16_to_float(struct fb_convert * cvt)2955 static void convert_fp16_to_float(struct fb_convert *cvt)
2956 {
2957 	int i, j;
2958 	uint16_t *fp16;
2959 	float *ptr = cvt->dst.ptr;
2960 	unsigned int float_stride = cvt->dst.fb->strides[0] / sizeof(*ptr);
2961 	unsigned int fp16_stride = cvt->src.fb->strides[0] / sizeof(*fp16);
2962 	const unsigned char *swz = rgbx_swizzle(cvt->src.fb->drm_format);
2963 	bool needs_reswizzle = swz != swizzle_rgbx;
2964 
2965 	uint16_t *buf = convert_src_get(cvt);
2966 	fp16 = buf + cvt->src.fb->offsets[0] / sizeof(*buf);
2967 
2968 	for (i = 0; i < cvt->dst.fb->height; i++) {
2969 		if (needs_reswizzle) {
2970 			const uint16_t *fp16_tmp = fp16;
2971 			float *rgb_tmp = ptr;
2972 
2973 			for (j = 0; j < cvt->dst.fb->width; j++) {
2974 				struct igt_vec4 rgb;
2975 
2976 				igt_half_to_float(fp16_tmp, rgb.d, 4);
2977 
2978 				rgb_tmp[0] = rgb.d[swz[0]];
2979 				rgb_tmp[1] = rgb.d[swz[1]];
2980 				rgb_tmp[2] = rgb.d[swz[2]];
2981 				rgb_tmp[3] = rgb.d[swz[3]];
2982 
2983 				rgb_tmp += 4;
2984 				fp16_tmp += 4;
2985 			}
2986 		} else {
2987 			igt_half_to_float(fp16, ptr, cvt->dst.fb->width * 4);
2988 		}
2989 
2990 		ptr += float_stride;
2991 		fp16 += fp16_stride;
2992 	}
2993 
2994 	convert_src_put(cvt, buf);
2995 }
2996 
convert_float_to_fp16(struct fb_convert * cvt)2997 static void convert_float_to_fp16(struct fb_convert *cvt)
2998 {
2999 	int i, j;
3000 	uint16_t *fp16 = (uint16_t*)((uint8_t*)cvt->dst.ptr + cvt->dst.fb->offsets[0]);
3001 	const float *ptr = cvt->src.ptr;
3002 	unsigned float_stride = cvt->src.fb->strides[0] / sizeof(*ptr);
3003 	unsigned fp16_stride = cvt->dst.fb->strides[0] / sizeof(*fp16);
3004 	const unsigned char *swz = rgbx_swizzle(cvt->dst.fb->drm_format);
3005 	bool needs_reswizzle = swz != swizzle_rgbx;
3006 
3007 	for (i = 0; i < cvt->dst.fb->height; i++) {
3008 		if (needs_reswizzle) {
3009 			const float *rgb_tmp = ptr;
3010 			uint16_t *fp16_tmp = fp16;
3011 
3012 			for (j = 0; j < cvt->dst.fb->width; j++) {
3013 				struct igt_vec4 rgb;
3014 
3015 				rgb.d[0] = rgb_tmp[swz[0]];
3016 				rgb.d[1] = rgb_tmp[swz[1]];
3017 				rgb.d[2] = rgb_tmp[swz[2]];
3018 				rgb.d[3] = rgb_tmp[swz[3]];
3019 
3020 				igt_float_to_half(rgb.d, fp16_tmp, 4);
3021 
3022 				rgb_tmp += 4;
3023 				fp16_tmp += 4;
3024 			}
3025 		} else {
3026 			igt_float_to_half(ptr, fp16, cvt->dst.fb->width * 4);
3027 		}
3028 
3029 		ptr += float_stride;
3030 		fp16 += fp16_stride;
3031 	}
3032 }
3033 
convert_pixman(struct fb_convert * cvt)3034 static void convert_pixman(struct fb_convert *cvt)
3035 {
3036 	pixman_format_code_t src_pixman = drm_format_to_pixman(cvt->src.fb->drm_format);
3037 	pixman_format_code_t dst_pixman = drm_format_to_pixman(cvt->dst.fb->drm_format);
3038 	pixman_image_t *dst_image, *src_image;
3039 	void *src_ptr;
3040 
3041 	igt_assert((src_pixman != PIXMAN_invalid) &&
3042 		   (dst_pixman != PIXMAN_invalid));
3043 
3044 	/* Pixman requires the stride to be aligned to 32 bits. */
3045 	igt_assert((cvt->src.fb->strides[0] % sizeof(uint32_t)) == 0);
3046 	igt_assert((cvt->dst.fb->strides[0] % sizeof(uint32_t)) == 0);
3047 
3048 	src_ptr = convert_src_get(cvt);
3049 
3050 	src_image = pixman_image_create_bits(src_pixman,
3051 					     cvt->src.fb->width,
3052 					     cvt->src.fb->height,
3053 					     src_ptr,
3054 					     cvt->src.fb->strides[0]);
3055 	igt_assert(src_image);
3056 
3057 	dst_image = pixman_image_create_bits(dst_pixman,
3058 					     cvt->dst.fb->width,
3059 					     cvt->dst.fb->height,
3060 					     cvt->dst.ptr,
3061 					     cvt->dst.fb->strides[0]);
3062 	igt_assert(dst_image);
3063 
3064 	pixman_image_composite(PIXMAN_OP_SRC, src_image, NULL, dst_image,
3065 			       0, 0, 0, 0, 0, 0,
3066 			       cvt->dst.fb->width, cvt->dst.fb->height);
3067 	pixman_image_unref(dst_image);
3068 	pixman_image_unref(src_image);
3069 
3070 	convert_src_put(cvt, src_ptr);
3071 }
3072 
fb_convert(struct fb_convert * cvt)3073 static void fb_convert(struct fb_convert *cvt)
3074 {
3075 	if ((drm_format_to_pixman(cvt->src.fb->drm_format) != PIXMAN_invalid) &&
3076 	    (drm_format_to_pixman(cvt->dst.fb->drm_format) != PIXMAN_invalid)) {
3077 		convert_pixman(cvt);
3078 		return;
3079 	} else if (cvt->dst.fb->drm_format == DRM_FORMAT_XRGB8888) {
3080 		switch (cvt->src.fb->drm_format) {
3081 		case DRM_FORMAT_XYUV8888:
3082 		case DRM_FORMAT_NV12:
3083 		case DRM_FORMAT_NV16:
3084 		case DRM_FORMAT_NV21:
3085 		case DRM_FORMAT_NV61:
3086 		case DRM_FORMAT_UYVY:
3087 		case DRM_FORMAT_VYUY:
3088 		case DRM_FORMAT_YUV420:
3089 		case DRM_FORMAT_YUV422:
3090 		case DRM_FORMAT_YUYV:
3091 		case DRM_FORMAT_YVU420:
3092 		case DRM_FORMAT_YVU422:
3093 		case DRM_FORMAT_YVYU:
3094 			convert_yuv_to_rgb24(cvt);
3095 			return;
3096 		}
3097 	} else if (cvt->src.fb->drm_format == DRM_FORMAT_XRGB8888) {
3098 		switch (cvt->dst.fb->drm_format) {
3099 		case DRM_FORMAT_XYUV8888:
3100 		case DRM_FORMAT_NV12:
3101 		case DRM_FORMAT_NV16:
3102 		case DRM_FORMAT_NV21:
3103 		case DRM_FORMAT_NV61:
3104 		case DRM_FORMAT_UYVY:
3105 		case DRM_FORMAT_VYUY:
3106 		case DRM_FORMAT_YUV420:
3107 		case DRM_FORMAT_YUV422:
3108 		case DRM_FORMAT_YUYV:
3109 		case DRM_FORMAT_YVU420:
3110 		case DRM_FORMAT_YVU422:
3111 		case DRM_FORMAT_YVYU:
3112 			convert_rgb24_to_yuv(cvt);
3113 			return;
3114 		}
3115 	} else if (cvt->dst.fb->drm_format == IGT_FORMAT_FLOAT) {
3116 		switch (cvt->src.fb->drm_format) {
3117 		case DRM_FORMAT_P010:
3118 		case DRM_FORMAT_P012:
3119 		case DRM_FORMAT_P016:
3120 		case DRM_FORMAT_Y210:
3121 		case DRM_FORMAT_Y212:
3122 		case DRM_FORMAT_Y216:
3123 		case DRM_FORMAT_XVYU12_16161616:
3124 		case DRM_FORMAT_XVYU16161616:
3125 			convert_yuv16_to_float(cvt, false);
3126 			return;
3127 		case DRM_FORMAT_Y410:
3128 			convert_Y410_to_float(cvt, true);
3129 			return;
3130 		case DRM_FORMAT_XVYU2101010:
3131 			convert_Y410_to_float(cvt, false);
3132 			return;
3133 		case DRM_FORMAT_Y412:
3134 		case DRM_FORMAT_Y416:
3135 			convert_yuv16_to_float(cvt, true);
3136 			return;
3137 		case DRM_FORMAT_XRGB16161616F:
3138 		case DRM_FORMAT_XBGR16161616F:
3139 		case DRM_FORMAT_ARGB16161616F:
3140 		case DRM_FORMAT_ABGR16161616F:
3141 			convert_fp16_to_float(cvt);
3142 			return;
3143 		}
3144 	} else if (cvt->src.fb->drm_format == IGT_FORMAT_FLOAT) {
3145 		switch (cvt->dst.fb->drm_format) {
3146 		case DRM_FORMAT_P010:
3147 		case DRM_FORMAT_P012:
3148 		case DRM_FORMAT_P016:
3149 		case DRM_FORMAT_Y210:
3150 		case DRM_FORMAT_Y212:
3151 		case DRM_FORMAT_Y216:
3152 		case DRM_FORMAT_XVYU12_16161616:
3153 		case DRM_FORMAT_XVYU16161616:
3154 			convert_float_to_yuv16(cvt, false);
3155 			return;
3156 		case DRM_FORMAT_Y410:
3157 			convert_float_to_Y410(cvt, true);
3158 			return;
3159 		case DRM_FORMAT_XVYU2101010:
3160 			convert_float_to_Y410(cvt, false);
3161 			return;
3162 		case DRM_FORMAT_Y412:
3163 		case DRM_FORMAT_Y416:
3164 			convert_float_to_yuv16(cvt, true);
3165 			return;
3166 		case DRM_FORMAT_XRGB16161616F:
3167 		case DRM_FORMAT_XBGR16161616F:
3168 		case DRM_FORMAT_ARGB16161616F:
3169 		case DRM_FORMAT_ABGR16161616F:
3170 			convert_float_to_fp16(cvt);
3171 			return;
3172 		}
3173 	}
3174 
3175 	igt_assert_f(false,
3176 		     "Conversion not implemented (from format 0x%x to 0x%x)\n",
3177 		     cvt->src.fb->drm_format, cvt->dst.fb->drm_format);
3178 }
3179 
destroy_cairo_surface__convert(void * arg)3180 static void destroy_cairo_surface__convert(void *arg)
3181 {
3182 	struct fb_convert_blit_upload *blit = arg;
3183 	struct igt_fb *fb = blit->base.fb;
3184 	struct fb_convert cvt = {
3185 		.dst	= {
3186 			.ptr	= blit->base.linear.map,
3187 			.fb	= &blit->base.linear.fb,
3188 		},
3189 
3190 		.src	= {
3191 			.ptr	= blit->shadow_ptr,
3192 			.fb	= &blit->shadow_fb,
3193 		},
3194 	};
3195 
3196 	fb_convert(&cvt);
3197 	igt_fb_destroy_cairo_shadow_buffer(&blit->shadow_fb, blit->shadow_ptr);
3198 
3199 	if (blit->base.linear.fb.gem_handle)
3200 		free_linear_mapping(&blit->base);
3201 	else
3202 		unmap_bo(fb, blit->base.linear.map);
3203 
3204 	free(blit);
3205 
3206 	fb->cairo_surface = NULL;
3207 }
3208 
create_cairo_surface__convert(int fd,struct igt_fb * fb)3209 static void create_cairo_surface__convert(int fd, struct igt_fb *fb)
3210 {
3211 	struct fb_convert_blit_upload *blit = calloc(1, sizeof(*blit));
3212 	struct fb_convert cvt = { };
3213 	const struct format_desc_struct *f = lookup_drm_format(fb->drm_format);
3214 	unsigned drm_format;
3215 	cairo_format_t cairo_id;
3216 
3217 	if (f->cairo_id != CAIRO_FORMAT_INVALID) {
3218 		cairo_id = f->cairo_id;
3219 
3220 		switch (f->cairo_id) {
3221 		case CAIRO_FORMAT_RGB96F:
3222 		case CAIRO_FORMAT_RGBA128F:
3223 			drm_format = IGT_FORMAT_FLOAT;
3224 			break;
3225 		case CAIRO_FORMAT_RGB24:
3226 			drm_format = DRM_FORMAT_XRGB8888;
3227 			break;
3228 		default:
3229 			igt_assert_f(0, "Unsupported format %u", f->cairo_id);
3230 		}
3231 	} else if (PIXMAN_FORMAT_A(f->pixman_id)) {
3232 		cairo_id = CAIRO_FORMAT_ARGB32;
3233 		drm_format = DRM_FORMAT_ARGB8888;
3234 	} else {
3235 		cairo_id = CAIRO_FORMAT_RGB24;
3236 		drm_format = DRM_FORMAT_XRGB8888;
3237 	}
3238 
3239 	igt_assert(blit);
3240 
3241 	blit->base.fd = fd;
3242 	blit->base.fb = fb;
3243 
3244 	blit->shadow_ptr = igt_fb_create_cairo_shadow_buffer(fd, drm_format,
3245 							     fb->width,
3246 							     fb->height,
3247 							     &blit->shadow_fb);
3248 	igt_assert(blit->shadow_ptr);
3249 
3250 	if (use_rendercopy(fb) || use_blitter(fb) || igt_vc4_is_tiled(fb->modifier)) {
3251 		setup_linear_mapping(&blit->base);
3252 	} else {
3253 		blit->base.linear.fb = *fb;
3254 		blit->base.linear.fb.gem_handle = 0;
3255 		blit->base.linear.map = map_bo(fd, fb);
3256 		igt_assert(blit->base.linear.map);
3257 
3258 		/* reading via gtt mmap is slow */
3259 		cvt.src.slow_reads = is_i915_device(fd);
3260 	}
3261 
3262 	cvt.dst.ptr = blit->shadow_ptr;
3263 	cvt.dst.fb = &blit->shadow_fb;
3264 	cvt.src.ptr = blit->base.linear.map;
3265 	cvt.src.fb = &blit->base.linear.fb;
3266 	fb_convert(&cvt);
3267 
3268 	fb->cairo_surface =
3269 		cairo_image_surface_create_for_data(blit->shadow_ptr,
3270 						    cairo_id,
3271 						    fb->width, fb->height,
3272 						    blit->shadow_fb.strides[0]);
3273 
3274 	cairo_surface_set_user_data(fb->cairo_surface,
3275 				    (cairo_user_data_key_t *)create_cairo_surface__convert,
3276 				    blit, destroy_cairo_surface__convert);
3277 }
3278 #endif /*defined(USE_CAIRO_PIXMAN)*/
3279 
3280 
3281 /**
3282  * igt_fb_map_buffer:
3283  * @fd: open drm file descriptor
3284  * @fb: pointer to an #igt_fb structure
3285  *
3286  * This function will creating a new mapping of the buffer and return a pointer
3287  * to the content of the supplied framebuffer's plane. This mapping needs to be
3288  * deleted using igt_fb_unmap_buffer().
3289  *
3290  * Returns:
3291  * A pointer to a buffer with the contents of the framebuffer
3292  */
igt_fb_map_buffer(int fd,struct igt_fb * fb)3293 void *igt_fb_map_buffer(int fd, struct igt_fb *fb)
3294 {
3295 	return map_bo(fd, fb);
3296 }
3297 
3298 /**
3299  * igt_fb_unmap_buffer:
3300  * @fb: pointer to the backing igt_fb structure
3301  * @buffer: pointer to the buffer previously mappped
3302  *
3303  * This function will unmap a buffer mapped previously with
3304  * igt_fb_map_buffer().
3305  */
igt_fb_unmap_buffer(struct igt_fb * fb,void * buffer)3306 void igt_fb_unmap_buffer(struct igt_fb *fb, void *buffer)
3307 {
3308 	return unmap_bo(fb, buffer);
3309 }
3310 
3311 #if defined(USE_CAIRO_PIXMAN)
3312 /**
3313  * igt_get_cairo_surface:
3314  * @fd: open drm file descriptor
3315  * @fb: pointer to an #igt_fb structure
3316  *
3317  * This function stores the contents of the supplied framebuffer's plane
3318  * into a cairo surface and returns it.
3319  *
3320  * Returns:
3321  * A pointer to a cairo surface with the contents of the framebuffer.
3322  */
igt_get_cairo_surface(int fd,struct igt_fb * fb)3323 cairo_surface_t *igt_get_cairo_surface(int fd, struct igt_fb *fb)
3324 {
3325 	const struct format_desc_struct *f = lookup_drm_format(fb->drm_format);
3326 
3327 	if (fb->cairo_surface == NULL) {
3328 		if (igt_format_is_yuv(fb->drm_format) ||
3329 		    igt_format_is_fp16(fb->drm_format) ||
3330 		    ((f->cairo_id == CAIRO_FORMAT_INVALID) &&
3331 		     (f->pixman_id != PIXMAN_invalid)))
3332 			create_cairo_surface__convert(fd, fb);
3333 		else if (use_blitter(fb) || use_rendercopy(fb) || igt_vc4_is_tiled(fb->modifier))
3334 			create_cairo_surface__gpu(fd, fb);
3335 		else
3336 			create_cairo_surface__gtt(fd, fb);
3337 
3338 		if (f->cairo_id == CAIRO_FORMAT_RGB96F ||
3339 		    f->cairo_id == CAIRO_FORMAT_RGBA128F) {
3340 			cairo_status_t status = cairo_surface_status(fb->cairo_surface);
3341 
3342 			igt_skip_on_f(status == CAIRO_STATUS_INVALID_FORMAT &&
3343 				      cairo_version() < CAIRO_VERSION_ENCODE(1, 17, 2),
3344 				      "Cairo version too old, need 1.17.2, have %s\n",
3345 				      cairo_version_string());
3346 
3347 			igt_skip_on_f(status == CAIRO_STATUS_NO_MEMORY &&
3348 				      pixman_version() < PIXMAN_VERSION_ENCODE(0, 36, 0),
3349 				      "Pixman version too old, need 0.36.0, have %s\n",
3350 				      pixman_version_string());
3351 		}
3352 	}
3353 
3354 	igt_assert(cairo_surface_status(fb->cairo_surface) == CAIRO_STATUS_SUCCESS);
3355 	return fb->cairo_surface;
3356 }
3357 
3358 /**
3359  * igt_get_cairo_ctx:
3360  * @fd: open i915 drm file descriptor
3361  * @fb: pointer to an #igt_fb structure
3362  *
3363  * This initializes a cairo surface for @fb and then allocates a drawing context
3364  * for it. The return cairo drawing context should be released by calling
3365  * igt_put_cairo_ctx(). This also sets a default font for drawing text on
3366  * framebuffers.
3367  *
3368  * Returns:
3369  * The created cairo drawing context.
3370  */
igt_get_cairo_ctx(int fd,struct igt_fb * fb)3371 cairo_t *igt_get_cairo_ctx(int fd, struct igt_fb *fb)
3372 {
3373 	cairo_surface_t *surface;
3374 	cairo_t *cr;
3375 
3376 	surface = igt_get_cairo_surface(fd, fb);
3377 	cr = cairo_create(surface);
3378 	cairo_surface_destroy(surface);
3379 	igt_assert(cairo_status(cr) == CAIRO_STATUS_SUCCESS);
3380 
3381 	cairo_select_font_face(cr, "Helvetica", CAIRO_FONT_SLANT_NORMAL,
3382 			       CAIRO_FONT_WEIGHT_NORMAL);
3383 	igt_assert(cairo_status(cr) == CAIRO_STATUS_SUCCESS);
3384 
3385 	return cr;
3386 }
3387 
3388 /**
3389  * igt_put_cairo_ctx:
3390  * @fd: open i915 drm file descriptor
3391  * @fb: pointer to an #igt_fb structure
3392  * @cr: the cairo context returned by igt_get_cairo_ctx.
3393  *
3394  * This releases the cairo surface @cr returned by igt_get_cairo_ctx()
3395  * for @fb, and writes the changes out to the framebuffer if cairo doesn't
3396  * have native support for the format.
3397  */
igt_put_cairo_ctx(int fd,struct igt_fb * fb,cairo_t * cr)3398 void igt_put_cairo_ctx(int fd, struct igt_fb *fb, cairo_t *cr)
3399 {
3400 	cairo_status_t ret = cairo_status(cr);
3401 	igt_assert_f(ret == CAIRO_STATUS_SUCCESS, "Cairo failed to draw with %s\n", cairo_status_to_string(ret));
3402 
3403 	cairo_destroy(cr);
3404 }
3405 #endif /*defined(USE_CAIRO_PIXMAN)*/
3406 
3407 /**
3408  * igt_remove_fb:
3409  * @fd: open i915 drm file descriptor
3410  * @fb: pointer to an #igt_fb structure
3411  *
3412  * This function releases all resources allocated in igt_create_fb() for @fb.
3413  * Note that if this framebuffer is still in use on a primary plane the kernel
3414  * will disable the corresponding crtc.
3415  */
igt_remove_fb(int fd,struct igt_fb * fb)3416 void igt_remove_fb(int fd, struct igt_fb *fb)
3417 {
3418 	if (!fb || !fb->fb_id)
3419 		return;
3420 
3421 #if defined(USE_CAIRO_PIXMAN)
3422 	cairo_surface_destroy(fb->cairo_surface);
3423 #endif
3424 	do_or_die(drmModeRmFB(fd, fb->fb_id));
3425 	if (fb->is_dumb)
3426 		kmstest_dumb_destroy(fd, fb->gem_handle);
3427 	else
3428 		gem_close(fd, fb->gem_handle);
3429 	fb->fb_id = 0;
3430 }
3431 
3432 #if defined(USE_CAIRO_PIXMAN)
3433 /**
3434  * igt_fb_convert_with_stride:
3435  * @dst: pointer to the #igt_fb structure that will store the conversion result
3436  * @src: pointer to the #igt_fb structure that stores the frame we convert
3437  * @dst_fourcc: DRM format specifier to convert to
3438  * @dst_modifier: DRM format modifier to convert to
3439  * @dst_stride: Stride for the resulting framebuffer (0 for automatic stride)
3440  *
3441  * This will convert a given @src content to the @dst_fourcc format,
3442  * storing the result in the @dst fb, allocating the @dst fb
3443  * underlying buffer with a stride of @dst_stride stride.
3444  *
3445  * Once done with @dst, the caller will have to call igt_remove_fb()
3446  * on it to free the associated resources.
3447  *
3448  * Returns:
3449  * The kms id of the created framebuffer.
3450  */
igt_fb_convert_with_stride(struct igt_fb * dst,struct igt_fb * src,uint32_t dst_fourcc,uint64_t dst_modifier,unsigned int dst_stride)3451 unsigned int igt_fb_convert_with_stride(struct igt_fb *dst, struct igt_fb *src,
3452 					uint32_t dst_fourcc,
3453 					uint64_t dst_modifier,
3454 					unsigned int dst_stride)
3455 {
3456 	/* Use the cairo api to convert */
3457 	cairo_surface_t *surf = igt_get_cairo_surface(src->fd, src);
3458 	cairo_t *cr;
3459 	int fb_id;
3460 
3461 	fb_id = igt_create_fb_with_bo_size(src->fd, src->width,
3462 					   src->height, dst_fourcc,
3463 					   dst_modifier,
3464 					   IGT_COLOR_YCBCR_BT709,
3465 					   IGT_COLOR_YCBCR_LIMITED_RANGE,
3466 					   dst, 0,
3467 					   dst_stride);
3468 	igt_assert(fb_id > 0);
3469 
3470 	cr = igt_get_cairo_ctx(dst->fd, dst);
3471 	cairo_set_source_surface(cr, surf, 0, 0);
3472 	cairo_paint(cr);
3473 	igt_put_cairo_ctx(dst->fd, dst, cr);
3474 
3475 	cairo_surface_destroy(surf);
3476 
3477 	return fb_id;
3478 }
3479 
3480 /**
3481  * igt_fb_convert:
3482  * @dst: pointer to the #igt_fb structure that will store the conversion result
3483  * @src: pointer to the #igt_fb structure that stores the frame we convert
3484  * @dst_fourcc: DRM format specifier to convert to
3485  * @dst_modifier: DRM format modifier to convert to
3486  *
3487  * This will convert a given @src content to the @dst_fourcc format,
3488  * storing the result in the @dst fb, allocating the @dst fb
3489  * underlying buffer.
3490  *
3491  * Once done with @dst, the caller will have to call igt_remove_fb()
3492  * on it to free the associated resources.
3493  *
3494  * Returns:
3495  * The kms id of the created framebuffer.
3496  */
igt_fb_convert(struct igt_fb * dst,struct igt_fb * src,uint32_t dst_fourcc,uint64_t dst_modifier)3497 unsigned int igt_fb_convert(struct igt_fb *dst, struct igt_fb *src,
3498 			    uint32_t dst_fourcc, uint64_t dst_modifier)
3499 {
3500 	return igt_fb_convert_with_stride(dst, src, dst_fourcc, dst_modifier,
3501 					  0);
3502 }
3503 #endif /*defined(USE_CAIRO_PIXMAN)*/
3504 
3505 /**
3506  * igt_bpp_depth_to_drm_format:
3507  * @bpp: desired bits per pixel
3508  * @depth: desired depth
3509  *
3510  * Returns:
3511  * The rgb drm fourcc pixel format code corresponding to the given @bpp and
3512  * @depth values.  Fails hard if no match was found.
3513  */
igt_bpp_depth_to_drm_format(int bpp,int depth)3514 uint32_t igt_bpp_depth_to_drm_format(int bpp, int depth)
3515 {
3516 	const struct format_desc_struct *f;
3517 
3518 	for_each_format(f)
3519 		if (f->plane_bpp[0] == bpp && f->depth == depth)
3520 			return f->drm_id;
3521 
3522 
3523 	igt_assert_f(0, "can't find drm format with bpp=%d, depth=%d\n", bpp,
3524 		     depth);
3525 }
3526 
3527 /**
3528  * igt_drm_format_to_bpp:
3529  * @drm_format: drm fourcc pixel format code
3530  *
3531  * Returns:
3532  * The bits per pixel for the given drm fourcc pixel format code. Fails hard if
3533  * no match was found.
3534  */
igt_drm_format_to_bpp(uint32_t drm_format)3535 uint32_t igt_drm_format_to_bpp(uint32_t drm_format)
3536 {
3537 	const struct format_desc_struct *f = lookup_drm_format(drm_format);
3538 
3539 	igt_assert_f(f, "can't find a bpp format for %08x (%s)\n",
3540 		     drm_format, igt_format_str(drm_format));
3541 
3542 	return f->plane_bpp[0];
3543 }
3544 
3545 /**
3546  * igt_format_str:
3547  * @drm_format: drm fourcc pixel format code
3548  *
3549  * Returns:
3550  * Human-readable fourcc pixel format code for @drm_format or "invalid" no match
3551  * was found.
3552  */
igt_format_str(uint32_t drm_format)3553 const char *igt_format_str(uint32_t drm_format)
3554 {
3555 	const struct format_desc_struct *f = lookup_drm_format(drm_format);
3556 
3557 	return f ? f->name : "invalid";
3558 }
3559 
3560 /**
3561  * igt_fb_supported_format:
3562  * @drm_format: drm fourcc to test.
3563  *
3564  * This functions returns whether @drm_format can be succesfully created by
3565  * igt_create_fb() and drawn to by igt_get_cairo_ctx().
3566  */
igt_fb_supported_format(uint32_t drm_format)3567 bool igt_fb_supported_format(uint32_t drm_format)
3568 {
3569 #if defined (USE_CAIRO_PIXMAN)
3570 	const struct format_desc_struct *f;
3571 
3572 	/*
3573 	 * C8 needs a LUT which (at least for the time being)
3574 	 * is the responsibility of each test. Not all tests
3575 	 * have the required code so let's keep C8 hidden from
3576 	 * most eyes.
3577 	 */
3578 	if (drm_format == DRM_FORMAT_C8)
3579 		return false;
3580 
3581 	for_each_format(f)
3582 		if (f->drm_id == drm_format)
3583 			return (f->cairo_id != CAIRO_FORMAT_INVALID) ||
3584 				(f->pixman_id != PIXMAN_invalid);
3585 
3586 	return false;
3587 #else
3588 	/* If we don't use Cairo/Pixman, all formats are equally good */
3589 	return true;
3590 #endif
3591 }
3592 
3593 /**
3594  * igt_format_is_yuv:
3595  * @drm_format: drm fourcc
3596  *
3597  * This functions returns whether @drm_format is YUV (as opposed to RGB).
3598  */
igt_format_is_yuv(uint32_t drm_format)3599 bool igt_format_is_yuv(uint32_t drm_format)
3600 {
3601 	switch (drm_format) {
3602 	case DRM_FORMAT_NV12:
3603 	case DRM_FORMAT_NV16:
3604 	case DRM_FORMAT_NV21:
3605 	case DRM_FORMAT_NV61:
3606 	case DRM_FORMAT_YUV420:
3607 	case DRM_FORMAT_YUV422:
3608 	case DRM_FORMAT_YVU420:
3609 	case DRM_FORMAT_YVU422:
3610 	case DRM_FORMAT_P010:
3611 	case DRM_FORMAT_P012:
3612 	case DRM_FORMAT_P016:
3613 	case DRM_FORMAT_Y210:
3614 	case DRM_FORMAT_Y212:
3615 	case DRM_FORMAT_Y216:
3616 	case DRM_FORMAT_XVYU2101010:
3617 	case DRM_FORMAT_XVYU12_16161616:
3618 	case DRM_FORMAT_XVYU16161616:
3619 	case DRM_FORMAT_Y410:
3620 	case DRM_FORMAT_Y412:
3621 	case DRM_FORMAT_Y416:
3622 	case DRM_FORMAT_YUYV:
3623 	case DRM_FORMAT_YVYU:
3624 	case DRM_FORMAT_UYVY:
3625 	case DRM_FORMAT_VYUY:
3626 	case DRM_FORMAT_XYUV8888:
3627 		return true;
3628 	default:
3629 		return false;
3630 	}
3631 }
3632 
3633 /**
3634  * igt_format_is_fp16
3635  * @drm_format: drm fourcc
3636  *
3637  * Check if the format is fp16.
3638  */
igt_format_is_fp16(uint32_t drm_format)3639 bool igt_format_is_fp16(uint32_t drm_format)
3640 {
3641 	switch (drm_format) {
3642 	case DRM_FORMAT_XRGB16161616F:
3643 	case DRM_FORMAT_ARGB16161616F:
3644 	case DRM_FORMAT_XBGR16161616F:
3645 	case DRM_FORMAT_ABGR16161616F:
3646 		return true;
3647 	default:
3648 		return false;
3649 	}
3650 }
3651 
3652 /**
3653  * igt_format_plane_bpp:
3654  * @drm_format: drm fourcc
3655  * @plane: format plane index
3656  *
3657  * This functions returns the number of bits per pixel for the given @plane
3658  * index of the @drm_format.
3659  */
igt_format_plane_bpp(uint32_t drm_format,int plane)3660 int igt_format_plane_bpp(uint32_t drm_format, int plane)
3661 {
3662 	const struct format_desc_struct *format =
3663 		lookup_drm_format(drm_format);
3664 
3665 	return format->plane_bpp[plane];
3666 }
3667 
3668 /**
3669  * igt_format_array_fill:
3670  * @formats_array: a pointer to the formats array pointer to be allocated
3671  * @count: a pointer to the number of elements contained in the allocated array
3672  * @allow_yuv: a boolean indicating whether YUV formats should be included
3673  *
3674  * This functions allocates and fills a @formats_array that lists the DRM
3675  * formats current available.
3676  */
igt_format_array_fill(uint32_t ** formats_array,unsigned int * count,bool allow_yuv)3677 void igt_format_array_fill(uint32_t **formats_array, unsigned int *count,
3678 			   bool allow_yuv)
3679 {
3680 	const struct format_desc_struct *format;
3681 	unsigned int index = 0;
3682 
3683 	*count = 0;
3684 
3685 	for_each_format(format) {
3686 		if (!allow_yuv && igt_format_is_yuv(format->drm_id))
3687 			continue;
3688 
3689 		(*count)++;
3690 	}
3691 
3692 	*formats_array = calloc(*count, sizeof(uint32_t));
3693 	igt_assert(*formats_array);
3694 
3695 	for_each_format(format) {
3696 		if (!allow_yuv && igt_format_is_yuv(format->drm_id))
3697 			continue;
3698 
3699 		(*formats_array)[index++] = format->drm_id;
3700 	}
3701 }
3702