blob: 1ba1aa7c19cf7fbee7878aeeb44ed74bec487e18 [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,
Ville Syrjälä5f8a33a2018-09-06 16:34:15 +0300218 uint64_t tiling, uint64_t *size_ret,
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100219 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,
Ville Syrjälä5f8a33a2018-09-06 16:34:15 +0300254 uint64_t *size_ret, unsigned *stride_ret)
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200255{
Ville Syrjälä5f8a33a2018-09-06 16:34:15 +0300256 unsigned int tile_width, tile_height, stride;
257 uint64_t size;
Ville Syrjäläe556d852018-02-27 22:48:46 +0200258 int byte_width = width * (format->plane_bpp[0] / 8);
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200259
Ville Syrjäläe556d852018-02-27 22:48:46 +0200260 igt_get_fb_tile_size(fd, tiling, format->plane_bpp[0], &tile_width, &tile_height);
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200261
Tomeu Vizoso85a1d452016-02-24 08:39:53 +0100262 if (tiling != LOCAL_DRM_FORMAT_MOD_NONE &&
263 intel_gen(intel_get_drm_devid(fd)) <= 3) {
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200264 /* Round the tiling up to the next power-of-two and the region
265 * up to the next pot fence size so that this works on all
266 * generations.
Daniel Vetter57d7db82014-03-26 09:06:11 +0100267 *
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200268 * This can still fail if the framebuffer is too large to be
269 * tiled. But then that failure is expected.
Daniel Vetter57d7db82014-03-26 09:06:11 +0100270 */
271
Ville Syrjälä20a7ead2018-09-07 22:12:26 +0300272 stride = max(byte_width, 512);
273 stride = roundup_power_of_two(stride);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100274
Ville Syrjälä20a7ead2018-09-07 22:12:26 +0300275 size = max((uint64_t) stride * height, 1024*1024);
276 size = roundup_power_of_two(size);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100277 } else {
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200278 stride = ALIGN(byte_width, tile_width);
Ville Syrjälä5f8a33a2018-09-06 16:34:15 +0300279 size = (uint64_t) stride * ALIGN(height, tile_height);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100280 }
281
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200282 *stride_ret = stride;
283 *size_ret = size;
284}
285
Tomeu Vizosoae649632016-11-10 10:25:24 +0100286/**
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100287 * igt_calc_fb_size:
288 * @fd: the DRM file descriptor
289 * @width: width of the framebuffer in pixels
290 * @height: height of the framebuffer in pixels
291 * @format: drm fourcc pixel format code
292 * @tiling: tiling layout of the framebuffer (as framebuffer modifier)
293 * @size_ret: returned size for the framebuffer
294 * @stride_ret: returned stride for the framebuffer
295 *
296 * This function returns valid stride and size values for a framebuffer with the
297 * specified parameters.
298 */
299void igt_calc_fb_size(int fd, int width, int height, uint32_t drm_format, uint64_t tiling,
Ville Syrjälä5f8a33a2018-09-06 16:34:15 +0300300 uint64_t *size_ret, unsigned *stride_ret)
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100301{
302 struct format_desc_struct *format = lookup_drm_format(drm_format);
303 igt_assert(format);
304
Ville Syrjäläe556d852018-02-27 22:48:46 +0200305 if (format->num_planes > 1)
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100306 calc_fb_size_planar(fd, width, height, format, tiling, size_ret, stride_ret, NULL);
307 else
308 calc_fb_size_packed(fd, width, height, format, tiling, size_ret, stride_ret);
309}
310
311/**
Tomeu Vizosoae649632016-11-10 10:25:24 +0100312 * igt_fb_mod_to_tiling:
313 * @modifier: DRM framebuffer modifier
314 *
315 * This function converts a DRM framebuffer modifier to its corresponding
316 * tiling constant.
317 *
318 * Returns:
319 * A tiling constant
320 */
321uint64_t igt_fb_mod_to_tiling(uint64_t modifier)
322{
323 switch (modifier) {
324 case LOCAL_DRM_FORMAT_MOD_NONE:
325 return I915_TILING_NONE;
326 case LOCAL_I915_FORMAT_MOD_X_TILED:
327 return I915_TILING_X;
328 case LOCAL_I915_FORMAT_MOD_Y_TILED:
329 return I915_TILING_Y;
330 case LOCAL_I915_FORMAT_MOD_Yf_TILED:
331 return I915_TILING_Yf;
332 default:
333 igt_assert(0);
334 }
335}
336
Praveen Paneri4437e212017-07-18 22:52:57 +0530337/**
338 * igt_fb_tiling_to_mod:
339 * @tiling: DRM framebuffer tiling
340 *
341 * This function converts a DRM framebuffer tiling to its corresponding
342 * modifier constant.
343 *
344 * Returns:
345 * A modifier constant
346 */
347uint64_t igt_fb_tiling_to_mod(uint64_t tiling)
348{
349 switch (tiling) {
350 case I915_TILING_NONE:
351 return LOCAL_DRM_FORMAT_MOD_NONE;
352 case I915_TILING_X:
353 return LOCAL_I915_FORMAT_MOD_X_TILED;
354 case I915_TILING_Y:
355 return LOCAL_I915_FORMAT_MOD_Y_TILED;
356 case I915_TILING_Yf:
357 return LOCAL_I915_FORMAT_MOD_Yf_TILED;
358 default:
359 igt_assert(0);
360 }
361}
362
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200363/* helpers to create nice-looking framebuffers */
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100364static int create_bo_for_fb(int fd, int width, int height,
Ville Syrjäläb6975342018-03-06 20:01:22 +0200365 enum igt_color_encoding color_encoding,
366 enum igt_color_range color_range,
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100367 struct format_desc_struct *format,
Ville Syrjälä5f8a33a2018-09-06 16:34:15 +0300368 uint64_t tiling, uint64_t size, unsigned stride,
369 uint64_t *size_ret, unsigned *stride_ret,
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100370 uint32_t *offsets, bool *is_dumb)
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200371{
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200372 int bo;
373
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100374 igt_assert(format);
375
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100376 if (offsets)
377 memset(offsets, 0, ARRAY_SIZE(format->plane_bpp) * sizeof(*offsets));
378
Ville Syrjälä87907562018-02-27 22:57:16 +0200379 if (tiling || size || stride || igt_format_is_yuv(format->drm_id)) {
Ville Syrjälä5f8a33a2018-09-06 16:34:15 +0300380 uint64_t calculated_size;
381 unsigned int calculated_stride;
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200382
Ville Syrjäläe556d852018-02-27 22:48:46 +0200383 if (format->num_planes > 1)
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100384 calc_fb_size_planar(fd, width, height, format, tiling,
385 &calculated_size, &calculated_stride, offsets);
386 else
387 calc_fb_size_packed(fd, width, height, format, tiling,
388 &calculated_size, &calculated_stride);
389
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200390 if (stride == 0)
391 stride = calculated_stride;
392 if (size == 0)
393 size = calculated_size;
394
395 if (is_dumb)
396 *is_dumb = false;
397
398 if (is_i915_device(fd)) {
Ville Syrjäläe867d652018-02-27 22:39:26 +0200399 void *ptr;
Ville Syrjäläb6975342018-03-06 20:01:22 +0200400 bool full_range = color_range == IGT_COLOR_YCBCR_FULL_RANGE;
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200401
402 bo = gem_create(fd, size);
Tomeu Vizosoae649632016-11-10 10:25:24 +0100403 gem_set_tiling(fd, bo, igt_fb_mod_to_tiling(tiling), stride);
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200404
Ville Syrjälä3bd68522018-09-05 19:55:43 +0300405 gem_set_domain(fd, bo,
406 I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
407
Chris Wilsond2805062016-08-18 13:56:18 +0100408 /* Ensure the framebuffer is preallocated */
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +0100409 ptr = gem_mmap__gtt(fd, bo, size, PROT_READ | PROT_WRITE);
410 igt_assert(*(uint32_t *)ptr == 0);
411
Ville Syrjäläe867d652018-02-27 22:39:26 +0200412 switch (format->drm_id) {
413 case DRM_FORMAT_NV12:
414 memset(ptr + offsets[0], full_range ? 0x00 : 0x10,
415 calculated_stride * height);
416 memset(ptr + offsets[1], 0x80,
417 calculated_stride * height/2);
418 break;
419 case DRM_FORMAT_YUYV:
420 case DRM_FORMAT_YVYU:
421 wmemset(ptr, full_range ? 0x80008000 : 0x80108010,
422 calculated_stride * height / sizeof(wchar_t));
423 break;
424 case DRM_FORMAT_UYVY:
425 case DRM_FORMAT_VYUY:
426 wmemset(ptr, full_range ? 0x00800080 : 0x10801080,
427 calculated_stride * height / sizeof(wchar_t));
428 break;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +0100429 }
Maarten Lankhorstd930b642017-02-09 10:42:01 +0100430 gem_munmap(ptr, size);
Chris Wilsond2805062016-08-18 13:56:18 +0100431
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200432 if (size_ret)
433 *size_ret = size;
434
435 if (stride_ret)
436 *stride_ret = stride;
437
438 return bo;
439 } else {
440 bool driver_has_gem_api = false;
441
442 igt_require(driver_has_gem_api);
443 return -EINVAL;
444 }
445 } else {
446 if (is_dumb)
447 *is_dumb = true;
448
Ville Syrjäläe556d852018-02-27 22:48:46 +0200449 return kmstest_dumb_create(fd, width, height,
450 format->plane_bpp[0],
451 stride_ret, size_ret);
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200452 }
453}
454
Tomeu Vizoso8a1a3862016-02-24 09:04:04 +0100455/**
456 * igt_create_bo_with_dimensions:
457 * @fd: open drm file descriptor
458 * @width: width of the buffer object in pixels
459 * @height: height of the buffer object in pixels
460 * @format: drm fourcc pixel format code
461 * @modifier: modifier corresponding to the tiling layout of the buffer object
462 * @stride: stride of the buffer object in bytes (0 for automatic stride)
463 * @size_ret: size of the buffer object as created by the kernel
464 * @stride_ret: stride of the buffer object as created by the kernel
465 * @is_dumb: whether the created buffer object is a dumb buffer or not
466 *
467 * This function allocates a gem buffer object matching the requested
468 * properties.
469 *
470 * Returns:
471 * The kms id of the created buffer object.
472 */
473int igt_create_bo_with_dimensions(int fd, int width, int height,
474 uint32_t format, uint64_t modifier,
Ville Syrjälä5f8a33a2018-09-06 16:34:15 +0300475 unsigned stride, uint64_t *size_ret,
Tomeu Vizoso8a1a3862016-02-24 09:04:04 +0100476 unsigned *stride_ret, bool *is_dumb)
477{
Ville Syrjäläb6975342018-03-06 20:01:22 +0200478 return create_bo_for_fb(fd, width, height,
479 IGT_COLOR_YCBCR_BT709,
480 IGT_COLOR_YCBCR_LIMITED_RANGE,
481 lookup_drm_format(format),
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100482 modifier, 0, stride, size_ret, stride_ret, NULL, is_dumb);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100483}
484
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100485/**
486 * igt_paint_color:
487 * @cr: cairo drawing context
488 * @x: pixel x-coordination of the fill rectangle
489 * @y: pixel y-coordination of the fill rectangle
490 * @w: width of the fill rectangle
491 * @h: height of the fill rectangle
492 * @r: red value to use as fill color
Thomas Woodd01ebbd2015-06-29 16:47:14 +0100493 * @g: green value to use as fill color
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100494 * @b: blue value to use as fill color
495 *
496 * This functions draws a solid rectangle with the given color using the drawing
497 * context @cr.
498 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100499void igt_paint_color(cairo_t *cr, int x, int y, int w, int h,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100500 double r, double g, double b)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100501{
502 cairo_rectangle(cr, x, y, w, h);
503 cairo_set_source_rgb(cr, r, g, b);
504 cairo_fill(cr);
505}
506
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100507/**
508 * igt_paint_color_alpha:
509 * @cr: cairo drawing context
510 * @x: pixel x-coordination of the fill rectangle
511 * @y: pixel y-coordination of the fill rectangle
512 * @w: width of the fill rectangle
513 * @h: height of the fill rectangle
514 * @r: red value to use as fill color
Thomas Woodd01ebbd2015-06-29 16:47:14 +0100515 * @g: green value to use as fill color
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100516 * @b: blue value to use as fill color
517 * @a: alpha value to use as fill color
518 *
519 * This functions draws a rectangle with the given color and alpha values using
520 * the drawing context @cr.
521 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100522void igt_paint_color_alpha(cairo_t *cr, int x, int y, int w, int h,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100523 double r, double g, double b, double a)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100524{
525 cairo_rectangle(cr, x, y, w, h);
526 cairo_set_source_rgba(cr, r, g, b, a);
527 cairo_fill(cr);
528}
529
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100530/**
531 * igt_paint_color_gradient:
532 * @cr: cairo drawing context
533 * @x: pixel x-coordination of the fill rectangle
534 * @y: pixel y-coordination of the fill rectangle
535 * @w: width of the fill rectangle
536 * @h: height of the fill rectangle
537 * @r: red value to use as fill color
Thomas Woodd01ebbd2015-06-29 16:47:14 +0100538 * @g: green value to use as fill color
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100539 * @b: blue value to use as fill color
540 *
541 * This functions draws a gradient into the rectangle which fades in from black
542 * to the given values using the drawing context @cr.
543 */
Daniel Vetter57d7db82014-03-26 09:06:11 +0100544void
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100545igt_paint_color_gradient(cairo_t *cr, int x, int y, int w, int h,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100546 int r, int g, int b)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100547{
548 cairo_pattern_t *pat;
549
550 pat = cairo_pattern_create_linear(x, y, x + w, y + h);
551 cairo_pattern_add_color_stop_rgba(pat, 1, 0, 0, 0, 1);
552 cairo_pattern_add_color_stop_rgba(pat, 0, r, g, b, 1);
553
554 cairo_rectangle(cr, x, y, w, h);
555 cairo_set_source(cr, pat);
556 cairo_fill(cr);
557 cairo_pattern_destroy(pat);
558}
559
Lionel Landwerlina5113102016-03-18 17:33:02 +0000560/**
561 * igt_paint_color_gradient_range:
562 * @cr: cairo drawing context
563 * @x: pixel x-coordination of the fill rectangle
564 * @y: pixel y-coordination of the fill rectangle
565 * @w: width of the fill rectangle
566 * @h: height of the fill rectangle
567 * @sr: red value to use as start gradient color
568 * @sg: green value to use as start gradient color
569 * @sb: blue value to use as start gradient color
570 * @er: red value to use as end gradient color
571 * @eg: green value to use as end gradient color
572 * @eb: blue value to use as end gradient color
573 *
574 * This functions draws a gradient into the rectangle which fades in
575 * from one color to the other using the drawing context @cr.
576 */
577void
578igt_paint_color_gradient_range(cairo_t *cr, int x, int y, int w, int h,
579 double sr, double sg, double sb,
580 double er, double eg, double eb)
581{
582 cairo_pattern_t *pat;
583
584 pat = cairo_pattern_create_linear(x, y, x + w, y + h);
585 cairo_pattern_add_color_stop_rgba(pat, 1, sr, sg, sb, 1);
586 cairo_pattern_add_color_stop_rgba(pat, 0, er, eg, eb, 1);
587
588 cairo_rectangle(cr, x, y, w, h);
589 cairo_set_source(cr, pat);
590 cairo_fill(cr);
591 cairo_pattern_destroy(pat);
592}
593
Daniel Vetter57d7db82014-03-26 09:06:11 +0100594static void
595paint_test_patterns(cairo_t *cr, int width, int height)
596{
597 double gr_height, gr_width;
598 int x, y;
599
600 y = height * 0.10;
601 gr_width = width * 0.75;
602 gr_height = height * 0.08;
603 x = (width / 2) - (gr_width / 2);
604
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100605 igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 1, 0, 0);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100606
607 y += gr_height;
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100608 igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 0, 1, 0);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100609
610 y += gr_height;
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100611 igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 0, 0, 1);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100612
613 y += gr_height;
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100614 igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 1, 1, 1);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100615}
616
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100617/**
618 * igt_cairo_printf_line:
619 * @cr: cairo drawing context
620 * @align: text alignment
621 * @yspacing: additional y-direction feed after this line
622 * @fmt: format string
623 * @...: optional arguments used in the format string
624 *
625 * This is a little helper to draw text onto framebuffers. All the initial setup
626 * (like setting the font size and the moving to the starting position) still
627 * needs to be done manually with explicit cairo calls on @cr.
628 *
629 * Returns:
630 * The width of the drawn text.
631 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100632int igt_cairo_printf_line(cairo_t *cr, enum igt_text_align align,
Daniel Vetter57d7db82014-03-26 09:06:11 +0100633 double yspacing, const char *fmt, ...)
634{
635 double x, y, xofs, yofs;
636 cairo_text_extents_t extents;
637 char *text;
638 va_list ap;
639 int ret;
640
641 va_start(ap, fmt);
642 ret = vasprintf(&text, fmt, ap);
643 igt_assert(ret >= 0);
644 va_end(ap);
645
646 cairo_text_extents(cr, text, &extents);
647
648 xofs = yofs = 0;
649 if (align & align_right)
650 xofs = -extents.width;
651 else if (align & align_hcenter)
652 xofs = -extents.width / 2;
653
654 if (align & align_top)
655 yofs = extents.height;
656 else if (align & align_vcenter)
657 yofs = extents.height / 2;
658
659 cairo_get_current_point(cr, &x, &y);
660 if (xofs || yofs)
661 cairo_rel_move_to(cr, xofs, yofs);
662
663 cairo_text_path(cr, text);
664 cairo_set_source_rgb(cr, 0, 0, 0);
665 cairo_stroke_preserve(cr);
666 cairo_set_source_rgb(cr, 1, 1, 1);
667 cairo_fill(cr);
668
669 cairo_move_to(cr, x, y + extents.height + yspacing);
670
671 free(text);
672
673 return extents.width;
674}
675
676static void
677paint_marker(cairo_t *cr, int x, int y)
678{
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100679 enum igt_text_align align;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100680 int xoff, yoff;
681
682 cairo_move_to(cr, x, y - 20);
683 cairo_line_to(cr, x, y + 20);
684 cairo_move_to(cr, x - 20, y);
685 cairo_line_to(cr, x + 20, y);
686 cairo_new_sub_path(cr);
687 cairo_arc(cr, x, y, 10, 0, M_PI * 2);
688 cairo_set_line_width(cr, 4);
689 cairo_set_source_rgb(cr, 0, 0, 0);
690 cairo_stroke_preserve(cr);
691 cairo_set_source_rgb(cr, 1, 1, 1);
692 cairo_set_line_width(cr, 2);
693 cairo_stroke(cr);
694
695 xoff = x ? -20 : 20;
696 align = x ? align_right : align_left;
697
698 yoff = y ? -20 : 20;
699 align |= y ? align_bottom : align_top;
700
701 cairo_move_to(cr, x + xoff, y + yoff);
702 cairo_set_font_size(cr, 18);
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100703 igt_cairo_printf_line(cr, align, 0, "(%d, %d)", x, y);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100704}
705
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100706/**
707 * igt_paint_test_pattern:
708 * @cr: cairo drawing context
709 * @width: width of the visible area
710 * @height: height of the visible area
711 *
712 * This functions draws an entire set of test patterns for the given visible
713 * area using the drawing context @cr. This is useful for manual visual
714 * inspection of displayed framebuffers.
715 *
716 * The test patterns include
717 * - corner markers to check for over/underscan and
718 * - a set of color and b/w gradients.
719 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100720void igt_paint_test_pattern(cairo_t *cr, int width, int height)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100721{
722 paint_test_patterns(cr, width, height);
723
724 cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
725
726 /* Paint corner markers */
727 paint_marker(cr, 0, 0);
728 paint_marker(cr, width, 0);
729 paint_marker(cr, 0, height);
730 paint_marker(cr, width, height);
731
732 igt_assert(!cairo_status(cr));
733}
734
Thomas Woodecb03262015-04-13 17:37:22 +0100735static cairo_status_t
736stdio_read_func(void *closure, unsigned char* data, unsigned int size)
737{
738 if (fread(data, 1, size, (FILE*)closure) != size)
739 return CAIRO_STATUS_READ_ERROR;
740
741 return CAIRO_STATUS_SUCCESS;
742}
743
Ville Syrjälä75f320c2017-09-21 15:39:23 +0300744cairo_surface_t *igt_cairo_image_surface_create_from_png(const char *filename)
745{
746 cairo_surface_t *image;
747 FILE *f;
748
749 f = igt_fopen_data(filename);
750 image = cairo_image_surface_create_from_png_stream(&stdio_read_func, f);
751 fclose(f);
752
753 return image;
754}
755
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100756/**
757 * igt_paint_image:
758 * @cr: cairo drawing context
759 * @filename: filename of the png image to draw
760 * @dst_x: pixel x-coordination of the destination rectangle
761 * @dst_y: pixel y-coordination of the destination rectangle
762 * @dst_width: width of the destination rectangle
763 * @dst_height: height of the destination rectangle
764 *
Thomas Woodecb03262015-04-13 17:37:22 +0100765 * This function can be used to draw a scaled version of the supplied png image,
766 * which is loaded from the package data directory.
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100767 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100768void igt_paint_image(cairo_t *cr, const char *filename,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100769 int dst_x, int dst_y, int dst_width, int dst_height)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100770{
771 cairo_surface_t *image;
772 int img_width, img_height;
773 double scale_x, scale_y;
774
Ville Syrjälä75f320c2017-09-21 15:39:23 +0300775 image = igt_cairo_image_surface_create_from_png(filename);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100776 igt_assert(cairo_surface_status(image) == CAIRO_STATUS_SUCCESS);
777
778 img_width = cairo_image_surface_get_width(image);
779 img_height = cairo_image_surface_get_height(image);
780
781 scale_x = (double)dst_width / img_width;
782 scale_y = (double)dst_height / img_height;
783
784 cairo_save(cr);
785
786 cairo_translate(cr, dst_x, dst_y);
787 cairo_scale(cr, scale_x, scale_y);
788 cairo_set_source_surface(cr, image, 0, 0);
789 cairo_paint(cr);
790
791 cairo_surface_destroy(image);
792
793 cairo_restore(cr);
794}
795
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100796/**
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100797 * igt_create_fb_with_bo_size:
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100798 * @fd: open i915 drm file descriptor
799 * @width: width of the framebuffer in pixel
800 * @height: height of the framebuffer in pixel
801 * @format: drm fourcc pixel format code
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000802 * @tiling: tiling layout of the framebuffer (as framebuffer modifier)
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100803 * @fb: pointer to an #igt_fb structure
Paulo Zanonicb7dd5d2015-11-05 16:18:55 -0200804 * @bo_size: size of the backing bo (0 for automatic size)
Paulo Zanonid6341372015-11-05 16:39:00 -0200805 * @bo_stride: stride of the backing bo (0 for automatic stride)
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100806 *
807 * This function allocates a gem buffer object suitable to back a framebuffer
808 * with the requested properties and then wraps it up in a drm framebuffer
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100809 * object of the requested size. All metadata is stored in @fb.
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100810 *
811 * The backing storage of the framebuffer is filled with all zeros, i.e. black
812 * for rgb pixel formats.
813 *
814 * Returns:
Damien Lespiau50166d22014-08-19 11:55:22 +0100815 * The kms id of the created framebuffer.
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100816 */
Damien Lespiau378e61e2014-06-23 14:53:24 +0100817unsigned int
818igt_create_fb_with_bo_size(int fd, int width, int height,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000819 uint32_t format, uint64_t tiling,
Ville Syrjälä5f8a33a2018-09-06 16:34:15 +0300820 struct igt_fb *fb, uint64_t bo_size,
Paulo Zanonid6341372015-11-05 16:39:00 -0200821 unsigned bo_stride)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100822{
Ville Syrjäläb6975342018-03-06 20:01:22 +0200823 /* FIXME allow the caller to pass these in */
824 enum igt_color_encoding color_encoding = IGT_COLOR_YCBCR_BT709;
825 enum igt_color_range color_range = IGT_COLOR_YCBCR_LIMITED_RANGE;
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100826 struct format_desc_struct *f = lookup_drm_format(format);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100827 uint32_t fb_id;
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100828 int i;
829
830 igt_assert_f(f, "DRM format %08x not found\n", format);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100831
832 memset(fb, 0, sizeof(*fb));
833
Ville Syrjälä5f8a33a2018-09-06 16:34:15 +0300834 igt_debug("%s(width=%d, height=%d, format=0x%x, tiling=0x%"PRIx64", size=%"PRIu64")\n",
Tomeu Vizoso8a1a3862016-02-24 09:04:04 +0100835 __func__, width, height, format, tiling, bo_size);
Ville Syrjäläb6975342018-03-06 20:01:22 +0200836 fb->gem_handle = create_bo_for_fb(fd, width, height,
837 color_encoding, color_range,
838 f, tiling, bo_size, bo_stride,
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100839 &fb->size, &fb->stride,
840 fb->offsets, &fb->is_dumb);
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200841 igt_assert(fb->gem_handle > 0);
Chris Wilsondb4cc742014-09-06 12:07:49 +0100842
Chris Wilsondb4cc742014-09-06 12:07:49 +0100843 igt_debug("%s(handle=%d, pitch=%d)\n",
Tvrtko Ursulineb93c1b2015-03-03 14:11:03 +0000844 __func__, fb->gem_handle, fb->stride);
845
846 if (tiling != LOCAL_DRM_FORMAT_MOD_NONE &&
847 tiling != LOCAL_I915_FORMAT_MOD_X_TILED) {
848 do_or_die(__kms_addfb(fd, fb->gem_handle, width, height,
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100849 fb->stride, format, tiling, fb->offsets,
Tvrtko Ursulineb93c1b2015-03-03 14:11:03 +0000850 LOCAL_DRM_MODE_FB_MODIFIERS, &fb_id));
851 } else {
852 uint32_t handles[4];
853 uint32_t pitches[4];
Tvrtko Ursulineb93c1b2015-03-03 14:11:03 +0000854
855 memset(handles, 0, sizeof(handles));
856 memset(pitches, 0, sizeof(pitches));
Tvrtko Ursulineb93c1b2015-03-03 14:11:03 +0000857
858 handles[0] = fb->gem_handle;
859 pitches[0] = fb->stride;
Ville Syrjäläe556d852018-02-27 22:48:46 +0200860 for (i = 0; i < f->num_planes; i++) {
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100861 handles[i] = fb->gem_handle;
862 pitches[i] = fb->stride;
863 }
Tvrtko Ursulineb93c1b2015-03-03 14:11:03 +0000864
865 do_or_die(drmModeAddFB2(fd, width, height, format,
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100866 handles, pitches, fb->offsets,
Tvrtko Ursulineb93c1b2015-03-03 14:11:03 +0000867 &fb_id, 0));
868 }
Daniel Vetter57d7db82014-03-26 09:06:11 +0100869
870 fb->width = width;
871 fb->height = height;
Damien Lespiau378e61e2014-06-23 14:53:24 +0100872 fb->tiling = tiling;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100873 fb->drm_format = format;
874 fb->fb_id = fb_id;
Tomeu Vizoso89b3ffe2016-02-24 09:04:41 +0100875 fb->fd = fd;
Ville Syrjäläe556d852018-02-27 22:48:46 +0200876 fb->num_planes = f->num_planes;
Ville Syrjäläb6975342018-03-06 20:01:22 +0200877 fb->color_encoding = color_encoding;
878 fb->color_range = color_range;
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100879
Ville Syrjäläe556d852018-02-27 22:48:46 +0200880 for (i = 0; i < f->num_planes; i++) {
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100881 fb->plane_bpp[i] = f->plane_bpp[i];
882 fb->plane_height[i] = planar_height(f, height, i);
883 fb->plane_width[i] = planar_width(f, width, i);
884 }
Daniel Vetter57d7db82014-03-26 09:06:11 +0100885
886 return fb_id;
887}
888
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100889/**
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100890 * igt_create_fb:
891 * @fd: open i915 drm file descriptor
892 * @width: width of the framebuffer in pixel
893 * @height: height of the framebuffer in pixel
894 * @format: drm fourcc pixel format code
Damien Lespiau378e61e2014-06-23 14:53:24 +0100895 * @tiling: tiling layout of the framebuffer
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100896 * @fb: pointer to an #igt_fb structure
897 *
898 * This function allocates a gem buffer object suitable to back a framebuffer
899 * with the requested properties and then wraps it up in a drm framebuffer
900 * object. All metadata is stored in @fb.
901 *
902 * The backing storage of the framebuffer is filled with all zeros, i.e. black
903 * for rgb pixel formats.
904 *
905 * Returns:
Damien Lespiau50166d22014-08-19 11:55:22 +0100906 * The kms id of the created framebuffer.
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100907 */
908unsigned int igt_create_fb(int fd, int width, int height, uint32_t format,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000909 uint64_t tiling, struct igt_fb *fb)
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100910{
Paulo Zanonid6341372015-11-05 16:39:00 -0200911 return igt_create_fb_with_bo_size(fd, width, height, format, tiling, fb,
912 0, 0);
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100913}
914
915/**
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100916 * igt_create_color_fb:
917 * @fd: open i915 drm file descriptor
918 * @width: width of the framebuffer in pixel
919 * @height: height of the framebuffer in pixel
920 * @format: drm fourcc pixel format code
Damien Lespiau378e61e2014-06-23 14:53:24 +0100921 * @tiling: tiling layout of the framebuffer
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100922 * @r: red value to use as fill color
Ville Syrjälä5b113d32015-12-17 01:39:31 +0200923 * @g: green value to use as fill color
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100924 * @b: blue value to use as fill color
925 * @fb: pointer to an #igt_fb structure
926 *
927 * This function allocates a gem buffer object suitable to back a framebuffer
928 * with the requested properties and then wraps it up in a drm framebuffer
929 * object. All metadata is stored in @fb.
930 *
931 * Compared to igt_create_fb() this function also fills the entire framebuffer
932 * with the given color, which is useful for some simple pipe crc based tests.
933 *
934 * Returns:
935 * The kms id of the created framebuffer on success or a negative error code on
936 * failure.
937 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100938unsigned int igt_create_color_fb(int fd, int width, int height,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000939 uint32_t format, uint64_t tiling,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100940 double r, double g, double b,
941 struct igt_fb *fb /* out */)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100942{
943 unsigned int fb_id;
944 cairo_t *cr;
945
Damien Lespiau378e61e2014-06-23 14:53:24 +0100946 fb_id = igt_create_fb(fd, width, height, format, tiling, fb);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100947 igt_assert(fb_id);
948
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100949 cr = igt_get_cairo_ctx(fd, fb);
950 igt_paint_color(cr, 0, 0, width, height, r, g, b);
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +0100951 igt_put_cairo_ctx(fd, fb, cr);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100952
953 return fb_id;
954}
955
Ville Syrjälä5b113d32015-12-17 01:39:31 +0200956/**
957 * igt_create_pattern_fb:
958 * @fd: open i915 drm file descriptor
959 * @width: width of the framebuffer in pixel
960 * @height: height of the framebuffer in pixel
961 * @format: drm fourcc pixel format code
962 * @tiling: tiling layout of the framebuffer
963 * @fb: pointer to an #igt_fb structure
964 *
965 * This function allocates a gem buffer object suitable to back a framebuffer
966 * with the requested properties and then wraps it up in a drm framebuffer
967 * object. All metadata is stored in @fb.
968 *
969 * Compared to igt_create_fb() this function also draws the standard test pattern
970 * into the framebuffer.
971 *
972 * Returns:
973 * The kms id of the created framebuffer on success or a negative error code on
974 * failure.
975 */
976unsigned int igt_create_pattern_fb(int fd, int width, int height,
977 uint32_t format, uint64_t tiling,
978 struct igt_fb *fb /* out */)
979{
980 unsigned int fb_id;
981 cairo_t *cr;
982
983 fb_id = igt_create_fb(fd, width, height, format, tiling, fb);
984 igt_assert(fb_id);
985
986 cr = igt_get_cairo_ctx(fd, fb);
987 igt_paint_test_pattern(cr, width, height);
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +0100988 igt_put_cairo_ctx(fd, fb, cr);
Ville Syrjälä5b113d32015-12-17 01:39:31 +0200989
990 return fb_id;
991}
992
993/**
994 * igt_create_color_pattern_fb:
995 * @fd: open i915 drm file descriptor
996 * @width: width of the framebuffer in pixel
997 * @height: height of the framebuffer in pixel
998 * @format: drm fourcc pixel format code
999 * @tiling: tiling layout of the framebuffer
1000 * @r: red value to use as fill color
1001 * @g: green value to use as fill color
1002 * @b: blue value to use as fill color
1003 * @fb: pointer to an #igt_fb structure
1004 *
1005 * This function allocates a gem buffer object suitable to back a framebuffer
1006 * with the requested properties and then wraps it up in a drm framebuffer
1007 * object. All metadata is stored in @fb.
1008 *
1009 * Compared to igt_create_fb() this function also fills the entire framebuffer
1010 * with the given color, and then draws the standard test pattern into the
1011 * framebuffer.
1012 *
1013 * Returns:
1014 * The kms id of the created framebuffer on success or a negative error code on
1015 * failure.
1016 */
1017unsigned int igt_create_color_pattern_fb(int fd, int width, int height,
1018 uint32_t format, uint64_t tiling,
1019 double r, double g, double b,
1020 struct igt_fb *fb /* out */)
1021{
1022 unsigned int fb_id;
1023 cairo_t *cr;
1024
1025 fb_id = igt_create_fb(fd, width, height, format, tiling, fb);
1026 igt_assert(fb_id);
1027
1028 cr = igt_get_cairo_ctx(fd, fb);
1029 igt_paint_color(cr, 0, 0, width, height, r, g, b);
1030 igt_paint_test_pattern(cr, width, height);
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +01001031 igt_put_cairo_ctx(fd, fb, cr);
Ville Syrjälä5b113d32015-12-17 01:39:31 +02001032
1033 return fb_id;
1034}
1035
1036/**
1037 * igt_create_image_fb:
1038 * @drm_fd: open i915 drm file descriptor
1039 * @width: width of the framebuffer in pixel or 0
1040 * @height: height of the framebuffer in pixel or 0
1041 * @format: drm fourcc pixel format code
1042 * @tiling: tiling layout of the framebuffer
1043 * @filename: filename of the png image to draw
1044 * @fb: pointer to an #igt_fb structure
1045 *
1046 * Create a framebuffer with the specified image. If @width is zero the
1047 * image width will be used. If @height is zero the image height will be used.
1048 *
1049 * Returns:
1050 * The kms id of the created framebuffer on success or a negative error code on
1051 * failure.
1052 */
1053unsigned int igt_create_image_fb(int fd, int width, int height,
1054 uint32_t format, uint64_t tiling,
1055 const char *filename,
1056 struct igt_fb *fb /* out */)
1057{
1058 cairo_surface_t *image;
1059 uint32_t fb_id;
1060 cairo_t *cr;
1061
Ville Syrjälä75f320c2017-09-21 15:39:23 +03001062 image = igt_cairo_image_surface_create_from_png(filename);
Ville Syrjälä5b113d32015-12-17 01:39:31 +02001063 igt_assert(cairo_surface_status(image) == CAIRO_STATUS_SUCCESS);
1064 if (width == 0)
1065 width = cairo_image_surface_get_width(image);
1066 if (height == 0)
1067 height = cairo_image_surface_get_height(image);
1068 cairo_surface_destroy(image);
1069
1070 fb_id = igt_create_fb(fd, width, height, format, tiling, fb);
1071
1072 cr = igt_get_cairo_ctx(fd, fb);
1073 igt_paint_image(cr, filename, 0, 0, width, height);
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +01001074 igt_put_cairo_ctx(fd, fb, cr);
Ville Syrjälä5b113d32015-12-17 01:39:31 +02001075
1076 return fb_id;
1077}
1078
Thomas Wood4cb19462014-08-04 16:14:51 +01001079struct box {
1080 int x, y, width, height;
1081};
1082
1083struct stereo_fb_layout {
1084 int fb_width, fb_height;
1085 struct box left, right;
1086};
1087
1088static void box_init(struct box *box, int x, int y, int bwidth, int bheight)
1089{
1090 box->x = x;
1091 box->y = y;
1092 box->width = bwidth;
1093 box->height = bheight;
1094}
1095
1096
1097static void stereo_fb_layout_from_mode(struct stereo_fb_layout *layout,
1098 drmModeModeInfo *mode)
1099{
1100 unsigned int format = mode->flags & DRM_MODE_FLAG_3D_MASK;
1101 const int hdisplay = mode->hdisplay, vdisplay = mode->vdisplay;
1102 int middle;
1103
1104 switch (format) {
1105 case DRM_MODE_FLAG_3D_TOP_AND_BOTTOM:
1106 layout->fb_width = hdisplay;
1107 layout->fb_height = vdisplay;
1108
1109 middle = vdisplay / 2;
1110 box_init(&layout->left, 0, 0, hdisplay, middle);
1111 box_init(&layout->right,
1112 0, middle, hdisplay, vdisplay - middle);
1113 break;
1114 case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF:
1115 layout->fb_width = hdisplay;
1116 layout->fb_height = vdisplay;
1117
1118 middle = hdisplay / 2;
1119 box_init(&layout->left, 0, 0, middle, vdisplay);
1120 box_init(&layout->right,
1121 middle, 0, hdisplay - middle, vdisplay);
1122 break;
1123 case DRM_MODE_FLAG_3D_FRAME_PACKING:
1124 {
1125 int vactive_space = mode->vtotal - vdisplay;
1126
1127 layout->fb_width = hdisplay;
1128 layout->fb_height = 2 * vdisplay + vactive_space;
1129
1130 box_init(&layout->left,
1131 0, 0, hdisplay, vdisplay);
1132 box_init(&layout->right,
1133 0, vdisplay + vactive_space, hdisplay, vdisplay);
1134 break;
1135 }
1136 default:
1137 igt_assert(0);
1138 }
1139}
1140
1141/**
1142 * igt_create_stereo_fb:
1143 * @drm_fd: open i915 drm file descriptor
1144 * @mode: A stereo 3D mode.
1145 * @format: drm fourcc pixel format code
1146 * @tiling: tiling layout of the framebuffer
1147 *
1148 * Create a framebuffer for use with the stereo 3D mode specified by @mode.
1149 *
1150 * Returns:
1151 * The kms id of the created framebuffer on success or a negative error code on
1152 * failure.
1153 */
1154unsigned int igt_create_stereo_fb(int drm_fd, drmModeModeInfo *mode,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +00001155 uint32_t format, uint64_t tiling)
Thomas Wood4cb19462014-08-04 16:14:51 +01001156{
1157 struct stereo_fb_layout layout;
1158 cairo_t *cr;
1159 uint32_t fb_id;
1160 struct igt_fb fb;
1161
1162 stereo_fb_layout_from_mode(&layout, mode);
1163 fb_id = igt_create_fb(drm_fd, layout.fb_width, layout.fb_height, format,
1164 tiling, &fb);
1165 cr = igt_get_cairo_ctx(drm_fd, &fb);
1166
Thomas Woodecb03262015-04-13 17:37:22 +01001167 igt_paint_image(cr, "1080p-left.png",
Thomas Wood4cb19462014-08-04 16:14:51 +01001168 layout.left.x, layout.left.y,
1169 layout.left.width, layout.left.height);
Thomas Woodecb03262015-04-13 17:37:22 +01001170 igt_paint_image(cr, "1080p-right.png",
Thomas Wood4cb19462014-08-04 16:14:51 +01001171 layout.right.x, layout.right.y,
1172 layout.right.width, layout.right.height);
1173
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +01001174 igt_put_cairo_ctx(drm_fd, &fb, cr);
Thomas Wood4cb19462014-08-04 16:14:51 +01001175
1176 return fb_id;
1177}
1178
Daniel Vetter57d7db82014-03-26 09:06:11 +01001179static cairo_format_t drm_format_to_cairo(uint32_t drm_format)
1180{
1181 struct format_desc_struct *f;
1182
1183 for_each_format(f)
1184 if (f->drm_id == drm_format)
1185 return f->cairo_id;
1186
Damien Lespiau54397ca2014-08-19 11:40:07 +01001187 igt_assert_f(0, "can't find a cairo format for %08x (%s)\n",
1188 drm_format, igt_format_str(drm_format));
Daniel Vetter57d7db82014-03-26 09:06:11 +01001189}
1190
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001191struct fb_blit_linear {
Ville Syrjälä5f8a33a2018-09-06 16:34:15 +03001192 uint64_t size;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001193 uint32_t handle;
Ville Syrjälä5f8a33a2018-09-06 16:34:15 +03001194 unsigned int stride;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001195 uint8_t *map;
1196 bool is_dumb;
1197 uint32_t offsets[4];
1198};
1199
Damien Lespiauff451a62015-03-03 14:11:04 +00001200struct fb_blit_upload {
1201 int fd;
1202 struct igt_fb *fb;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001203 struct fb_blit_linear linear;
Damien Lespiauff451a62015-03-03 14:11:04 +00001204};
1205
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001206static void free_linear_mapping(int fd, struct igt_fb *fb, struct fb_blit_linear *linear)
1207{
1208 unsigned int obj_tiling = igt_fb_mod_to_tiling(fb->tiling);
1209 int i;
1210
1211 gem_munmap(linear->map, linear->size);
1212 gem_set_domain(fd, linear->handle,
1213 I915_GEM_DOMAIN_GTT, 0);
1214
1215 for (i = 0; i < fb->num_planes; i++)
1216 igt_blitter_fast_copy__raw(fd,
1217 linear->handle,
1218 linear->offsets[i],
1219 linear->stride,
1220 I915_TILING_NONE,
1221 0, 0, /* src_x, src_y */
1222 fb->plane_width[i], fb->plane_height[i],
1223 fb->plane_bpp[i],
1224 fb->gem_handle,
1225 fb->offsets[i],
1226 fb->stride,
1227 obj_tiling,
1228 0, 0 /* dst_x, dst_y */);
1229
1230 gem_sync(fd, linear->handle);
1231 gem_close(fd, linear->handle);
1232}
1233
Damien Lespiauff451a62015-03-03 14:11:04 +00001234static void destroy_cairo_surface__blit(void *arg)
1235{
1236 struct fb_blit_upload *blit = arg;
Damien Lespiauff451a62015-03-03 14:11:04 +00001237
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001238 blit->fb->cairo_surface = NULL;
Damien Lespiauff451a62015-03-03 14:11:04 +00001239
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001240 free_linear_mapping(blit->fd, blit->fb, &blit->linear);
Damien Lespiauff451a62015-03-03 14:11:04 +00001241
1242 free(blit);
1243}
1244
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001245static void setup_linear_mapping(int fd, struct igt_fb *fb, struct fb_blit_linear *linear)
Damien Lespiauff451a62015-03-03 14:11:04 +00001246{
Tomeu Vizosoae649632016-11-10 10:25:24 +01001247 unsigned int obj_tiling = igt_fb_mod_to_tiling(fb->tiling);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001248 int i;
Damien Lespiauff451a62015-03-03 14:11:04 +00001249
1250 /*
1251 * We create a linear BO that we'll map for the CPU to write to (using
1252 * cairo). This linear bo will be then blitted to its final
1253 * destination, tiling it at the same time.
1254 */
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001255 linear->handle = create_bo_for_fb(fd, fb->width, fb->height,
Ville Syrjäläb6975342018-03-06 20:01:22 +02001256 fb->color_encoding, fb->color_range,
1257 lookup_drm_format(fb->drm_format),
1258 LOCAL_DRM_FORMAT_MOD_NONE, 0,
1259 0, &linear->size,
1260 &linear->stride,
1261 linear->offsets, &linear->is_dumb);
Damien Lespiauff451a62015-03-03 14:11:04 +00001262
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001263 igt_assert(linear->handle > 0);
Tvrtko Ursulin30a13602015-04-29 13:24:34 +01001264
1265 /* Copy fb content to linear BO */
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001266 gem_set_domain(fd, linear->handle,
Tvrtko Ursulin30a13602015-04-29 13:24:34 +01001267 I915_GEM_DOMAIN_GTT, 0);
1268
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001269 for (i = 0; i < fb->num_planes; i++)
1270 igt_blitter_fast_copy__raw(fd,
1271 fb->gem_handle,
1272 fb->offsets[i],
1273 fb->stride,
1274 obj_tiling,
1275 0, 0, /* src_x, src_y */
1276 fb->plane_width[i], fb->plane_height[i],
1277 fb->plane_bpp[i],
1278 linear->handle, linear->offsets[i],
1279 linear->stride,
1280 I915_TILING_NONE,
1281 0, 0 /* dst_x, dst_y */);
Tvrtko Ursulin30a13602015-04-29 13:24:34 +01001282
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001283 gem_sync(fd, linear->handle);
Tvrtko Ursulin30a13602015-04-29 13:24:34 +01001284
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001285 gem_set_domain(fd, linear->handle,
Tvrtko Ursulin30a13602015-04-29 13:24:34 +01001286 I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
1287
1288 /* Setup cairo context */
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001289 linear->map = gem_mmap__cpu(fd, linear->handle,
1290 0, linear->size, PROT_READ | PROT_WRITE);
1291}
1292
1293static void create_cairo_surface__blit(int fd, struct igt_fb *fb)
1294{
1295 struct fb_blit_upload *blit;
1296 cairo_format_t cairo_format;
1297
1298 blit = malloc(sizeof(*blit));
1299 igt_assert(blit);
1300
1301 blit->fd = fd;
1302 blit->fb = fb;
1303 setup_linear_mapping(fd, fb, &blit->linear);
Damien Lespiauff451a62015-03-03 14:11:04 +00001304
Damien Lespiauff451a62015-03-03 14:11:04 +00001305 cairo_format = drm_format_to_cairo(fb->drm_format);
1306 fb->cairo_surface =
1307 cairo_image_surface_create_for_data(blit->linear.map,
1308 cairo_format,
1309 fb->width, fb->height,
1310 blit->linear.stride);
Chris Wilson18d0b1e2016-03-02 14:12:12 +00001311 fb->domain = I915_GEM_DOMAIN_GTT;
Damien Lespiauff451a62015-03-03 14:11:04 +00001312
1313 cairo_surface_set_user_data(fb->cairo_surface,
1314 (cairo_user_data_key_t *)create_cairo_surface__blit,
1315 blit, destroy_cairo_surface__blit);
1316}
1317
Tomeu Vizosoa2d5b342016-03-07 16:25:43 +01001318/**
1319 * igt_dirty_fb:
1320 * @fd: open drm file descriptor
1321 * @fb: pointer to an #igt_fb structure
1322 *
1323 * Flushes out the whole framebuffer.
1324 *
1325 * Returns: 0 upon success.
1326 */
1327int igt_dirty_fb(int fd, struct igt_fb *fb)
1328{
1329 return drmModeDirtyFB(fb->fd, fb->fb_id, NULL, 0);
1330}
1331
Damien Lespiau4aadbc82014-06-23 16:41:43 +01001332static void destroy_cairo_surface__gtt(void *arg)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001333{
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01001334 struct igt_fb *fb = arg;
Damien Lespiau72357f32014-07-11 14:45:37 +01001335
Maarten Lankhorstd930b642017-02-09 10:42:01 +01001336 gem_munmap(cairo_image_surface_get_data(fb->cairo_surface), fb->size);
Damien Lespiau72357f32014-07-11 14:45:37 +01001337 fb->cairo_surface = NULL;
Tomeu Vizoso89b3ffe2016-02-24 09:04:41 +01001338
1339 if (fb->is_dumb)
1340 igt_dirty_fb(fb->fd, fb);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001341}
1342
Damien Lespiau4aadbc82014-06-23 16:41:43 +01001343static void create_cairo_surface__gtt(int fd, struct igt_fb *fb)
1344{
Tomeu Vizoso89b3ffe2016-02-24 09:04:41 +01001345 void *ptr;
1346
Ville Syrjälä3bd68522018-09-05 19:55:43 +03001347 gem_set_domain(fd, fb->gem_handle,
1348 I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
1349
Tomeu Vizoso89b3ffe2016-02-24 09:04:41 +01001350 if (fb->is_dumb)
1351 ptr = kmstest_dumb_map_buffer(fd, fb->gem_handle, fb->size,
1352 PROT_READ | PROT_WRITE);
1353 else
1354 ptr = gem_mmap__gtt(fd, fb->gem_handle, fb->size,
1355 PROT_READ | PROT_WRITE);
Ville Syrjälä106fe212015-10-09 18:36:24 +03001356
Damien Lespiau4aadbc82014-06-23 16:41:43 +01001357 fb->cairo_surface =
Ville Syrjälä106fe212015-10-09 18:36:24 +03001358 cairo_image_surface_create_for_data(ptr,
Damien Lespiau4aadbc82014-06-23 16:41:43 +01001359 drm_format_to_cairo(fb->drm_format),
1360 fb->width, fb->height, fb->stride);
Chris Wilson18d0b1e2016-03-02 14:12:12 +00001361 fb->domain = I915_GEM_DOMAIN_GTT;
Damien Lespiau4aadbc82014-06-23 16:41:43 +01001362
1363 cairo_surface_set_user_data(fb->cairo_surface,
1364 (cairo_user_data_key_t *)create_cairo_surface__gtt,
1365 fb, destroy_cairo_surface__gtt);
1366}
1367
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001368struct fb_convert_blit_upload {
1369 int fd;
1370 struct igt_fb *fb;
1371
1372 struct {
Ville Syrjälä5f8a33a2018-09-06 16:34:15 +03001373 uint64_t size;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001374 uint8_t *map;
Ville Syrjälä5f8a33a2018-09-06 16:34:15 +03001375 unsigned stride;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001376 } rgb24;
1377
1378 struct fb_blit_linear linear;
1379};
1380
Ville Syrjäläee26fef2018-02-27 22:38:05 +02001381static uint8_t clamprgb(float val)
1382{
Ville Syrjäläd1a93aa2018-06-06 20:36:44 +03001383 return clamp((int)(val + 0.5f), 0, 255);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001384}
1385
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001386static void read_rgb(struct igt_vec4 *rgb, const uint8_t *rgb24)
1387{
1388 rgb->d[0] = rgb24[2];
1389 rgb->d[1] = rgb24[1];
1390 rgb->d[2] = rgb24[0];
1391 rgb->d[3] = 1.0f;
1392}
1393
1394static void write_rgb(uint8_t *rgb24, const struct igt_vec4 *rgb)
1395{
1396 rgb24[2] = clamprgb(rgb->d[0]);
1397 rgb24[1] = clamprgb(rgb->d[1]);
1398 rgb24[0] = clamprgb(rgb->d[2]);
1399}
1400
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001401static void convert_nv12_to_rgb24(struct igt_fb *fb, struct fb_convert_blit_upload *blit)
1402{
1403 int i, j;
1404 const uint8_t *y, *uv;
1405 uint8_t *rgb24 = blit->rgb24.map;
1406 unsigned rgb24_stride = blit->rgb24.stride, planar_stride = blit->linear.stride;
1407 uint8_t *buf = malloc(blit->linear.size);
Ville Syrjäläb6975342018-03-06 20:01:22 +02001408 struct igt_mat4 m = igt_ycbcr_to_rgb_matrix(fb->color_encoding,
1409 fb->color_range);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001410
1411 /*
1412 * Reading from the BO is awfully slow because of lack of read caching,
1413 * it's faster to copy the whole BO to a temporary buffer and convert
1414 * from there.
1415 */
Chris Wilson6a06d012018-02-27 21:45:14 +00001416 igt_memcpy_from_wc(buf, blit->linear.map, blit->linear.size);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001417 y = &buf[blit->linear.offsets[0]];
1418 uv = &buf[blit->linear.offsets[1]];
1419
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001420 for (i = 0; i < fb->height / 2; i++) {
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001421 for (j = 0; j < fb->width / 2; j++) {
1422 /* Convert 2x2 pixel blocks */
1423 struct igt_vec4 yuv[4];
1424 struct igt_vec4 rgb[4];
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001425
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001426 yuv[0].d[0] = y[j * 2 + 0];
1427 yuv[1].d[0] = y[j * 2 + 1];
1428 yuv[2].d[0] = y[j * 2 + 0 + planar_stride];
1429 yuv[3].d[0] = y[j * 2 + 1 + planar_stride];
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001430
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001431 yuv[0].d[1] = yuv[1].d[1] = yuv[2].d[1] = yuv[3].d[1] = uv[j * 2 + 0];
1432 yuv[0].d[2] = yuv[1].d[2] = yuv[2].d[2] = yuv[3].d[2] = uv[j * 2 + 1];
1433 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 +01001434
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001435 rgb[0] = igt_matrix_transform(&m, &yuv[0]);
1436 rgb[1] = igt_matrix_transform(&m, &yuv[1]);
1437 rgb[2] = igt_matrix_transform(&m, &yuv[2]);
1438 rgb[3] = igt_matrix_transform(&m, &yuv[3]);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001439
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001440 write_rgb(&rgb24[j * 8 + 0], &rgb[0]);
1441 write_rgb(&rgb24[j * 8 + 4], &rgb[1]);
1442 write_rgb(&rgb24[j * 8 + 0 + rgb24_stride], &rgb[2]);
1443 write_rgb(&rgb24[j * 8 + 4 + rgb24_stride], &rgb[3]);
1444 }
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001445
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001446 if (fb->width & 1) {
1447 /* Convert 1x2 pixel block */
1448 struct igt_vec4 yuv[2];
1449 struct igt_vec4 rgb[2];
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001450
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001451 yuv[0].d[0] = y[j * 2 + 0];
1452 yuv[1].d[0] = y[j * 2 + 0 + planar_stride];
1453
1454 yuv[0].d[1] = yuv[1].d[1] = uv[j * 2 + 0];
1455 yuv[0].d[2] = yuv[1].d[2] = uv[j * 2 + 1];
1456 yuv[0].d[3] = yuv[1].d[3] = 1.0f;
1457
1458 rgb[0] = igt_matrix_transform(&m, &yuv[0]);
1459 rgb[1] = igt_matrix_transform(&m, &yuv[1]);
1460
1461 write_rgb(&rgb24[j * 8 + 0], &rgb[0]);
1462 write_rgb(&rgb24[j * 8 + 0 + rgb24_stride], &rgb[1]);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001463 }
1464
1465 rgb24 += 2 * rgb24_stride;
1466 y += 2 * planar_stride;
1467 uv += planar_stride;
1468 }
1469
1470 if (fb->height & 1) {
1471 /* Convert last row */
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001472 for (j = 0; j < fb->width / 2; j++) {
1473 /* Convert 2x1 pixel blocks */
1474 struct igt_vec4 yuv[2];
1475 struct igt_vec4 rgb[2];
1476
1477 yuv[0].d[0] = y[j * 2 + 0];
1478 yuv[1].d[0] = y[j * 2 + 1];
1479 yuv[0].d[1] = yuv[1].d[1] = uv[j * 2 + 0];
1480 yuv[0].d[2] = yuv[1].d[2] = uv[j * 2 + 1];
1481 yuv[0].d[3] = yuv[1].d[3] = 1.0f;
1482
1483 rgb[0] = igt_matrix_transform(&m, &yuv[0]);
1484 rgb[1] = igt_matrix_transform(&m, &yuv[1]);
1485
1486 write_rgb(&rgb24[j * 8 + 0], &rgb[0]);
1487 write_rgb(&rgb24[j * 8 + 4], &rgb[0]);
1488 }
1489
1490 if (fb->width & 1) {
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001491 /* Convert single pixel */
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001492 struct igt_vec4 yuv;
1493 struct igt_vec4 rgb;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001494
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001495 yuv.d[0] = y[j * 2 + 0];
1496 yuv.d[1] = uv[j * 2 + 0];
1497 yuv.d[2] = uv[j * 2 + 1];
1498 yuv.d[3] = 1.0f;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001499
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001500 rgb = igt_matrix_transform(&m, &yuv);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001501
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001502 write_rgb(&rgb24[j * 8 + 0], &rgb);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001503 }
1504 }
1505
1506 free(buf);
1507}
1508
1509static void convert_rgb24_to_nv12(struct igt_fb *fb, struct fb_convert_blit_upload *blit)
1510{
1511 int i, j;
1512 uint8_t *y = &blit->linear.map[blit->linear.offsets[0]];
1513 uint8_t *uv = &blit->linear.map[blit->linear.offsets[1]];
1514 const uint8_t *rgb24 = blit->rgb24.map;
1515 unsigned rgb24_stride = blit->rgb24.stride;
1516 unsigned planar_stride = blit->linear.stride;
Ville Syrjäläb6975342018-03-06 20:01:22 +02001517 struct igt_mat4 m = igt_rgb_to_ycbcr_matrix(fb->color_encoding,
1518 fb->color_range);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001519
1520 igt_assert_f(fb->drm_format == DRM_FORMAT_NV12,
1521 "Conversion not implemented for !NV12 planar formats\n");
1522
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001523 for (i = 0; i < fb->height / 2; i++) {
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001524 for (j = 0; j < fb->width / 2; j++) {
1525 /* Convert 2x2 pixel blocks */
1526 struct igt_vec4 rgb[4];
1527 struct igt_vec4 yuv[4];
1528
1529 read_rgb(&rgb[0], &rgb24[j * 8 + 0]);
1530 read_rgb(&rgb[1], &rgb24[j * 8 + 4]);
1531 read_rgb(&rgb[2], &rgb24[j * 8 + 0 + rgb24_stride]);
1532 read_rgb(&rgb[3], &rgb24[j * 8 + 4 + rgb24_stride]);
1533
1534 yuv[0] = igt_matrix_transform(&m, &rgb[0]);
1535 yuv[1] = igt_matrix_transform(&m, &rgb[1]);
1536 yuv[2] = igt_matrix_transform(&m, &rgb[2]);
1537 yuv[3] = igt_matrix_transform(&m, &rgb[3]);
1538
1539 y[j * 2 + 0] = yuv[0].d[0];
1540 y[j * 2 + 1] = yuv[1].d[0];
1541 y[j * 2 + 0 + planar_stride] = yuv[2].d[0];
1542 y[j * 2 + 1 + planar_stride] = yuv[3].d[0];
1543
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001544 /*
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001545 * We assume the MPEG2 chroma siting convention, where
1546 * pixel center for Cb'Cr' is between the left top and
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001547 * bottom pixel in a 2x2 block, so take the average.
1548 */
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001549 uv[j * 2 + 0] = (yuv[0].d[1] + yuv[2].d[1]) / 2.0f;
1550 uv[j * 2 + 1] = (yuv[0].d[2] + yuv[2].d[2]) / 2.0f;
1551 }
1552
1553 if (fb->width & 1) {
1554 /* Convert 1x2 pixel block */
1555 struct igt_vec4 rgb[2];
1556 struct igt_vec4 yuv[2];
1557
1558 read_rgb(&rgb[0], &rgb24[j * 8 + 0]);
1559 read_rgb(&rgb[2], &rgb24[j * 8 + 0 + rgb24_stride]);
1560
1561 yuv[0] = igt_matrix_transform(&m, &rgb[0]);
1562 yuv[1] = igt_matrix_transform(&m, &rgb[1]);
1563
1564 y[j * 2 + 0] = yuv[0].d[0];
1565 y[j * 2 + 0 + planar_stride] = yuv[1].d[0];
1566
1567 /*
1568 * We assume the MPEG2 chroma siting convention, where
1569 * pixel center for Cb'Cr' is between the left top and
1570 * bottom pixel in a 2x2 block, so take the average.
1571 */
1572 uv[j * 2 + 0] = (yuv[0].d[1] + yuv[1].d[1]) / 2.0f;
1573 uv[j * 2 + 1] = (yuv[0].d[2] + yuv[1].d[2]) / 2.0f;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001574 }
1575
1576 rgb24 += 2 * rgb24_stride;
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001577 y += 2 * planar_stride;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001578 uv += planar_stride;
1579 }
1580
1581 /* Last row cannot be interpolated between 2 pixels, take the single value */
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001582 if (fb->height & 1) {
1583 for (j = 0; j < fb->width / 2; j++) {
1584 /* Convert 2x1 pixel blocks */
1585 struct igt_vec4 rgb[2];
1586 struct igt_vec4 yuv[2];
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001587
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001588 read_rgb(&rgb[0], &rgb24[j * 8 + 0]);
1589 read_rgb(&rgb[1], &rgb24[j * 8 + 4]);
1590
1591 yuv[0] = igt_matrix_transform(&m, &rgb[0]);
1592 yuv[1] = igt_matrix_transform(&m, &rgb[1]);
1593
1594 y[j * 2 + 0] = yuv[0].d[0];
1595 y[j * 2 + 1] = yuv[1].d[0];
1596 uv[j * 2 + 0] = yuv[0].d[1];
1597 uv[j * 2 + 1] = yuv[0].d[2];
1598 }
1599
1600 if (fb->width & 1) {
1601 /* Convert single pixel */
1602 struct igt_vec4 rgb;
1603 struct igt_vec4 yuv;
1604
1605 read_rgb(&rgb, &rgb24[j * 8 + 0]);
1606
1607 yuv = igt_matrix_transform(&m, &rgb);
1608
1609 y[j * 2 + 0] = yuv.d[0];
1610 uv[j * 2 + 0] = yuv.d[1];
1611 uv[j * 2 + 1] = yuv.d[2];
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001612 }
1613 }
1614}
1615
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001616/* { Y0, U, Y1, V } */
1617static const unsigned char swizzle_yuyv[] = { 0, 1, 2, 3 };
1618static const unsigned char swizzle_yvyu[] = { 0, 3, 2, 1 };
1619static const unsigned char swizzle_uyvy[] = { 1, 0, 3, 2 };
1620static const unsigned char swizzle_vyuy[] = { 1, 2, 3, 0 };
1621
1622static const unsigned char *yuyv_swizzle(uint32_t format)
1623{
1624 switch (format) {
1625 default:
1626 case DRM_FORMAT_YUYV:
1627 return swizzle_yuyv;
1628 case DRM_FORMAT_YVYU:
1629 return swizzle_yvyu;
1630 case DRM_FORMAT_UYVY:
1631 return swizzle_uyvy;
1632 case DRM_FORMAT_VYUY:
1633 return swizzle_vyuy;
1634 }
1635}
1636
1637static void convert_yuyv_to_rgb24(struct igt_fb *fb, struct fb_convert_blit_upload *blit,
1638 const unsigned char swz[4])
1639{
1640 int i, j;
1641 const uint8_t *yuyv;
1642 uint8_t *rgb24 = blit->rgb24.map;
1643 unsigned rgb24_stride = blit->rgb24.stride, yuyv_stride = blit->linear.stride;
1644 uint8_t *buf = malloc(blit->linear.size);
Ville Syrjäläb6975342018-03-06 20:01:22 +02001645 struct igt_mat4 m = igt_ycbcr_to_rgb_matrix(fb->color_encoding,
1646 fb->color_range);
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001647
1648 /*
1649 * Reading from the BO is awfully slow because of lack of read caching,
1650 * it's faster to copy the whole BO to a temporary buffer and convert
1651 * from there.
1652 */
1653 igt_memcpy_from_wc(buf, blit->linear.map, blit->linear.size);
1654 yuyv = buf;
1655
1656 for (i = 0; i < fb->height; i++) {
1657 for (j = 0; j < fb->width / 2; j++) {
1658 /* Convert 2x1 pixel blocks */
1659 struct igt_vec4 yuv[2];
1660 struct igt_vec4 rgb[2];
1661
1662 yuv[0].d[0] = yuyv[j * 4 + swz[0]];
1663 yuv[1].d[0] = yuyv[j * 4 + swz[2]];
1664 yuv[0].d[1] = yuv[1].d[1] = yuyv[j * 4 + swz[1]];
1665 yuv[0].d[2] = yuv[1].d[2] = yuyv[j * 4 + swz[3]];
1666 yuv[0].d[3] = yuv[1].d[3] = 1.0f;
1667
1668 rgb[0] = igt_matrix_transform(&m, &yuv[0]);
1669 rgb[1] = igt_matrix_transform(&m, &yuv[1]);
1670
1671 write_rgb(&rgb24[j * 8 + 0], &rgb[0]);
1672 write_rgb(&rgb24[j * 8 + 4], &rgb[1]);
1673 }
1674
1675 if (fb->width & 1) {
1676 struct igt_vec4 yuv;
1677 struct igt_vec4 rgb;
1678
1679 yuv.d[0] = yuyv[j * 4 + swz[0]];
1680 yuv.d[1] = yuyv[j * 4 + swz[1]];
1681 yuv.d[2] = yuyv[j * 4 + swz[3]];
1682 yuv.d[3] = 1.0f;
1683
1684 rgb = igt_matrix_transform(&m, &yuv);
1685
1686 write_rgb(&rgb24[j * 8 + 0], &rgb);
1687 }
1688
1689 rgb24 += rgb24_stride;
1690 yuyv += yuyv_stride;
1691 }
1692
1693 free(buf);
1694}
1695
1696static void convert_rgb24_to_yuyv(struct igt_fb *fb, struct fb_convert_blit_upload *blit,
1697 const unsigned char swz[4])
1698{
1699 int i, j;
1700 uint8_t *yuyv = blit->linear.map;
1701 const uint8_t *rgb24 = blit->rgb24.map;
1702 unsigned rgb24_stride = blit->rgb24.stride;
1703 unsigned yuyv_stride = blit->linear.stride;
Ville Syrjäläb6975342018-03-06 20:01:22 +02001704 struct igt_mat4 m = igt_rgb_to_ycbcr_matrix(fb->color_encoding,
1705 fb->color_range);
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001706
1707 igt_assert_f(fb->drm_format == DRM_FORMAT_YUYV ||
1708 fb->drm_format == DRM_FORMAT_YVYU ||
1709 fb->drm_format == DRM_FORMAT_UYVY ||
1710 fb->drm_format == DRM_FORMAT_VYUY,
1711 "Conversion not implemented for !YUYV planar formats\n");
1712
1713 for (i = 0; i < fb->height; i++) {
1714 for (j = 0; j < fb->width / 2; j++) {
1715 /* Convert 2x1 pixel blocks */
1716 struct igt_vec4 rgb[2];
1717 struct igt_vec4 yuv[2];
1718
1719 read_rgb(&rgb[0], &rgb24[j * 8 + 0]);
1720 read_rgb(&rgb[1], &rgb24[j * 8 + 4]);
1721
1722 yuv[0] = igt_matrix_transform(&m, &rgb[0]);
1723 yuv[1] = igt_matrix_transform(&m, &rgb[1]);
1724
1725 yuyv[j * 4 + swz[0]] = yuv[0].d[0];
1726 yuyv[j * 4 + swz[2]] = yuv[1].d[0];
1727 yuyv[j * 4 + swz[1]] = (yuv[0].d[1] + yuv[1].d[1]) / 2.0f;
1728 yuyv[j * 4 + swz[3]] = (yuv[0].d[2] + yuv[1].d[2]) / 2.0f;
1729 }
1730
1731 if (fb->width & 1) {
1732 struct igt_vec4 rgb;
1733 struct igt_vec4 yuv;
1734
1735 read_rgb(&rgb, &rgb24[j * 8 + 0]);
1736
1737 yuv = igt_matrix_transform(&m, &rgb);
1738
1739 yuyv[j * 4 + swz[0]] = yuv.d[0];
1740 yuyv[j * 4 + swz[1]] = yuv.d[1];
1741 yuyv[j * 4 + swz[3]] = yuv.d[2];
1742 }
1743
1744 rgb24 += rgb24_stride;
1745 yuyv += yuyv_stride;
1746 }
1747}
1748
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001749static void destroy_cairo_surface__convert(void *arg)
1750{
1751 struct fb_convert_blit_upload *blit = arg;
1752 struct igt_fb *fb = blit->fb;
1753
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001754 /* Convert linear rgb back! */
1755 switch(fb->drm_format) {
1756 case DRM_FORMAT_NV12:
1757 convert_rgb24_to_nv12(fb, blit);
1758 break;
1759 case DRM_FORMAT_YUYV:
1760 case DRM_FORMAT_YVYU:
1761 case DRM_FORMAT_UYVY:
1762 case DRM_FORMAT_VYUY:
1763 convert_rgb24_to_yuyv(fb, blit, yuyv_swizzle(fb->drm_format));
1764 break;
1765 default:
1766 igt_assert_f(false, "Conversion not implemented for formats 0x%x\n",
1767 fb->drm_format);
1768 }
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001769
1770 munmap(blit->rgb24.map, blit->rgb24.size);
1771
1772 if (blit->linear.handle)
1773 free_linear_mapping(blit->fd, blit->fb, &blit->linear);
1774 else
1775 gem_munmap(blit->linear.map, fb->size);
1776
1777 free(blit);
1778
1779 fb->cairo_surface = NULL;
1780}
1781
1782static void create_cairo_surface__convert(int fd, struct igt_fb *fb)
1783{
1784 struct fb_convert_blit_upload *blit = malloc(sizeof(*blit));
1785 igt_assert(blit);
1786
1787 blit->fd = fd;
1788 blit->fb = fb;
1789 blit->rgb24.stride = ALIGN(fb->width * 4, 16);
Ville Syrjälä5f8a33a2018-09-06 16:34:15 +03001790 blit->rgb24.size = ALIGN((uint64_t) blit->rgb24.stride * fb->height, sysconf(_SC_PAGESIZE));
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001791 blit->rgb24.map = mmap(NULL, blit->rgb24.size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
1792 igt_assert(blit->rgb24.map != MAP_FAILED);
1793
1794 if (fb->tiling == LOCAL_I915_FORMAT_MOD_Y_TILED ||
1795 fb->tiling == LOCAL_I915_FORMAT_MOD_Yf_TILED) {
1796 setup_linear_mapping(fd, fb, &blit->linear);
1797 } else {
1798 blit->linear.handle = 0;
Ville Syrjälä3bd68522018-09-05 19:55:43 +03001799 gem_set_domain(fd, fb->gem_handle,
1800 I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001801 blit->linear.map = gem_mmap__gtt(fd, fb->gem_handle, fb->size,
1802 PROT_READ | PROT_WRITE);
1803 igt_assert(blit->linear.map);
1804 blit->linear.stride = fb->stride;
1805 blit->linear.size = fb->size;
1806 memcpy(blit->linear.offsets, fb->offsets, sizeof(fb->offsets));
1807 }
1808
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001809 /* Convert to linear rgb! */
1810 switch(fb->drm_format) {
1811 case DRM_FORMAT_NV12:
1812 convert_nv12_to_rgb24(fb, blit);
1813 break;
1814 case DRM_FORMAT_YUYV:
1815 case DRM_FORMAT_YVYU:
1816 case DRM_FORMAT_UYVY:
1817 case DRM_FORMAT_VYUY:
1818 convert_yuyv_to_rgb24(fb, blit, yuyv_swizzle(fb->drm_format));
1819 break;
1820 default:
1821 igt_assert_f(false, "Conversion not implemented for formats 0x%x\n",
1822 fb->drm_format);
1823 }
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001824
1825 fb->cairo_surface =
1826 cairo_image_surface_create_for_data(blit->rgb24.map,
1827 CAIRO_FORMAT_RGB24,
1828 fb->width, fb->height,
1829 blit->rgb24.stride);
1830
1831 cairo_surface_set_user_data(fb->cairo_surface,
1832 (cairo_user_data_key_t *)create_cairo_surface__convert,
1833 blit, destroy_cairo_surface__convert);
1834}
1835
Paul Kocialkowskib4ad3972017-07-19 16:46:04 +03001836/**
1837 * igt_get_cairo_surface:
1838 * @fd: open drm file descriptor
1839 * @fb: pointer to an #igt_fb structure
1840 *
Maarten Lankhorst918ea422018-01-19 12:47:11 +01001841 * This function stores the contents of the supplied framebuffer's plane
1842 * into a cairo surface and returns it.
Paul Kocialkowskib4ad3972017-07-19 16:46:04 +03001843 *
1844 * Returns:
1845 * A pointer to a cairo surface with the contents of the framebuffer.
1846 */
1847cairo_surface_t *igt_get_cairo_surface(int fd, struct igt_fb *fb)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001848{
Damien Lespiauff451a62015-03-03 14:11:04 +00001849 if (fb->cairo_surface == NULL) {
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001850 if (igt_format_is_yuv(fb->drm_format))
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001851 create_cairo_surface__convert(fd, fb);
1852 else if (fb->tiling == LOCAL_I915_FORMAT_MOD_Y_TILED ||
Damien Lespiauff451a62015-03-03 14:11:04 +00001853 fb->tiling == LOCAL_I915_FORMAT_MOD_Yf_TILED)
1854 create_cairo_surface__blit(fd, fb);
1855 else
1856 create_cairo_surface__gtt(fd, fb);
1857 }
Daniel Vetter57d7db82014-03-26 09:06:11 +01001858
Daniel Vetter57d7db82014-03-26 09:06:11 +01001859 igt_assert(cairo_surface_status(fb->cairo_surface) == CAIRO_STATUS_SUCCESS);
Damien Lespiau0db75bb2014-06-30 16:34:20 +01001860 return fb->cairo_surface;
Daniel Vetter57d7db82014-03-26 09:06:11 +01001861}
1862
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001863/**
1864 * igt_get_cairo_ctx:
1865 * @fd: open i915 drm file descriptor
1866 * @fb: pointer to an #igt_fb structure
1867 *
1868 * This initializes a cairo surface for @fb and then allocates a drawing context
1869 * for it. The return cairo drawing context should be released by calling
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +01001870 * igt_put_cairo_ctx(). This also sets a default font for drawing text on
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001871 * framebuffers.
1872 *
1873 * Returns:
1874 * The created cairo drawing context.
1875 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01001876cairo_t *igt_get_cairo_ctx(int fd, struct igt_fb *fb)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001877{
1878 cairo_surface_t *surface;
1879 cairo_t *cr;
1880
Paul Kocialkowskib4ad3972017-07-19 16:46:04 +03001881 surface = igt_get_cairo_surface(fd, fb);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001882 cr = cairo_create(surface);
1883 cairo_surface_destroy(surface);
Daniel Vetter7568edf2014-03-26 16:36:46 +01001884 igt_assert(cairo_status(cr) == CAIRO_STATUS_SUCCESS);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001885
Daniel Vetter7568edf2014-03-26 16:36:46 +01001886 cairo_select_font_face(cr, "Helvetica", CAIRO_FONT_SLANT_NORMAL,
1887 CAIRO_FONT_WEIGHT_NORMAL);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001888 igt_assert(cairo_status(cr) == CAIRO_STATUS_SUCCESS);
1889
1890 return cr;
1891}
1892
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001893/**
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +01001894 * igt_put_cairo_ctx:
1895 * @fd: open i915 drm file descriptor
1896 * @fb: pointer to an #igt_fb structure
1897 * @cr: the cairo context returned by igt_get_cairo_ctx.
1898 *
1899 * This releases the cairo surface @cr returned by igt_get_cairo_ctx()
1900 * for @fb, and writes the changes out to the framebuffer if cairo doesn't
1901 * have native support for the format.
1902 */
1903void igt_put_cairo_ctx(int fd, struct igt_fb *fb, cairo_t *cr)
1904{
1905 cairo_status_t ret = cairo_status(cr);
1906 igt_assert_f(ret == CAIRO_STATUS_SUCCESS, "Cairo failed to draw with %s\n", cairo_status_to_string(ret));
1907
1908 cairo_destroy(cr);
1909}
1910
1911/**
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001912 * igt_remove_fb:
1913 * @fd: open i915 drm file descriptor
1914 * @fb: pointer to an #igt_fb structure
1915 *
1916 * This function releases all resources allocated in igt_create_fb() for @fb.
1917 * Note that if this framebuffer is still in use on a primary plane the kernel
1918 * will disable the corresponding crtc.
1919 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01001920void igt_remove_fb(int fd, struct igt_fb *fb)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001921{
Maarten Lankhorste62de1c2018-02-02 10:58:42 +01001922 if (!fb || !fb->fb_id)
1923 return;
1924
Daniel Vetter57d7db82014-03-26 09:06:11 +01001925 cairo_surface_destroy(fb->cairo_surface);
1926 do_or_die(drmModeRmFB(fd, fb->fb_id));
1927 gem_close(fd, fb->gem_handle);
Maarten Lankhorste62de1c2018-02-02 10:58:42 +01001928 fb->fb_id = 0;
Daniel Vetter57d7db82014-03-26 09:06:11 +01001929}
1930
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001931/**
1932 * igt_bpp_depth_to_drm_format:
1933 * @bpp: desired bits per pixel
1934 * @depth: desired depth
1935 *
1936 * Returns:
1937 * The rgb drm fourcc pixel format code corresponding to the given @bpp and
1938 * @depth values. Fails hard if no match was found.
1939 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01001940uint32_t igt_bpp_depth_to_drm_format(int bpp, int depth)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001941{
1942 struct format_desc_struct *f;
1943
1944 for_each_format(f)
Ville Syrjäläe556d852018-02-27 22:48:46 +02001945 if (f->plane_bpp[0] == bpp && f->depth == depth)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001946 return f->drm_id;
1947
Damien Lespiau54397ca2014-08-19 11:40:07 +01001948
1949 igt_assert_f(0, "can't find drm format with bpp=%d, depth=%d\n", bpp,
1950 depth);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001951}
1952
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001953/**
1954 * igt_drm_format_to_bpp:
1955 * @drm_format: drm fourcc pixel format code
1956 *
1957 * Returns:
1958 * The bits per pixel for the given drm fourcc pixel format code. Fails hard if
1959 * no match was found.
1960 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01001961uint32_t igt_drm_format_to_bpp(uint32_t drm_format)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001962{
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +01001963 struct format_desc_struct *f = lookup_drm_format(drm_format);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001964
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +01001965 igt_assert_f(f, "can't find a bpp format for %08x (%s)\n",
Damien Lespiau54397ca2014-08-19 11:40:07 +01001966 drm_format, igt_format_str(drm_format));
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +01001967
Ville Syrjäläe556d852018-02-27 22:48:46 +02001968 return f->plane_bpp[0];
Daniel Vetter57d7db82014-03-26 09:06:11 +01001969}
1970
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001971/**
1972 * igt_format_str:
1973 * @drm_format: drm fourcc pixel format code
1974 *
1975 * Returns:
1976 * Human-readable fourcc pixel format code for @drm_format or "invalid" no match
1977 * was found.
1978 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01001979const char *igt_format_str(uint32_t drm_format)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001980{
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +01001981 struct format_desc_struct *f = lookup_drm_format(drm_format);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001982
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +01001983 return f ? f->name : "invalid";
Daniel Vetter57d7db82014-03-26 09:06:11 +01001984}
1985
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001986/**
Maarten Lankhorstc60cf3b2018-02-02 11:32:40 +01001987 * igt_fb_supported_format:
1988 * @drm_format: drm fourcc to test.
1989 *
1990 * This functions returns whether @drm_format can be succesfully created by
1991 * igt_create_fb() and drawn to by igt_get_cairo_ctx().
1992 */
1993bool igt_fb_supported_format(uint32_t drm_format)
1994{
1995 struct format_desc_struct *f;
1996
1997 for_each_format(f)
1998 if (f->drm_id == drm_format)
1999 return f->cairo_id != CAIRO_FORMAT_INVALID;
2000
2001 return false;
2002}
Ville Syrjälä40bf6d02018-05-18 23:32:32 +03002003
2004/**
2005 * igt_format_is_yuv:
2006 * @drm_format: drm fourcc
2007 *
2008 * This functions returns whether @drm_format is YUV (as opposed to RGB).
2009 */
2010bool igt_format_is_yuv(uint32_t drm_format)
2011{
2012 switch (drm_format) {
2013 case DRM_FORMAT_NV12:
2014 case DRM_FORMAT_YUYV:
2015 case DRM_FORMAT_YVYU:
2016 case DRM_FORMAT_UYVY:
2017 case DRM_FORMAT_VYUY:
2018 return true;
2019 default:
2020 return false;
2021 }
2022}