blob: ae71d9673228c9bf7a507017978a3d8c65bce3cc [file] [log] [blame]
Daniel Vetter57d7db82014-03-26 09:06:11 +01001/*
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
Daniel Vetter57d7db82014-03-26 09:06:11 +010028#include <stdio.h>
29#include <math.h>
Ville Syrjäläe867d652018-02-27 22:39:26 +020030#include <wchar.h>
Mike Frysinger030977e2018-01-10 17:12:15 -050031#include <inttypes.h>
Daniel Vetter57d7db82014-03-26 09:06:11 +010032
33#include "drmtest.h"
Ville Syrjäläee26fef2018-02-27 22:38:05 +020034#include "igt_aux.h"
Ville Syrjälä1c7ef382018-02-27 22:59:25 +020035#include "igt_color_encoding.h"
Daniel Vetter57d7db82014-03-26 09:06:11 +010036#include "igt_fb.h"
Tomeu Vizoso8a1a3862016-02-24 09:04:04 +010037#include "igt_kms.h"
Ville Syrjälä1c7ef382018-02-27 22:59:25 +020038#include "igt_matrix.h"
Chris Wilson6a06d012018-02-27 21:45:14 +000039#include "igt_x86.h"
Daniel Vetter57d7db82014-03-26 09:06:11 +010040#include "ioctl_wrappers.h"
Lionel Landwerlin8bde13a2018-05-06 23:08:46 +010041#include "intel_batchbuffer.h"
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -020042#include "intel_chipset.h"
Daniel Vetter57d7db82014-03-26 09:06:11 +010043
Daniel Vetterc6c2b2b2014-03-26 15:15:49 +010044/**
45 * SECTION:igt_fb
46 * @short_description: Framebuffer handling and drawing library
Damien Lespiau6ebd8c22015-06-26 14:28:41 +010047 * @title: Framebuffer
Thomas Woodf0381d12015-09-07 09:26:01 +010048 * @include: igt.h
Daniel Vetter3d9e63f2014-03-26 16:37:15 +010049 *
50 * This library contains helper functions for handling kms framebuffer objects
51 * using #igt_fb structures to track all the metadata. igt_create_fb() creates
Thomas Woodd01ebbd2015-06-29 16:47:14 +010052 * a basic framebuffer and igt_remove_fb() cleans everything up again.
Daniel Vetter3d9e63f2014-03-26 16:37:15 +010053 *
54 * It also supports drawing using the cairo library and provides some simplified
55 * helper functions to easily draw test patterns. The main function to create a
56 * cairo drawing context for a framebuffer object is igt_get_cairo_ctx().
57 *
58 * Finally it also pulls in the drm fourcc headers and provides some helper
59 * functions to work with these pixel format codes.
Daniel Vetterc6c2b2b2014-03-26 15:15:49 +010060 */
61
Daniel Vetter57d7db82014-03-26 09:06:11 +010062/* drm fourcc/cairo format maps */
Daniel Vetter57d7db82014-03-26 09:06:11 +010063static struct format_desc_struct {
Ville Syrjäläe556d852018-02-27 22:48:46 +020064 const char *name;
Daniel Vetter57d7db82014-03-26 09:06:11 +010065 uint32_t drm_id;
66 cairo_format_t cairo_id;
Daniel Vetter57d7db82014-03-26 09:06:11 +010067 int depth;
Ville Syrjäläe556d852018-02-27 22:48:46 +020068 int num_planes;
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +010069 int plane_bpp[4];
Daniel Vetter57d7db82014-03-26 09:06:11 +010070} format_desc[] = {
Ville Syrjäläe556d852018-02-27 22:48:46 +020071 { .name = "RGB565", .depth = 16, .drm_id = DRM_FORMAT_RGB565,
72 .cairo_id = CAIRO_FORMAT_RGB16_565,
73 .num_planes = 1, .plane_bpp = { 16, },
74 },
75 { .name = "XRGB8888", .depth = 24, .drm_id = DRM_FORMAT_XRGB8888,
76 .cairo_id = CAIRO_FORMAT_RGB24,
77 .num_planes = 1, .plane_bpp = { 32, },
78 },
79 { .name = "XRGB2101010", .depth = 30, .drm_id = DRM_FORMAT_XRGB2101010,
80 .cairo_id = CAIRO_FORMAT_RGB30,
81 .num_planes = 1, .plane_bpp = { 32, },
82 },
83 { .name = "ARGB8888", .depth = 32, .drm_id = DRM_FORMAT_ARGB8888,
84 .cairo_id = CAIRO_FORMAT_ARGB32,
85 .num_planes = 1, .plane_bpp = { 32, },
86 },
87 { .name = "NV12", .depth = -1, .drm_id = DRM_FORMAT_NV12,
88 .cairo_id = CAIRO_FORMAT_RGB24,
89 .num_planes = 2, .plane_bpp = { 8, 16, },
90 },
Ville Syrjäläfed97c42018-02-27 22:58:01 +020091 { .name = "YUYV", .depth = -1, .drm_id = DRM_FORMAT_YUYV,
92 .cairo_id = CAIRO_FORMAT_RGB24,
93 .num_planes = 1, .plane_bpp = { 16, },
94 },
95 { .name = "YVYU", .depth = -1, .drm_id = DRM_FORMAT_YVYU,
96 .cairo_id = CAIRO_FORMAT_RGB24,
97 .num_planes = 1, .plane_bpp = { 16, },
98 },
99 { .name = "UYVY", .depth = -1, .drm_id = DRM_FORMAT_UYVY,
100 .cairo_id = CAIRO_FORMAT_RGB24,
101 .num_planes = 1, .plane_bpp = { 16, },
102 },
103 { .name = "VYUY", .depth = -1, .drm_id = DRM_FORMAT_VYUY,
104 .cairo_id = CAIRO_FORMAT_RGB24,
105 .num_planes = 1, .plane_bpp = { 16, },
106 },
Daniel Vetter57d7db82014-03-26 09:06:11 +0100107};
Daniel Vetter57d7db82014-03-26 09:06:11 +0100108#define for_each_format(f) \
109 for (f = format_desc; f - format_desc < ARRAY_SIZE(format_desc); f++)
110
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100111static struct format_desc_struct *lookup_drm_format(uint32_t drm_format)
112{
113 struct format_desc_struct *format;
114
115 for_each_format(format) {
116 if (format->drm_id != drm_format)
117 continue;
118
119 return format;
120 }
121
122 return NULL;
123}
124
Praveen Paneri4bb45412017-07-18 22:52:56 +0530125/**
126 * igt_get_fb_tile_size:
127 * @fd: the DRM file descriptor
128 * @tiling: tiling layout of the framebuffer (as framebuffer modifier)
129 * @fb_bpp: bits per pixel of the framebuffer
130 * @width_ret: width of the tile in bytes
131 * @height_ret: height of the tile in lines
132 *
133 * This function returns width and height of a tile based on the given tiling
134 * format.
135 */
136void igt_get_fb_tile_size(int fd, uint64_t tiling, int fb_bpp,
137 unsigned *width_ret, unsigned *height_ret)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100138{
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200139 switch (tiling) {
140 case LOCAL_DRM_FORMAT_MOD_NONE:
141 *width_ret = 64;
142 *height_ret = 1;
143 break;
144 case LOCAL_I915_FORMAT_MOD_X_TILED:
Tomeu Vizoso85a1d452016-02-24 08:39:53 +0100145 igt_require_intel(fd);
146 if (intel_gen(intel_get_drm_devid(fd)) == 2) {
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200147 *width_ret = 128;
148 *height_ret = 16;
149 } else {
150 *width_ret = 512;
151 *height_ret = 8;
152 }
153 break;
154 case LOCAL_I915_FORMAT_MOD_Y_TILED:
Tomeu Vizoso85a1d452016-02-24 08:39:53 +0100155 igt_require_intel(fd);
156 if (intel_gen(intel_get_drm_devid(fd)) == 2) {
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200157 *width_ret = 128;
Ville Syrjälä037bc692016-02-12 21:28:54 +0200158 *height_ret = 16;
Tomeu Vizoso85a1d452016-02-24 08:39:53 +0100159 } else if (IS_915(intel_get_drm_devid(fd))) {
Ville Syrjälä037bc692016-02-12 21:28:54 +0200160 *width_ret = 512;
161 *height_ret = 8;
162 } else {
163 *width_ret = 128;
164 *height_ret = 32;
165 }
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200166 break;
167 case LOCAL_I915_FORMAT_MOD_Yf_TILED:
Tomeu Vizoso85a1d452016-02-24 08:39:53 +0100168 igt_require_intel(fd);
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200169 switch (fb_bpp) {
170 case 8:
171 *width_ret = 64;
172 *height_ret = 64;
173 break;
174 case 16:
175 case 32:
176 *width_ret = 128;
177 *height_ret = 32;
178 break;
179 case 64:
180 case 128:
181 *width_ret = 256;
182 *height_ret = 16;
183 break;
184 default:
185 igt_assert(false);
186 }
187 break;
188 default:
189 igt_assert(false);
190 }
191}
192
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100193static unsigned planar_width(struct format_desc_struct *format, unsigned width, int plane)
194{
195 if (format->drm_id == DRM_FORMAT_NV12 && plane == 1)
196 return (width + 1) / 2;
197
198 return width;
199}
200
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100201static unsigned planar_stride(struct format_desc_struct *format, unsigned width, int plane)
202{
203 unsigned cpp = format->plane_bpp[plane] / 8;
204
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100205 return planar_width(format, width, plane) * cpp;
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100206}
207
208static unsigned planar_height(struct format_desc_struct *format, unsigned height, int plane)
209{
210 if (format->drm_id == DRM_FORMAT_NV12 && plane == 1)
211 return (height + 1) / 2;
212
213 return height;
214}
215
216static void calc_fb_size_planar(int fd, int width, int height,
217 struct format_desc_struct *format,
218 uint64_t tiling, unsigned *size_ret,
219 unsigned *stride_ret, unsigned *offsets)
220{
221 int plane;
222 unsigned stride = 0, tile_width, tile_height;
223
224 *size_ret = 0;
225
Ville Syrjäläe556d852018-02-27 22:48:46 +0200226 for (plane = 0; plane < format->num_planes; plane++) {
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100227 unsigned plane_stride;
228
229 igt_get_fb_tile_size(fd, tiling, format->plane_bpp[plane], &tile_width, &tile_height);
230
231 plane_stride = ALIGN(planar_stride(format, width, plane), tile_width);
232 if (stride < plane_stride)
233 stride = plane_stride;
234 }
235
Ville Syrjäläe556d852018-02-27 22:48:46 +0200236 for (plane = 0; plane < format->num_planes; plane++) {
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100237 if (offsets)
238 offsets[plane] = *size_ret;
239
240 igt_get_fb_tile_size(fd, tiling, format->plane_bpp[plane], &tile_width, &tile_height);
241
242 *size_ret += stride * ALIGN(planar_height(format, height, plane), tile_height);
243 }
244
245 if (offsets)
246 for (; plane < ARRAY_SIZE(format->plane_bpp); plane++)
247 offsets[plane] = 0;
248
249 *stride_ret = stride;
250}
251
252static void calc_fb_size_packed(int fd, int width, int height,
253 struct format_desc_struct *format, uint64_t tiling,
254 unsigned *size_ret, unsigned *stride_ret)
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200255{
256 unsigned int tile_width, tile_height, stride, size;
Ville Syrjäläe556d852018-02-27 22:48:46 +0200257 int byte_width = width * (format->plane_bpp[0] / 8);
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200258
Ville Syrjäläe556d852018-02-27 22:48:46 +0200259 igt_get_fb_tile_size(fd, tiling, format->plane_bpp[0], &tile_width, &tile_height);
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200260
Tomeu Vizoso85a1d452016-02-24 08:39:53 +0100261 if (tiling != LOCAL_DRM_FORMAT_MOD_NONE &&
262 intel_gen(intel_get_drm_devid(fd)) <= 3) {
Daniel Vetter57d7db82014-03-26 09:06:11 +0100263 int v;
264
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200265 /* Round the tiling up to the next power-of-two and the region
266 * up to the next pot fence size so that this works on all
267 * generations.
Daniel Vetter57d7db82014-03-26 09:06:11 +0100268 *
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200269 * This can still fail if the framebuffer is too large to be
270 * tiled. But then that failure is expected.
Daniel Vetter57d7db82014-03-26 09:06:11 +0100271 */
272
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100273 v = byte_width;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100274 for (stride = 512; stride < v; stride *= 2)
275 ;
276
277 v = stride * height;
278 for (size = 1024*1024; size < v; size *= 2)
279 ;
280 } else {
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200281 stride = ALIGN(byte_width, tile_width);
282 size = stride * ALIGN(height, tile_height);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100283 }
284
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200285 *stride_ret = stride;
286 *size_ret = size;
287}
288
Tomeu Vizosoae649632016-11-10 10:25:24 +0100289/**
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100290 * igt_calc_fb_size:
291 * @fd: the DRM file descriptor
292 * @width: width of the framebuffer in pixels
293 * @height: height of the framebuffer in pixels
294 * @format: drm fourcc pixel format code
295 * @tiling: tiling layout of the framebuffer (as framebuffer modifier)
296 * @size_ret: returned size for the framebuffer
297 * @stride_ret: returned stride for the framebuffer
298 *
299 * This function returns valid stride and size values for a framebuffer with the
300 * specified parameters.
301 */
302void igt_calc_fb_size(int fd, int width, int height, uint32_t drm_format, uint64_t tiling,
303 unsigned *size_ret, unsigned *stride_ret)
304{
305 struct format_desc_struct *format = lookup_drm_format(drm_format);
306 igt_assert(format);
307
Ville Syrjäläe556d852018-02-27 22:48:46 +0200308 if (format->num_planes > 1)
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100309 calc_fb_size_planar(fd, width, height, format, tiling, size_ret, stride_ret, NULL);
310 else
311 calc_fb_size_packed(fd, width, height, format, tiling, size_ret, stride_ret);
312}
313
314/**
Tomeu Vizosoae649632016-11-10 10:25:24 +0100315 * igt_fb_mod_to_tiling:
316 * @modifier: DRM framebuffer modifier
317 *
318 * This function converts a DRM framebuffer modifier to its corresponding
319 * tiling constant.
320 *
321 * Returns:
322 * A tiling constant
323 */
324uint64_t igt_fb_mod_to_tiling(uint64_t modifier)
325{
326 switch (modifier) {
327 case LOCAL_DRM_FORMAT_MOD_NONE:
328 return I915_TILING_NONE;
329 case LOCAL_I915_FORMAT_MOD_X_TILED:
330 return I915_TILING_X;
331 case LOCAL_I915_FORMAT_MOD_Y_TILED:
332 return I915_TILING_Y;
333 case LOCAL_I915_FORMAT_MOD_Yf_TILED:
334 return I915_TILING_Yf;
335 default:
336 igt_assert(0);
337 }
338}
339
Praveen Paneri4437e212017-07-18 22:52:57 +0530340/**
341 * igt_fb_tiling_to_mod:
342 * @tiling: DRM framebuffer tiling
343 *
344 * This function converts a DRM framebuffer tiling to its corresponding
345 * modifier constant.
346 *
347 * Returns:
348 * A modifier constant
349 */
350uint64_t igt_fb_tiling_to_mod(uint64_t tiling)
351{
352 switch (tiling) {
353 case I915_TILING_NONE:
354 return LOCAL_DRM_FORMAT_MOD_NONE;
355 case I915_TILING_X:
356 return LOCAL_I915_FORMAT_MOD_X_TILED;
357 case I915_TILING_Y:
358 return LOCAL_I915_FORMAT_MOD_Y_TILED;
359 case I915_TILING_Yf:
360 return LOCAL_I915_FORMAT_MOD_Yf_TILED;
361 default:
362 igt_assert(0);
363 }
364}
365
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200366/* helpers to create nice-looking framebuffers */
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100367static int create_bo_for_fb(int fd, int width, int height,
Ville Syrjäläb6975342018-03-06 20:01:22 +0200368 enum igt_color_encoding color_encoding,
369 enum igt_color_range color_range,
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100370 struct format_desc_struct *format,
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200371 uint64_t tiling, unsigned size, unsigned stride,
372 unsigned *size_ret, unsigned *stride_ret,
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100373 uint32_t *offsets, bool *is_dumb)
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200374{
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200375 int bo;
376
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100377 igt_assert(format);
378
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100379 if (offsets)
380 memset(offsets, 0, ARRAY_SIZE(format->plane_bpp) * sizeof(*offsets));
381
Ville Syrjälä87907562018-02-27 22:57:16 +0200382 if (tiling || size || stride || igt_format_is_yuv(format->drm_id)) {
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200383 unsigned calculated_size, calculated_stride;
384
Ville Syrjäläe556d852018-02-27 22:48:46 +0200385 if (format->num_planes > 1)
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100386 calc_fb_size_planar(fd, width, height, format, tiling,
387 &calculated_size, &calculated_stride, offsets);
388 else
389 calc_fb_size_packed(fd, width, height, format, tiling,
390 &calculated_size, &calculated_stride);
391
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200392 if (stride == 0)
393 stride = calculated_stride;
394 if (size == 0)
395 size = calculated_size;
396
397 if (is_dumb)
398 *is_dumb = false;
399
400 if (is_i915_device(fd)) {
Ville Syrjäläe867d652018-02-27 22:39:26 +0200401 void *ptr;
Ville Syrjäläb6975342018-03-06 20:01:22 +0200402 bool full_range = color_range == IGT_COLOR_YCBCR_FULL_RANGE;
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200403
404 bo = gem_create(fd, size);
Tomeu Vizosoae649632016-11-10 10:25:24 +0100405 gem_set_tiling(fd, bo, igt_fb_mod_to_tiling(tiling), stride);
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200406
Chris Wilsond2805062016-08-18 13:56:18 +0100407 /* Ensure the framebuffer is preallocated */
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +0100408 ptr = gem_mmap__gtt(fd, bo, size, PROT_READ | PROT_WRITE);
409 igt_assert(*(uint32_t *)ptr == 0);
410
Ville Syrjäläe867d652018-02-27 22:39:26 +0200411 switch (format->drm_id) {
412 case DRM_FORMAT_NV12:
413 memset(ptr + offsets[0], full_range ? 0x00 : 0x10,
414 calculated_stride * height);
415 memset(ptr + offsets[1], 0x80,
416 calculated_stride * height/2);
417 break;
418 case DRM_FORMAT_YUYV:
419 case DRM_FORMAT_YVYU:
420 wmemset(ptr, full_range ? 0x80008000 : 0x80108010,
421 calculated_stride * height / sizeof(wchar_t));
422 break;
423 case DRM_FORMAT_UYVY:
424 case DRM_FORMAT_VYUY:
425 wmemset(ptr, full_range ? 0x00800080 : 0x10801080,
426 calculated_stride * height / sizeof(wchar_t));
427 break;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +0100428 }
Maarten Lankhorstd930b642017-02-09 10:42:01 +0100429 gem_munmap(ptr, size);
Chris Wilsond2805062016-08-18 13:56:18 +0100430
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200431 if (size_ret)
432 *size_ret = size;
433
434 if (stride_ret)
435 *stride_ret = stride;
436
437 return bo;
438 } else {
439 bool driver_has_gem_api = false;
440
441 igt_require(driver_has_gem_api);
442 return -EINVAL;
443 }
444 } else {
445 if (is_dumb)
446 *is_dumb = true;
447
Ville Syrjäläe556d852018-02-27 22:48:46 +0200448 return kmstest_dumb_create(fd, width, height,
449 format->plane_bpp[0],
450 stride_ret, size_ret);
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200451 }
452}
453
Tomeu Vizoso8a1a3862016-02-24 09:04:04 +0100454/**
455 * igt_create_bo_with_dimensions:
456 * @fd: open drm file descriptor
457 * @width: width of the buffer object in pixels
458 * @height: height of the buffer object in pixels
459 * @format: drm fourcc pixel format code
460 * @modifier: modifier corresponding to the tiling layout of the buffer object
461 * @stride: stride of the buffer object in bytes (0 for automatic stride)
462 * @size_ret: size of the buffer object as created by the kernel
463 * @stride_ret: stride of the buffer object as created by the kernel
464 * @is_dumb: whether the created buffer object is a dumb buffer or not
465 *
466 * This function allocates a gem buffer object matching the requested
467 * properties.
468 *
469 * Returns:
470 * The kms id of the created buffer object.
471 */
472int igt_create_bo_with_dimensions(int fd, int width, int height,
473 uint32_t format, uint64_t modifier,
474 unsigned stride, unsigned *size_ret,
475 unsigned *stride_ret, bool *is_dumb)
476{
Ville Syrjäläb6975342018-03-06 20:01:22 +0200477 return create_bo_for_fb(fd, width, height,
478 IGT_COLOR_YCBCR_BT709,
479 IGT_COLOR_YCBCR_LIMITED_RANGE,
480 lookup_drm_format(format),
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100481 modifier, 0, stride, size_ret, stride_ret, NULL, is_dumb);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100482}
483
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100484/**
485 * igt_paint_color:
486 * @cr: cairo drawing context
487 * @x: pixel x-coordination of the fill rectangle
488 * @y: pixel y-coordination of the fill rectangle
489 * @w: width of the fill rectangle
490 * @h: height of the fill rectangle
491 * @r: red value to use as fill color
Thomas Woodd01ebbd2015-06-29 16:47:14 +0100492 * @g: green value to use as fill color
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100493 * @b: blue value to use as fill color
494 *
495 * This functions draws a solid rectangle with the given color using the drawing
496 * context @cr.
497 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100498void igt_paint_color(cairo_t *cr, int x, int y, int w, int h,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100499 double r, double g, double b)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100500{
501 cairo_rectangle(cr, x, y, w, h);
502 cairo_set_source_rgb(cr, r, g, b);
503 cairo_fill(cr);
504}
505
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100506/**
507 * igt_paint_color_alpha:
508 * @cr: cairo drawing context
509 * @x: pixel x-coordination of the fill rectangle
510 * @y: pixel y-coordination of the fill rectangle
511 * @w: width of the fill rectangle
512 * @h: height of the fill rectangle
513 * @r: red value to use as fill color
Thomas Woodd01ebbd2015-06-29 16:47:14 +0100514 * @g: green value to use as fill color
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100515 * @b: blue value to use as fill color
516 * @a: alpha value to use as fill color
517 *
518 * This functions draws a rectangle with the given color and alpha values using
519 * the drawing context @cr.
520 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100521void igt_paint_color_alpha(cairo_t *cr, int x, int y, int w, int h,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100522 double r, double g, double b, double a)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100523{
524 cairo_rectangle(cr, x, y, w, h);
525 cairo_set_source_rgba(cr, r, g, b, a);
526 cairo_fill(cr);
527}
528
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100529/**
530 * igt_paint_color_gradient:
531 * @cr: cairo drawing context
532 * @x: pixel x-coordination of the fill rectangle
533 * @y: pixel y-coordination of the fill rectangle
534 * @w: width of the fill rectangle
535 * @h: height of the fill rectangle
536 * @r: red value to use as fill color
Thomas Woodd01ebbd2015-06-29 16:47:14 +0100537 * @g: green value to use as fill color
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100538 * @b: blue value to use as fill color
539 *
540 * This functions draws a gradient into the rectangle which fades in from black
541 * to the given values using the drawing context @cr.
542 */
Daniel Vetter57d7db82014-03-26 09:06:11 +0100543void
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100544igt_paint_color_gradient(cairo_t *cr, int x, int y, int w, int h,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100545 int r, int g, int b)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100546{
547 cairo_pattern_t *pat;
548
549 pat = cairo_pattern_create_linear(x, y, x + w, y + h);
550 cairo_pattern_add_color_stop_rgba(pat, 1, 0, 0, 0, 1);
551 cairo_pattern_add_color_stop_rgba(pat, 0, r, g, b, 1);
552
553 cairo_rectangle(cr, x, y, w, h);
554 cairo_set_source(cr, pat);
555 cairo_fill(cr);
556 cairo_pattern_destroy(pat);
557}
558
Lionel Landwerlina5113102016-03-18 17:33:02 +0000559/**
560 * igt_paint_color_gradient_range:
561 * @cr: cairo drawing context
562 * @x: pixel x-coordination of the fill rectangle
563 * @y: pixel y-coordination of the fill rectangle
564 * @w: width of the fill rectangle
565 * @h: height of the fill rectangle
566 * @sr: red value to use as start gradient color
567 * @sg: green value to use as start gradient color
568 * @sb: blue value to use as start gradient color
569 * @er: red value to use as end gradient color
570 * @eg: green value to use as end gradient color
571 * @eb: blue value to use as end gradient color
572 *
573 * This functions draws a gradient into the rectangle which fades in
574 * from one color to the other using the drawing context @cr.
575 */
576void
577igt_paint_color_gradient_range(cairo_t *cr, int x, int y, int w, int h,
578 double sr, double sg, double sb,
579 double er, double eg, double eb)
580{
581 cairo_pattern_t *pat;
582
583 pat = cairo_pattern_create_linear(x, y, x + w, y + h);
584 cairo_pattern_add_color_stop_rgba(pat, 1, sr, sg, sb, 1);
585 cairo_pattern_add_color_stop_rgba(pat, 0, er, eg, eb, 1);
586
587 cairo_rectangle(cr, x, y, w, h);
588 cairo_set_source(cr, pat);
589 cairo_fill(cr);
590 cairo_pattern_destroy(pat);
591}
592
Daniel Vetter57d7db82014-03-26 09:06:11 +0100593static void
594paint_test_patterns(cairo_t *cr, int width, int height)
595{
596 double gr_height, gr_width;
597 int x, y;
598
599 y = height * 0.10;
600 gr_width = width * 0.75;
601 gr_height = height * 0.08;
602 x = (width / 2) - (gr_width / 2);
603
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100604 igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 1, 0, 0);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100605
606 y += gr_height;
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100607 igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 0, 1, 0);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100608
609 y += gr_height;
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100610 igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 0, 0, 1);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100611
612 y += gr_height;
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100613 igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 1, 1, 1);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100614}
615
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100616/**
617 * igt_cairo_printf_line:
618 * @cr: cairo drawing context
619 * @align: text alignment
620 * @yspacing: additional y-direction feed after this line
621 * @fmt: format string
622 * @...: optional arguments used in the format string
623 *
624 * This is a little helper to draw text onto framebuffers. All the initial setup
625 * (like setting the font size and the moving to the starting position) still
626 * needs to be done manually with explicit cairo calls on @cr.
627 *
628 * Returns:
629 * The width of the drawn text.
630 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100631int igt_cairo_printf_line(cairo_t *cr, enum igt_text_align align,
Daniel Vetter57d7db82014-03-26 09:06:11 +0100632 double yspacing, const char *fmt, ...)
633{
634 double x, y, xofs, yofs;
635 cairo_text_extents_t extents;
636 char *text;
637 va_list ap;
638 int ret;
639
640 va_start(ap, fmt);
641 ret = vasprintf(&text, fmt, ap);
642 igt_assert(ret >= 0);
643 va_end(ap);
644
645 cairo_text_extents(cr, text, &extents);
646
647 xofs = yofs = 0;
648 if (align & align_right)
649 xofs = -extents.width;
650 else if (align & align_hcenter)
651 xofs = -extents.width / 2;
652
653 if (align & align_top)
654 yofs = extents.height;
655 else if (align & align_vcenter)
656 yofs = extents.height / 2;
657
658 cairo_get_current_point(cr, &x, &y);
659 if (xofs || yofs)
660 cairo_rel_move_to(cr, xofs, yofs);
661
662 cairo_text_path(cr, text);
663 cairo_set_source_rgb(cr, 0, 0, 0);
664 cairo_stroke_preserve(cr);
665 cairo_set_source_rgb(cr, 1, 1, 1);
666 cairo_fill(cr);
667
668 cairo_move_to(cr, x, y + extents.height + yspacing);
669
670 free(text);
671
672 return extents.width;
673}
674
675static void
676paint_marker(cairo_t *cr, int x, int y)
677{
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100678 enum igt_text_align align;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100679 int xoff, yoff;
680
681 cairo_move_to(cr, x, y - 20);
682 cairo_line_to(cr, x, y + 20);
683 cairo_move_to(cr, x - 20, y);
684 cairo_line_to(cr, x + 20, y);
685 cairo_new_sub_path(cr);
686 cairo_arc(cr, x, y, 10, 0, M_PI * 2);
687 cairo_set_line_width(cr, 4);
688 cairo_set_source_rgb(cr, 0, 0, 0);
689 cairo_stroke_preserve(cr);
690 cairo_set_source_rgb(cr, 1, 1, 1);
691 cairo_set_line_width(cr, 2);
692 cairo_stroke(cr);
693
694 xoff = x ? -20 : 20;
695 align = x ? align_right : align_left;
696
697 yoff = y ? -20 : 20;
698 align |= y ? align_bottom : align_top;
699
700 cairo_move_to(cr, x + xoff, y + yoff);
701 cairo_set_font_size(cr, 18);
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100702 igt_cairo_printf_line(cr, align, 0, "(%d, %d)", x, y);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100703}
704
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100705/**
706 * igt_paint_test_pattern:
707 * @cr: cairo drawing context
708 * @width: width of the visible area
709 * @height: height of the visible area
710 *
711 * This functions draws an entire set of test patterns for the given visible
712 * area using the drawing context @cr. This is useful for manual visual
713 * inspection of displayed framebuffers.
714 *
715 * The test patterns include
716 * - corner markers to check for over/underscan and
717 * - a set of color and b/w gradients.
718 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100719void igt_paint_test_pattern(cairo_t *cr, int width, int height)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100720{
721 paint_test_patterns(cr, width, height);
722
723 cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
724
725 /* Paint corner markers */
726 paint_marker(cr, 0, 0);
727 paint_marker(cr, width, 0);
728 paint_marker(cr, 0, height);
729 paint_marker(cr, width, height);
730
731 igt_assert(!cairo_status(cr));
732}
733
Thomas Woodecb03262015-04-13 17:37:22 +0100734static cairo_status_t
735stdio_read_func(void *closure, unsigned char* data, unsigned int size)
736{
737 if (fread(data, 1, size, (FILE*)closure) != size)
738 return CAIRO_STATUS_READ_ERROR;
739
740 return CAIRO_STATUS_SUCCESS;
741}
742
Ville Syrjälä75f320c2017-09-21 15:39:23 +0300743cairo_surface_t *igt_cairo_image_surface_create_from_png(const char *filename)
744{
745 cairo_surface_t *image;
746 FILE *f;
747
748 f = igt_fopen_data(filename);
749 image = cairo_image_surface_create_from_png_stream(&stdio_read_func, f);
750 fclose(f);
751
752 return image;
753}
754
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100755/**
756 * igt_paint_image:
757 * @cr: cairo drawing context
758 * @filename: filename of the png image to draw
759 * @dst_x: pixel x-coordination of the destination rectangle
760 * @dst_y: pixel y-coordination of the destination rectangle
761 * @dst_width: width of the destination rectangle
762 * @dst_height: height of the destination rectangle
763 *
Thomas Woodecb03262015-04-13 17:37:22 +0100764 * This function can be used to draw a scaled version of the supplied png image,
765 * which is loaded from the package data directory.
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100766 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100767void igt_paint_image(cairo_t *cr, const char *filename,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100768 int dst_x, int dst_y, int dst_width, int dst_height)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100769{
770 cairo_surface_t *image;
771 int img_width, img_height;
772 double scale_x, scale_y;
773
Ville Syrjälä75f320c2017-09-21 15:39:23 +0300774 image = igt_cairo_image_surface_create_from_png(filename);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100775 igt_assert(cairo_surface_status(image) == CAIRO_STATUS_SUCCESS);
776
777 img_width = cairo_image_surface_get_width(image);
778 img_height = cairo_image_surface_get_height(image);
779
780 scale_x = (double)dst_width / img_width;
781 scale_y = (double)dst_height / img_height;
782
783 cairo_save(cr);
784
785 cairo_translate(cr, dst_x, dst_y);
786 cairo_scale(cr, scale_x, scale_y);
787 cairo_set_source_surface(cr, image, 0, 0);
788 cairo_paint(cr);
789
790 cairo_surface_destroy(image);
791
792 cairo_restore(cr);
793}
794
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100795/**
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100796 * igt_create_fb_with_bo_size:
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100797 * @fd: open i915 drm file descriptor
798 * @width: width of the framebuffer in pixel
799 * @height: height of the framebuffer in pixel
800 * @format: drm fourcc pixel format code
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000801 * @tiling: tiling layout of the framebuffer (as framebuffer modifier)
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100802 * @fb: pointer to an #igt_fb structure
Paulo Zanonicb7dd5d2015-11-05 16:18:55 -0200803 * @bo_size: size of the backing bo (0 for automatic size)
Paulo Zanonid6341372015-11-05 16:39:00 -0200804 * @bo_stride: stride of the backing bo (0 for automatic stride)
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100805 *
806 * This function allocates a gem buffer object suitable to back a framebuffer
807 * with the requested properties and then wraps it up in a drm framebuffer
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100808 * object of the requested size. All metadata is stored in @fb.
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100809 *
810 * The backing storage of the framebuffer is filled with all zeros, i.e. black
811 * for rgb pixel formats.
812 *
813 * Returns:
Damien Lespiau50166d22014-08-19 11:55:22 +0100814 * The kms id of the created framebuffer.
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100815 */
Damien Lespiau378e61e2014-06-23 14:53:24 +0100816unsigned int
817igt_create_fb_with_bo_size(int fd, int width, int height,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000818 uint32_t format, uint64_t tiling,
Paulo Zanonid6341372015-11-05 16:39:00 -0200819 struct igt_fb *fb, unsigned bo_size,
820 unsigned bo_stride)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100821{
Ville Syrjäläb6975342018-03-06 20:01:22 +0200822 /* FIXME allow the caller to pass these in */
823 enum igt_color_encoding color_encoding = IGT_COLOR_YCBCR_BT709;
824 enum igt_color_range color_range = IGT_COLOR_YCBCR_LIMITED_RANGE;
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100825 struct format_desc_struct *f = lookup_drm_format(format);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100826 uint32_t fb_id;
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100827 int i;
828
829 igt_assert_f(f, "DRM format %08x not found\n", format);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100830
831 memset(fb, 0, sizeof(*fb));
832
Tomeu Vizoso8a1a3862016-02-24 09:04:04 +0100833 igt_debug("%s(width=%d, height=%d, format=0x%x, tiling=0x%"PRIx64", size=%d)\n",
834 __func__, width, height, format, tiling, bo_size);
Ville Syrjäläb6975342018-03-06 20:01:22 +0200835 fb->gem_handle = create_bo_for_fb(fd, width, height,
836 color_encoding, color_range,
837 f, tiling, bo_size, bo_stride,
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100838 &fb->size, &fb->stride,
839 fb->offsets, &fb->is_dumb);
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200840 igt_assert(fb->gem_handle > 0);
Chris Wilsondb4cc742014-09-06 12:07:49 +0100841
Chris Wilsondb4cc742014-09-06 12:07:49 +0100842 igt_debug("%s(handle=%d, pitch=%d)\n",
Tvrtko Ursulineb93c1b2015-03-03 14:11:03 +0000843 __func__, fb->gem_handle, fb->stride);
844
845 if (tiling != LOCAL_DRM_FORMAT_MOD_NONE &&
846 tiling != LOCAL_I915_FORMAT_MOD_X_TILED) {
847 do_or_die(__kms_addfb(fd, fb->gem_handle, width, height,
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100848 fb->stride, format, tiling, fb->offsets,
Tvrtko Ursulineb93c1b2015-03-03 14:11:03 +0000849 LOCAL_DRM_MODE_FB_MODIFIERS, &fb_id));
850 } else {
851 uint32_t handles[4];
852 uint32_t pitches[4];
Tvrtko Ursulineb93c1b2015-03-03 14:11:03 +0000853
854 memset(handles, 0, sizeof(handles));
855 memset(pitches, 0, sizeof(pitches));
Tvrtko Ursulineb93c1b2015-03-03 14:11:03 +0000856
857 handles[0] = fb->gem_handle;
858 pitches[0] = fb->stride;
Ville Syrjäläe556d852018-02-27 22:48:46 +0200859 for (i = 0; i < f->num_planes; i++) {
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100860 handles[i] = fb->gem_handle;
861 pitches[i] = fb->stride;
862 }
Tvrtko Ursulineb93c1b2015-03-03 14:11:03 +0000863
864 do_or_die(drmModeAddFB2(fd, width, height, format,
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100865 handles, pitches, fb->offsets,
Tvrtko Ursulineb93c1b2015-03-03 14:11:03 +0000866 &fb_id, 0));
867 }
Daniel Vetter57d7db82014-03-26 09:06:11 +0100868
869 fb->width = width;
870 fb->height = height;
Damien Lespiau378e61e2014-06-23 14:53:24 +0100871 fb->tiling = tiling;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100872 fb->drm_format = format;
873 fb->fb_id = fb_id;
Tomeu Vizoso89b3ffe2016-02-24 09:04:41 +0100874 fb->fd = fd;
Ville Syrjäläe556d852018-02-27 22:48:46 +0200875 fb->num_planes = f->num_planes;
Ville Syrjäläb6975342018-03-06 20:01:22 +0200876 fb->color_encoding = color_encoding;
877 fb->color_range = color_range;
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100878
Ville Syrjäläe556d852018-02-27 22:48:46 +0200879 for (i = 0; i < f->num_planes; i++) {
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100880 fb->plane_bpp[i] = f->plane_bpp[i];
881 fb->plane_height[i] = planar_height(f, height, i);
882 fb->plane_width[i] = planar_width(f, width, i);
883 }
Daniel Vetter57d7db82014-03-26 09:06:11 +0100884
885 return fb_id;
886}
887
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100888/**
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100889 * igt_create_fb:
890 * @fd: open i915 drm file descriptor
891 * @width: width of the framebuffer in pixel
892 * @height: height of the framebuffer in pixel
893 * @format: drm fourcc pixel format code
Damien Lespiau378e61e2014-06-23 14:53:24 +0100894 * @tiling: tiling layout of the framebuffer
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100895 * @fb: pointer to an #igt_fb structure
896 *
897 * This function allocates a gem buffer object suitable to back a framebuffer
898 * with the requested properties and then wraps it up in a drm framebuffer
899 * object. All metadata is stored in @fb.
900 *
901 * The backing storage of the framebuffer is filled with all zeros, i.e. black
902 * for rgb pixel formats.
903 *
904 * Returns:
Damien Lespiau50166d22014-08-19 11:55:22 +0100905 * The kms id of the created framebuffer.
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100906 */
907unsigned int igt_create_fb(int fd, int width, int height, uint32_t format,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000908 uint64_t tiling, struct igt_fb *fb)
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100909{
Paulo Zanonid6341372015-11-05 16:39:00 -0200910 return igt_create_fb_with_bo_size(fd, width, height, format, tiling, fb,
911 0, 0);
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100912}
913
914/**
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100915 * igt_create_color_fb:
916 * @fd: open i915 drm file descriptor
917 * @width: width of the framebuffer in pixel
918 * @height: height of the framebuffer in pixel
919 * @format: drm fourcc pixel format code
Damien Lespiau378e61e2014-06-23 14:53:24 +0100920 * @tiling: tiling layout of the framebuffer
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100921 * @r: red value to use as fill color
Ville Syrjälä5b113d32015-12-17 01:39:31 +0200922 * @g: green value to use as fill color
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100923 * @b: blue value to use as fill color
924 * @fb: pointer to an #igt_fb structure
925 *
926 * This function allocates a gem buffer object suitable to back a framebuffer
927 * with the requested properties and then wraps it up in a drm framebuffer
928 * object. All metadata is stored in @fb.
929 *
930 * Compared to igt_create_fb() this function also fills the entire framebuffer
931 * with the given color, which is useful for some simple pipe crc based tests.
932 *
933 * Returns:
934 * The kms id of the created framebuffer on success or a negative error code on
935 * failure.
936 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100937unsigned int igt_create_color_fb(int fd, int width, int height,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000938 uint32_t format, uint64_t tiling,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100939 double r, double g, double b,
940 struct igt_fb *fb /* out */)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100941{
942 unsigned int fb_id;
943 cairo_t *cr;
944
Damien Lespiau378e61e2014-06-23 14:53:24 +0100945 fb_id = igt_create_fb(fd, width, height, format, tiling, fb);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100946 igt_assert(fb_id);
947
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100948 cr = igt_get_cairo_ctx(fd, fb);
949 igt_paint_color(cr, 0, 0, width, height, r, g, b);
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +0100950 igt_put_cairo_ctx(fd, fb, cr);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100951
952 return fb_id;
953}
954
Ville Syrjälä5b113d32015-12-17 01:39:31 +0200955/**
956 * igt_create_pattern_fb:
957 * @fd: open i915 drm file descriptor
958 * @width: width of the framebuffer in pixel
959 * @height: height of the framebuffer in pixel
960 * @format: drm fourcc pixel format code
961 * @tiling: tiling layout of the framebuffer
962 * @fb: pointer to an #igt_fb structure
963 *
964 * This function allocates a gem buffer object suitable to back a framebuffer
965 * with the requested properties and then wraps it up in a drm framebuffer
966 * object. All metadata is stored in @fb.
967 *
968 * Compared to igt_create_fb() this function also draws the standard test pattern
969 * into the framebuffer.
970 *
971 * Returns:
972 * The kms id of the created framebuffer on success or a negative error code on
973 * failure.
974 */
975unsigned int igt_create_pattern_fb(int fd, int width, int height,
976 uint32_t format, uint64_t tiling,
977 struct igt_fb *fb /* out */)
978{
979 unsigned int fb_id;
980 cairo_t *cr;
981
982 fb_id = igt_create_fb(fd, width, height, format, tiling, fb);
983 igt_assert(fb_id);
984
985 cr = igt_get_cairo_ctx(fd, fb);
986 igt_paint_test_pattern(cr, width, height);
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +0100987 igt_put_cairo_ctx(fd, fb, cr);
Ville Syrjälä5b113d32015-12-17 01:39:31 +0200988
989 return fb_id;
990}
991
992/**
993 * igt_create_color_pattern_fb:
994 * @fd: open i915 drm file descriptor
995 * @width: width of the framebuffer in pixel
996 * @height: height of the framebuffer in pixel
997 * @format: drm fourcc pixel format code
998 * @tiling: tiling layout of the framebuffer
999 * @r: red value to use as fill color
1000 * @g: green value to use as fill color
1001 * @b: blue value to use as fill color
1002 * @fb: pointer to an #igt_fb structure
1003 *
1004 * This function allocates a gem buffer object suitable to back a framebuffer
1005 * with the requested properties and then wraps it up in a drm framebuffer
1006 * object. All metadata is stored in @fb.
1007 *
1008 * Compared to igt_create_fb() this function also fills the entire framebuffer
1009 * with the given color, and then draws the standard test pattern into the
1010 * framebuffer.
1011 *
1012 * Returns:
1013 * The kms id of the created framebuffer on success or a negative error code on
1014 * failure.
1015 */
1016unsigned int igt_create_color_pattern_fb(int fd, int width, int height,
1017 uint32_t format, uint64_t tiling,
1018 double r, double g, double b,
1019 struct igt_fb *fb /* out */)
1020{
1021 unsigned int fb_id;
1022 cairo_t *cr;
1023
1024 fb_id = igt_create_fb(fd, width, height, format, tiling, fb);
1025 igt_assert(fb_id);
1026
1027 cr = igt_get_cairo_ctx(fd, fb);
1028 igt_paint_color(cr, 0, 0, width, height, r, g, b);
1029 igt_paint_test_pattern(cr, width, height);
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +01001030 igt_put_cairo_ctx(fd, fb, cr);
Ville Syrjälä5b113d32015-12-17 01:39:31 +02001031
1032 return fb_id;
1033}
1034
1035/**
1036 * igt_create_image_fb:
1037 * @drm_fd: open i915 drm file descriptor
1038 * @width: width of the framebuffer in pixel or 0
1039 * @height: height of the framebuffer in pixel or 0
1040 * @format: drm fourcc pixel format code
1041 * @tiling: tiling layout of the framebuffer
1042 * @filename: filename of the png image to draw
1043 * @fb: pointer to an #igt_fb structure
1044 *
1045 * Create a framebuffer with the specified image. If @width is zero the
1046 * image width will be used. If @height is zero the image height will be used.
1047 *
1048 * Returns:
1049 * The kms id of the created framebuffer on success or a negative error code on
1050 * failure.
1051 */
1052unsigned int igt_create_image_fb(int fd, int width, int height,
1053 uint32_t format, uint64_t tiling,
1054 const char *filename,
1055 struct igt_fb *fb /* out */)
1056{
1057 cairo_surface_t *image;
1058 uint32_t fb_id;
1059 cairo_t *cr;
1060
Ville Syrjälä75f320c2017-09-21 15:39:23 +03001061 image = igt_cairo_image_surface_create_from_png(filename);
Ville Syrjälä5b113d32015-12-17 01:39:31 +02001062 igt_assert(cairo_surface_status(image) == CAIRO_STATUS_SUCCESS);
1063 if (width == 0)
1064 width = cairo_image_surface_get_width(image);
1065 if (height == 0)
1066 height = cairo_image_surface_get_height(image);
1067 cairo_surface_destroy(image);
1068
1069 fb_id = igt_create_fb(fd, width, height, format, tiling, fb);
1070
1071 cr = igt_get_cairo_ctx(fd, fb);
1072 igt_paint_image(cr, filename, 0, 0, width, height);
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +01001073 igt_put_cairo_ctx(fd, fb, cr);
Ville Syrjälä5b113d32015-12-17 01:39:31 +02001074
1075 return fb_id;
1076}
1077
Thomas Wood4cb19462014-08-04 16:14:51 +01001078struct box {
1079 int x, y, width, height;
1080};
1081
1082struct stereo_fb_layout {
1083 int fb_width, fb_height;
1084 struct box left, right;
1085};
1086
1087static void box_init(struct box *box, int x, int y, int bwidth, int bheight)
1088{
1089 box->x = x;
1090 box->y = y;
1091 box->width = bwidth;
1092 box->height = bheight;
1093}
1094
1095
1096static void stereo_fb_layout_from_mode(struct stereo_fb_layout *layout,
1097 drmModeModeInfo *mode)
1098{
1099 unsigned int format = mode->flags & DRM_MODE_FLAG_3D_MASK;
1100 const int hdisplay = mode->hdisplay, vdisplay = mode->vdisplay;
1101 int middle;
1102
1103 switch (format) {
1104 case DRM_MODE_FLAG_3D_TOP_AND_BOTTOM:
1105 layout->fb_width = hdisplay;
1106 layout->fb_height = vdisplay;
1107
1108 middle = vdisplay / 2;
1109 box_init(&layout->left, 0, 0, hdisplay, middle);
1110 box_init(&layout->right,
1111 0, middle, hdisplay, vdisplay - middle);
1112 break;
1113 case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF:
1114 layout->fb_width = hdisplay;
1115 layout->fb_height = vdisplay;
1116
1117 middle = hdisplay / 2;
1118 box_init(&layout->left, 0, 0, middle, vdisplay);
1119 box_init(&layout->right,
1120 middle, 0, hdisplay - middle, vdisplay);
1121 break;
1122 case DRM_MODE_FLAG_3D_FRAME_PACKING:
1123 {
1124 int vactive_space = mode->vtotal - vdisplay;
1125
1126 layout->fb_width = hdisplay;
1127 layout->fb_height = 2 * vdisplay + vactive_space;
1128
1129 box_init(&layout->left,
1130 0, 0, hdisplay, vdisplay);
1131 box_init(&layout->right,
1132 0, vdisplay + vactive_space, hdisplay, vdisplay);
1133 break;
1134 }
1135 default:
1136 igt_assert(0);
1137 }
1138}
1139
1140/**
1141 * igt_create_stereo_fb:
1142 * @drm_fd: open i915 drm file descriptor
1143 * @mode: A stereo 3D mode.
1144 * @format: drm fourcc pixel format code
1145 * @tiling: tiling layout of the framebuffer
1146 *
1147 * Create a framebuffer for use with the stereo 3D mode specified by @mode.
1148 *
1149 * Returns:
1150 * The kms id of the created framebuffer on success or a negative error code on
1151 * failure.
1152 */
1153unsigned int igt_create_stereo_fb(int drm_fd, drmModeModeInfo *mode,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +00001154 uint32_t format, uint64_t tiling)
Thomas Wood4cb19462014-08-04 16:14:51 +01001155{
1156 struct stereo_fb_layout layout;
1157 cairo_t *cr;
1158 uint32_t fb_id;
1159 struct igt_fb fb;
1160
1161 stereo_fb_layout_from_mode(&layout, mode);
1162 fb_id = igt_create_fb(drm_fd, layout.fb_width, layout.fb_height, format,
1163 tiling, &fb);
1164 cr = igt_get_cairo_ctx(drm_fd, &fb);
1165
Thomas Woodecb03262015-04-13 17:37:22 +01001166 igt_paint_image(cr, "1080p-left.png",
Thomas Wood4cb19462014-08-04 16:14:51 +01001167 layout.left.x, layout.left.y,
1168 layout.left.width, layout.left.height);
Thomas Woodecb03262015-04-13 17:37:22 +01001169 igt_paint_image(cr, "1080p-right.png",
Thomas Wood4cb19462014-08-04 16:14:51 +01001170 layout.right.x, layout.right.y,
1171 layout.right.width, layout.right.height);
1172
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +01001173 igt_put_cairo_ctx(drm_fd, &fb, cr);
Thomas Wood4cb19462014-08-04 16:14:51 +01001174
1175 return fb_id;
1176}
1177
Daniel Vetter57d7db82014-03-26 09:06:11 +01001178static cairo_format_t drm_format_to_cairo(uint32_t drm_format)
1179{
1180 struct format_desc_struct *f;
1181
1182 for_each_format(f)
1183 if (f->drm_id == drm_format)
1184 return f->cairo_id;
1185
Damien Lespiau54397ca2014-08-19 11:40:07 +01001186 igt_assert_f(0, "can't find a cairo format for %08x (%s)\n",
1187 drm_format, igt_format_str(drm_format));
Daniel Vetter57d7db82014-03-26 09:06:11 +01001188}
1189
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001190struct fb_blit_linear {
1191 uint32_t handle;
1192 unsigned size, stride;
1193 uint8_t *map;
1194 bool is_dumb;
1195 uint32_t offsets[4];
1196};
1197
Damien Lespiauff451a62015-03-03 14:11:04 +00001198struct fb_blit_upload {
1199 int fd;
1200 struct igt_fb *fb;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001201 struct fb_blit_linear linear;
Damien Lespiauff451a62015-03-03 14:11:04 +00001202};
1203
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001204static void free_linear_mapping(int fd, struct igt_fb *fb, struct fb_blit_linear *linear)
1205{
1206 unsigned int obj_tiling = igt_fb_mod_to_tiling(fb->tiling);
1207 int i;
1208
1209 gem_munmap(linear->map, linear->size);
1210 gem_set_domain(fd, linear->handle,
1211 I915_GEM_DOMAIN_GTT, 0);
1212
1213 for (i = 0; i < fb->num_planes; i++)
1214 igt_blitter_fast_copy__raw(fd,
1215 linear->handle,
1216 linear->offsets[i],
1217 linear->stride,
1218 I915_TILING_NONE,
1219 0, 0, /* src_x, src_y */
1220 fb->plane_width[i], fb->plane_height[i],
1221 fb->plane_bpp[i],
1222 fb->gem_handle,
1223 fb->offsets[i],
1224 fb->stride,
1225 obj_tiling,
1226 0, 0 /* dst_x, dst_y */);
1227
1228 gem_sync(fd, linear->handle);
1229 gem_close(fd, linear->handle);
1230}
1231
Damien Lespiauff451a62015-03-03 14:11:04 +00001232static void destroy_cairo_surface__blit(void *arg)
1233{
1234 struct fb_blit_upload *blit = arg;
Damien Lespiauff451a62015-03-03 14:11:04 +00001235
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001236 blit->fb->cairo_surface = NULL;
Damien Lespiauff451a62015-03-03 14:11:04 +00001237
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001238 free_linear_mapping(blit->fd, blit->fb, &blit->linear);
Damien Lespiauff451a62015-03-03 14:11:04 +00001239
1240 free(blit);
1241}
1242
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001243static void setup_linear_mapping(int fd, struct igt_fb *fb, struct fb_blit_linear *linear)
Damien Lespiauff451a62015-03-03 14:11:04 +00001244{
Tomeu Vizosoae649632016-11-10 10:25:24 +01001245 unsigned int obj_tiling = igt_fb_mod_to_tiling(fb->tiling);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001246 int i;
Damien Lespiauff451a62015-03-03 14:11:04 +00001247
1248 /*
1249 * We create a linear BO that we'll map for the CPU to write to (using
1250 * cairo). This linear bo will be then blitted to its final
1251 * destination, tiling it at the same time.
1252 */
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001253 linear->handle = create_bo_for_fb(fd, fb->width, fb->height,
Ville Syrjäläb6975342018-03-06 20:01:22 +02001254 fb->color_encoding, fb->color_range,
1255 lookup_drm_format(fb->drm_format),
1256 LOCAL_DRM_FORMAT_MOD_NONE, 0,
1257 0, &linear->size,
1258 &linear->stride,
1259 linear->offsets, &linear->is_dumb);
Damien Lespiauff451a62015-03-03 14:11:04 +00001260
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001261 igt_assert(linear->handle > 0);
Tvrtko Ursulin30a13602015-04-29 13:24:34 +01001262
1263 /* Copy fb content to linear BO */
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001264 gem_set_domain(fd, linear->handle,
Tvrtko Ursulin30a13602015-04-29 13:24:34 +01001265 I915_GEM_DOMAIN_GTT, 0);
1266
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001267 for (i = 0; i < fb->num_planes; i++)
1268 igt_blitter_fast_copy__raw(fd,
1269 fb->gem_handle,
1270 fb->offsets[i],
1271 fb->stride,
1272 obj_tiling,
1273 0, 0, /* src_x, src_y */
1274 fb->plane_width[i], fb->plane_height[i],
1275 fb->plane_bpp[i],
1276 linear->handle, linear->offsets[i],
1277 linear->stride,
1278 I915_TILING_NONE,
1279 0, 0 /* dst_x, dst_y */);
Tvrtko Ursulin30a13602015-04-29 13:24:34 +01001280
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001281 gem_sync(fd, linear->handle);
Tvrtko Ursulin30a13602015-04-29 13:24:34 +01001282
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001283 gem_set_domain(fd, linear->handle,
Tvrtko Ursulin30a13602015-04-29 13:24:34 +01001284 I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
1285
1286 /* Setup cairo context */
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001287 linear->map = gem_mmap__cpu(fd, linear->handle,
1288 0, linear->size, PROT_READ | PROT_WRITE);
1289}
1290
1291static void create_cairo_surface__blit(int fd, struct igt_fb *fb)
1292{
1293 struct fb_blit_upload *blit;
1294 cairo_format_t cairo_format;
1295
1296 blit = malloc(sizeof(*blit));
1297 igt_assert(blit);
1298
1299 blit->fd = fd;
1300 blit->fb = fb;
1301 setup_linear_mapping(fd, fb, &blit->linear);
Damien Lespiauff451a62015-03-03 14:11:04 +00001302
Damien Lespiauff451a62015-03-03 14:11:04 +00001303 cairo_format = drm_format_to_cairo(fb->drm_format);
1304 fb->cairo_surface =
1305 cairo_image_surface_create_for_data(blit->linear.map,
1306 cairo_format,
1307 fb->width, fb->height,
1308 blit->linear.stride);
Chris Wilson18d0b1e2016-03-02 14:12:12 +00001309 fb->domain = I915_GEM_DOMAIN_GTT;
Damien Lespiauff451a62015-03-03 14:11:04 +00001310
1311 cairo_surface_set_user_data(fb->cairo_surface,
1312 (cairo_user_data_key_t *)create_cairo_surface__blit,
1313 blit, destroy_cairo_surface__blit);
1314}
1315
Tomeu Vizosoa2d5b342016-03-07 16:25:43 +01001316/**
1317 * igt_dirty_fb:
1318 * @fd: open drm file descriptor
1319 * @fb: pointer to an #igt_fb structure
1320 *
1321 * Flushes out the whole framebuffer.
1322 *
1323 * Returns: 0 upon success.
1324 */
1325int igt_dirty_fb(int fd, struct igt_fb *fb)
1326{
1327 return drmModeDirtyFB(fb->fd, fb->fb_id, NULL, 0);
1328}
1329
Damien Lespiau4aadbc82014-06-23 16:41:43 +01001330static void destroy_cairo_surface__gtt(void *arg)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001331{
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01001332 struct igt_fb *fb = arg;
Damien Lespiau72357f32014-07-11 14:45:37 +01001333
Maarten Lankhorstd930b642017-02-09 10:42:01 +01001334 gem_munmap(cairo_image_surface_get_data(fb->cairo_surface), fb->size);
Damien Lespiau72357f32014-07-11 14:45:37 +01001335 fb->cairo_surface = NULL;
Tomeu Vizoso89b3ffe2016-02-24 09:04:41 +01001336
1337 if (fb->is_dumb)
1338 igt_dirty_fb(fb->fd, fb);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001339}
1340
Damien Lespiau4aadbc82014-06-23 16:41:43 +01001341static void create_cairo_surface__gtt(int fd, struct igt_fb *fb)
1342{
Tomeu Vizoso89b3ffe2016-02-24 09:04:41 +01001343 void *ptr;
1344
1345 if (fb->is_dumb)
1346 ptr = kmstest_dumb_map_buffer(fd, fb->gem_handle, fb->size,
1347 PROT_READ | PROT_WRITE);
1348 else
1349 ptr = gem_mmap__gtt(fd, fb->gem_handle, fb->size,
1350 PROT_READ | PROT_WRITE);
Ville Syrjälä106fe212015-10-09 18:36:24 +03001351
Damien Lespiau4aadbc82014-06-23 16:41:43 +01001352 fb->cairo_surface =
Ville Syrjälä106fe212015-10-09 18:36:24 +03001353 cairo_image_surface_create_for_data(ptr,
Damien Lespiau4aadbc82014-06-23 16:41:43 +01001354 drm_format_to_cairo(fb->drm_format),
1355 fb->width, fb->height, fb->stride);
Chris Wilson18d0b1e2016-03-02 14:12:12 +00001356 fb->domain = I915_GEM_DOMAIN_GTT;
Damien Lespiau4aadbc82014-06-23 16:41:43 +01001357
1358 cairo_surface_set_user_data(fb->cairo_surface,
1359 (cairo_user_data_key_t *)create_cairo_surface__gtt,
1360 fb, destroy_cairo_surface__gtt);
1361}
1362
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001363struct fb_convert_blit_upload {
1364 int fd;
1365 struct igt_fb *fb;
1366
1367 struct {
1368 uint8_t *map;
1369 unsigned stride, size;
1370 } rgb24;
1371
1372 struct fb_blit_linear linear;
1373};
1374
Ville Syrjäläee26fef2018-02-27 22:38:05 +02001375static uint8_t clamprgb(float val)
1376{
Ville Syrjäläd1a93aa2018-06-06 20:36:44 +03001377 return clamp((int)(val + 0.5f), 0, 255);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001378}
1379
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001380static void read_rgb(struct igt_vec4 *rgb, const uint8_t *rgb24)
1381{
1382 rgb->d[0] = rgb24[2];
1383 rgb->d[1] = rgb24[1];
1384 rgb->d[2] = rgb24[0];
1385 rgb->d[3] = 1.0f;
1386}
1387
1388static void write_rgb(uint8_t *rgb24, const struct igt_vec4 *rgb)
1389{
1390 rgb24[2] = clamprgb(rgb->d[0]);
1391 rgb24[1] = clamprgb(rgb->d[1]);
1392 rgb24[0] = clamprgb(rgb->d[2]);
1393}
1394
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001395static void convert_nv12_to_rgb24(struct igt_fb *fb, struct fb_convert_blit_upload *blit)
1396{
1397 int i, j;
1398 const uint8_t *y, *uv;
1399 uint8_t *rgb24 = blit->rgb24.map;
1400 unsigned rgb24_stride = blit->rgb24.stride, planar_stride = blit->linear.stride;
1401 uint8_t *buf = malloc(blit->linear.size);
Ville Syrjäläb6975342018-03-06 20:01:22 +02001402 struct igt_mat4 m = igt_ycbcr_to_rgb_matrix(fb->color_encoding,
1403 fb->color_range);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001404
1405 /*
1406 * Reading from the BO is awfully slow because of lack of read caching,
1407 * it's faster to copy the whole BO to a temporary buffer and convert
1408 * from there.
1409 */
Chris Wilson6a06d012018-02-27 21:45:14 +00001410 igt_memcpy_from_wc(buf, blit->linear.map, blit->linear.size);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001411 y = &buf[blit->linear.offsets[0]];
1412 uv = &buf[blit->linear.offsets[1]];
1413
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001414 for (i = 0; i < fb->height / 2; i++) {
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001415 for (j = 0; j < fb->width / 2; j++) {
1416 /* Convert 2x2 pixel blocks */
1417 struct igt_vec4 yuv[4];
1418 struct igt_vec4 rgb[4];
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001419
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001420 yuv[0].d[0] = y[j * 2 + 0];
1421 yuv[1].d[0] = y[j * 2 + 1];
1422 yuv[2].d[0] = y[j * 2 + 0 + planar_stride];
1423 yuv[3].d[0] = y[j * 2 + 1 + planar_stride];
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001424
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001425 yuv[0].d[1] = yuv[1].d[1] = yuv[2].d[1] = yuv[3].d[1] = uv[j * 2 + 0];
1426 yuv[0].d[2] = yuv[1].d[2] = yuv[2].d[2] = yuv[3].d[2] = uv[j * 2 + 1];
1427 yuv[0].d[3] = yuv[1].d[3] = yuv[2].d[3] = yuv[3].d[3] = 1.0f;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001428
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001429 rgb[0] = igt_matrix_transform(&m, &yuv[0]);
1430 rgb[1] = igt_matrix_transform(&m, &yuv[1]);
1431 rgb[2] = igt_matrix_transform(&m, &yuv[2]);
1432 rgb[3] = igt_matrix_transform(&m, &yuv[3]);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001433
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001434 write_rgb(&rgb24[j * 8 + 0], &rgb[0]);
1435 write_rgb(&rgb24[j * 8 + 4], &rgb[1]);
1436 write_rgb(&rgb24[j * 8 + 0 + rgb24_stride], &rgb[2]);
1437 write_rgb(&rgb24[j * 8 + 4 + rgb24_stride], &rgb[3]);
1438 }
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001439
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001440 if (fb->width & 1) {
1441 /* Convert 1x2 pixel block */
1442 struct igt_vec4 yuv[2];
1443 struct igt_vec4 rgb[2];
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001444
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001445 yuv[0].d[0] = y[j * 2 + 0];
1446 yuv[1].d[0] = y[j * 2 + 0 + planar_stride];
1447
1448 yuv[0].d[1] = yuv[1].d[1] = uv[j * 2 + 0];
1449 yuv[0].d[2] = yuv[1].d[2] = uv[j * 2 + 1];
1450 yuv[0].d[3] = yuv[1].d[3] = 1.0f;
1451
1452 rgb[0] = igt_matrix_transform(&m, &yuv[0]);
1453 rgb[1] = igt_matrix_transform(&m, &yuv[1]);
1454
1455 write_rgb(&rgb24[j * 8 + 0], &rgb[0]);
1456 write_rgb(&rgb24[j * 8 + 0 + rgb24_stride], &rgb[1]);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001457 }
1458
1459 rgb24 += 2 * rgb24_stride;
1460 y += 2 * planar_stride;
1461 uv += planar_stride;
1462 }
1463
1464 if (fb->height & 1) {
1465 /* Convert last row */
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001466 for (j = 0; j < fb->width / 2; j++) {
1467 /* Convert 2x1 pixel blocks */
1468 struct igt_vec4 yuv[2];
1469 struct igt_vec4 rgb[2];
1470
1471 yuv[0].d[0] = y[j * 2 + 0];
1472 yuv[1].d[0] = y[j * 2 + 1];
1473 yuv[0].d[1] = yuv[1].d[1] = uv[j * 2 + 0];
1474 yuv[0].d[2] = yuv[1].d[2] = uv[j * 2 + 1];
1475 yuv[0].d[3] = yuv[1].d[3] = 1.0f;
1476
1477 rgb[0] = igt_matrix_transform(&m, &yuv[0]);
1478 rgb[1] = igt_matrix_transform(&m, &yuv[1]);
1479
1480 write_rgb(&rgb24[j * 8 + 0], &rgb[0]);
1481 write_rgb(&rgb24[j * 8 + 4], &rgb[0]);
1482 }
1483
1484 if (fb->width & 1) {
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001485 /* Convert single pixel */
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001486 struct igt_vec4 yuv;
1487 struct igt_vec4 rgb;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001488
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001489 yuv.d[0] = y[j * 2 + 0];
1490 yuv.d[1] = uv[j * 2 + 0];
1491 yuv.d[2] = uv[j * 2 + 1];
1492 yuv.d[3] = 1.0f;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001493
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001494 rgb = igt_matrix_transform(&m, &yuv);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001495
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001496 write_rgb(&rgb24[j * 8 + 0], &rgb);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001497 }
1498 }
1499
1500 free(buf);
1501}
1502
1503static void convert_rgb24_to_nv12(struct igt_fb *fb, struct fb_convert_blit_upload *blit)
1504{
1505 int i, j;
1506 uint8_t *y = &blit->linear.map[blit->linear.offsets[0]];
1507 uint8_t *uv = &blit->linear.map[blit->linear.offsets[1]];
1508 const uint8_t *rgb24 = blit->rgb24.map;
1509 unsigned rgb24_stride = blit->rgb24.stride;
1510 unsigned planar_stride = blit->linear.stride;
Ville Syrjäläb6975342018-03-06 20:01:22 +02001511 struct igt_mat4 m = igt_rgb_to_ycbcr_matrix(fb->color_encoding,
1512 fb->color_range);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001513
1514 igt_assert_f(fb->drm_format == DRM_FORMAT_NV12,
1515 "Conversion not implemented for !NV12 planar formats\n");
1516
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001517 for (i = 0; i < fb->height / 2; i++) {
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001518 for (j = 0; j < fb->width / 2; j++) {
1519 /* Convert 2x2 pixel blocks */
1520 struct igt_vec4 rgb[4];
1521 struct igt_vec4 yuv[4];
1522
1523 read_rgb(&rgb[0], &rgb24[j * 8 + 0]);
1524 read_rgb(&rgb[1], &rgb24[j * 8 + 4]);
1525 read_rgb(&rgb[2], &rgb24[j * 8 + 0 + rgb24_stride]);
1526 read_rgb(&rgb[3], &rgb24[j * 8 + 4 + rgb24_stride]);
1527
1528 yuv[0] = igt_matrix_transform(&m, &rgb[0]);
1529 yuv[1] = igt_matrix_transform(&m, &rgb[1]);
1530 yuv[2] = igt_matrix_transform(&m, &rgb[2]);
1531 yuv[3] = igt_matrix_transform(&m, &rgb[3]);
1532
1533 y[j * 2 + 0] = yuv[0].d[0];
1534 y[j * 2 + 1] = yuv[1].d[0];
1535 y[j * 2 + 0 + planar_stride] = yuv[2].d[0];
1536 y[j * 2 + 1 + planar_stride] = yuv[3].d[0];
1537
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001538 /*
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001539 * We assume the MPEG2 chroma siting convention, where
1540 * pixel center for Cb'Cr' is between the left top and
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001541 * bottom pixel in a 2x2 block, so take the average.
1542 */
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001543 uv[j * 2 + 0] = (yuv[0].d[1] + yuv[2].d[1]) / 2.0f;
1544 uv[j * 2 + 1] = (yuv[0].d[2] + yuv[2].d[2]) / 2.0f;
1545 }
1546
1547 if (fb->width & 1) {
1548 /* Convert 1x2 pixel block */
1549 struct igt_vec4 rgb[2];
1550 struct igt_vec4 yuv[2];
1551
1552 read_rgb(&rgb[0], &rgb24[j * 8 + 0]);
1553 read_rgb(&rgb[2], &rgb24[j * 8 + 0 + rgb24_stride]);
1554
1555 yuv[0] = igt_matrix_transform(&m, &rgb[0]);
1556 yuv[1] = igt_matrix_transform(&m, &rgb[1]);
1557
1558 y[j * 2 + 0] = yuv[0].d[0];
1559 y[j * 2 + 0 + planar_stride] = yuv[1].d[0];
1560
1561 /*
1562 * We assume the MPEG2 chroma siting convention, where
1563 * pixel center for Cb'Cr' is between the left top and
1564 * bottom pixel in a 2x2 block, so take the average.
1565 */
1566 uv[j * 2 + 0] = (yuv[0].d[1] + yuv[1].d[1]) / 2.0f;
1567 uv[j * 2 + 1] = (yuv[0].d[2] + yuv[1].d[2]) / 2.0f;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001568 }
1569
1570 rgb24 += 2 * rgb24_stride;
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001571 y += 2 * planar_stride;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001572 uv += planar_stride;
1573 }
1574
1575 /* Last row cannot be interpolated between 2 pixels, take the single value */
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001576 if (fb->height & 1) {
1577 for (j = 0; j < fb->width / 2; j++) {
1578 /* Convert 2x1 pixel blocks */
1579 struct igt_vec4 rgb[2];
1580 struct igt_vec4 yuv[2];
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001581
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001582 read_rgb(&rgb[0], &rgb24[j * 8 + 0]);
1583 read_rgb(&rgb[1], &rgb24[j * 8 + 4]);
1584
1585 yuv[0] = igt_matrix_transform(&m, &rgb[0]);
1586 yuv[1] = igt_matrix_transform(&m, &rgb[1]);
1587
1588 y[j * 2 + 0] = yuv[0].d[0];
1589 y[j * 2 + 1] = yuv[1].d[0];
1590 uv[j * 2 + 0] = yuv[0].d[1];
1591 uv[j * 2 + 1] = yuv[0].d[2];
1592 }
1593
1594 if (fb->width & 1) {
1595 /* Convert single pixel */
1596 struct igt_vec4 rgb;
1597 struct igt_vec4 yuv;
1598
1599 read_rgb(&rgb, &rgb24[j * 8 + 0]);
1600
1601 yuv = igt_matrix_transform(&m, &rgb);
1602
1603 y[j * 2 + 0] = yuv.d[0];
1604 uv[j * 2 + 0] = yuv.d[1];
1605 uv[j * 2 + 1] = yuv.d[2];
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001606 }
1607 }
1608}
1609
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001610/* { Y0, U, Y1, V } */
1611static const unsigned char swizzle_yuyv[] = { 0, 1, 2, 3 };
1612static const unsigned char swizzle_yvyu[] = { 0, 3, 2, 1 };
1613static const unsigned char swizzle_uyvy[] = { 1, 0, 3, 2 };
1614static const unsigned char swizzle_vyuy[] = { 1, 2, 3, 0 };
1615
1616static const unsigned char *yuyv_swizzle(uint32_t format)
1617{
1618 switch (format) {
1619 default:
1620 case DRM_FORMAT_YUYV:
1621 return swizzle_yuyv;
1622 case DRM_FORMAT_YVYU:
1623 return swizzle_yvyu;
1624 case DRM_FORMAT_UYVY:
1625 return swizzle_uyvy;
1626 case DRM_FORMAT_VYUY:
1627 return swizzle_vyuy;
1628 }
1629}
1630
1631static void convert_yuyv_to_rgb24(struct igt_fb *fb, struct fb_convert_blit_upload *blit,
1632 const unsigned char swz[4])
1633{
1634 int i, j;
1635 const uint8_t *yuyv;
1636 uint8_t *rgb24 = blit->rgb24.map;
1637 unsigned rgb24_stride = blit->rgb24.stride, yuyv_stride = blit->linear.stride;
1638 uint8_t *buf = malloc(blit->linear.size);
Ville Syrjäläb6975342018-03-06 20:01:22 +02001639 struct igt_mat4 m = igt_ycbcr_to_rgb_matrix(fb->color_encoding,
1640 fb->color_range);
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001641
1642 /*
1643 * Reading from the BO is awfully slow because of lack of read caching,
1644 * it's faster to copy the whole BO to a temporary buffer and convert
1645 * from there.
1646 */
1647 igt_memcpy_from_wc(buf, blit->linear.map, blit->linear.size);
1648 yuyv = buf;
1649
1650 for (i = 0; i < fb->height; i++) {
1651 for (j = 0; j < fb->width / 2; j++) {
1652 /* Convert 2x1 pixel blocks */
1653 struct igt_vec4 yuv[2];
1654 struct igt_vec4 rgb[2];
1655
1656 yuv[0].d[0] = yuyv[j * 4 + swz[0]];
1657 yuv[1].d[0] = yuyv[j * 4 + swz[2]];
1658 yuv[0].d[1] = yuv[1].d[1] = yuyv[j * 4 + swz[1]];
1659 yuv[0].d[2] = yuv[1].d[2] = yuyv[j * 4 + swz[3]];
1660 yuv[0].d[3] = yuv[1].d[3] = 1.0f;
1661
1662 rgb[0] = igt_matrix_transform(&m, &yuv[0]);
1663 rgb[1] = igt_matrix_transform(&m, &yuv[1]);
1664
1665 write_rgb(&rgb24[j * 8 + 0], &rgb[0]);
1666 write_rgb(&rgb24[j * 8 + 4], &rgb[1]);
1667 }
1668
1669 if (fb->width & 1) {
1670 struct igt_vec4 yuv;
1671 struct igt_vec4 rgb;
1672
1673 yuv.d[0] = yuyv[j * 4 + swz[0]];
1674 yuv.d[1] = yuyv[j * 4 + swz[1]];
1675 yuv.d[2] = yuyv[j * 4 + swz[3]];
1676 yuv.d[3] = 1.0f;
1677
1678 rgb = igt_matrix_transform(&m, &yuv);
1679
1680 write_rgb(&rgb24[j * 8 + 0], &rgb);
1681 }
1682
1683 rgb24 += rgb24_stride;
1684 yuyv += yuyv_stride;
1685 }
1686
1687 free(buf);
1688}
1689
1690static void convert_rgb24_to_yuyv(struct igt_fb *fb, struct fb_convert_blit_upload *blit,
1691 const unsigned char swz[4])
1692{
1693 int i, j;
1694 uint8_t *yuyv = blit->linear.map;
1695 const uint8_t *rgb24 = blit->rgb24.map;
1696 unsigned rgb24_stride = blit->rgb24.stride;
1697 unsigned yuyv_stride = blit->linear.stride;
Ville Syrjäläb6975342018-03-06 20:01:22 +02001698 struct igt_mat4 m = igt_rgb_to_ycbcr_matrix(fb->color_encoding,
1699 fb->color_range);
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001700
1701 igt_assert_f(fb->drm_format == DRM_FORMAT_YUYV ||
1702 fb->drm_format == DRM_FORMAT_YVYU ||
1703 fb->drm_format == DRM_FORMAT_UYVY ||
1704 fb->drm_format == DRM_FORMAT_VYUY,
1705 "Conversion not implemented for !YUYV planar formats\n");
1706
1707 for (i = 0; i < fb->height; i++) {
1708 for (j = 0; j < fb->width / 2; j++) {
1709 /* Convert 2x1 pixel blocks */
1710 struct igt_vec4 rgb[2];
1711 struct igt_vec4 yuv[2];
1712
1713 read_rgb(&rgb[0], &rgb24[j * 8 + 0]);
1714 read_rgb(&rgb[1], &rgb24[j * 8 + 4]);
1715
1716 yuv[0] = igt_matrix_transform(&m, &rgb[0]);
1717 yuv[1] = igt_matrix_transform(&m, &rgb[1]);
1718
1719 yuyv[j * 4 + swz[0]] = yuv[0].d[0];
1720 yuyv[j * 4 + swz[2]] = yuv[1].d[0];
1721 yuyv[j * 4 + swz[1]] = (yuv[0].d[1] + yuv[1].d[1]) / 2.0f;
1722 yuyv[j * 4 + swz[3]] = (yuv[0].d[2] + yuv[1].d[2]) / 2.0f;
1723 }
1724
1725 if (fb->width & 1) {
1726 struct igt_vec4 rgb;
1727 struct igt_vec4 yuv;
1728
1729 read_rgb(&rgb, &rgb24[j * 8 + 0]);
1730
1731 yuv = igt_matrix_transform(&m, &rgb);
1732
1733 yuyv[j * 4 + swz[0]] = yuv.d[0];
1734 yuyv[j * 4 + swz[1]] = yuv.d[1];
1735 yuyv[j * 4 + swz[3]] = yuv.d[2];
1736 }
1737
1738 rgb24 += rgb24_stride;
1739 yuyv += yuyv_stride;
1740 }
1741}
1742
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001743static void destroy_cairo_surface__convert(void *arg)
1744{
1745 struct fb_convert_blit_upload *blit = arg;
1746 struct igt_fb *fb = blit->fb;
1747
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001748 /* Convert linear rgb back! */
1749 switch(fb->drm_format) {
1750 case DRM_FORMAT_NV12:
1751 convert_rgb24_to_nv12(fb, blit);
1752 break;
1753 case DRM_FORMAT_YUYV:
1754 case DRM_FORMAT_YVYU:
1755 case DRM_FORMAT_UYVY:
1756 case DRM_FORMAT_VYUY:
1757 convert_rgb24_to_yuyv(fb, blit, yuyv_swizzle(fb->drm_format));
1758 break;
1759 default:
1760 igt_assert_f(false, "Conversion not implemented for formats 0x%x\n",
1761 fb->drm_format);
1762 }
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001763
1764 munmap(blit->rgb24.map, blit->rgb24.size);
1765
1766 if (blit->linear.handle)
1767 free_linear_mapping(blit->fd, blit->fb, &blit->linear);
1768 else
1769 gem_munmap(blit->linear.map, fb->size);
1770
1771 free(blit);
1772
1773 fb->cairo_surface = NULL;
1774}
1775
1776static void create_cairo_surface__convert(int fd, struct igt_fb *fb)
1777{
1778 struct fb_convert_blit_upload *blit = malloc(sizeof(*blit));
1779 igt_assert(blit);
1780
1781 blit->fd = fd;
1782 blit->fb = fb;
1783 blit->rgb24.stride = ALIGN(fb->width * 4, 16);
1784 blit->rgb24.size = ALIGN(blit->rgb24.stride * fb->height, sysconf(_SC_PAGESIZE));
1785 blit->rgb24.map = mmap(NULL, blit->rgb24.size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
1786 igt_assert(blit->rgb24.map != MAP_FAILED);
1787
1788 if (fb->tiling == LOCAL_I915_FORMAT_MOD_Y_TILED ||
1789 fb->tiling == LOCAL_I915_FORMAT_MOD_Yf_TILED) {
1790 setup_linear_mapping(fd, fb, &blit->linear);
1791 } else {
1792 blit->linear.handle = 0;
1793 blit->linear.map = gem_mmap__gtt(fd, fb->gem_handle, fb->size,
1794 PROT_READ | PROT_WRITE);
1795 igt_assert(blit->linear.map);
1796 blit->linear.stride = fb->stride;
1797 blit->linear.size = fb->size;
1798 memcpy(blit->linear.offsets, fb->offsets, sizeof(fb->offsets));
1799 }
1800
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001801 /* Convert to linear rgb! */
1802 switch(fb->drm_format) {
1803 case DRM_FORMAT_NV12:
1804 convert_nv12_to_rgb24(fb, blit);
1805 break;
1806 case DRM_FORMAT_YUYV:
1807 case DRM_FORMAT_YVYU:
1808 case DRM_FORMAT_UYVY:
1809 case DRM_FORMAT_VYUY:
1810 convert_yuyv_to_rgb24(fb, blit, yuyv_swizzle(fb->drm_format));
1811 break;
1812 default:
1813 igt_assert_f(false, "Conversion not implemented for formats 0x%x\n",
1814 fb->drm_format);
1815 }
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001816
1817 fb->cairo_surface =
1818 cairo_image_surface_create_for_data(blit->rgb24.map,
1819 CAIRO_FORMAT_RGB24,
1820 fb->width, fb->height,
1821 blit->rgb24.stride);
1822
1823 cairo_surface_set_user_data(fb->cairo_surface,
1824 (cairo_user_data_key_t *)create_cairo_surface__convert,
1825 blit, destroy_cairo_surface__convert);
1826}
1827
Paul Kocialkowskib4ad3972017-07-19 16:46:04 +03001828/**
1829 * igt_get_cairo_surface:
1830 * @fd: open drm file descriptor
1831 * @fb: pointer to an #igt_fb structure
1832 *
Maarten Lankhorst918ea422018-01-19 12:47:11 +01001833 * This function stores the contents of the supplied framebuffer's plane
1834 * into a cairo surface and returns it.
Paul Kocialkowskib4ad3972017-07-19 16:46:04 +03001835 *
1836 * Returns:
1837 * A pointer to a cairo surface with the contents of the framebuffer.
1838 */
1839cairo_surface_t *igt_get_cairo_surface(int fd, struct igt_fb *fb)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001840{
Damien Lespiauff451a62015-03-03 14:11:04 +00001841 if (fb->cairo_surface == NULL) {
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001842 if (igt_format_is_yuv(fb->drm_format))
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001843 create_cairo_surface__convert(fd, fb);
1844 else if (fb->tiling == LOCAL_I915_FORMAT_MOD_Y_TILED ||
Damien Lespiauff451a62015-03-03 14:11:04 +00001845 fb->tiling == LOCAL_I915_FORMAT_MOD_Yf_TILED)
1846 create_cairo_surface__blit(fd, fb);
1847 else
1848 create_cairo_surface__gtt(fd, fb);
1849 }
Daniel Vetter57d7db82014-03-26 09:06:11 +01001850
Tomeu Vizoso89b3ffe2016-02-24 09:04:41 +01001851 if (!fb->is_dumb)
1852 gem_set_domain(fd, fb->gem_handle, I915_GEM_DOMAIN_CPU,
1853 I915_GEM_DOMAIN_CPU);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001854
1855 igt_assert(cairo_surface_status(fb->cairo_surface) == CAIRO_STATUS_SUCCESS);
Damien Lespiau0db75bb2014-06-30 16:34:20 +01001856 return fb->cairo_surface;
Daniel Vetter57d7db82014-03-26 09:06:11 +01001857}
1858
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001859/**
1860 * igt_get_cairo_ctx:
1861 * @fd: open i915 drm file descriptor
1862 * @fb: pointer to an #igt_fb structure
1863 *
1864 * This initializes a cairo surface for @fb and then allocates a drawing context
1865 * for it. The return cairo drawing context should be released by calling
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +01001866 * igt_put_cairo_ctx(). This also sets a default font for drawing text on
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001867 * framebuffers.
1868 *
1869 * Returns:
1870 * The created cairo drawing context.
1871 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01001872cairo_t *igt_get_cairo_ctx(int fd, struct igt_fb *fb)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001873{
1874 cairo_surface_t *surface;
1875 cairo_t *cr;
1876
Paul Kocialkowskib4ad3972017-07-19 16:46:04 +03001877 surface = igt_get_cairo_surface(fd, fb);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001878 cr = cairo_create(surface);
1879 cairo_surface_destroy(surface);
Daniel Vetter7568edf2014-03-26 16:36:46 +01001880 igt_assert(cairo_status(cr) == CAIRO_STATUS_SUCCESS);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001881
Daniel Vetter7568edf2014-03-26 16:36:46 +01001882 cairo_select_font_face(cr, "Helvetica", CAIRO_FONT_SLANT_NORMAL,
1883 CAIRO_FONT_WEIGHT_NORMAL);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001884 igt_assert(cairo_status(cr) == CAIRO_STATUS_SUCCESS);
1885
1886 return cr;
1887}
1888
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001889/**
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +01001890 * igt_put_cairo_ctx:
1891 * @fd: open i915 drm file descriptor
1892 * @fb: pointer to an #igt_fb structure
1893 * @cr: the cairo context returned by igt_get_cairo_ctx.
1894 *
1895 * This releases the cairo surface @cr returned by igt_get_cairo_ctx()
1896 * for @fb, and writes the changes out to the framebuffer if cairo doesn't
1897 * have native support for the format.
1898 */
1899void igt_put_cairo_ctx(int fd, struct igt_fb *fb, cairo_t *cr)
1900{
1901 cairo_status_t ret = cairo_status(cr);
1902 igt_assert_f(ret == CAIRO_STATUS_SUCCESS, "Cairo failed to draw with %s\n", cairo_status_to_string(ret));
1903
1904 cairo_destroy(cr);
1905}
1906
1907/**
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001908 * igt_remove_fb:
1909 * @fd: open i915 drm file descriptor
1910 * @fb: pointer to an #igt_fb structure
1911 *
1912 * This function releases all resources allocated in igt_create_fb() for @fb.
1913 * Note that if this framebuffer is still in use on a primary plane the kernel
1914 * will disable the corresponding crtc.
1915 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01001916void igt_remove_fb(int fd, struct igt_fb *fb)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001917{
Maarten Lankhorste62de1c2018-02-02 10:58:42 +01001918 if (!fb || !fb->fb_id)
1919 return;
1920
Daniel Vetter57d7db82014-03-26 09:06:11 +01001921 cairo_surface_destroy(fb->cairo_surface);
1922 do_or_die(drmModeRmFB(fd, fb->fb_id));
1923 gem_close(fd, fb->gem_handle);
Maarten Lankhorste62de1c2018-02-02 10:58:42 +01001924 fb->fb_id = 0;
Daniel Vetter57d7db82014-03-26 09:06:11 +01001925}
1926
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001927/**
1928 * igt_bpp_depth_to_drm_format:
1929 * @bpp: desired bits per pixel
1930 * @depth: desired depth
1931 *
1932 * Returns:
1933 * The rgb drm fourcc pixel format code corresponding to the given @bpp and
1934 * @depth values. Fails hard if no match was found.
1935 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01001936uint32_t igt_bpp_depth_to_drm_format(int bpp, int depth)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001937{
1938 struct format_desc_struct *f;
1939
1940 for_each_format(f)
Ville Syrjäläe556d852018-02-27 22:48:46 +02001941 if (f->plane_bpp[0] == bpp && f->depth == depth)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001942 return f->drm_id;
1943
Damien Lespiau54397ca2014-08-19 11:40:07 +01001944
1945 igt_assert_f(0, "can't find drm format with bpp=%d, depth=%d\n", bpp,
1946 depth);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001947}
1948
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001949/**
1950 * igt_drm_format_to_bpp:
1951 * @drm_format: drm fourcc pixel format code
1952 *
1953 * Returns:
1954 * The bits per pixel for the given drm fourcc pixel format code. Fails hard if
1955 * no match was found.
1956 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01001957uint32_t igt_drm_format_to_bpp(uint32_t drm_format)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001958{
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +01001959 struct format_desc_struct *f = lookup_drm_format(drm_format);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001960
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +01001961 igt_assert_f(f, "can't find a bpp format for %08x (%s)\n",
Damien Lespiau54397ca2014-08-19 11:40:07 +01001962 drm_format, igt_format_str(drm_format));
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +01001963
Ville Syrjäläe556d852018-02-27 22:48:46 +02001964 return f->plane_bpp[0];
Daniel Vetter57d7db82014-03-26 09:06:11 +01001965}
1966
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001967/**
1968 * igt_format_str:
1969 * @drm_format: drm fourcc pixel format code
1970 *
1971 * Returns:
1972 * Human-readable fourcc pixel format code for @drm_format or "invalid" no match
1973 * was found.
1974 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01001975const char *igt_format_str(uint32_t drm_format)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001976{
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +01001977 struct format_desc_struct *f = lookup_drm_format(drm_format);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001978
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +01001979 return f ? f->name : "invalid";
Daniel Vetter57d7db82014-03-26 09:06:11 +01001980}
1981
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001982/**
Maarten Lankhorstc60cf3b2018-02-02 11:32:40 +01001983 * igt_fb_supported_format:
1984 * @drm_format: drm fourcc to test.
1985 *
1986 * This functions returns whether @drm_format can be succesfully created by
1987 * igt_create_fb() and drawn to by igt_get_cairo_ctx().
1988 */
1989bool igt_fb_supported_format(uint32_t drm_format)
1990{
1991 struct format_desc_struct *f;
1992
1993 for_each_format(f)
1994 if (f->drm_id == drm_format)
1995 return f->cairo_id != CAIRO_FORMAT_INVALID;
1996
1997 return false;
1998}
Ville Syrjälä40bf6d02018-05-18 23:32:32 +03001999
2000/**
2001 * igt_format_is_yuv:
2002 * @drm_format: drm fourcc
2003 *
2004 * This functions returns whether @drm_format is YUV (as opposed to RGB).
2005 */
2006bool igt_format_is_yuv(uint32_t drm_format)
2007{
2008 switch (drm_format) {
2009 case DRM_FORMAT_NV12:
2010 case DRM_FORMAT_YUYV:
2011 case DRM_FORMAT_YVYU:
2012 case DRM_FORMAT_UYVY:
2013 case DRM_FORMAT_VYUY:
2014 return true;
2015 default:
2016 return false;
2017 }
2018}