blob: dc227493dbb257d278ea7cb510f73578a22403d7 [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 */
Ville Syrjäläef43fce2018-07-18 20:26:22 +030063static const 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 },
Maxime Riparda3d88d32018-10-04 14:38:56 +020075 { .name = "RGB888", .depth = -1, .drm_id = DRM_FORMAT_RGB888,
76 .cairo_id = CAIRO_FORMAT_INVALID,
77 .num_planes = 1, .plane_bpp = { 24, },
78 },
Ville Syrjäläe556d852018-02-27 22:48:46 +020079 { .name = "XRGB8888", .depth = 24, .drm_id = DRM_FORMAT_XRGB8888,
80 .cairo_id = CAIRO_FORMAT_RGB24,
81 .num_planes = 1, .plane_bpp = { 32, },
82 },
83 { .name = "XRGB2101010", .depth = 30, .drm_id = DRM_FORMAT_XRGB2101010,
84 .cairo_id = CAIRO_FORMAT_RGB30,
85 .num_planes = 1, .plane_bpp = { 32, },
86 },
87 { .name = "ARGB8888", .depth = 32, .drm_id = DRM_FORMAT_ARGB8888,
88 .cairo_id = CAIRO_FORMAT_ARGB32,
89 .num_planes = 1, .plane_bpp = { 32, },
90 },
91 { .name = "NV12", .depth = -1, .drm_id = DRM_FORMAT_NV12,
92 .cairo_id = CAIRO_FORMAT_RGB24,
93 .num_planes = 2, .plane_bpp = { 8, 16, },
94 },
Ville Syrjäläfed97c42018-02-27 22:58:01 +020095 { .name = "YUYV", .depth = -1, .drm_id = DRM_FORMAT_YUYV,
96 .cairo_id = CAIRO_FORMAT_RGB24,
97 .num_planes = 1, .plane_bpp = { 16, },
98 },
99 { .name = "YVYU", .depth = -1, .drm_id = DRM_FORMAT_YVYU,
100 .cairo_id = CAIRO_FORMAT_RGB24,
101 .num_planes = 1, .plane_bpp = { 16, },
102 },
103 { .name = "UYVY", .depth = -1, .drm_id = DRM_FORMAT_UYVY,
104 .cairo_id = CAIRO_FORMAT_RGB24,
105 .num_planes = 1, .plane_bpp = { 16, },
106 },
107 { .name = "VYUY", .depth = -1, .drm_id = DRM_FORMAT_VYUY,
108 .cairo_id = CAIRO_FORMAT_RGB24,
109 .num_planes = 1, .plane_bpp = { 16, },
110 },
Daniel Vetter57d7db82014-03-26 09:06:11 +0100111};
Daniel Vetter57d7db82014-03-26 09:06:11 +0100112#define for_each_format(f) \
113 for (f = format_desc; f - format_desc < ARRAY_SIZE(format_desc); f++)
114
Ville Syrjäläef43fce2018-07-18 20:26:22 +0300115static const struct format_desc_struct *lookup_drm_format(uint32_t drm_format)
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100116{
Ville Syrjäläef43fce2018-07-18 20:26:22 +0300117 const struct format_desc_struct *format;
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100118
119 for_each_format(format) {
120 if (format->drm_id != drm_format)
121 continue;
122
123 return format;
124 }
125
126 return NULL;
127}
128
Praveen Paneri4bb45412017-07-18 22:52:56 +0530129/**
130 * igt_get_fb_tile_size:
131 * @fd: the DRM file descriptor
132 * @tiling: tiling layout of the framebuffer (as framebuffer modifier)
133 * @fb_bpp: bits per pixel of the framebuffer
134 * @width_ret: width of the tile in bytes
135 * @height_ret: height of the tile in lines
136 *
137 * This function returns width and height of a tile based on the given tiling
138 * format.
139 */
140void igt_get_fb_tile_size(int fd, uint64_t tiling, int fb_bpp,
141 unsigned *width_ret, unsigned *height_ret)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100142{
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200143 switch (tiling) {
144 case LOCAL_DRM_FORMAT_MOD_NONE:
145 *width_ret = 64;
146 *height_ret = 1;
147 break;
148 case LOCAL_I915_FORMAT_MOD_X_TILED:
Tomeu Vizoso85a1d452016-02-24 08:39:53 +0100149 igt_require_intel(fd);
150 if (intel_gen(intel_get_drm_devid(fd)) == 2) {
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200151 *width_ret = 128;
152 *height_ret = 16;
153 } else {
154 *width_ret = 512;
155 *height_ret = 8;
156 }
157 break;
158 case LOCAL_I915_FORMAT_MOD_Y_TILED:
Tomeu Vizoso85a1d452016-02-24 08:39:53 +0100159 igt_require_intel(fd);
160 if (intel_gen(intel_get_drm_devid(fd)) == 2) {
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200161 *width_ret = 128;
Ville Syrjälä037bc692016-02-12 21:28:54 +0200162 *height_ret = 16;
Tomeu Vizoso85a1d452016-02-24 08:39:53 +0100163 } else if (IS_915(intel_get_drm_devid(fd))) {
Ville Syrjälä037bc692016-02-12 21:28:54 +0200164 *width_ret = 512;
165 *height_ret = 8;
166 } else {
167 *width_ret = 128;
168 *height_ret = 32;
169 }
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200170 break;
171 case LOCAL_I915_FORMAT_MOD_Yf_TILED:
Tomeu Vizoso85a1d452016-02-24 08:39:53 +0100172 igt_require_intel(fd);
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200173 switch (fb_bpp) {
174 case 8:
175 *width_ret = 64;
176 *height_ret = 64;
177 break;
178 case 16:
179 case 32:
180 *width_ret = 128;
181 *height_ret = 32;
182 break;
183 case 64:
184 case 128:
185 *width_ret = 256;
186 *height_ret = 16;
187 break;
188 default:
189 igt_assert(false);
190 }
191 break;
192 default:
193 igt_assert(false);
194 }
195}
196
Ville Syrjälä22383612018-07-17 18:32:38 +0300197static unsigned fb_plane_width(const struct igt_fb *fb, int plane)
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100198{
Ville Syrjälä22383612018-07-17 18:32:38 +0300199 if (fb->drm_format == DRM_FORMAT_NV12 && plane == 1)
200 return DIV_ROUND_UP(fb->width, 2);
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100201
Ville Syrjälä22383612018-07-17 18:32:38 +0300202 return fb->width;
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100203}
204
Ville Syrjälä22383612018-07-17 18:32:38 +0300205static unsigned fb_plane_bpp(const struct igt_fb *fb, int plane)
Ville Syrjälä72bf5972018-07-17 18:11:40 +0300206{
Ville Syrjälä22383612018-07-17 18:32:38 +0300207 const struct format_desc_struct *format = lookup_drm_format(fb->drm_format);
208
Ville Syrjälä72bf5972018-07-17 18:11:40 +0300209 return format->plane_bpp[plane];
210}
211
Ville Syrjälä22383612018-07-17 18:32:38 +0300212static unsigned fb_plane_height(const struct igt_fb *fb, int plane)
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100213{
Ville Syrjälä22383612018-07-17 18:32:38 +0300214 if (fb->drm_format == DRM_FORMAT_NV12 && plane == 1)
215 return DIV_ROUND_UP(fb->height, 2);
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100216
Ville Syrjälä22383612018-07-17 18:32:38 +0300217 return fb->height;
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100218}
219
Ville Syrjälä22383612018-07-17 18:32:38 +0300220static int fb_num_planes(const struct igt_fb *fb)
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100221{
Ville Syrjälä22383612018-07-17 18:32:38 +0300222 const struct format_desc_struct *format = lookup_drm_format(fb->drm_format);
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100223
Ville Syrjäläb7298a72018-07-17 18:25:34 +0300224 return format->num_planes;
225}
226
Ville Syrjälä22383612018-07-17 18:32:38 +0300227static void fb_init(struct igt_fb *fb,
228 int fd, int width, int height,
229 uint32_t drm_format,
230 uint64_t modifier,
231 enum igt_color_encoding color_encoding,
232 enum igt_color_range color_range)
Ville Syrjäläc3edd792018-07-17 18:18:14 +0300233{
Ville Syrjälä22383612018-07-17 18:32:38 +0300234 const struct format_desc_struct *f = lookup_drm_format(drm_format);
Ville Syrjäläc3edd792018-07-17 18:18:14 +0300235
Ville Syrjälä22383612018-07-17 18:32:38 +0300236 igt_assert_f(f, "DRM format %08x not found\n", drm_format);
237
238 memset(fb, 0, sizeof(*fb));
239
240 fb->width = width;
241 fb->height = height;
242 fb->tiling = modifier;
243 fb->drm_format = drm_format;
244 fb->fd = fd;
245 fb->num_planes = fb_num_planes(fb);
246 fb->color_encoding = color_encoding;
247 fb->color_range = color_range;
248
249 for (int i = 0; i < fb->num_planes; i++) {
250 fb->plane_bpp[i] = fb_plane_bpp(fb, i);
251 fb->plane_height[i] = fb_plane_height(fb, i);
252 fb->plane_width[i] = fb_plane_width(fb, i);
253 }
254}
255
256static uint32_t calc_plane_stride(struct igt_fb *fb, int plane)
257{
258 uint32_t min_stride = fb->plane_width[plane] *
259 (fb->plane_bpp[plane] / 8);
260
261 if (fb->tiling != LOCAL_DRM_FORMAT_MOD_NONE &&
262 intel_gen(intel_get_drm_devid(fb->fd)) <= 3) {
Ville Syrjäläc3edd792018-07-17 18:18:14 +0300263 uint32_t stride;
264
265 /* 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.
268 *
269 * This can still fail if the framebuffer is too large to be
270 * tiled. But then that failure is expected.
271 */
272
273 stride = max(min_stride, 512);
274 stride = roundup_power_of_two(stride);
275
276 return stride;
277 } else {
278 unsigned int tile_width, tile_height;
279
Ville Syrjälä22383612018-07-17 18:32:38 +0300280 igt_get_fb_tile_size(fb->fd, fb->tiling, fb->plane_bpp[plane],
Ville Syrjäläc3edd792018-07-17 18:18:14 +0300281 &tile_width, &tile_height);
282
283 return ALIGN(min_stride, tile_width);
284 }
285}
286
Ville Syrjälä22383612018-07-17 18:32:38 +0300287static uint64_t calc_plane_size(struct igt_fb *fb, int plane)
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100288{
Ville Syrjälä22383612018-07-17 18:32:38 +0300289 if (fb->tiling != LOCAL_DRM_FORMAT_MOD_NONE &&
290 intel_gen(intel_get_drm_devid(fb->fd)) <= 3) {
291 uint64_t min_size = (uint64_t) fb->strides[plane] *
292 fb->plane_height[plane];
Ville Syrjälä4d2598f2018-07-18 17:56:56 +0300293 uint64_t size;
294
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200295 /* Round the tiling up to the next power-of-two and the region
296 * up to the next pot fence size so that this works on all
297 * generations.
Daniel Vetter57d7db82014-03-26 09:06:11 +0100298 *
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200299 * This can still fail if the framebuffer is too large to be
300 * tiled. But then that failure is expected.
Daniel Vetter57d7db82014-03-26 09:06:11 +0100301 */
302
Ville Syrjälä4d2598f2018-07-18 17:56:56 +0300303 size = max(min_size, 1024*1024);
Ville Syrjälä20a7ead2018-09-07 22:12:26 +0300304 size = roundup_power_of_two(size);
Ville Syrjälä4d2598f2018-07-18 17:56:56 +0300305
306 return size;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100307 } else {
Ville Syrjäläc3edd792018-07-17 18:18:14 +0300308 unsigned int tile_width, tile_height;
309
Ville Syrjälä22383612018-07-17 18:32:38 +0300310 igt_get_fb_tile_size(fb->fd, fb->tiling, fb->plane_bpp[plane],
Ville Syrjäläc3edd792018-07-17 18:18:14 +0300311 &tile_width, &tile_height);
Ville Syrjälä94540e32018-07-18 21:17:05 +0300312
Ville Syrjälä22383612018-07-17 18:32:38 +0300313 return (uint64_t) fb->strides[plane] *
314 ALIGN(fb->plane_height[plane], tile_height);
Ville Syrjälä4d2598f2018-07-18 17:56:56 +0300315 }
316}
317
Ville Syrjälä22383612018-07-17 18:32:38 +0300318static uint64_t calc_fb_size(struct igt_fb *fb)
Ville Syrjälä4d2598f2018-07-18 17:56:56 +0300319{
320 uint64_t size = 0;
321 int plane;
322
Ville Syrjälä22383612018-07-17 18:32:38 +0300323 for (plane = 0; plane < fb->num_planes; plane++) {
324 /* respect the stride requested by the caller */
325 if (!fb->strides[plane])
326 fb->strides[plane] = calc_plane_stride(fb, plane);
Ville Syrjälä4d2598f2018-07-18 17:56:56 +0300327
Ville Syrjälä22383612018-07-17 18:32:38 +0300328 fb->offsets[plane] = size;
Ville Syrjälä4d2598f2018-07-18 17:56:56 +0300329
Ville Syrjälä22383612018-07-17 18:32:38 +0300330 size += calc_plane_size(fb, plane);
Ville Syrjälä4d2598f2018-07-18 17:56:56 +0300331 }
332
333 return size;
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200334}
335
Tomeu Vizosoae649632016-11-10 10:25:24 +0100336/**
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100337 * igt_calc_fb_size:
338 * @fd: the DRM file descriptor
339 * @width: width of the framebuffer in pixels
340 * @height: height of the framebuffer in pixels
341 * @format: drm fourcc pixel format code
342 * @tiling: tiling layout of the framebuffer (as framebuffer modifier)
343 * @size_ret: returned size for the framebuffer
344 * @stride_ret: returned stride for the framebuffer
345 *
346 * This function returns valid stride and size values for a framebuffer with the
347 * specified parameters.
348 */
349void 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 +0300350 uint64_t *size_ret, unsigned *stride_ret)
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100351{
Ville Syrjälä22383612018-07-17 18:32:38 +0300352 struct igt_fb fb;
Ville Syrjälä4d2598f2018-07-18 17:56:56 +0300353
Ville Syrjälä22383612018-07-17 18:32:38 +0300354 fb_init(&fb, fd, width, height, drm_format, tiling,
355 IGT_COLOR_YCBCR_BT709, IGT_COLOR_YCBCR_LIMITED_RANGE);
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100356
Ville Syrjälä22383612018-07-17 18:32:38 +0300357 fb.size = calc_fb_size(&fb);
358
359 if (size_ret)
360 *size_ret = fb.size;
361 if (stride_ret)
362 *stride_ret = fb.strides[0];
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100363}
364
365/**
Tomeu Vizosoae649632016-11-10 10:25:24 +0100366 * igt_fb_mod_to_tiling:
367 * @modifier: DRM framebuffer modifier
368 *
369 * This function converts a DRM framebuffer modifier to its corresponding
370 * tiling constant.
371 *
372 * Returns:
373 * A tiling constant
374 */
375uint64_t igt_fb_mod_to_tiling(uint64_t modifier)
376{
377 switch (modifier) {
378 case LOCAL_DRM_FORMAT_MOD_NONE:
379 return I915_TILING_NONE;
380 case LOCAL_I915_FORMAT_MOD_X_TILED:
381 return I915_TILING_X;
382 case LOCAL_I915_FORMAT_MOD_Y_TILED:
383 return I915_TILING_Y;
384 case LOCAL_I915_FORMAT_MOD_Yf_TILED:
385 return I915_TILING_Yf;
386 default:
387 igt_assert(0);
388 }
389}
390
Praveen Paneri4437e212017-07-18 22:52:57 +0530391/**
392 * igt_fb_tiling_to_mod:
393 * @tiling: DRM framebuffer tiling
394 *
395 * This function converts a DRM framebuffer tiling to its corresponding
396 * modifier constant.
397 *
398 * Returns:
399 * A modifier constant
400 */
401uint64_t igt_fb_tiling_to_mod(uint64_t tiling)
402{
403 switch (tiling) {
404 case I915_TILING_NONE:
405 return LOCAL_DRM_FORMAT_MOD_NONE;
406 case I915_TILING_X:
407 return LOCAL_I915_FORMAT_MOD_X_TILED;
408 case I915_TILING_Y:
409 return LOCAL_I915_FORMAT_MOD_Y_TILED;
410 case I915_TILING_Yf:
411 return LOCAL_I915_FORMAT_MOD_Yf_TILED;
412 default:
413 igt_assert(0);
414 }
415}
416
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200417/* helpers to create nice-looking framebuffers */
Ville Syrjälä22383612018-07-17 18:32:38 +0300418static int create_bo_for_fb(struct igt_fb *fb)
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200419{
Ville Syrjälä22383612018-07-17 18:32:38 +0300420 int fd = fb->fd;
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200421
Ville Syrjälä22383612018-07-17 18:32:38 +0300422 if (fb->tiling || fb->size || fb->strides[0] || igt_format_is_yuv(fb->drm_format)) {
423 uint64_t size;
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100424
Ville Syrjälä22383612018-07-17 18:32:38 +0300425 size = calc_fb_size(fb);
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100426
Ville Syrjälä22383612018-07-17 18:32:38 +0300427 /* respect the size requested by the caller */
428 if (fb->size == 0)
429 fb->size = size;
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200430
Ville Syrjälä22383612018-07-17 18:32:38 +0300431 fb->is_dumb = false;
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200432
433 if (is_i915_device(fd)) {
Ville Syrjäläe867d652018-02-27 22:39:26 +0200434 void *ptr;
Ville Syrjälä22383612018-07-17 18:32:38 +0300435 bool full_range = fb->color_range == IGT_COLOR_YCBCR_FULL_RANGE;
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200436
Ville Syrjälä22383612018-07-17 18:32:38 +0300437 fb->gem_handle = gem_create(fd, fb->size);
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200438
Ville Syrjälä22383612018-07-17 18:32:38 +0300439 gem_set_tiling(fd, fb->gem_handle,
440 igt_fb_mod_to_tiling(fb->tiling),
441 fb->strides[0]);
442
443 gem_set_domain(fd, fb->gem_handle,
Ville Syrjälä3bd68522018-09-05 19:55:43 +0300444 I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
445
Chris Wilsond2805062016-08-18 13:56:18 +0100446 /* Ensure the framebuffer is preallocated */
Ville Syrjälä22383612018-07-17 18:32:38 +0300447 ptr = gem_mmap__gtt(fd, fb->gem_handle,
448 fb->size, PROT_READ | PROT_WRITE);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +0100449 igt_assert(*(uint32_t *)ptr == 0);
450
Ville Syrjälä22383612018-07-17 18:32:38 +0300451 switch (fb->drm_format) {
Ville Syrjäläe867d652018-02-27 22:39:26 +0200452 case DRM_FORMAT_NV12:
Ville Syrjälä22383612018-07-17 18:32:38 +0300453 memset(ptr + fb->offsets[0],
454 full_range ? 0x00 : 0x10,
455 fb->strides[0] * fb->plane_height[0]);
456 memset(ptr + fb->offsets[1],
457 0x80,
458 fb->strides[1] * fb->plane_height[1]);
Ville Syrjäläe867d652018-02-27 22:39:26 +0200459 break;
460 case DRM_FORMAT_YUYV:
461 case DRM_FORMAT_YVYU:
Ville Syrjälä22383612018-07-17 18:32:38 +0300462 wmemset(ptr + fb->offsets[0],
463 full_range ? 0x80008000 : 0x80108010,
464 fb->strides[0] * fb->plane_height[0] / sizeof(wchar_t));
Ville Syrjäläe867d652018-02-27 22:39:26 +0200465 break;
466 case DRM_FORMAT_UYVY:
467 case DRM_FORMAT_VYUY:
Ville Syrjälä22383612018-07-17 18:32:38 +0300468 wmemset(ptr + fb->offsets[0],
469 full_range ? 0x00800080 : 0x10801080,
470 fb->strides[0] * fb->plane_height[0] / sizeof(wchar_t));
Ville Syrjäläe867d652018-02-27 22:39:26 +0200471 break;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +0100472 }
Ville Syrjälä22383612018-07-17 18:32:38 +0300473 gem_munmap(ptr, fb->size);
Chris Wilsond2805062016-08-18 13:56:18 +0100474
Ville Syrjälä22383612018-07-17 18:32:38 +0300475 return fb->gem_handle;
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200476 } else {
477 bool driver_has_gem_api = false;
478
479 igt_require(driver_has_gem_api);
480 return -EINVAL;
481 }
482 } else {
Ville Syrjälä22383612018-07-17 18:32:38 +0300483 fb->is_dumb = true;
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200484
Ville Syrjälä22383612018-07-17 18:32:38 +0300485 fb->gem_handle = kmstest_dumb_create(fd, fb->width, fb->height,
486 fb->plane_bpp[0],
487 &fb->strides[0], &fb->size);
488
489 return fb->gem_handle;
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200490 }
491}
492
Tomeu Vizoso8a1a3862016-02-24 09:04:04 +0100493/**
494 * igt_create_bo_with_dimensions:
495 * @fd: open drm file descriptor
496 * @width: width of the buffer object in pixels
497 * @height: height of the buffer object in pixels
498 * @format: drm fourcc pixel format code
499 * @modifier: modifier corresponding to the tiling layout of the buffer object
500 * @stride: stride of the buffer object in bytes (0 for automatic stride)
501 * @size_ret: size of the buffer object as created by the kernel
502 * @stride_ret: stride of the buffer object as created by the kernel
503 * @is_dumb: whether the created buffer object is a dumb buffer or not
504 *
505 * This function allocates a gem buffer object matching the requested
506 * properties.
507 *
508 * Returns:
509 * The kms id of the created buffer object.
510 */
511int igt_create_bo_with_dimensions(int fd, int width, int height,
512 uint32_t format, uint64_t modifier,
Ville Syrjälä5f8a33a2018-09-06 16:34:15 +0300513 unsigned stride, uint64_t *size_ret,
Tomeu Vizoso8a1a3862016-02-24 09:04:04 +0100514 unsigned *stride_ret, bool *is_dumb)
515{
Ville Syrjälä22383612018-07-17 18:32:38 +0300516 struct igt_fb fb;
517
518 fb_init(&fb, fd, width, height, format, modifier,
519 IGT_COLOR_YCBCR_BT709, IGT_COLOR_YCBCR_LIMITED_RANGE);
520
521 for (int i = 0; i < fb.num_planes; i++)
522 fb.strides[i] = stride;
523
524 create_bo_for_fb(&fb);
525
526 if (size_ret)
527 *size_ret = fb.size;
528 if (stride_ret)
529 *stride_ret = fb.strides[0];
530 if (is_dumb)
531 *is_dumb = fb.is_dumb;
532
533 return fb.gem_handle;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100534}
535
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100536/**
537 * igt_paint_color:
538 * @cr: cairo drawing context
539 * @x: pixel x-coordination of the fill rectangle
540 * @y: pixel y-coordination of the fill rectangle
541 * @w: width of the fill rectangle
542 * @h: height of the fill rectangle
543 * @r: red value to use as fill color
Thomas Woodd01ebbd2015-06-29 16:47:14 +0100544 * @g: green value to use as fill color
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100545 * @b: blue value to use as fill color
546 *
547 * This functions draws a solid rectangle with the given color using the drawing
548 * context @cr.
549 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100550void igt_paint_color(cairo_t *cr, int x, int y, int w, int h,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100551 double r, double g, double b)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100552{
553 cairo_rectangle(cr, x, y, w, h);
554 cairo_set_source_rgb(cr, r, g, b);
555 cairo_fill(cr);
556}
557
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100558/**
559 * igt_paint_color_alpha:
560 * @cr: cairo drawing context
561 * @x: pixel x-coordination of the fill rectangle
562 * @y: pixel y-coordination of the fill rectangle
563 * @w: width of the fill rectangle
564 * @h: height of the fill rectangle
565 * @r: red value to use as fill color
Thomas Woodd01ebbd2015-06-29 16:47:14 +0100566 * @g: green value to use as fill color
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100567 * @b: blue value to use as fill color
568 * @a: alpha value to use as fill color
569 *
570 * This functions draws a rectangle with the given color and alpha values using
571 * the drawing context @cr.
572 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100573void igt_paint_color_alpha(cairo_t *cr, int x, int y, int w, int h,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100574 double r, double g, double b, double a)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100575{
576 cairo_rectangle(cr, x, y, w, h);
577 cairo_set_source_rgba(cr, r, g, b, a);
578 cairo_fill(cr);
579}
580
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100581/**
582 * igt_paint_color_gradient:
583 * @cr: cairo drawing context
584 * @x: pixel x-coordination of the fill rectangle
585 * @y: pixel y-coordination of the fill rectangle
586 * @w: width of the fill rectangle
587 * @h: height of the fill rectangle
588 * @r: red value to use as fill color
Thomas Woodd01ebbd2015-06-29 16:47:14 +0100589 * @g: green value to use as fill color
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100590 * @b: blue value to use as fill color
591 *
592 * This functions draws a gradient into the rectangle which fades in from black
593 * to the given values using the drawing context @cr.
594 */
Daniel Vetter57d7db82014-03-26 09:06:11 +0100595void
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100596igt_paint_color_gradient(cairo_t *cr, int x, int y, int w, int h,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100597 int r, int g, int b)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100598{
599 cairo_pattern_t *pat;
600
601 pat = cairo_pattern_create_linear(x, y, x + w, y + h);
602 cairo_pattern_add_color_stop_rgba(pat, 1, 0, 0, 0, 1);
603 cairo_pattern_add_color_stop_rgba(pat, 0, r, g, b, 1);
604
605 cairo_rectangle(cr, x, y, w, h);
606 cairo_set_source(cr, pat);
607 cairo_fill(cr);
608 cairo_pattern_destroy(pat);
609}
610
Lionel Landwerlina5113102016-03-18 17:33:02 +0000611/**
612 * igt_paint_color_gradient_range:
613 * @cr: cairo drawing context
614 * @x: pixel x-coordination of the fill rectangle
615 * @y: pixel y-coordination of the fill rectangle
616 * @w: width of the fill rectangle
617 * @h: height of the fill rectangle
618 * @sr: red value to use as start gradient color
619 * @sg: green value to use as start gradient color
620 * @sb: blue value to use as start gradient color
621 * @er: red value to use as end gradient color
622 * @eg: green value to use as end gradient color
623 * @eb: blue value to use as end gradient color
624 *
625 * This functions draws a gradient into the rectangle which fades in
626 * from one color to the other using the drawing context @cr.
627 */
628void
629igt_paint_color_gradient_range(cairo_t *cr, int x, int y, int w, int h,
630 double sr, double sg, double sb,
631 double er, double eg, double eb)
632{
633 cairo_pattern_t *pat;
634
635 pat = cairo_pattern_create_linear(x, y, x + w, y + h);
636 cairo_pattern_add_color_stop_rgba(pat, 1, sr, sg, sb, 1);
637 cairo_pattern_add_color_stop_rgba(pat, 0, er, eg, eb, 1);
638
639 cairo_rectangle(cr, x, y, w, h);
640 cairo_set_source(cr, pat);
641 cairo_fill(cr);
642 cairo_pattern_destroy(pat);
643}
644
Daniel Vetter57d7db82014-03-26 09:06:11 +0100645static void
646paint_test_patterns(cairo_t *cr, int width, int height)
647{
648 double gr_height, gr_width;
649 int x, y;
650
651 y = height * 0.10;
652 gr_width = width * 0.75;
653 gr_height = height * 0.08;
654 x = (width / 2) - (gr_width / 2);
655
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100656 igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 1, 0, 0);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100657
658 y += gr_height;
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100659 igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 0, 1, 0);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100660
661 y += gr_height;
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100662 igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 0, 0, 1);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100663
664 y += gr_height;
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100665 igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 1, 1, 1);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100666}
667
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100668/**
669 * igt_cairo_printf_line:
670 * @cr: cairo drawing context
671 * @align: text alignment
672 * @yspacing: additional y-direction feed after this line
673 * @fmt: format string
674 * @...: optional arguments used in the format string
675 *
676 * This is a little helper to draw text onto framebuffers. All the initial setup
677 * (like setting the font size and the moving to the starting position) still
678 * needs to be done manually with explicit cairo calls on @cr.
679 *
680 * Returns:
681 * The width of the drawn text.
682 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100683int igt_cairo_printf_line(cairo_t *cr, enum igt_text_align align,
Daniel Vetter57d7db82014-03-26 09:06:11 +0100684 double yspacing, const char *fmt, ...)
685{
686 double x, y, xofs, yofs;
687 cairo_text_extents_t extents;
688 char *text;
689 va_list ap;
690 int ret;
691
692 va_start(ap, fmt);
693 ret = vasprintf(&text, fmt, ap);
694 igt_assert(ret >= 0);
695 va_end(ap);
696
697 cairo_text_extents(cr, text, &extents);
698
699 xofs = yofs = 0;
700 if (align & align_right)
701 xofs = -extents.width;
702 else if (align & align_hcenter)
703 xofs = -extents.width / 2;
704
705 if (align & align_top)
706 yofs = extents.height;
707 else if (align & align_vcenter)
708 yofs = extents.height / 2;
709
710 cairo_get_current_point(cr, &x, &y);
711 if (xofs || yofs)
712 cairo_rel_move_to(cr, xofs, yofs);
713
714 cairo_text_path(cr, text);
715 cairo_set_source_rgb(cr, 0, 0, 0);
716 cairo_stroke_preserve(cr);
717 cairo_set_source_rgb(cr, 1, 1, 1);
718 cairo_fill(cr);
719
720 cairo_move_to(cr, x, y + extents.height + yspacing);
721
722 free(text);
723
724 return extents.width;
725}
726
727static void
728paint_marker(cairo_t *cr, int x, int y)
729{
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100730 enum igt_text_align align;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100731 int xoff, yoff;
732
733 cairo_move_to(cr, x, y - 20);
734 cairo_line_to(cr, x, y + 20);
735 cairo_move_to(cr, x - 20, y);
736 cairo_line_to(cr, x + 20, y);
737 cairo_new_sub_path(cr);
738 cairo_arc(cr, x, y, 10, 0, M_PI * 2);
739 cairo_set_line_width(cr, 4);
740 cairo_set_source_rgb(cr, 0, 0, 0);
741 cairo_stroke_preserve(cr);
742 cairo_set_source_rgb(cr, 1, 1, 1);
743 cairo_set_line_width(cr, 2);
744 cairo_stroke(cr);
745
746 xoff = x ? -20 : 20;
747 align = x ? align_right : align_left;
748
749 yoff = y ? -20 : 20;
750 align |= y ? align_bottom : align_top;
751
752 cairo_move_to(cr, x + xoff, y + yoff);
753 cairo_set_font_size(cr, 18);
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100754 igt_cairo_printf_line(cr, align, 0, "(%d, %d)", x, y);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100755}
756
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100757/**
758 * igt_paint_test_pattern:
759 * @cr: cairo drawing context
760 * @width: width of the visible area
761 * @height: height of the visible area
762 *
763 * This functions draws an entire set of test patterns for the given visible
764 * area using the drawing context @cr. This is useful for manual visual
765 * inspection of displayed framebuffers.
766 *
767 * The test patterns include
768 * - corner markers to check for over/underscan and
769 * - a set of color and b/w gradients.
770 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100771void igt_paint_test_pattern(cairo_t *cr, int width, int height)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100772{
773 paint_test_patterns(cr, width, height);
774
775 cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
776
777 /* Paint corner markers */
778 paint_marker(cr, 0, 0);
779 paint_marker(cr, width, 0);
780 paint_marker(cr, 0, height);
781 paint_marker(cr, width, height);
782
783 igt_assert(!cairo_status(cr));
784}
785
Thomas Woodecb03262015-04-13 17:37:22 +0100786static cairo_status_t
787stdio_read_func(void *closure, unsigned char* data, unsigned int size)
788{
789 if (fread(data, 1, size, (FILE*)closure) != size)
790 return CAIRO_STATUS_READ_ERROR;
791
792 return CAIRO_STATUS_SUCCESS;
793}
794
Ville Syrjälä75f320c2017-09-21 15:39:23 +0300795cairo_surface_t *igt_cairo_image_surface_create_from_png(const char *filename)
796{
797 cairo_surface_t *image;
798 FILE *f;
799
800 f = igt_fopen_data(filename);
801 image = cairo_image_surface_create_from_png_stream(&stdio_read_func, f);
802 fclose(f);
803
804 return image;
805}
806
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100807/**
808 * igt_paint_image:
809 * @cr: cairo drawing context
810 * @filename: filename of the png image to draw
811 * @dst_x: pixel x-coordination of the destination rectangle
812 * @dst_y: pixel y-coordination of the destination rectangle
813 * @dst_width: width of the destination rectangle
814 * @dst_height: height of the destination rectangle
815 *
Thomas Woodecb03262015-04-13 17:37:22 +0100816 * This function can be used to draw a scaled version of the supplied png image,
817 * which is loaded from the package data directory.
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100818 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100819void igt_paint_image(cairo_t *cr, const char *filename,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100820 int dst_x, int dst_y, int dst_width, int dst_height)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100821{
822 cairo_surface_t *image;
823 int img_width, img_height;
824 double scale_x, scale_y;
825
Ville Syrjälä75f320c2017-09-21 15:39:23 +0300826 image = igt_cairo_image_surface_create_from_png(filename);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100827 igt_assert(cairo_surface_status(image) == CAIRO_STATUS_SUCCESS);
828
829 img_width = cairo_image_surface_get_width(image);
830 img_height = cairo_image_surface_get_height(image);
831
832 scale_x = (double)dst_width / img_width;
833 scale_y = (double)dst_height / img_height;
834
835 cairo_save(cr);
836
837 cairo_translate(cr, dst_x, dst_y);
838 cairo_scale(cr, scale_x, scale_y);
839 cairo_set_source_surface(cr, image, 0, 0);
840 cairo_paint(cr);
841
842 cairo_surface_destroy(image);
843
844 cairo_restore(cr);
845}
846
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100847/**
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100848 * igt_create_fb_with_bo_size:
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100849 * @fd: open i915 drm file descriptor
850 * @width: width of the framebuffer in pixel
851 * @height: height of the framebuffer in pixel
852 * @format: drm fourcc pixel format code
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000853 * @tiling: tiling layout of the framebuffer (as framebuffer modifier)
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100854 * @fb: pointer to an #igt_fb structure
Paulo Zanonicb7dd5d2015-11-05 16:18:55 -0200855 * @bo_size: size of the backing bo (0 for automatic size)
Paulo Zanonid6341372015-11-05 16:39:00 -0200856 * @bo_stride: stride of the backing bo (0 for automatic stride)
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100857 *
858 * This function allocates a gem buffer object suitable to back a framebuffer
859 * with the requested properties and then wraps it up in a drm framebuffer
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100860 * object of the requested size. All metadata is stored in @fb.
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100861 *
862 * The backing storage of the framebuffer is filled with all zeros, i.e. black
863 * for rgb pixel formats.
864 *
865 * Returns:
Damien Lespiau50166d22014-08-19 11:55:22 +0100866 * The kms id of the created framebuffer.
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100867 */
Damien Lespiau378e61e2014-06-23 14:53:24 +0100868unsigned int
869igt_create_fb_with_bo_size(int fd, int width, int height,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000870 uint32_t format, uint64_t tiling,
Ville Syrjälä5f8a33a2018-09-06 16:34:15 +0300871 struct igt_fb *fb, uint64_t bo_size,
Paulo Zanonid6341372015-11-05 16:39:00 -0200872 unsigned bo_stride)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100873{
Ville Syrjäläb6975342018-03-06 20:01:22 +0200874 /* FIXME allow the caller to pass these in */
875 enum igt_color_encoding color_encoding = IGT_COLOR_YCBCR_BT709;
876 enum igt_color_range color_range = IGT_COLOR_YCBCR_LIMITED_RANGE;
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100877
Ville Syrjälä22383612018-07-17 18:32:38 +0300878 fb_init(fb, fd, width, height, format, tiling,
879 color_encoding, color_range);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100880
Ville Syrjälä22383612018-07-17 18:32:38 +0300881 for (int i = 0; i < fb->num_planes; i++)
882 fb->strides[i] = bo_stride;
883
884 fb->size = bo_size;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100885
Ville Syrjälä5f8a33a2018-09-06 16:34:15 +0300886 igt_debug("%s(width=%d, height=%d, format=0x%x, tiling=0x%"PRIx64", size=%"PRIu64")\n",
Tomeu Vizoso8a1a3862016-02-24 09:04:04 +0100887 __func__, width, height, format, tiling, bo_size);
Ville Syrjälä22383612018-07-17 18:32:38 +0300888
889 create_bo_for_fb(fb);
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200890 igt_assert(fb->gem_handle > 0);
Chris Wilsondb4cc742014-09-06 12:07:49 +0100891
Chris Wilsondb4cc742014-09-06 12:07:49 +0100892 igt_debug("%s(handle=%d, pitch=%d)\n",
Ville Syrjälä22383612018-07-17 18:32:38 +0300893 __func__, fb->gem_handle, fb->strides[0]);
Tvrtko Ursulineb93c1b2015-03-03 14:11:03 +0000894
Ville Syrjälä22383612018-07-17 18:32:38 +0300895 do_or_die(__kms_addfb(fb->fd, fb->gem_handle,
896 fb->width, fb->height,
897 fb->drm_format, fb->tiling,
898 fb->strides, fb->offsets, fb->num_planes,
899 LOCAL_DRM_MODE_FB_MODIFIERS,
900 &fb->fb_id));
Ville Syrjälä42359ed2018-07-17 18:50:13 +0300901
Ville Syrjälä22383612018-07-17 18:32:38 +0300902 return fb->fb_id;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100903}
904
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100905/**
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100906 * igt_create_fb:
907 * @fd: open i915 drm file descriptor
908 * @width: width of the framebuffer in pixel
909 * @height: height of the framebuffer in pixel
910 * @format: drm fourcc pixel format code
Damien Lespiau378e61e2014-06-23 14:53:24 +0100911 * @tiling: tiling layout of the framebuffer
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100912 * @fb: pointer to an #igt_fb structure
913 *
914 * This function allocates a gem buffer object suitable to back a framebuffer
915 * with the requested properties and then wraps it up in a drm framebuffer
916 * object. All metadata is stored in @fb.
917 *
918 * The backing storage of the framebuffer is filled with all zeros, i.e. black
919 * for rgb pixel formats.
920 *
921 * Returns:
Damien Lespiau50166d22014-08-19 11:55:22 +0100922 * The kms id of the created framebuffer.
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100923 */
924unsigned int igt_create_fb(int fd, int width, int height, uint32_t format,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000925 uint64_t tiling, struct igt_fb *fb)
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100926{
Paulo Zanonid6341372015-11-05 16:39:00 -0200927 return igt_create_fb_with_bo_size(fd, width, height, format, tiling, fb,
928 0, 0);
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100929}
930
931/**
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100932 * igt_create_color_fb:
933 * @fd: open i915 drm file descriptor
934 * @width: width of the framebuffer in pixel
935 * @height: height of the framebuffer in pixel
936 * @format: drm fourcc pixel format code
Damien Lespiau378e61e2014-06-23 14:53:24 +0100937 * @tiling: tiling layout of the framebuffer
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100938 * @r: red value to use as fill color
Ville Syrjälä5b113d32015-12-17 01:39:31 +0200939 * @g: green value to use as fill color
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100940 * @b: blue value to use as fill color
941 * @fb: pointer to an #igt_fb structure
942 *
943 * This function allocates a gem buffer object suitable to back a framebuffer
944 * with the requested properties and then wraps it up in a drm framebuffer
945 * object. All metadata is stored in @fb.
946 *
947 * Compared to igt_create_fb() this function also fills the entire framebuffer
948 * with the given color, which is useful for some simple pipe crc based tests.
949 *
950 * Returns:
951 * The kms id of the created framebuffer on success or a negative error code on
952 * failure.
953 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100954unsigned int igt_create_color_fb(int fd, int width, int height,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000955 uint32_t format, uint64_t tiling,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100956 double r, double g, double b,
957 struct igt_fb *fb /* out */)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100958{
959 unsigned int fb_id;
960 cairo_t *cr;
961
Damien Lespiau378e61e2014-06-23 14:53:24 +0100962 fb_id = igt_create_fb(fd, width, height, format, tiling, fb);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100963 igt_assert(fb_id);
964
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100965 cr = igt_get_cairo_ctx(fd, fb);
966 igt_paint_color(cr, 0, 0, width, height, r, g, b);
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +0100967 igt_put_cairo_ctx(fd, fb, cr);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100968
969 return fb_id;
970}
971
Ville Syrjälä5b113d32015-12-17 01:39:31 +0200972/**
973 * igt_create_pattern_fb:
974 * @fd: open i915 drm file descriptor
975 * @width: width of the framebuffer in pixel
976 * @height: height of the framebuffer in pixel
977 * @format: drm fourcc pixel format code
978 * @tiling: tiling layout of the framebuffer
979 * @fb: pointer to an #igt_fb structure
980 *
981 * This function allocates a gem buffer object suitable to back a framebuffer
982 * with the requested properties and then wraps it up in a drm framebuffer
983 * object. All metadata is stored in @fb.
984 *
985 * Compared to igt_create_fb() this function also draws the standard test pattern
986 * into the framebuffer.
987 *
988 * Returns:
989 * The kms id of the created framebuffer on success or a negative error code on
990 * failure.
991 */
992unsigned int igt_create_pattern_fb(int fd, int width, int height,
993 uint32_t format, uint64_t tiling,
994 struct igt_fb *fb /* out */)
995{
996 unsigned int fb_id;
997 cairo_t *cr;
998
999 fb_id = igt_create_fb(fd, width, height, format, tiling, fb);
1000 igt_assert(fb_id);
1001
1002 cr = igt_get_cairo_ctx(fd, fb);
1003 igt_paint_test_pattern(cr, width, height);
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +01001004 igt_put_cairo_ctx(fd, fb, cr);
Ville Syrjälä5b113d32015-12-17 01:39:31 +02001005
1006 return fb_id;
1007}
1008
1009/**
1010 * igt_create_color_pattern_fb:
1011 * @fd: open i915 drm file descriptor
1012 * @width: width of the framebuffer in pixel
1013 * @height: height of the framebuffer in pixel
1014 * @format: drm fourcc pixel format code
1015 * @tiling: tiling layout of the framebuffer
1016 * @r: red value to use as fill color
1017 * @g: green value to use as fill color
1018 * @b: blue value to use as fill color
1019 * @fb: pointer to an #igt_fb structure
1020 *
1021 * This function allocates a gem buffer object suitable to back a framebuffer
1022 * with the requested properties and then wraps it up in a drm framebuffer
1023 * object. All metadata is stored in @fb.
1024 *
1025 * Compared to igt_create_fb() this function also fills the entire framebuffer
1026 * with the given color, and then draws the standard test pattern into the
1027 * framebuffer.
1028 *
1029 * Returns:
1030 * The kms id of the created framebuffer on success or a negative error code on
1031 * failure.
1032 */
1033unsigned int igt_create_color_pattern_fb(int fd, int width, int height,
1034 uint32_t format, uint64_t tiling,
1035 double r, double g, double b,
1036 struct igt_fb *fb /* out */)
1037{
1038 unsigned int fb_id;
1039 cairo_t *cr;
1040
1041 fb_id = igt_create_fb(fd, width, height, format, tiling, fb);
1042 igt_assert(fb_id);
1043
1044 cr = igt_get_cairo_ctx(fd, fb);
1045 igt_paint_color(cr, 0, 0, width, height, r, g, b);
1046 igt_paint_test_pattern(cr, width, height);
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +01001047 igt_put_cairo_ctx(fd, fb, cr);
Ville Syrjälä5b113d32015-12-17 01:39:31 +02001048
1049 return fb_id;
1050}
1051
1052/**
1053 * igt_create_image_fb:
1054 * @drm_fd: open i915 drm file descriptor
1055 * @width: width of the framebuffer in pixel or 0
1056 * @height: height of the framebuffer in pixel or 0
1057 * @format: drm fourcc pixel format code
1058 * @tiling: tiling layout of the framebuffer
1059 * @filename: filename of the png image to draw
1060 * @fb: pointer to an #igt_fb structure
1061 *
1062 * Create a framebuffer with the specified image. If @width is zero the
1063 * image width will be used. If @height is zero the image height will be used.
1064 *
1065 * Returns:
1066 * The kms id of the created framebuffer on success or a negative error code on
1067 * failure.
1068 */
1069unsigned int igt_create_image_fb(int fd, int width, int height,
1070 uint32_t format, uint64_t tiling,
1071 const char *filename,
1072 struct igt_fb *fb /* out */)
1073{
1074 cairo_surface_t *image;
1075 uint32_t fb_id;
1076 cairo_t *cr;
1077
Ville Syrjälä75f320c2017-09-21 15:39:23 +03001078 image = igt_cairo_image_surface_create_from_png(filename);
Ville Syrjälä5b113d32015-12-17 01:39:31 +02001079 igt_assert(cairo_surface_status(image) == CAIRO_STATUS_SUCCESS);
1080 if (width == 0)
1081 width = cairo_image_surface_get_width(image);
1082 if (height == 0)
1083 height = cairo_image_surface_get_height(image);
1084 cairo_surface_destroy(image);
1085
1086 fb_id = igt_create_fb(fd, width, height, format, tiling, fb);
1087
1088 cr = igt_get_cairo_ctx(fd, fb);
1089 igt_paint_image(cr, filename, 0, 0, width, height);
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +01001090 igt_put_cairo_ctx(fd, fb, cr);
Ville Syrjälä5b113d32015-12-17 01:39:31 +02001091
1092 return fb_id;
1093}
1094
Thomas Wood4cb19462014-08-04 16:14:51 +01001095struct box {
1096 int x, y, width, height;
1097};
1098
1099struct stereo_fb_layout {
1100 int fb_width, fb_height;
1101 struct box left, right;
1102};
1103
1104static void box_init(struct box *box, int x, int y, int bwidth, int bheight)
1105{
1106 box->x = x;
1107 box->y = y;
1108 box->width = bwidth;
1109 box->height = bheight;
1110}
1111
1112
1113static void stereo_fb_layout_from_mode(struct stereo_fb_layout *layout,
1114 drmModeModeInfo *mode)
1115{
1116 unsigned int format = mode->flags & DRM_MODE_FLAG_3D_MASK;
1117 const int hdisplay = mode->hdisplay, vdisplay = mode->vdisplay;
1118 int middle;
1119
1120 switch (format) {
1121 case DRM_MODE_FLAG_3D_TOP_AND_BOTTOM:
1122 layout->fb_width = hdisplay;
1123 layout->fb_height = vdisplay;
1124
1125 middle = vdisplay / 2;
1126 box_init(&layout->left, 0, 0, hdisplay, middle);
1127 box_init(&layout->right,
1128 0, middle, hdisplay, vdisplay - middle);
1129 break;
1130 case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF:
1131 layout->fb_width = hdisplay;
1132 layout->fb_height = vdisplay;
1133
1134 middle = hdisplay / 2;
1135 box_init(&layout->left, 0, 0, middle, vdisplay);
1136 box_init(&layout->right,
1137 middle, 0, hdisplay - middle, vdisplay);
1138 break;
1139 case DRM_MODE_FLAG_3D_FRAME_PACKING:
1140 {
1141 int vactive_space = mode->vtotal - vdisplay;
1142
1143 layout->fb_width = hdisplay;
1144 layout->fb_height = 2 * vdisplay + vactive_space;
1145
1146 box_init(&layout->left,
1147 0, 0, hdisplay, vdisplay);
1148 box_init(&layout->right,
1149 0, vdisplay + vactive_space, hdisplay, vdisplay);
1150 break;
1151 }
1152 default:
1153 igt_assert(0);
1154 }
1155}
1156
1157/**
1158 * igt_create_stereo_fb:
1159 * @drm_fd: open i915 drm file descriptor
1160 * @mode: A stereo 3D mode.
1161 * @format: drm fourcc pixel format code
1162 * @tiling: tiling layout of the framebuffer
1163 *
1164 * Create a framebuffer for use with the stereo 3D mode specified by @mode.
1165 *
1166 * Returns:
1167 * The kms id of the created framebuffer on success or a negative error code on
1168 * failure.
1169 */
1170unsigned int igt_create_stereo_fb(int drm_fd, drmModeModeInfo *mode,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +00001171 uint32_t format, uint64_t tiling)
Thomas Wood4cb19462014-08-04 16:14:51 +01001172{
1173 struct stereo_fb_layout layout;
1174 cairo_t *cr;
1175 uint32_t fb_id;
1176 struct igt_fb fb;
1177
1178 stereo_fb_layout_from_mode(&layout, mode);
1179 fb_id = igt_create_fb(drm_fd, layout.fb_width, layout.fb_height, format,
1180 tiling, &fb);
1181 cr = igt_get_cairo_ctx(drm_fd, &fb);
1182
Thomas Woodecb03262015-04-13 17:37:22 +01001183 igt_paint_image(cr, "1080p-left.png",
Thomas Wood4cb19462014-08-04 16:14:51 +01001184 layout.left.x, layout.left.y,
1185 layout.left.width, layout.left.height);
Thomas Woodecb03262015-04-13 17:37:22 +01001186 igt_paint_image(cr, "1080p-right.png",
Thomas Wood4cb19462014-08-04 16:14:51 +01001187 layout.right.x, layout.right.y,
1188 layout.right.width, layout.right.height);
1189
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +01001190 igt_put_cairo_ctx(drm_fd, &fb, cr);
Thomas Wood4cb19462014-08-04 16:14:51 +01001191
1192 return fb_id;
1193}
1194
Daniel Vetter57d7db82014-03-26 09:06:11 +01001195static cairo_format_t drm_format_to_cairo(uint32_t drm_format)
1196{
Ville Syrjäläef43fce2018-07-18 20:26:22 +03001197 const struct format_desc_struct *f;
Daniel Vetter57d7db82014-03-26 09:06:11 +01001198
1199 for_each_format(f)
1200 if (f->drm_id == drm_format)
1201 return f->cairo_id;
1202
Damien Lespiau54397ca2014-08-19 11:40:07 +01001203 igt_assert_f(0, "can't find a cairo format for %08x (%s)\n",
1204 drm_format, igt_format_str(drm_format));
Daniel Vetter57d7db82014-03-26 09:06:11 +01001205}
1206
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001207struct fb_blit_linear {
Ville Syrjälä22383612018-07-17 18:32:38 +03001208 struct igt_fb fb;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001209 uint8_t *map;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001210};
1211
Damien Lespiauff451a62015-03-03 14:11:04 +00001212struct fb_blit_upload {
1213 int fd;
1214 struct igt_fb *fb;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001215 struct fb_blit_linear linear;
Damien Lespiauff451a62015-03-03 14:11:04 +00001216};
1217
Ville Syrjälä6f5d6b02018-07-18 20:11:52 +03001218static void blitcopy(const struct igt_fb *dst_fb,
1219 const struct igt_fb *src_fb)
1220{
1221 igt_assert_eq(dst_fb->fd, src_fb->fd);
1222 igt_assert_eq(dst_fb->num_planes, src_fb->num_planes);
1223
1224 for (int i = 0; i < dst_fb->num_planes; i++) {
1225 igt_assert_eq(dst_fb->plane_bpp[i], src_fb->plane_bpp[i]);
1226 igt_assert_eq(dst_fb->plane_width[i], src_fb->plane_width[i]);
1227 igt_assert_eq(dst_fb->plane_height[i], src_fb->plane_height[i]);
1228
1229 igt_blitter_fast_copy__raw(dst_fb->fd,
1230 src_fb->gem_handle,
1231 src_fb->offsets[i],
1232 src_fb->strides[i],
1233 igt_fb_mod_to_tiling(src_fb->tiling),
1234 0, 0, /* src_x, src_y */
1235 dst_fb->plane_width[i], dst_fb->plane_height[i],
1236 dst_fb->plane_bpp[i],
1237 dst_fb->gem_handle,
1238 dst_fb->offsets[i],
1239 dst_fb->strides[i],
1240 igt_fb_mod_to_tiling(dst_fb->tiling),
1241 0, 0 /* dst_x, dst_y */);
1242 }
1243}
1244
Ville Syrjälä74261fd2018-07-17 16:20:34 +03001245static void free_linear_mapping(struct fb_blit_upload *blit)
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001246{
Ville Syrjälä74261fd2018-07-17 16:20:34 +03001247 int fd = blit->fd;
1248 struct igt_fb *fb = blit->fb;
1249 struct fb_blit_linear *linear = &blit->linear;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001250
Ville Syrjälä22383612018-07-17 18:32:38 +03001251 gem_munmap(linear->map, linear->fb.size);
1252 gem_set_domain(fd, linear->fb.gem_handle,
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001253 I915_GEM_DOMAIN_GTT, 0);
1254
Ville Syrjälä6f5d6b02018-07-18 20:11:52 +03001255 blitcopy(fb, &linear->fb);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001256
Ville Syrjälä22383612018-07-17 18:32:38 +03001257 gem_sync(fd, linear->fb.gem_handle);
1258 gem_close(fd, linear->fb.gem_handle);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001259}
1260
Damien Lespiauff451a62015-03-03 14:11:04 +00001261static void destroy_cairo_surface__blit(void *arg)
1262{
1263 struct fb_blit_upload *blit = arg;
Damien Lespiauff451a62015-03-03 14:11:04 +00001264
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001265 blit->fb->cairo_surface = NULL;
Damien Lespiauff451a62015-03-03 14:11:04 +00001266
Ville Syrjälä74261fd2018-07-17 16:20:34 +03001267 free_linear_mapping(blit);
Damien Lespiauff451a62015-03-03 14:11:04 +00001268
1269 free(blit);
1270}
1271
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001272static void setup_linear_mapping(int fd, struct igt_fb *fb, struct fb_blit_linear *linear)
Damien Lespiauff451a62015-03-03 14:11:04 +00001273{
Damien Lespiauff451a62015-03-03 14:11:04 +00001274 /*
1275 * We create a linear BO that we'll map for the CPU to write to (using
1276 * cairo). This linear bo will be then blitted to its final
1277 * destination, tiling it at the same time.
1278 */
Damien Lespiauff451a62015-03-03 14:11:04 +00001279
Ville Syrjälä22383612018-07-17 18:32:38 +03001280 fb_init(&linear->fb, fb->fd, fb->width, fb->height,
1281 fb->drm_format, LOCAL_DRM_FORMAT_MOD_NONE,
1282 fb->color_encoding, fb->color_range);
1283
1284 create_bo_for_fb(&linear->fb);
1285
1286 igt_assert(linear->fb.gem_handle > 0);
Tvrtko Ursulin30a13602015-04-29 13:24:34 +01001287
1288 /* Copy fb content to linear BO */
Ville Syrjälä22383612018-07-17 18:32:38 +03001289 gem_set_domain(fd, linear->fb.gem_handle,
Tvrtko Ursulin30a13602015-04-29 13:24:34 +01001290 I915_GEM_DOMAIN_GTT, 0);
1291
Ville Syrjälä6f5d6b02018-07-18 20:11:52 +03001292 blitcopy(&linear->fb, fb);
Tvrtko Ursulin30a13602015-04-29 13:24:34 +01001293
Ville Syrjälä22383612018-07-17 18:32:38 +03001294 gem_sync(fd, linear->fb.gem_handle);
Tvrtko Ursulin30a13602015-04-29 13:24:34 +01001295
Ville Syrjälä22383612018-07-17 18:32:38 +03001296 gem_set_domain(fd, linear->fb.gem_handle,
Tvrtko Ursulin30a13602015-04-29 13:24:34 +01001297 I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
1298
1299 /* Setup cairo context */
Ville Syrjälä22383612018-07-17 18:32:38 +03001300 linear->map = gem_mmap__cpu(fd, linear->fb.gem_handle,
1301 0, linear->fb.size, PROT_READ | PROT_WRITE);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001302}
1303
1304static void create_cairo_surface__blit(int fd, struct igt_fb *fb)
1305{
1306 struct fb_blit_upload *blit;
1307 cairo_format_t cairo_format;
1308
1309 blit = malloc(sizeof(*blit));
1310 igt_assert(blit);
1311
1312 blit->fd = fd;
1313 blit->fb = fb;
1314 setup_linear_mapping(fd, fb, &blit->linear);
Damien Lespiauff451a62015-03-03 14:11:04 +00001315
Damien Lespiauff451a62015-03-03 14:11:04 +00001316 cairo_format = drm_format_to_cairo(fb->drm_format);
1317 fb->cairo_surface =
1318 cairo_image_surface_create_for_data(blit->linear.map,
1319 cairo_format,
1320 fb->width, fb->height,
Ville Syrjälä22383612018-07-17 18:32:38 +03001321 blit->linear.fb.strides[0]);
Chris Wilson18d0b1e2016-03-02 14:12:12 +00001322 fb->domain = I915_GEM_DOMAIN_GTT;
Damien Lespiauff451a62015-03-03 14:11:04 +00001323
1324 cairo_surface_set_user_data(fb->cairo_surface,
1325 (cairo_user_data_key_t *)create_cairo_surface__blit,
1326 blit, destroy_cairo_surface__blit);
1327}
1328
Tomeu Vizosoa2d5b342016-03-07 16:25:43 +01001329/**
1330 * igt_dirty_fb:
1331 * @fd: open drm file descriptor
1332 * @fb: pointer to an #igt_fb structure
1333 *
1334 * Flushes out the whole framebuffer.
1335 *
1336 * Returns: 0 upon success.
1337 */
1338int igt_dirty_fb(int fd, struct igt_fb *fb)
1339{
1340 return drmModeDirtyFB(fb->fd, fb->fb_id, NULL, 0);
1341}
1342
Maxime Ripard3415b192018-10-04 14:38:54 +02001343static void unmap_bo(struct igt_fb *fb, void *ptr)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001344{
Maxime Ripard3415b192018-10-04 14:38:54 +02001345 gem_munmap(ptr, fb->size);
Tomeu Vizoso89b3ffe2016-02-24 09:04:41 +01001346
1347 if (fb->is_dumb)
1348 igt_dirty_fb(fb->fd, fb);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001349}
1350
Maxime Ripard3415b192018-10-04 14:38:54 +02001351static void destroy_cairo_surface__gtt(void *arg)
1352{
1353 struct igt_fb *fb = arg;
1354
1355 unmap_bo(fb, cairo_image_surface_get_data(fb->cairo_surface));
1356 fb->cairo_surface = NULL;
1357}
1358
1359static void *map_bo(int fd, struct igt_fb *fb)
Damien Lespiau4aadbc82014-06-23 16:41:43 +01001360{
Tomeu Vizoso89b3ffe2016-02-24 09:04:41 +01001361 void *ptr;
1362
Maxime Ripard80bb4432018-10-04 14:38:55 +02001363 if (is_i915_device(fd))
1364 gem_set_domain(fd, fb->gem_handle,
1365 I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
Ville Syrjälä3bd68522018-09-05 19:55:43 +03001366
Tomeu Vizoso89b3ffe2016-02-24 09:04:41 +01001367 if (fb->is_dumb)
1368 ptr = kmstest_dumb_map_buffer(fd, fb->gem_handle, fb->size,
1369 PROT_READ | PROT_WRITE);
1370 else
1371 ptr = gem_mmap__gtt(fd, fb->gem_handle, fb->size,
1372 PROT_READ | PROT_WRITE);
Ville Syrjälä106fe212015-10-09 18:36:24 +03001373
Maxime Ripard3415b192018-10-04 14:38:54 +02001374 return ptr;
1375}
1376
1377static void create_cairo_surface__gtt(int fd, struct igt_fb *fb)
1378{
1379 void *ptr = map_bo(fd, fb);
1380
Damien Lespiau4aadbc82014-06-23 16:41:43 +01001381 fb->cairo_surface =
Ville Syrjälä106fe212015-10-09 18:36:24 +03001382 cairo_image_surface_create_for_data(ptr,
Damien Lespiau4aadbc82014-06-23 16:41:43 +01001383 drm_format_to_cairo(fb->drm_format),
Ville Syrjälä22383612018-07-17 18:32:38 +03001384 fb->width, fb->height, fb->strides[0]);
Chris Wilson18d0b1e2016-03-02 14:12:12 +00001385 fb->domain = I915_GEM_DOMAIN_GTT;
Damien Lespiau4aadbc82014-06-23 16:41:43 +01001386
1387 cairo_surface_set_user_data(fb->cairo_surface,
1388 (cairo_user_data_key_t *)create_cairo_surface__gtt,
1389 fb, destroy_cairo_surface__gtt);
1390}
1391
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001392struct fb_convert_blit_upload {
Ville Syrjälä3ed2a602018-07-17 16:15:34 +03001393 struct fb_blit_upload base;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001394
Maxime Ripardc7128362018-10-04 14:38:57 +02001395 struct igt_fb shadow_fb;
1396 uint8_t *shadow_ptr;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001397};
1398
Maxime Ripardc7128362018-10-04 14:38:57 +02001399static void *igt_fb_create_cairo_shadow_buffer(int fd,
1400 unsigned int width,
1401 unsigned int height,
1402 struct igt_fb *shadow)
1403{
1404 void *ptr;
1405
1406 igt_assert(shadow);
1407
1408 fb_init(shadow, fd, width, height,
1409 DRM_FORMAT_RGB888, LOCAL_DRM_FORMAT_MOD_NONE,
1410 IGT_COLOR_YCBCR_BT709, IGT_COLOR_YCBCR_LIMITED_RANGE);
1411
1412 shadow->strides[0] = ALIGN(width * 4, 16);
1413 shadow->size = ALIGN(shadow->strides[0] * height,
1414 sysconf(_SC_PAGESIZE));
1415 ptr = mmap(NULL, shadow->size, PROT_READ | PROT_WRITE,
1416 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
1417 igt_assert(ptr != MAP_FAILED);
1418
1419 return ptr;
1420}
1421
1422static void igt_fb_destroy_cairo_shadow_buffer(struct igt_fb *shadow,
1423 void *ptr)
1424{
1425 munmap(ptr, shadow->size);
1426}
1427
Ville Syrjäläee26fef2018-02-27 22:38:05 +02001428static uint8_t clamprgb(float val)
1429{
Ville Syrjäläd1a93aa2018-06-06 20:36:44 +03001430 return clamp((int)(val + 0.5f), 0, 255);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001431}
1432
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001433static void read_rgb(struct igt_vec4 *rgb, const uint8_t *rgb24)
1434{
1435 rgb->d[0] = rgb24[2];
1436 rgb->d[1] = rgb24[1];
1437 rgb->d[2] = rgb24[0];
1438 rgb->d[3] = 1.0f;
1439}
1440
1441static void write_rgb(uint8_t *rgb24, const struct igt_vec4 *rgb)
1442{
1443 rgb24[2] = clamprgb(rgb->d[0]);
1444 rgb24[1] = clamprgb(rgb->d[1]);
1445 rgb24[0] = clamprgb(rgb->d[2]);
1446}
1447
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001448struct fb_convert_buf {
1449 void *ptr;
1450 struct igt_fb *fb;
1451};
1452
1453struct fb_convert {
1454 struct fb_convert_buf dst;
1455 struct fb_convert_buf src;
1456};
1457
1458static void convert_nv12_to_rgb24(struct fb_convert *cvt)
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001459{
1460 int i, j;
1461 const uint8_t *y, *uv;
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001462 uint8_t *rgb24 = cvt->dst.ptr;
1463 unsigned int rgb24_stride = cvt->dst.fb->strides[0];
1464 unsigned int planar_stride = cvt->src.fb->strides[0];
1465 uint8_t *buf = malloc(cvt->src.fb->size);
1466 struct igt_mat4 m = igt_ycbcr_to_rgb_matrix(cvt->src.fb->color_encoding,
1467 cvt->src.fb->color_range);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001468
1469 /*
1470 * Reading from the BO is awfully slow because of lack of read caching,
1471 * it's faster to copy the whole BO to a temporary buffer and convert
1472 * from there.
1473 */
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001474 igt_memcpy_from_wc(buf, cvt->src.ptr, cvt->src.fb->size);
1475 y = cvt->src.ptr + cvt->src.fb->offsets[0];
1476 uv = cvt->src.ptr + cvt->src.fb->offsets[1];
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001477
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001478 for (i = 0; i < cvt->dst.fb->height / 2; i++) {
1479 for (j = 0; j < cvt->dst.fb->width / 2; j++) {
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001480 /* Convert 2x2 pixel blocks */
1481 struct igt_vec4 yuv[4];
1482 struct igt_vec4 rgb[4];
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001483
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001484 yuv[0].d[0] = y[j * 2 + 0];
1485 yuv[1].d[0] = y[j * 2 + 1];
1486 yuv[2].d[0] = y[j * 2 + 0 + planar_stride];
1487 yuv[3].d[0] = y[j * 2 + 1 + planar_stride];
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001488
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001489 yuv[0].d[1] = yuv[1].d[1] = yuv[2].d[1] = yuv[3].d[1] = uv[j * 2 + 0];
1490 yuv[0].d[2] = yuv[1].d[2] = yuv[2].d[2] = yuv[3].d[2] = uv[j * 2 + 1];
1491 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 +01001492
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001493 rgb[0] = igt_matrix_transform(&m, &yuv[0]);
1494 rgb[1] = igt_matrix_transform(&m, &yuv[1]);
1495 rgb[2] = igt_matrix_transform(&m, &yuv[2]);
1496 rgb[3] = igt_matrix_transform(&m, &yuv[3]);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001497
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001498 write_rgb(&rgb24[j * 8 + 0], &rgb[0]);
1499 write_rgb(&rgb24[j * 8 + 4], &rgb[1]);
1500 write_rgb(&rgb24[j * 8 + 0 + rgb24_stride], &rgb[2]);
1501 write_rgb(&rgb24[j * 8 + 4 + rgb24_stride], &rgb[3]);
1502 }
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001503
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001504 if (cvt->dst.fb->width & 1) {
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001505 /* Convert 1x2 pixel block */
1506 struct igt_vec4 yuv[2];
1507 struct igt_vec4 rgb[2];
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001508
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001509 yuv[0].d[0] = y[j * 2 + 0];
1510 yuv[1].d[0] = y[j * 2 + 0 + planar_stride];
1511
1512 yuv[0].d[1] = yuv[1].d[1] = uv[j * 2 + 0];
1513 yuv[0].d[2] = yuv[1].d[2] = uv[j * 2 + 1];
1514 yuv[0].d[3] = yuv[1].d[3] = 1.0f;
1515
1516 rgb[0] = igt_matrix_transform(&m, &yuv[0]);
1517 rgb[1] = igt_matrix_transform(&m, &yuv[1]);
1518
1519 write_rgb(&rgb24[j * 8 + 0], &rgb[0]);
1520 write_rgb(&rgb24[j * 8 + 0 + rgb24_stride], &rgb[1]);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001521 }
1522
1523 rgb24 += 2 * rgb24_stride;
1524 y += 2 * planar_stride;
1525 uv += planar_stride;
1526 }
1527
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001528 if (cvt->dst.fb->height & 1) {
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001529 /* Convert last row */
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001530 for (j = 0; j < cvt->dst.fb->width / 2; j++) {
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001531 /* Convert 2x1 pixel blocks */
1532 struct igt_vec4 yuv[2];
1533 struct igt_vec4 rgb[2];
1534
1535 yuv[0].d[0] = y[j * 2 + 0];
1536 yuv[1].d[0] = y[j * 2 + 1];
1537 yuv[0].d[1] = yuv[1].d[1] = uv[j * 2 + 0];
1538 yuv[0].d[2] = yuv[1].d[2] = uv[j * 2 + 1];
1539 yuv[0].d[3] = yuv[1].d[3] = 1.0f;
1540
1541 rgb[0] = igt_matrix_transform(&m, &yuv[0]);
1542 rgb[1] = igt_matrix_transform(&m, &yuv[1]);
1543
1544 write_rgb(&rgb24[j * 8 + 0], &rgb[0]);
1545 write_rgb(&rgb24[j * 8 + 4], &rgb[0]);
1546 }
1547
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001548 if (cvt->dst.fb->width & 1) {
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001549 /* Convert single pixel */
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001550 struct igt_vec4 yuv;
1551 struct igt_vec4 rgb;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001552
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001553 yuv.d[0] = y[j * 2 + 0];
1554 yuv.d[1] = uv[j * 2 + 0];
1555 yuv.d[2] = uv[j * 2 + 1];
1556 yuv.d[3] = 1.0f;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001557
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001558 rgb = igt_matrix_transform(&m, &yuv);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001559
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001560 write_rgb(&rgb24[j * 8 + 0], &rgb);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001561 }
1562 }
1563
1564 free(buf);
1565}
1566
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001567static void convert_rgb24_to_nv12(struct fb_convert *cvt)
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001568{
1569 int i, j;
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001570 uint8_t *y = cvt->dst.ptr + cvt->dst.fb->offsets[0];
1571 uint8_t *uv = cvt->dst.ptr + cvt->dst.fb->offsets[1];
1572 const uint8_t *rgb24 = cvt->src.ptr;
1573 unsigned rgb24_stride = cvt->src.fb->strides[0];
1574 unsigned planar_stride = cvt->dst.fb->strides[0];
1575 struct igt_mat4 m = igt_rgb_to_ycbcr_matrix(cvt->dst.fb->color_encoding,
1576 cvt->dst.fb->color_range);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001577
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001578 igt_assert_f(cvt->dst.fb->drm_format == DRM_FORMAT_NV12,
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001579 "Conversion not implemented for !NV12 planar formats\n");
1580
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001581 for (i = 0; i < cvt->dst.fb->height / 2; i++) {
1582 for (j = 0; j < cvt->dst.fb->width / 2; j++) {
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001583 /* Convert 2x2 pixel blocks */
1584 struct igt_vec4 rgb[4];
1585 struct igt_vec4 yuv[4];
1586
1587 read_rgb(&rgb[0], &rgb24[j * 8 + 0]);
1588 read_rgb(&rgb[1], &rgb24[j * 8 + 4]);
1589 read_rgb(&rgb[2], &rgb24[j * 8 + 0 + rgb24_stride]);
1590 read_rgb(&rgb[3], &rgb24[j * 8 + 4 + rgb24_stride]);
1591
1592 yuv[0] = igt_matrix_transform(&m, &rgb[0]);
1593 yuv[1] = igt_matrix_transform(&m, &rgb[1]);
1594 yuv[2] = igt_matrix_transform(&m, &rgb[2]);
1595 yuv[3] = igt_matrix_transform(&m, &rgb[3]);
1596
1597 y[j * 2 + 0] = yuv[0].d[0];
1598 y[j * 2 + 1] = yuv[1].d[0];
1599 y[j * 2 + 0 + planar_stride] = yuv[2].d[0];
1600 y[j * 2 + 1 + planar_stride] = yuv[3].d[0];
1601
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001602 /*
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001603 * We assume the MPEG2 chroma siting convention, where
1604 * pixel center for Cb'Cr' is between the left top and
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001605 * bottom pixel in a 2x2 block, so take the average.
1606 */
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001607 uv[j * 2 + 0] = (yuv[0].d[1] + yuv[2].d[1]) / 2.0f;
1608 uv[j * 2 + 1] = (yuv[0].d[2] + yuv[2].d[2]) / 2.0f;
1609 }
1610
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001611 if (cvt->dst.fb->width & 1) {
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001612 /* Convert 1x2 pixel block */
1613 struct igt_vec4 rgb[2];
1614 struct igt_vec4 yuv[2];
1615
1616 read_rgb(&rgb[0], &rgb24[j * 8 + 0]);
1617 read_rgb(&rgb[2], &rgb24[j * 8 + 0 + rgb24_stride]);
1618
1619 yuv[0] = igt_matrix_transform(&m, &rgb[0]);
1620 yuv[1] = igt_matrix_transform(&m, &rgb[1]);
1621
1622 y[j * 2 + 0] = yuv[0].d[0];
1623 y[j * 2 + 0 + planar_stride] = yuv[1].d[0];
1624
1625 /*
1626 * We assume the MPEG2 chroma siting convention, where
1627 * pixel center for Cb'Cr' is between the left top and
1628 * bottom pixel in a 2x2 block, so take the average.
1629 */
1630 uv[j * 2 + 0] = (yuv[0].d[1] + yuv[1].d[1]) / 2.0f;
1631 uv[j * 2 + 1] = (yuv[0].d[2] + yuv[1].d[2]) / 2.0f;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001632 }
1633
1634 rgb24 += 2 * rgb24_stride;
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001635 y += 2 * planar_stride;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001636 uv += planar_stride;
1637 }
1638
1639 /* Last row cannot be interpolated between 2 pixels, take the single value */
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001640 if (cvt->dst.fb->height & 1) {
1641 for (j = 0; j < cvt->dst.fb->width / 2; j++) {
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001642 /* Convert 2x1 pixel blocks */
1643 struct igt_vec4 rgb[2];
1644 struct igt_vec4 yuv[2];
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001645
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001646 read_rgb(&rgb[0], &rgb24[j * 8 + 0]);
1647 read_rgb(&rgb[1], &rgb24[j * 8 + 4]);
1648
1649 yuv[0] = igt_matrix_transform(&m, &rgb[0]);
1650 yuv[1] = igt_matrix_transform(&m, &rgb[1]);
1651
1652 y[j * 2 + 0] = yuv[0].d[0];
1653 y[j * 2 + 1] = yuv[1].d[0];
1654 uv[j * 2 + 0] = yuv[0].d[1];
1655 uv[j * 2 + 1] = yuv[0].d[2];
1656 }
1657
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001658 if (cvt->dst.fb->width & 1) {
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001659 /* Convert single pixel */
1660 struct igt_vec4 rgb;
1661 struct igt_vec4 yuv;
1662
1663 read_rgb(&rgb, &rgb24[j * 8 + 0]);
1664
1665 yuv = igt_matrix_transform(&m, &rgb);
1666
1667 y[j * 2 + 0] = yuv.d[0];
1668 uv[j * 2 + 0] = yuv.d[1];
1669 uv[j * 2 + 1] = yuv.d[2];
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001670 }
1671 }
1672}
1673
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001674/* { Y0, U, Y1, V } */
1675static const unsigned char swizzle_yuyv[] = { 0, 1, 2, 3 };
1676static const unsigned char swizzle_yvyu[] = { 0, 3, 2, 1 };
1677static const unsigned char swizzle_uyvy[] = { 1, 0, 3, 2 };
1678static const unsigned char swizzle_vyuy[] = { 1, 2, 3, 0 };
1679
1680static const unsigned char *yuyv_swizzle(uint32_t format)
1681{
1682 switch (format) {
1683 default:
1684 case DRM_FORMAT_YUYV:
1685 return swizzle_yuyv;
1686 case DRM_FORMAT_YVYU:
1687 return swizzle_yvyu;
1688 case DRM_FORMAT_UYVY:
1689 return swizzle_uyvy;
1690 case DRM_FORMAT_VYUY:
1691 return swizzle_vyuy;
1692 }
1693}
1694
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001695static void convert_yuyv_to_rgb24(struct fb_convert *cvt)
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001696{
1697 int i, j;
1698 const uint8_t *yuyv;
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001699 uint8_t *rgb24 = cvt->dst.ptr;
1700 unsigned int rgb24_stride = cvt->dst.fb->strides[0];
1701 unsigned int yuyv_stride = cvt->src.fb->strides[0];
1702 uint8_t *buf = malloc(cvt->src.fb->size);
1703 struct igt_mat4 m = igt_ycbcr_to_rgb_matrix(cvt->src.fb->color_encoding,
1704 cvt->src.fb->color_range);
1705 const unsigned char *swz = yuyv_swizzle(cvt->src.fb->drm_format);
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001706
1707 /*
1708 * Reading from the BO is awfully slow because of lack of read caching,
1709 * it's faster to copy the whole BO to a temporary buffer and convert
1710 * from there.
1711 */
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001712 igt_memcpy_from_wc(buf, cvt->src.ptr, cvt->src.fb->size);
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001713 yuyv = buf;
1714
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001715 for (i = 0; i < cvt->dst.fb->height; i++) {
1716 for (j = 0; j < cvt->dst.fb->width / 2; j++) {
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001717 /* Convert 2x1 pixel blocks */
1718 struct igt_vec4 yuv[2];
1719 struct igt_vec4 rgb[2];
1720
1721 yuv[0].d[0] = yuyv[j * 4 + swz[0]];
1722 yuv[1].d[0] = yuyv[j * 4 + swz[2]];
1723 yuv[0].d[1] = yuv[1].d[1] = yuyv[j * 4 + swz[1]];
1724 yuv[0].d[2] = yuv[1].d[2] = yuyv[j * 4 + swz[3]];
1725 yuv[0].d[3] = yuv[1].d[3] = 1.0f;
1726
1727 rgb[0] = igt_matrix_transform(&m, &yuv[0]);
1728 rgb[1] = igt_matrix_transform(&m, &yuv[1]);
1729
1730 write_rgb(&rgb24[j * 8 + 0], &rgb[0]);
1731 write_rgb(&rgb24[j * 8 + 4], &rgb[1]);
1732 }
1733
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001734 if (cvt->dst.fb->width & 1) {
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001735 struct igt_vec4 yuv;
1736 struct igt_vec4 rgb;
1737
1738 yuv.d[0] = yuyv[j * 4 + swz[0]];
1739 yuv.d[1] = yuyv[j * 4 + swz[1]];
1740 yuv.d[2] = yuyv[j * 4 + swz[3]];
1741 yuv.d[3] = 1.0f;
1742
1743 rgb = igt_matrix_transform(&m, &yuv);
1744
1745 write_rgb(&rgb24[j * 8 + 0], &rgb);
1746 }
1747
1748 rgb24 += rgb24_stride;
1749 yuyv += yuyv_stride;
1750 }
1751
1752 free(buf);
1753}
1754
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001755static void convert_rgb24_to_yuyv(struct fb_convert *cvt)
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001756{
1757 int i, j;
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001758 uint8_t *yuyv = cvt->dst.ptr;
1759 const uint8_t *rgb24 = cvt->src.ptr;
1760 unsigned rgb24_stride = cvt->src.fb->strides[0];
1761 unsigned yuyv_stride = cvt->dst.fb->strides[0];
1762 struct igt_mat4 m = igt_rgb_to_ycbcr_matrix(cvt->dst.fb->color_encoding,
1763 cvt->dst.fb->color_range);
1764 const unsigned char *swz = yuyv_swizzle(cvt->dst.fb->drm_format);
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001765
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001766 igt_assert_f(cvt->dst.fb->drm_format == DRM_FORMAT_YUYV ||
1767 cvt->dst.fb->drm_format == DRM_FORMAT_YVYU ||
1768 cvt->dst.fb->drm_format == DRM_FORMAT_UYVY ||
1769 cvt->dst.fb->drm_format == DRM_FORMAT_VYUY,
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001770 "Conversion not implemented for !YUYV planar formats\n");
1771
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001772 for (i = 0; i < cvt->dst.fb->height; i++) {
1773 for (j = 0; j < cvt->dst.fb->width / 2; j++) {
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001774 /* Convert 2x1 pixel blocks */
1775 struct igt_vec4 rgb[2];
1776 struct igt_vec4 yuv[2];
1777
1778 read_rgb(&rgb[0], &rgb24[j * 8 + 0]);
1779 read_rgb(&rgb[1], &rgb24[j * 8 + 4]);
1780
1781 yuv[0] = igt_matrix_transform(&m, &rgb[0]);
1782 yuv[1] = igt_matrix_transform(&m, &rgb[1]);
1783
1784 yuyv[j * 4 + swz[0]] = yuv[0].d[0];
1785 yuyv[j * 4 + swz[2]] = yuv[1].d[0];
1786 yuyv[j * 4 + swz[1]] = (yuv[0].d[1] + yuv[1].d[1]) / 2.0f;
1787 yuyv[j * 4 + swz[3]] = (yuv[0].d[2] + yuv[1].d[2]) / 2.0f;
1788 }
1789
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001790 if (cvt->dst.fb->width & 1) {
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001791 struct igt_vec4 rgb;
1792 struct igt_vec4 yuv;
1793
1794 read_rgb(&rgb, &rgb24[j * 8 + 0]);
1795
1796 yuv = igt_matrix_transform(&m, &rgb);
1797
1798 yuyv[j * 4 + swz[0]] = yuv.d[0];
1799 yuyv[j * 4 + swz[1]] = yuv.d[1];
1800 yuyv[j * 4 + swz[3]] = yuv.d[2];
1801 }
1802
1803 rgb24 += rgb24_stride;
1804 yuyv += yuyv_stride;
1805 }
1806}
1807
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001808static void fb_convert(struct fb_convert *cvt)
1809{
1810 if (cvt->dst.fb->drm_format == DRM_FORMAT_RGB888) {
1811 switch (cvt->src.fb->drm_format) {
1812 case DRM_FORMAT_NV12:
1813 convert_nv12_to_rgb24(cvt);
1814 return;
1815 case DRM_FORMAT_YUYV:
1816 case DRM_FORMAT_YVYU:
1817 case DRM_FORMAT_UYVY:
1818 case DRM_FORMAT_VYUY:
1819 convert_yuyv_to_rgb24(cvt);
1820 return;
1821 }
1822 } else if (cvt->src.fb->drm_format == DRM_FORMAT_RGB888) {
1823 switch (cvt->dst.fb->drm_format) {
1824 case DRM_FORMAT_NV12:
1825 convert_rgb24_to_nv12(cvt);
1826 return;
1827 case DRM_FORMAT_YUYV:
1828 case DRM_FORMAT_YVYU:
1829 case DRM_FORMAT_UYVY:
1830 case DRM_FORMAT_VYUY:
1831 convert_rgb24_to_yuyv(cvt);
1832 return;
1833 }
1834 }
1835
1836 igt_assert_f(false,
1837 "Conversion not implemented (from format 0x%x to 0x%x)\n",
1838 cvt->src.fb->drm_format, cvt->dst.fb->drm_format);
1839}
1840
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001841static void destroy_cairo_surface__convert(void *arg)
1842{
1843 struct fb_convert_blit_upload *blit = arg;
Ville Syrjälä3ed2a602018-07-17 16:15:34 +03001844 struct igt_fb *fb = blit->base.fb;
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001845 struct fb_convert cvt = {
1846 .dst = {
1847 .ptr = blit->base.linear.map,
1848 .fb = blit->base.fb,
1849 },
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001850
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001851 .src = {
1852 .ptr = blit->shadow_ptr,
1853 .fb = &blit->shadow_fb,
1854 },
1855 };
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001856
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001857 fb_convert(&cvt);
Maxime Ripardc7128362018-10-04 14:38:57 +02001858 igt_fb_destroy_cairo_shadow_buffer(&blit->shadow_fb, blit->shadow_ptr);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001859
Ville Syrjälä22383612018-07-17 18:32:38 +03001860 if (blit->base.linear.fb.gem_handle)
Ville Syrjälä74261fd2018-07-17 16:20:34 +03001861 free_linear_mapping(&blit->base);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001862 else
Maxime Ripard3415b192018-10-04 14:38:54 +02001863 unmap_bo(fb, blit->base.linear.map);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001864
1865 free(blit);
1866
1867 fb->cairo_surface = NULL;
1868}
1869
1870static void create_cairo_surface__convert(int fd, struct igt_fb *fb)
1871{
1872 struct fb_convert_blit_upload *blit = malloc(sizeof(*blit));
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001873 struct fb_convert cvt = { 0 };
Maxime Ripardc7128362018-10-04 14:38:57 +02001874
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001875 igt_assert(blit);
1876
Ville Syrjälä3ed2a602018-07-17 16:15:34 +03001877 blit->base.fd = fd;
1878 blit->base.fb = fb;
Maxime Ripardc7128362018-10-04 14:38:57 +02001879 blit->shadow_ptr = igt_fb_create_cairo_shadow_buffer(fd,
1880 fb->width,
1881 fb->height,
1882 &blit->shadow_fb);
1883 igt_assert(blit->shadow_ptr);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001884
1885 if (fb->tiling == LOCAL_I915_FORMAT_MOD_Y_TILED ||
1886 fb->tiling == LOCAL_I915_FORMAT_MOD_Yf_TILED) {
Ville Syrjälä3ed2a602018-07-17 16:15:34 +03001887 setup_linear_mapping(fd, fb, &blit->base.linear);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001888 } else {
Ville Syrjälä22383612018-07-17 18:32:38 +03001889 blit->base.linear.fb.gem_handle = 0;
Maxime Ripard3415b192018-10-04 14:38:54 +02001890 blit->base.linear.map = map_bo(fd, fb);
Ville Syrjälä3ed2a602018-07-17 16:15:34 +03001891 igt_assert(blit->base.linear.map);
Ville Syrjälä22383612018-07-17 18:32:38 +03001892 blit->base.linear.fb.size = fb->size;
1893 memcpy(blit->base.linear.fb.strides, fb->strides, sizeof(fb->strides));
1894 memcpy(blit->base.linear.fb.offsets, fb->offsets, sizeof(fb->offsets));
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001895 }
1896
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001897 cvt.dst.ptr = blit->shadow_ptr;
1898 cvt.dst.fb = &blit->shadow_fb;
1899 cvt.src.ptr = blit->base.linear.map;
1900 cvt.src.fb = blit->base.fb;
1901 fb_convert(&cvt);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001902
1903 fb->cairo_surface =
Maxime Ripardc7128362018-10-04 14:38:57 +02001904 cairo_image_surface_create_for_data(blit->shadow_ptr,
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001905 CAIRO_FORMAT_RGB24,
1906 fb->width, fb->height,
Maxime Ripardc7128362018-10-04 14:38:57 +02001907 blit->shadow_fb.strides[0]);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001908
1909 cairo_surface_set_user_data(fb->cairo_surface,
1910 (cairo_user_data_key_t *)create_cairo_surface__convert,
1911 blit, destroy_cairo_surface__convert);
1912}
1913
Paul Kocialkowskib4ad3972017-07-19 16:46:04 +03001914/**
Maxime Ripard3415b192018-10-04 14:38:54 +02001915 * igt_fb_map_buffer:
1916 * @fd: open drm file descriptor
1917 * @fb: pointer to an #igt_fb structure
1918 *
1919 * This function will creating a new mapping of the buffer and return a pointer
1920 * to the content of the supplied framebuffer's plane. This mapping needs to be
1921 * deleted using igt_fb_unmap_buffer().
1922 *
1923 * Returns:
1924 * A pointer to a buffer with the contents of the framebuffer
1925 */
1926void *igt_fb_map_buffer(int fd, struct igt_fb *fb)
1927{
1928 return map_bo(fd, fb);
1929}
1930
1931/**
1932 * igt_fb_unmap_buffer:
1933 * @fb: pointer to the backing igt_fb structure
1934 * @buffer: pointer to the buffer previously mappped
1935 *
1936 * This function will unmap a buffer mapped previously with
1937 * igt_fb_map_buffer().
1938 */
1939void igt_fb_unmap_buffer(struct igt_fb *fb, void *buffer)
1940{
1941 return unmap_bo(fb, buffer);
1942}
1943
1944/**
Paul Kocialkowskib4ad3972017-07-19 16:46:04 +03001945 * igt_get_cairo_surface:
1946 * @fd: open drm file descriptor
1947 * @fb: pointer to an #igt_fb structure
1948 *
Maarten Lankhorst918ea422018-01-19 12:47:11 +01001949 * This function stores the contents of the supplied framebuffer's plane
1950 * into a cairo surface and returns it.
Paul Kocialkowskib4ad3972017-07-19 16:46:04 +03001951 *
1952 * Returns:
1953 * A pointer to a cairo surface with the contents of the framebuffer.
1954 */
1955cairo_surface_t *igt_get_cairo_surface(int fd, struct igt_fb *fb)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001956{
Damien Lespiauff451a62015-03-03 14:11:04 +00001957 if (fb->cairo_surface == NULL) {
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001958 if (igt_format_is_yuv(fb->drm_format))
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001959 create_cairo_surface__convert(fd, fb);
1960 else if (fb->tiling == LOCAL_I915_FORMAT_MOD_Y_TILED ||
Damien Lespiauff451a62015-03-03 14:11:04 +00001961 fb->tiling == LOCAL_I915_FORMAT_MOD_Yf_TILED)
1962 create_cairo_surface__blit(fd, fb);
1963 else
1964 create_cairo_surface__gtt(fd, fb);
1965 }
Daniel Vetter57d7db82014-03-26 09:06:11 +01001966
Daniel Vetter57d7db82014-03-26 09:06:11 +01001967 igt_assert(cairo_surface_status(fb->cairo_surface) == CAIRO_STATUS_SUCCESS);
Damien Lespiau0db75bb2014-06-30 16:34:20 +01001968 return fb->cairo_surface;
Daniel Vetter57d7db82014-03-26 09:06:11 +01001969}
1970
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001971/**
1972 * igt_get_cairo_ctx:
1973 * @fd: open i915 drm file descriptor
1974 * @fb: pointer to an #igt_fb structure
1975 *
1976 * This initializes a cairo surface for @fb and then allocates a drawing context
1977 * for it. The return cairo drawing context should be released by calling
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +01001978 * igt_put_cairo_ctx(). This also sets a default font for drawing text on
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001979 * framebuffers.
1980 *
1981 * Returns:
1982 * The created cairo drawing context.
1983 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01001984cairo_t *igt_get_cairo_ctx(int fd, struct igt_fb *fb)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001985{
1986 cairo_surface_t *surface;
1987 cairo_t *cr;
1988
Paul Kocialkowskib4ad3972017-07-19 16:46:04 +03001989 surface = igt_get_cairo_surface(fd, fb);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001990 cr = cairo_create(surface);
1991 cairo_surface_destroy(surface);
Daniel Vetter7568edf2014-03-26 16:36:46 +01001992 igt_assert(cairo_status(cr) == CAIRO_STATUS_SUCCESS);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001993
Daniel Vetter7568edf2014-03-26 16:36:46 +01001994 cairo_select_font_face(cr, "Helvetica", CAIRO_FONT_SLANT_NORMAL,
1995 CAIRO_FONT_WEIGHT_NORMAL);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001996 igt_assert(cairo_status(cr) == CAIRO_STATUS_SUCCESS);
1997
1998 return cr;
1999}
2000
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01002001/**
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +01002002 * igt_put_cairo_ctx:
2003 * @fd: open i915 drm file descriptor
2004 * @fb: pointer to an #igt_fb structure
2005 * @cr: the cairo context returned by igt_get_cairo_ctx.
2006 *
2007 * This releases the cairo surface @cr returned by igt_get_cairo_ctx()
2008 * for @fb, and writes the changes out to the framebuffer if cairo doesn't
2009 * have native support for the format.
2010 */
2011void igt_put_cairo_ctx(int fd, struct igt_fb *fb, cairo_t *cr)
2012{
2013 cairo_status_t ret = cairo_status(cr);
2014 igt_assert_f(ret == CAIRO_STATUS_SUCCESS, "Cairo failed to draw with %s\n", cairo_status_to_string(ret));
2015
2016 cairo_destroy(cr);
2017}
2018
2019/**
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01002020 * igt_remove_fb:
2021 * @fd: open i915 drm file descriptor
2022 * @fb: pointer to an #igt_fb structure
2023 *
2024 * This function releases all resources allocated in igt_create_fb() for @fb.
2025 * Note that if this framebuffer is still in use on a primary plane the kernel
2026 * will disable the corresponding crtc.
2027 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01002028void igt_remove_fb(int fd, struct igt_fb *fb)
Daniel Vetter57d7db82014-03-26 09:06:11 +01002029{
Maarten Lankhorste62de1c2018-02-02 10:58:42 +01002030 if (!fb || !fb->fb_id)
2031 return;
2032
Daniel Vetter57d7db82014-03-26 09:06:11 +01002033 cairo_surface_destroy(fb->cairo_surface);
2034 do_or_die(drmModeRmFB(fd, fb->fb_id));
2035 gem_close(fd, fb->gem_handle);
Maarten Lankhorste62de1c2018-02-02 10:58:42 +01002036 fb->fb_id = 0;
Daniel Vetter57d7db82014-03-26 09:06:11 +01002037}
2038
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01002039/**
2040 * igt_bpp_depth_to_drm_format:
2041 * @bpp: desired bits per pixel
2042 * @depth: desired depth
2043 *
2044 * Returns:
2045 * The rgb drm fourcc pixel format code corresponding to the given @bpp and
2046 * @depth values. Fails hard if no match was found.
2047 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01002048uint32_t igt_bpp_depth_to_drm_format(int bpp, int depth)
Daniel Vetter57d7db82014-03-26 09:06:11 +01002049{
Ville Syrjäläef43fce2018-07-18 20:26:22 +03002050 const struct format_desc_struct *f;
Daniel Vetter57d7db82014-03-26 09:06:11 +01002051
2052 for_each_format(f)
Ville Syrjäläe556d852018-02-27 22:48:46 +02002053 if (f->plane_bpp[0] == bpp && f->depth == depth)
Daniel Vetter57d7db82014-03-26 09:06:11 +01002054 return f->drm_id;
2055
Damien Lespiau54397ca2014-08-19 11:40:07 +01002056
2057 igt_assert_f(0, "can't find drm format with bpp=%d, depth=%d\n", bpp,
2058 depth);
Daniel Vetter57d7db82014-03-26 09:06:11 +01002059}
2060
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01002061/**
2062 * igt_drm_format_to_bpp:
2063 * @drm_format: drm fourcc pixel format code
2064 *
2065 * Returns:
2066 * The bits per pixel for the given drm fourcc pixel format code. Fails hard if
2067 * no match was found.
2068 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01002069uint32_t igt_drm_format_to_bpp(uint32_t drm_format)
Daniel Vetter57d7db82014-03-26 09:06:11 +01002070{
Ville Syrjäläef43fce2018-07-18 20:26:22 +03002071 const struct format_desc_struct *f = lookup_drm_format(drm_format);
Daniel Vetter57d7db82014-03-26 09:06:11 +01002072
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +01002073 igt_assert_f(f, "can't find a bpp format for %08x (%s)\n",
Damien Lespiau54397ca2014-08-19 11:40:07 +01002074 drm_format, igt_format_str(drm_format));
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +01002075
Ville Syrjäläe556d852018-02-27 22:48:46 +02002076 return f->plane_bpp[0];
Daniel Vetter57d7db82014-03-26 09:06:11 +01002077}
2078
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01002079/**
2080 * igt_format_str:
2081 * @drm_format: drm fourcc pixel format code
2082 *
2083 * Returns:
2084 * Human-readable fourcc pixel format code for @drm_format or "invalid" no match
2085 * was found.
2086 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01002087const char *igt_format_str(uint32_t drm_format)
Daniel Vetter57d7db82014-03-26 09:06:11 +01002088{
Ville Syrjäläef43fce2018-07-18 20:26:22 +03002089 const struct format_desc_struct *f = lookup_drm_format(drm_format);
Daniel Vetter57d7db82014-03-26 09:06:11 +01002090
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +01002091 return f ? f->name : "invalid";
Daniel Vetter57d7db82014-03-26 09:06:11 +01002092}
2093
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01002094/**
Maarten Lankhorstc60cf3b2018-02-02 11:32:40 +01002095 * igt_fb_supported_format:
2096 * @drm_format: drm fourcc to test.
2097 *
2098 * This functions returns whether @drm_format can be succesfully created by
2099 * igt_create_fb() and drawn to by igt_get_cairo_ctx().
2100 */
2101bool igt_fb_supported_format(uint32_t drm_format)
2102{
Ville Syrjäläef43fce2018-07-18 20:26:22 +03002103 const struct format_desc_struct *f;
Maarten Lankhorstc60cf3b2018-02-02 11:32:40 +01002104
2105 for_each_format(f)
2106 if (f->drm_id == drm_format)
2107 return f->cairo_id != CAIRO_FORMAT_INVALID;
2108
2109 return false;
2110}
Ville Syrjälä40bf6d02018-05-18 23:32:32 +03002111
2112/**
2113 * igt_format_is_yuv:
2114 * @drm_format: drm fourcc
2115 *
2116 * This functions returns whether @drm_format is YUV (as opposed to RGB).
2117 */
2118bool igt_format_is_yuv(uint32_t drm_format)
2119{
2120 switch (drm_format) {
2121 case DRM_FORMAT_NV12:
2122 case DRM_FORMAT_YUYV:
2123 case DRM_FORMAT_YVYU:
2124 case DRM_FORMAT_UYVY:
2125 case DRM_FORMAT_VYUY:
2126 return true;
2127 default:
2128 return false;
2129 }
2130}