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, ¶ms);
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, ¶ms);
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, ¶ms);
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, ¶ms);
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