blob: 3a4827c35b04b1add900d4fccd55e3b9e94493ef [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>
Maxime Ripard3fa65f42018-10-04 14:39:03 +020032#include <pixman.h>
Daniel Vetter57d7db82014-03-26 09:06:11 +010033
34#include "drmtest.h"
Ville Syrjäläee26fef2018-02-27 22:38:05 +020035#include "igt_aux.h"
Ville Syrjälä1c7ef382018-02-27 22:59:25 +020036#include "igt_color_encoding.h"
Daniel Vetter57d7db82014-03-26 09:06:11 +010037#include "igt_fb.h"
Tomeu Vizoso8a1a3862016-02-24 09:04:04 +010038#include "igt_kms.h"
Ville Syrjälä1c7ef382018-02-27 22:59:25 +020039#include "igt_matrix.h"
Chris Wilson6a06d012018-02-27 21:45:14 +000040#include "igt_x86.h"
Daniel Vetter57d7db82014-03-26 09:06:11 +010041#include "ioctl_wrappers.h"
Lionel Landwerlin8bde13a2018-05-06 23:08:46 +010042#include "intel_batchbuffer.h"
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -020043#include "intel_chipset.h"
Daniel Vetter57d7db82014-03-26 09:06:11 +010044
Daniel Vetterc6c2b2b2014-03-26 15:15:49 +010045/**
46 * SECTION:igt_fb
47 * @short_description: Framebuffer handling and drawing library
Damien Lespiau6ebd8c22015-06-26 14:28:41 +010048 * @title: Framebuffer
Thomas Woodf0381d12015-09-07 09:26:01 +010049 * @include: igt.h
Daniel Vetter3d9e63f2014-03-26 16:37:15 +010050 *
51 * This library contains helper functions for handling kms framebuffer objects
52 * using #igt_fb structures to track all the metadata. igt_create_fb() creates
Thomas Woodd01ebbd2015-06-29 16:47:14 +010053 * a basic framebuffer and igt_remove_fb() cleans everything up again.
Daniel Vetter3d9e63f2014-03-26 16:37:15 +010054 *
55 * It also supports drawing using the cairo library and provides some simplified
56 * helper functions to easily draw test patterns. The main function to create a
57 * cairo drawing context for a framebuffer object is igt_get_cairo_ctx().
58 *
59 * Finally it also pulls in the drm fourcc headers and provides some helper
60 * functions to work with these pixel format codes.
Daniel Vetterc6c2b2b2014-03-26 15:15:49 +010061 */
62
Maxime Ripard3fa65f42018-10-04 14:39:03 +020063#define PIXMAN_invalid 0
64
Daniel Vetter57d7db82014-03-26 09:06:11 +010065/* drm fourcc/cairo format maps */
Ville Syrjäläef43fce2018-07-18 20:26:22 +030066static const struct format_desc_struct {
Ville Syrjäläe556d852018-02-27 22:48:46 +020067 const char *name;
Daniel Vetter57d7db82014-03-26 09:06:11 +010068 uint32_t drm_id;
69 cairo_format_t cairo_id;
Maxime Ripard3fa65f42018-10-04 14:39:03 +020070 pixman_format_code_t pixman_id;
Daniel Vetter57d7db82014-03-26 09:06:11 +010071 int depth;
Ville Syrjäläe556d852018-02-27 22:48:46 +020072 int num_planes;
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +010073 int plane_bpp[4];
Maxime Ripard915c58a2019-01-25 15:58:30 +010074 uint8_t hsub;
75 uint8_t vsub;
Daniel Vetter57d7db82014-03-26 09:06:11 +010076} format_desc[] = {
Maxime Ripardaedb0442018-10-04 14:39:04 +020077 { .name = "ARGB1555", .depth = -1, .drm_id = DRM_FORMAT_ARGB1555,
78 .cairo_id = CAIRO_FORMAT_INVALID,
79 .pixman_id = PIXMAN_a1r5g5b5,
80 .num_planes = 1, .plane_bpp = { 16, },
Maxime Ripard915c58a2019-01-25 15:58:30 +010081 .hsub = 1, .vsub = 1,
Maxime Ripardaedb0442018-10-04 14:39:04 +020082 },
83 { .name = "XRGB1555", .depth = -1, .drm_id = DRM_FORMAT_XRGB1555,
84 .cairo_id = CAIRO_FORMAT_INVALID,
85 .pixman_id = PIXMAN_x1r5g5b5,
86 .num_planes = 1, .plane_bpp = { 16, },
Maxime Ripard915c58a2019-01-25 15:58:30 +010087 .hsub = 1, .vsub = 1,
Maxime Ripardaedb0442018-10-04 14:39:04 +020088 },
Ville Syrjäläe556d852018-02-27 22:48:46 +020089 { .name = "RGB565", .depth = 16, .drm_id = DRM_FORMAT_RGB565,
90 .cairo_id = CAIRO_FORMAT_RGB16_565,
Maxime Ripard3fa65f42018-10-04 14:39:03 +020091 .pixman_id = PIXMAN_r5g6b5,
Ville Syrjäläe556d852018-02-27 22:48:46 +020092 .num_planes = 1, .plane_bpp = { 16, },
Maxime Ripard915c58a2019-01-25 15:58:30 +010093 .hsub = 1, .vsub = 1,
Ville Syrjäläe556d852018-02-27 22:48:46 +020094 },
Maxime Ripardaedb0442018-10-04 14:39:04 +020095 { .name = "BGR565", .depth = -1, .drm_id = DRM_FORMAT_BGR565,
96 .cairo_id = CAIRO_FORMAT_INVALID,
97 .pixman_id = PIXMAN_b5g6r5,
98 .num_planes = 1, .plane_bpp = { 16, },
Maxime Ripard915c58a2019-01-25 15:58:30 +010099 .hsub = 1, .vsub = 1,
Maxime Ripardaedb0442018-10-04 14:39:04 +0200100 },
101 { .name = "BGR888", .depth = -1, .drm_id = DRM_FORMAT_BGR888,
102 .cairo_id = CAIRO_FORMAT_INVALID,
103 .pixman_id = PIXMAN_b8g8r8,
104 .num_planes = 1, .plane_bpp = { 24, },
Maxime Ripard915c58a2019-01-25 15:58:30 +0100105 .hsub = 1, .vsub = 1,
Maxime Ripardaedb0442018-10-04 14:39:04 +0200106 },
Maxime Riparda3d88d32018-10-04 14:38:56 +0200107 { .name = "RGB888", .depth = -1, .drm_id = DRM_FORMAT_RGB888,
108 .cairo_id = CAIRO_FORMAT_INVALID,
Maxime Ripard3fa65f42018-10-04 14:39:03 +0200109 .pixman_id = PIXMAN_r8g8b8,
Maxime Riparda3d88d32018-10-04 14:38:56 +0200110 .num_planes = 1, .plane_bpp = { 24, },
Maxime Ripard915c58a2019-01-25 15:58:30 +0100111 .hsub = 1, .vsub = 1,
Maxime Riparda3d88d32018-10-04 14:38:56 +0200112 },
Stanislav Lisovskiyf05c8c22018-12-17 16:30:28 +0200113 { .name = "XYUV8888", .depth = -1, .drm_id = DRM_FORMAT_XYUV8888,
114 .cairo_id = CAIRO_FORMAT_RGB24,
115 .num_planes = 1, .plane_bpp = { 32, },
Maxime Ripard915c58a2019-01-25 15:58:30 +0100116 .hsub = 1, .vsub = 1,
Stanislav Lisovskiyf05c8c22018-12-17 16:30:28 +0200117 },
Ville Syrjäläe556d852018-02-27 22:48:46 +0200118 { .name = "XRGB8888", .depth = 24, .drm_id = DRM_FORMAT_XRGB8888,
119 .cairo_id = CAIRO_FORMAT_RGB24,
Maxime Ripard3fa65f42018-10-04 14:39:03 +0200120 .pixman_id = PIXMAN_x8r8g8b8,
Ville Syrjäläe556d852018-02-27 22:48:46 +0200121 .num_planes = 1, .plane_bpp = { 32, },
Maxime Ripard915c58a2019-01-25 15:58:30 +0100122 .hsub = 1, .vsub = 1,
Ville Syrjäläe556d852018-02-27 22:48:46 +0200123 },
Maxime Ripardaedb0442018-10-04 14:39:04 +0200124 { .name = "XBGR8888", .depth = -1, .drm_id = DRM_FORMAT_XBGR8888,
125 .cairo_id = CAIRO_FORMAT_INVALID,
126 .pixman_id = PIXMAN_x8b8g8r8,
127 .num_planes = 1, .plane_bpp = { 32, },
Maxime Ripard915c58a2019-01-25 15:58:30 +0100128 .hsub = 1, .vsub = 1,
Maxime Ripardaedb0442018-10-04 14:39:04 +0200129 },
Ville Syrjäläe556d852018-02-27 22:48:46 +0200130 { .name = "XRGB2101010", .depth = 30, .drm_id = DRM_FORMAT_XRGB2101010,
131 .cairo_id = CAIRO_FORMAT_RGB30,
Maxime Ripard3fa65f42018-10-04 14:39:03 +0200132 .pixman_id = PIXMAN_x2r10g10b10,
Ville Syrjäläe556d852018-02-27 22:48:46 +0200133 .num_planes = 1, .plane_bpp = { 32, },
Maxime Ripard915c58a2019-01-25 15:58:30 +0100134 .hsub = 1, .vsub = 1,
Ville Syrjäläe556d852018-02-27 22:48:46 +0200135 },
136 { .name = "ARGB8888", .depth = 32, .drm_id = DRM_FORMAT_ARGB8888,
137 .cairo_id = CAIRO_FORMAT_ARGB32,
Maxime Ripard3fa65f42018-10-04 14:39:03 +0200138 .pixman_id = PIXMAN_a8r8g8b8,
Ville Syrjäläe556d852018-02-27 22:48:46 +0200139 .num_planes = 1, .plane_bpp = { 32, },
Maxime Ripard915c58a2019-01-25 15:58:30 +0100140 .hsub = 1, .vsub = 1,
Ville Syrjäläe556d852018-02-27 22:48:46 +0200141 },
Maxime Ripardaedb0442018-10-04 14:39:04 +0200142 { .name = "ABGR8888", .depth = -1, .drm_id = DRM_FORMAT_ABGR8888,
143 .cairo_id = CAIRO_FORMAT_INVALID,
144 .pixman_id = PIXMAN_a8b8g8r8,
145 .num_planes = 1, .plane_bpp = { 32, },
Maxime Ripard915c58a2019-01-25 15:58:30 +0100146 .hsub = 1, .vsub = 1,
Maxime Ripardaedb0442018-10-04 14:39:04 +0200147 },
Ville Syrjäläe556d852018-02-27 22:48:46 +0200148 { .name = "NV12", .depth = -1, .drm_id = DRM_FORMAT_NV12,
149 .cairo_id = CAIRO_FORMAT_RGB24,
150 .num_planes = 2, .plane_bpp = { 8, 16, },
Maxime Ripard915c58a2019-01-25 15:58:30 +0100151 .hsub = 2, .vsub = 2,
Ville Syrjäläe556d852018-02-27 22:48:46 +0200152 },
Maxime Ripard3b2b80b2019-02-08 14:18:58 +0100153 { .name = "NV16", .depth = -1, .drm_id = DRM_FORMAT_NV16,
154 .cairo_id = CAIRO_FORMAT_RGB24,
155 .num_planes = 2, .plane_bpp = { 8, 16, },
156 .hsub = 2, .vsub = 1,
157 },
158 { .name = "NV21", .depth = -1, .drm_id = DRM_FORMAT_NV21,
159 .cairo_id = CAIRO_FORMAT_RGB24,
160 .num_planes = 2, .plane_bpp = { 8, 16, },
161 .hsub = 2, .vsub = 2,
162 },
163 { .name = "NV61", .depth = -1, .drm_id = DRM_FORMAT_NV61,
164 .cairo_id = CAIRO_FORMAT_RGB24,
165 .num_planes = 2, .plane_bpp = { 8, 16, },
166 .hsub = 2, .vsub = 1,
167 },
Ville Syrjäläfed97c42018-02-27 22:58:01 +0200168 { .name = "YUYV", .depth = -1, .drm_id = DRM_FORMAT_YUYV,
169 .cairo_id = CAIRO_FORMAT_RGB24,
170 .num_planes = 1, .plane_bpp = { 16, },
Maxime Ripard915c58a2019-01-25 15:58:30 +0100171 .hsub = 2, .vsub = 1,
Ville Syrjäläfed97c42018-02-27 22:58:01 +0200172 },
173 { .name = "YVYU", .depth = -1, .drm_id = DRM_FORMAT_YVYU,
174 .cairo_id = CAIRO_FORMAT_RGB24,
175 .num_planes = 1, .plane_bpp = { 16, },
Maxime Ripard915c58a2019-01-25 15:58:30 +0100176 .hsub = 2, .vsub = 1,
Ville Syrjäläfed97c42018-02-27 22:58:01 +0200177 },
178 { .name = "UYVY", .depth = -1, .drm_id = DRM_FORMAT_UYVY,
179 .cairo_id = CAIRO_FORMAT_RGB24,
180 .num_planes = 1, .plane_bpp = { 16, },
Maxime Ripard915c58a2019-01-25 15:58:30 +0100181 .hsub = 2, .vsub = 1,
Ville Syrjäläfed97c42018-02-27 22:58:01 +0200182 },
183 { .name = "VYUY", .depth = -1, .drm_id = DRM_FORMAT_VYUY,
184 .cairo_id = CAIRO_FORMAT_RGB24,
185 .num_planes = 1, .plane_bpp = { 16, },
Maxime Ripard915c58a2019-01-25 15:58:30 +0100186 .hsub = 2, .vsub = 1,
Ville Syrjäläfed97c42018-02-27 22:58:01 +0200187 },
Maxime Ripard3b2b80b2019-02-08 14:18:58 +0100188 { .name = "YU12", .depth = -1, .drm_id = DRM_FORMAT_YUV420,
189 .cairo_id = CAIRO_FORMAT_RGB24,
190 .num_planes = 3, .plane_bpp = { 8, 8, 8, },
191 .hsub = 2, .vsub = 2,
192 },
193 { .name = "YU16", .depth = -1, .drm_id = DRM_FORMAT_YUV422,
194 .cairo_id = CAIRO_FORMAT_RGB24,
195 .num_planes = 3, .plane_bpp = { 8, 8, 8, },
196 .hsub = 2, .vsub = 1,
197 },
198 { .name = "YV12", .depth = -1, .drm_id = DRM_FORMAT_YVU420,
199 .cairo_id = CAIRO_FORMAT_RGB24,
200 .num_planes = 3, .plane_bpp = { 8, 8, 8, },
201 .hsub = 2, .vsub = 2,
202 },
203 { .name = "YV16", .depth = -1, .drm_id = DRM_FORMAT_YVU422,
204 .cairo_id = CAIRO_FORMAT_RGB24,
205 .num_planes = 3, .plane_bpp = { 8, 8, 8, },
206 .hsub = 2, .vsub = 1,
207 },
Daniel Vetter57d7db82014-03-26 09:06:11 +0100208};
Daniel Vetter57d7db82014-03-26 09:06:11 +0100209#define for_each_format(f) \
210 for (f = format_desc; f - format_desc < ARRAY_SIZE(format_desc); f++)
211
Ville Syrjäläef43fce2018-07-18 20:26:22 +0300212static const struct format_desc_struct *lookup_drm_format(uint32_t drm_format)
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100213{
Ville Syrjäläef43fce2018-07-18 20:26:22 +0300214 const struct format_desc_struct *format;
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100215
216 for_each_format(format) {
217 if (format->drm_id != drm_format)
218 continue;
219
220 return format;
221 }
222
223 return NULL;
224}
225
Praveen Paneri4bb45412017-07-18 22:52:56 +0530226/**
227 * igt_get_fb_tile_size:
228 * @fd: the DRM file descriptor
229 * @tiling: tiling layout of the framebuffer (as framebuffer modifier)
230 * @fb_bpp: bits per pixel of the framebuffer
231 * @width_ret: width of the tile in bytes
232 * @height_ret: height of the tile in lines
233 *
234 * This function returns width and height of a tile based on the given tiling
235 * format.
236 */
237void igt_get_fb_tile_size(int fd, uint64_t tiling, int fb_bpp,
238 unsigned *width_ret, unsigned *height_ret)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100239{
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200240 switch (tiling) {
241 case LOCAL_DRM_FORMAT_MOD_NONE:
Maxime Ripard6112f952019-01-25 15:58:31 +0100242 if (is_i915_device(fd))
243 *width_ret = 64;
244 else
245 *width_ret = 1;
246
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200247 *height_ret = 1;
248 break;
249 case LOCAL_I915_FORMAT_MOD_X_TILED:
Tomeu Vizoso85a1d452016-02-24 08:39:53 +0100250 igt_require_intel(fd);
251 if (intel_gen(intel_get_drm_devid(fd)) == 2) {
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200252 *width_ret = 128;
253 *height_ret = 16;
254 } else {
255 *width_ret = 512;
256 *height_ret = 8;
257 }
258 break;
259 case LOCAL_I915_FORMAT_MOD_Y_TILED:
Tomeu Vizoso85a1d452016-02-24 08:39:53 +0100260 igt_require_intel(fd);
261 if (intel_gen(intel_get_drm_devid(fd)) == 2) {
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200262 *width_ret = 128;
Ville Syrjälä037bc692016-02-12 21:28:54 +0200263 *height_ret = 16;
Tomeu Vizoso85a1d452016-02-24 08:39:53 +0100264 } else if (IS_915(intel_get_drm_devid(fd))) {
Ville Syrjälä037bc692016-02-12 21:28:54 +0200265 *width_ret = 512;
266 *height_ret = 8;
267 } else {
268 *width_ret = 128;
269 *height_ret = 32;
270 }
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200271 break;
272 case LOCAL_I915_FORMAT_MOD_Yf_TILED:
Tomeu Vizoso85a1d452016-02-24 08:39:53 +0100273 igt_require_intel(fd);
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200274 switch (fb_bpp) {
275 case 8:
276 *width_ret = 64;
277 *height_ret = 64;
278 break;
279 case 16:
280 case 32:
281 *width_ret = 128;
282 *height_ret = 32;
283 break;
284 case 64:
285 case 128:
286 *width_ret = 256;
287 *height_ret = 16;
288 break;
289 default:
290 igt_assert(false);
291 }
292 break;
293 default:
294 igt_assert(false);
295 }
296}
297
Ville Syrjälä22383612018-07-17 18:32:38 +0300298static unsigned fb_plane_width(const struct igt_fb *fb, int plane)
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100299{
Maxime Ripard915c58a2019-01-25 15:58:30 +0100300 const struct format_desc_struct *format = lookup_drm_format(fb->drm_format);
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100301
Maxime Ripard915c58a2019-01-25 15:58:30 +0100302 if (plane == 0)
303 return fb->width;
304
305 return DIV_ROUND_UP(fb->width, format->hsub);
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100306}
307
Ville Syrjälä22383612018-07-17 18:32:38 +0300308static unsigned fb_plane_bpp(const struct igt_fb *fb, int plane)
Ville Syrjälä72bf5972018-07-17 18:11:40 +0300309{
Ville Syrjälä22383612018-07-17 18:32:38 +0300310 const struct format_desc_struct *format = lookup_drm_format(fb->drm_format);
311
Ville Syrjälä72bf5972018-07-17 18:11:40 +0300312 return format->plane_bpp[plane];
313}
314
Ville Syrjälä22383612018-07-17 18:32:38 +0300315static unsigned fb_plane_height(const struct igt_fb *fb, int plane)
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100316{
Maxime Ripard915c58a2019-01-25 15:58:30 +0100317 const struct format_desc_struct *format = lookup_drm_format(fb->drm_format);
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100318
Maxime Ripard915c58a2019-01-25 15:58:30 +0100319 if (plane == 0)
320 return fb->height;
321
322 return DIV_ROUND_UP(fb->height, format->vsub);
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100323}
324
Ville Syrjälä22383612018-07-17 18:32:38 +0300325static int fb_num_planes(const struct igt_fb *fb)
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100326{
Ville Syrjälä22383612018-07-17 18:32:38 +0300327 const struct format_desc_struct *format = lookup_drm_format(fb->drm_format);
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100328
Ville Syrjäläb7298a72018-07-17 18:25:34 +0300329 return format->num_planes;
330}
331
Ville Syrjälä22383612018-07-17 18:32:38 +0300332static void fb_init(struct igt_fb *fb,
333 int fd, int width, int height,
334 uint32_t drm_format,
335 uint64_t modifier,
336 enum igt_color_encoding color_encoding,
337 enum igt_color_range color_range)
Ville Syrjäläc3edd792018-07-17 18:18:14 +0300338{
Ville Syrjälä22383612018-07-17 18:32:38 +0300339 const struct format_desc_struct *f = lookup_drm_format(drm_format);
Ville Syrjäläc3edd792018-07-17 18:18:14 +0300340
Ville Syrjälä22383612018-07-17 18:32:38 +0300341 igt_assert_f(f, "DRM format %08x not found\n", drm_format);
342
343 memset(fb, 0, sizeof(*fb));
344
345 fb->width = width;
346 fb->height = height;
347 fb->tiling = modifier;
348 fb->drm_format = drm_format;
349 fb->fd = fd;
350 fb->num_planes = fb_num_planes(fb);
351 fb->color_encoding = color_encoding;
352 fb->color_range = color_range;
353
354 for (int i = 0; i < fb->num_planes; i++) {
355 fb->plane_bpp[i] = fb_plane_bpp(fb, i);
356 fb->plane_height[i] = fb_plane_height(fb, i);
357 fb->plane_width[i] = fb_plane_width(fb, i);
358 }
359}
360
361static uint32_t calc_plane_stride(struct igt_fb *fb, int plane)
362{
363 uint32_t min_stride = fb->plane_width[plane] *
364 (fb->plane_bpp[plane] / 8);
365
366 if (fb->tiling != LOCAL_DRM_FORMAT_MOD_NONE &&
367 intel_gen(intel_get_drm_devid(fb->fd)) <= 3) {
Ville Syrjäläc3edd792018-07-17 18:18:14 +0300368 uint32_t stride;
369
370 /* Round the tiling up to the next power-of-two and the region
371 * up to the next pot fence size so that this works on all
372 * generations.
373 *
374 * This can still fail if the framebuffer is too large to be
375 * tiled. But then that failure is expected.
376 */
377
378 stride = max(min_stride, 512);
379 stride = roundup_power_of_two(stride);
380
381 return stride;
382 } else {
383 unsigned int tile_width, tile_height;
384
Ville Syrjälä22383612018-07-17 18:32:38 +0300385 igt_get_fb_tile_size(fb->fd, fb->tiling, fb->plane_bpp[plane],
Ville Syrjäläc3edd792018-07-17 18:18:14 +0300386 &tile_width, &tile_height);
387
388 return ALIGN(min_stride, tile_width);
389 }
390}
391
Ville Syrjälä22383612018-07-17 18:32:38 +0300392static uint64_t calc_plane_size(struct igt_fb *fb, int plane)
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100393{
Ville Syrjälä22383612018-07-17 18:32:38 +0300394 if (fb->tiling != LOCAL_DRM_FORMAT_MOD_NONE &&
395 intel_gen(intel_get_drm_devid(fb->fd)) <= 3) {
396 uint64_t min_size = (uint64_t) fb->strides[plane] *
397 fb->plane_height[plane];
Ville Syrjälä4d2598f2018-07-18 17:56:56 +0300398 uint64_t size;
399
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200400 /* Round the tiling up to the next power-of-two and the region
401 * up to the next pot fence size so that this works on all
402 * generations.
Daniel Vetter57d7db82014-03-26 09:06:11 +0100403 *
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200404 * This can still fail if the framebuffer is too large to be
405 * tiled. But then that failure is expected.
Daniel Vetter57d7db82014-03-26 09:06:11 +0100406 */
407
Ville Syrjälä4d2598f2018-07-18 17:56:56 +0300408 size = max(min_size, 1024*1024);
Ville Syrjälä20a7ead2018-09-07 22:12:26 +0300409 size = roundup_power_of_two(size);
Ville Syrjälä4d2598f2018-07-18 17:56:56 +0300410
411 return size;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100412 } else {
Ville Syrjäläc3edd792018-07-17 18:18:14 +0300413 unsigned int tile_width, tile_height;
414
Ville Syrjälä22383612018-07-17 18:32:38 +0300415 igt_get_fb_tile_size(fb->fd, fb->tiling, fb->plane_bpp[plane],
Ville Syrjäläc3edd792018-07-17 18:18:14 +0300416 &tile_width, &tile_height);
Ville Syrjälä94540e32018-07-18 21:17:05 +0300417
Ville Syrjälä22383612018-07-17 18:32:38 +0300418 return (uint64_t) fb->strides[plane] *
419 ALIGN(fb->plane_height[plane], tile_height);
Ville Syrjälä4d2598f2018-07-18 17:56:56 +0300420 }
421}
422
Ville Syrjälä22383612018-07-17 18:32:38 +0300423static uint64_t calc_fb_size(struct igt_fb *fb)
Ville Syrjälä4d2598f2018-07-18 17:56:56 +0300424{
425 uint64_t size = 0;
426 int plane;
427
Ville Syrjälä22383612018-07-17 18:32:38 +0300428 for (plane = 0; plane < fb->num_planes; plane++) {
429 /* respect the stride requested by the caller */
430 if (!fb->strides[plane])
431 fb->strides[plane] = calc_plane_stride(fb, plane);
Ville Syrjälä4d2598f2018-07-18 17:56:56 +0300432
Ville Syrjälä22383612018-07-17 18:32:38 +0300433 fb->offsets[plane] = size;
Ville Syrjälä4d2598f2018-07-18 17:56:56 +0300434
Ville Syrjälä22383612018-07-17 18:32:38 +0300435 size += calc_plane_size(fb, plane);
Ville Syrjälä4d2598f2018-07-18 17:56:56 +0300436 }
437
438 return size;
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200439}
440
Tomeu Vizosoae649632016-11-10 10:25:24 +0100441/**
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100442 * igt_calc_fb_size:
443 * @fd: the DRM file descriptor
444 * @width: width of the framebuffer in pixels
445 * @height: height of the framebuffer in pixels
446 * @format: drm fourcc pixel format code
447 * @tiling: tiling layout of the framebuffer (as framebuffer modifier)
448 * @size_ret: returned size for the framebuffer
449 * @stride_ret: returned stride for the framebuffer
450 *
451 * This function returns valid stride and size values for a framebuffer with the
452 * specified parameters.
453 */
454void 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 +0300455 uint64_t *size_ret, unsigned *stride_ret)
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100456{
Ville Syrjälä22383612018-07-17 18:32:38 +0300457 struct igt_fb fb;
Ville Syrjälä4d2598f2018-07-18 17:56:56 +0300458
Ville Syrjälä22383612018-07-17 18:32:38 +0300459 fb_init(&fb, fd, width, height, drm_format, tiling,
460 IGT_COLOR_YCBCR_BT709, IGT_COLOR_YCBCR_LIMITED_RANGE);
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100461
Ville Syrjälä22383612018-07-17 18:32:38 +0300462 fb.size = calc_fb_size(&fb);
463
464 if (size_ret)
465 *size_ret = fb.size;
466 if (stride_ret)
467 *stride_ret = fb.strides[0];
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100468}
469
470/**
Tomeu Vizosoae649632016-11-10 10:25:24 +0100471 * igt_fb_mod_to_tiling:
472 * @modifier: DRM framebuffer modifier
473 *
474 * This function converts a DRM framebuffer modifier to its corresponding
475 * tiling constant.
476 *
477 * Returns:
478 * A tiling constant
479 */
480uint64_t igt_fb_mod_to_tiling(uint64_t modifier)
481{
482 switch (modifier) {
483 case LOCAL_DRM_FORMAT_MOD_NONE:
484 return I915_TILING_NONE;
485 case LOCAL_I915_FORMAT_MOD_X_TILED:
486 return I915_TILING_X;
487 case LOCAL_I915_FORMAT_MOD_Y_TILED:
488 return I915_TILING_Y;
489 case LOCAL_I915_FORMAT_MOD_Yf_TILED:
490 return I915_TILING_Yf;
491 default:
492 igt_assert(0);
493 }
494}
495
Praveen Paneri4437e212017-07-18 22:52:57 +0530496/**
497 * igt_fb_tiling_to_mod:
498 * @tiling: DRM framebuffer tiling
499 *
500 * This function converts a DRM framebuffer tiling to its corresponding
501 * modifier constant.
502 *
503 * Returns:
504 * A modifier constant
505 */
506uint64_t igt_fb_tiling_to_mod(uint64_t tiling)
507{
508 switch (tiling) {
509 case I915_TILING_NONE:
510 return LOCAL_DRM_FORMAT_MOD_NONE;
511 case I915_TILING_X:
512 return LOCAL_I915_FORMAT_MOD_X_TILED;
513 case I915_TILING_Y:
514 return LOCAL_I915_FORMAT_MOD_Y_TILED;
515 case I915_TILING_Yf:
516 return LOCAL_I915_FORMAT_MOD_Yf_TILED;
517 default:
518 igt_assert(0);
519 }
520}
521
Maxime Ripard49e44e82019-01-25 15:58:33 +0100522static void clear_yuv_buffer(struct igt_fb *fb)
523{
524 bool full_range = fb->color_range == IGT_COLOR_YCBCR_FULL_RANGE;
525 void *ptr;
526
527 igt_assert(igt_format_is_yuv(fb->drm_format));
528
529 /* Ensure the framebuffer is preallocated */
530 ptr = igt_fb_map_buffer(fb->fd, fb);
531 igt_assert(*(uint32_t *)ptr == 0);
532
533 switch (fb->drm_format) {
534 case DRM_FORMAT_NV12:
535 memset(ptr + fb->offsets[0],
536 full_range ? 0x00 : 0x10,
537 fb->strides[0] * fb->plane_height[0]);
538 memset(ptr + fb->offsets[1],
539 0x80,
540 fb->strides[1] * fb->plane_height[1]);
541 break;
542 case DRM_FORMAT_XYUV8888:
543 wmemset(ptr + fb->offsets[0], full_range ? 0x00008080 : 0x00108080,
544 fb->strides[0] * fb->plane_height[0] / sizeof(wchar_t));
545 break;
546 case DRM_FORMAT_YUYV:
547 case DRM_FORMAT_YVYU:
548 wmemset(ptr + fb->offsets[0],
549 full_range ? 0x80008000 : 0x80108010,
550 fb->strides[0] * fb->plane_height[0] / sizeof(wchar_t));
551 break;
552 case DRM_FORMAT_UYVY:
553 case DRM_FORMAT_VYUY:
554 wmemset(ptr + fb->offsets[0],
555 full_range ? 0x00800080 : 0x10801080,
556 fb->strides[0] * fb->plane_height[0] / sizeof(wchar_t));
557 break;
558 }
559
560 igt_fb_unmap_buffer(fb, ptr);
561}
562
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200563/* helpers to create nice-looking framebuffers */
Ville Syrjälä22383612018-07-17 18:32:38 +0300564static int create_bo_for_fb(struct igt_fb *fb)
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200565{
Maxime Ripardd6e79072019-02-08 14:18:54 +0100566 const struct format_desc_struct *fmt = lookup_drm_format(fb->drm_format);
567 unsigned int bpp = 0;
568 unsigned int plane;
Maxime Ripard91c95152019-02-08 14:18:55 +0100569 unsigned *strides = &fb->strides[0];
Ville Syrjälä22383612018-07-17 18:32:38 +0300570 int fd = fb->fd;
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200571
Maxime Ripard270e8222019-02-08 14:18:57 +0100572 if (is_i915_device(fd) &&
573 (fb->tiling || fb->size || fb->strides[0] || igt_format_is_yuv(fb->drm_format))) {
Ville Syrjälä22383612018-07-17 18:32:38 +0300574 uint64_t size;
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100575
Ville Syrjälä22383612018-07-17 18:32:38 +0300576 size = calc_fb_size(fb);
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100577
Ville Syrjälä22383612018-07-17 18:32:38 +0300578 /* respect the size requested by the caller */
579 if (fb->size == 0)
580 fb->size = size;
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200581
Ville Syrjälä22383612018-07-17 18:32:38 +0300582 fb->is_dumb = false;
Maxime Ripard270e8222019-02-08 14:18:57 +0100583 fb->gem_handle = gem_create(fd, fb->size);
584 gem_set_tiling(fd, fb->gem_handle,
585 igt_fb_mod_to_tiling(fb->tiling),
586 fb->strides[0]);
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200587
Maxime Ripard270e8222019-02-08 14:18:57 +0100588 goto out;
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200589 }
Maxime Ripardad6e1db2019-02-08 14:18:52 +0100590
Maxime Ripard77c6f0a2019-02-08 14:18:53 +0100591 /*
592 * The current dumb buffer allocation API doesn't really allow to
593 * specify a custom size or stride. Yet the caller is free to specify
594 * them, so we need to make sure to error out in this case.
595 */
596 igt_assert(fb->size == 0);
597 igt_assert(fb->strides[0] == 0);
598
599 fb->size = calc_fb_size(fb);
Maxime Ripardd6e79072019-02-08 14:18:54 +0100600 for (plane = 0; plane < fb->num_planes; plane++)
601 bpp += DIV_ROUND_UP(fb->plane_bpp[plane],
602 plane ? fmt->hsub * fmt->vsub : 1);
Maxime Ripard77c6f0a2019-02-08 14:18:53 +0100603
Maxime Ripardad6e1db2019-02-08 14:18:52 +0100604 fb->is_dumb = true;
Maxime Ripard91c95152019-02-08 14:18:55 +0100605
606 /*
607 * We can't really pass the stride array here since the dumb
608 * buffer allocation is assuming that it operates on one
609 * plane, and therefore will calculate the stride as if each
610 * pixel was stored on a single plane.
611 *
612 * This might cause issues at some point on drivers that would
613 * change the stride of YUV buffers, but we haven't
614 * encountered any yet.
615 */
616 if (fb->num_planes > 1)
617 strides = NULL;
618
Maxime Ripardad6e1db2019-02-08 14:18:52 +0100619 fb->gem_handle = kmstest_dumb_create(fd, fb->width, fb->height,
Maxime Ripard91c95152019-02-08 14:18:55 +0100620 bpp, strides, &fb->size);
Maxime Ripardad6e1db2019-02-08 14:18:52 +0100621
Maxime Ripard270e8222019-02-08 14:18:57 +0100622out:
Maxime Ripard062508c2019-02-08 14:18:56 +0100623 if (igt_format_is_yuv(fb->drm_format))
624 clear_yuv_buffer(fb);
625
Maxime Ripardad6e1db2019-02-08 14:18:52 +0100626 return fb->gem_handle;
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200627}
628
Tomeu Vizoso8a1a3862016-02-24 09:04:04 +0100629/**
630 * igt_create_bo_with_dimensions:
631 * @fd: open drm file descriptor
632 * @width: width of the buffer object in pixels
633 * @height: height of the buffer object in pixels
634 * @format: drm fourcc pixel format code
635 * @modifier: modifier corresponding to the tiling layout of the buffer object
636 * @stride: stride of the buffer object in bytes (0 for automatic stride)
637 * @size_ret: size of the buffer object as created by the kernel
638 * @stride_ret: stride of the buffer object as created by the kernel
639 * @is_dumb: whether the created buffer object is a dumb buffer or not
640 *
641 * This function allocates a gem buffer object matching the requested
642 * properties.
643 *
644 * Returns:
645 * The kms id of the created buffer object.
646 */
647int igt_create_bo_with_dimensions(int fd, int width, int height,
648 uint32_t format, uint64_t modifier,
Ville Syrjälä5f8a33a2018-09-06 16:34:15 +0300649 unsigned stride, uint64_t *size_ret,
Tomeu Vizoso8a1a3862016-02-24 09:04:04 +0100650 unsigned *stride_ret, bool *is_dumb)
651{
Ville Syrjälä22383612018-07-17 18:32:38 +0300652 struct igt_fb fb;
653
654 fb_init(&fb, fd, width, height, format, modifier,
655 IGT_COLOR_YCBCR_BT709, IGT_COLOR_YCBCR_LIMITED_RANGE);
656
657 for (int i = 0; i < fb.num_planes; i++)
658 fb.strides[i] = stride;
659
660 create_bo_for_fb(&fb);
661
662 if (size_ret)
663 *size_ret = fb.size;
664 if (stride_ret)
665 *stride_ret = fb.strides[0];
666 if (is_dumb)
667 *is_dumb = fb.is_dumb;
668
669 return fb.gem_handle;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100670}
671
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100672/**
673 * igt_paint_color:
674 * @cr: cairo drawing context
675 * @x: pixel x-coordination of the fill rectangle
676 * @y: pixel y-coordination of the fill rectangle
677 * @w: width of the fill rectangle
678 * @h: height of the fill rectangle
679 * @r: red value to use as fill color
Thomas Woodd01ebbd2015-06-29 16:47:14 +0100680 * @g: green value to use as fill color
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100681 * @b: blue value to use as fill color
682 *
683 * This functions draws a solid rectangle with the given color using the drawing
684 * context @cr.
685 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100686void igt_paint_color(cairo_t *cr, int x, int y, int w, int h,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100687 double r, double g, double b)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100688{
689 cairo_rectangle(cr, x, y, w, h);
690 cairo_set_source_rgb(cr, r, g, b);
691 cairo_fill(cr);
692}
693
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100694/**
695 * igt_paint_color_alpha:
696 * @cr: cairo drawing context
697 * @x: pixel x-coordination of the fill rectangle
698 * @y: pixel y-coordination of the fill rectangle
699 * @w: width of the fill rectangle
700 * @h: height of the fill rectangle
701 * @r: red value to use as fill color
Thomas Woodd01ebbd2015-06-29 16:47:14 +0100702 * @g: green value to use as fill color
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100703 * @b: blue value to use as fill color
704 * @a: alpha value to use as fill color
705 *
706 * This functions draws a rectangle with the given color and alpha values using
707 * the drawing context @cr.
708 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100709void igt_paint_color_alpha(cairo_t *cr, int x, int y, int w, int h,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100710 double r, double g, double b, double a)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100711{
712 cairo_rectangle(cr, x, y, w, h);
713 cairo_set_source_rgba(cr, r, g, b, a);
714 cairo_fill(cr);
715}
716
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100717/**
718 * igt_paint_color_gradient:
719 * @cr: cairo drawing context
720 * @x: pixel x-coordination of the fill rectangle
721 * @y: pixel y-coordination of the fill rectangle
722 * @w: width of the fill rectangle
723 * @h: height of the fill rectangle
724 * @r: red value to use as fill color
Thomas Woodd01ebbd2015-06-29 16:47:14 +0100725 * @g: green value to use as fill color
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100726 * @b: blue value to use as fill color
727 *
728 * This functions draws a gradient into the rectangle which fades in from black
729 * to the given values using the drawing context @cr.
730 */
Daniel Vetter57d7db82014-03-26 09:06:11 +0100731void
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100732igt_paint_color_gradient(cairo_t *cr, int x, int y, int w, int h,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100733 int r, int g, int b)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100734{
735 cairo_pattern_t *pat;
736
737 pat = cairo_pattern_create_linear(x, y, x + w, y + h);
738 cairo_pattern_add_color_stop_rgba(pat, 1, 0, 0, 0, 1);
739 cairo_pattern_add_color_stop_rgba(pat, 0, r, g, b, 1);
740
741 cairo_rectangle(cr, x, y, w, h);
742 cairo_set_source(cr, pat);
743 cairo_fill(cr);
744 cairo_pattern_destroy(pat);
745}
746
Lionel Landwerlina5113102016-03-18 17:33:02 +0000747/**
748 * igt_paint_color_gradient_range:
749 * @cr: cairo drawing context
750 * @x: pixel x-coordination of the fill rectangle
751 * @y: pixel y-coordination of the fill rectangle
752 * @w: width of the fill rectangle
753 * @h: height of the fill rectangle
754 * @sr: red value to use as start gradient color
755 * @sg: green value to use as start gradient color
756 * @sb: blue value to use as start gradient color
757 * @er: red value to use as end gradient color
758 * @eg: green value to use as end gradient color
759 * @eb: blue value to use as end gradient color
760 *
761 * This functions draws a gradient into the rectangle which fades in
762 * from one color to the other using the drawing context @cr.
763 */
764void
765igt_paint_color_gradient_range(cairo_t *cr, int x, int y, int w, int h,
766 double sr, double sg, double sb,
767 double er, double eg, double eb)
768{
769 cairo_pattern_t *pat;
770
771 pat = cairo_pattern_create_linear(x, y, x + w, y + h);
772 cairo_pattern_add_color_stop_rgba(pat, 1, sr, sg, sb, 1);
773 cairo_pattern_add_color_stop_rgba(pat, 0, er, eg, eb, 1);
774
775 cairo_rectangle(cr, x, y, w, h);
776 cairo_set_source(cr, pat);
777 cairo_fill(cr);
778 cairo_pattern_destroy(pat);
779}
780
Daniel Vetter57d7db82014-03-26 09:06:11 +0100781static void
782paint_test_patterns(cairo_t *cr, int width, int height)
783{
784 double gr_height, gr_width;
785 int x, y;
786
787 y = height * 0.10;
788 gr_width = width * 0.75;
789 gr_height = height * 0.08;
790 x = (width / 2) - (gr_width / 2);
791
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100792 igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 1, 0, 0);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100793
794 y += gr_height;
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100795 igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 0, 1, 0);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100796
797 y += gr_height;
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100798 igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 0, 0, 1);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100799
800 y += gr_height;
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100801 igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 1, 1, 1);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100802}
803
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100804/**
805 * igt_cairo_printf_line:
806 * @cr: cairo drawing context
807 * @align: text alignment
808 * @yspacing: additional y-direction feed after this line
809 * @fmt: format string
810 * @...: optional arguments used in the format string
811 *
812 * This is a little helper to draw text onto framebuffers. All the initial setup
813 * (like setting the font size and the moving to the starting position) still
814 * needs to be done manually with explicit cairo calls on @cr.
815 *
816 * Returns:
817 * The width of the drawn text.
818 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100819int igt_cairo_printf_line(cairo_t *cr, enum igt_text_align align,
Daniel Vetter57d7db82014-03-26 09:06:11 +0100820 double yspacing, const char *fmt, ...)
821{
822 double x, y, xofs, yofs;
823 cairo_text_extents_t extents;
824 char *text;
825 va_list ap;
826 int ret;
827
828 va_start(ap, fmt);
829 ret = vasprintf(&text, fmt, ap);
830 igt_assert(ret >= 0);
831 va_end(ap);
832
833 cairo_text_extents(cr, text, &extents);
834
835 xofs = yofs = 0;
836 if (align & align_right)
837 xofs = -extents.width;
838 else if (align & align_hcenter)
839 xofs = -extents.width / 2;
840
841 if (align & align_top)
842 yofs = extents.height;
843 else if (align & align_vcenter)
844 yofs = extents.height / 2;
845
846 cairo_get_current_point(cr, &x, &y);
847 if (xofs || yofs)
848 cairo_rel_move_to(cr, xofs, yofs);
849
850 cairo_text_path(cr, text);
851 cairo_set_source_rgb(cr, 0, 0, 0);
852 cairo_stroke_preserve(cr);
853 cairo_set_source_rgb(cr, 1, 1, 1);
854 cairo_fill(cr);
855
856 cairo_move_to(cr, x, y + extents.height + yspacing);
857
858 free(text);
859
860 return extents.width;
861}
862
863static void
864paint_marker(cairo_t *cr, int x, int y)
865{
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100866 enum igt_text_align align;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100867 int xoff, yoff;
868
869 cairo_move_to(cr, x, y - 20);
870 cairo_line_to(cr, x, y + 20);
871 cairo_move_to(cr, x - 20, y);
872 cairo_line_to(cr, x + 20, y);
873 cairo_new_sub_path(cr);
874 cairo_arc(cr, x, y, 10, 0, M_PI * 2);
875 cairo_set_line_width(cr, 4);
876 cairo_set_source_rgb(cr, 0, 0, 0);
877 cairo_stroke_preserve(cr);
878 cairo_set_source_rgb(cr, 1, 1, 1);
879 cairo_set_line_width(cr, 2);
880 cairo_stroke(cr);
881
882 xoff = x ? -20 : 20;
883 align = x ? align_right : align_left;
884
885 yoff = y ? -20 : 20;
886 align |= y ? align_bottom : align_top;
887
888 cairo_move_to(cr, x + xoff, y + yoff);
889 cairo_set_font_size(cr, 18);
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100890 igt_cairo_printf_line(cr, align, 0, "(%d, %d)", x, y);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100891}
892
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100893/**
894 * igt_paint_test_pattern:
895 * @cr: cairo drawing context
896 * @width: width of the visible area
897 * @height: height of the visible area
898 *
899 * This functions draws an entire set of test patterns for the given visible
900 * area using the drawing context @cr. This is useful for manual visual
901 * inspection of displayed framebuffers.
902 *
903 * The test patterns include
904 * - corner markers to check for over/underscan and
905 * - a set of color and b/w gradients.
906 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100907void igt_paint_test_pattern(cairo_t *cr, int width, int height)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100908{
909 paint_test_patterns(cr, width, height);
910
911 cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
912
913 /* Paint corner markers */
914 paint_marker(cr, 0, 0);
915 paint_marker(cr, width, 0);
916 paint_marker(cr, 0, height);
917 paint_marker(cr, width, height);
918
919 igt_assert(!cairo_status(cr));
920}
921
Thomas Woodecb03262015-04-13 17:37:22 +0100922static cairo_status_t
923stdio_read_func(void *closure, unsigned char* data, unsigned int size)
924{
925 if (fread(data, 1, size, (FILE*)closure) != size)
926 return CAIRO_STATUS_READ_ERROR;
927
928 return CAIRO_STATUS_SUCCESS;
929}
930
Ville Syrjälä75f320c2017-09-21 15:39:23 +0300931cairo_surface_t *igt_cairo_image_surface_create_from_png(const char *filename)
932{
933 cairo_surface_t *image;
934 FILE *f;
935
936 f = igt_fopen_data(filename);
937 image = cairo_image_surface_create_from_png_stream(&stdio_read_func, f);
938 fclose(f);
939
940 return image;
941}
942
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100943/**
944 * igt_paint_image:
945 * @cr: cairo drawing context
946 * @filename: filename of the png image to draw
947 * @dst_x: pixel x-coordination of the destination rectangle
948 * @dst_y: pixel y-coordination of the destination rectangle
949 * @dst_width: width of the destination rectangle
950 * @dst_height: height of the destination rectangle
951 *
Thomas Woodecb03262015-04-13 17:37:22 +0100952 * This function can be used to draw a scaled version of the supplied png image,
953 * which is loaded from the package data directory.
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100954 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100955void igt_paint_image(cairo_t *cr, const char *filename,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100956 int dst_x, int dst_y, int dst_width, int dst_height)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100957{
958 cairo_surface_t *image;
959 int img_width, img_height;
960 double scale_x, scale_y;
961
Ville Syrjälä75f320c2017-09-21 15:39:23 +0300962 image = igt_cairo_image_surface_create_from_png(filename);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100963 igt_assert(cairo_surface_status(image) == CAIRO_STATUS_SUCCESS);
964
965 img_width = cairo_image_surface_get_width(image);
966 img_height = cairo_image_surface_get_height(image);
967
968 scale_x = (double)dst_width / img_width;
969 scale_y = (double)dst_height / img_height;
970
971 cairo_save(cr);
972
973 cairo_translate(cr, dst_x, dst_y);
974 cairo_scale(cr, scale_x, scale_y);
975 cairo_set_source_surface(cr, image, 0, 0);
976 cairo_paint(cr);
977
978 cairo_surface_destroy(image);
979
980 cairo_restore(cr);
981}
982
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100983/**
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100984 * igt_create_fb_with_bo_size:
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100985 * @fd: open i915 drm file descriptor
986 * @width: width of the framebuffer in pixel
987 * @height: height of the framebuffer in pixel
988 * @format: drm fourcc pixel format code
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000989 * @tiling: tiling layout of the framebuffer (as framebuffer modifier)
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100990 * @fb: pointer to an #igt_fb structure
Paulo Zanonicb7dd5d2015-11-05 16:18:55 -0200991 * @bo_size: size of the backing bo (0 for automatic size)
Paulo Zanonid6341372015-11-05 16:39:00 -0200992 * @bo_stride: stride of the backing bo (0 for automatic stride)
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100993 *
994 * This function allocates a gem buffer object suitable to back a framebuffer
995 * with the requested properties and then wraps it up in a drm framebuffer
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100996 * object of the requested size. All metadata is stored in @fb.
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100997 *
998 * The backing storage of the framebuffer is filled with all zeros, i.e. black
999 * for rgb pixel formats.
1000 *
1001 * Returns:
Damien Lespiau50166d22014-08-19 11:55:22 +01001002 * The kms id of the created framebuffer.
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001003 */
Damien Lespiau378e61e2014-06-23 14:53:24 +01001004unsigned int
1005igt_create_fb_with_bo_size(int fd, int width, int height,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +00001006 uint32_t format, uint64_t tiling,
Ville Syrjälä5f8a33a2018-09-06 16:34:15 +03001007 struct igt_fb *fb, uint64_t bo_size,
Paulo Zanonid6341372015-11-05 16:39:00 -02001008 unsigned bo_stride)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001009{
Ville Syrjäläb6975342018-03-06 20:01:22 +02001010 /* FIXME allow the caller to pass these in */
1011 enum igt_color_encoding color_encoding = IGT_COLOR_YCBCR_BT709;
1012 enum igt_color_range color_range = IGT_COLOR_YCBCR_LIMITED_RANGE;
Deepak Rawat759af702018-10-16 15:23:39 -07001013 uint32_t flags = 0;
Maarten Lankhorst918ea422018-01-19 12:47:11 +01001014
Ville Syrjälä22383612018-07-17 18:32:38 +03001015 fb_init(fb, fd, width, height, format, tiling,
1016 color_encoding, color_range);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001017
Ville Syrjälä22383612018-07-17 18:32:38 +03001018 for (int i = 0; i < fb->num_planes; i++)
1019 fb->strides[i] = bo_stride;
1020
1021 fb->size = bo_size;
Daniel Vetter57d7db82014-03-26 09:06:11 +01001022
Ville Syrjälä5f8a33a2018-09-06 16:34:15 +03001023 igt_debug("%s(width=%d, height=%d, format=0x%x, tiling=0x%"PRIx64", size=%"PRIu64")\n",
Tomeu Vizoso8a1a3862016-02-24 09:04:04 +01001024 __func__, width, height, format, tiling, bo_size);
Ville Syrjälä22383612018-07-17 18:32:38 +03001025
1026 create_bo_for_fb(fb);
Tomeu Vizoso7be235c2016-04-22 11:08:45 +02001027 igt_assert(fb->gem_handle > 0);
Chris Wilsondb4cc742014-09-06 12:07:49 +01001028
Chris Wilsondb4cc742014-09-06 12:07:49 +01001029 igt_debug("%s(handle=%d, pitch=%d)\n",
Ville Syrjälä22383612018-07-17 18:32:38 +03001030 __func__, fb->gem_handle, fb->strides[0]);
Tvrtko Ursulineb93c1b2015-03-03 14:11:03 +00001031
Deepak Rawat759af702018-10-16 15:23:39 -07001032 if (fb->tiling || igt_has_fb_modifiers(fd))
1033 flags = LOCAL_DRM_MODE_FB_MODIFIERS;
1034
Ville Syrjälä22383612018-07-17 18:32:38 +03001035 do_or_die(__kms_addfb(fb->fd, fb->gem_handle,
1036 fb->width, fb->height,
1037 fb->drm_format, fb->tiling,
Deepak Rawat759af702018-10-16 15:23:39 -07001038 fb->strides, fb->offsets, fb->num_planes, flags,
Ville Syrjälä22383612018-07-17 18:32:38 +03001039 &fb->fb_id));
Ville Syrjälä42359ed2018-07-17 18:50:13 +03001040
Ville Syrjälä22383612018-07-17 18:32:38 +03001041 return fb->fb_id;
Daniel Vetter57d7db82014-03-26 09:06:11 +01001042}
1043
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001044/**
Oscar Mateo5bdd4d92014-05-16 14:07:11 +01001045 * igt_create_fb:
1046 * @fd: open i915 drm file descriptor
1047 * @width: width of the framebuffer in pixel
1048 * @height: height of the framebuffer in pixel
1049 * @format: drm fourcc pixel format code
Damien Lespiau378e61e2014-06-23 14:53:24 +01001050 * @tiling: tiling layout of the framebuffer
Oscar Mateo5bdd4d92014-05-16 14:07:11 +01001051 * @fb: pointer to an #igt_fb structure
1052 *
1053 * This function allocates a gem buffer object suitable to back a framebuffer
1054 * with the requested properties and then wraps it up in a drm framebuffer
1055 * object. All metadata is stored in @fb.
1056 *
1057 * The backing storage of the framebuffer is filled with all zeros, i.e. black
1058 * for rgb pixel formats.
1059 *
1060 * Returns:
Damien Lespiau50166d22014-08-19 11:55:22 +01001061 * The kms id of the created framebuffer.
Oscar Mateo5bdd4d92014-05-16 14:07:11 +01001062 */
1063unsigned int igt_create_fb(int fd, int width, int height, uint32_t format,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +00001064 uint64_t tiling, struct igt_fb *fb)
Oscar Mateo5bdd4d92014-05-16 14:07:11 +01001065{
Paulo Zanonid6341372015-11-05 16:39:00 -02001066 return igt_create_fb_with_bo_size(fd, width, height, format, tiling, fb,
1067 0, 0);
Oscar Mateo5bdd4d92014-05-16 14:07:11 +01001068}
1069
1070/**
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001071 * igt_create_color_fb:
1072 * @fd: open i915 drm file descriptor
1073 * @width: width of the framebuffer in pixel
1074 * @height: height of the framebuffer in pixel
1075 * @format: drm fourcc pixel format code
Damien Lespiau378e61e2014-06-23 14:53:24 +01001076 * @tiling: tiling layout of the framebuffer
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001077 * @r: red value to use as fill color
Ville Syrjälä5b113d32015-12-17 01:39:31 +02001078 * @g: green value to use as fill color
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001079 * @b: blue value to use as fill color
1080 * @fb: pointer to an #igt_fb structure
1081 *
1082 * This function allocates a gem buffer object suitable to back a framebuffer
1083 * with the requested properties and then wraps it up in a drm framebuffer
1084 * object. All metadata is stored in @fb.
1085 *
1086 * Compared to igt_create_fb() this function also fills the entire framebuffer
1087 * with the given color, which is useful for some simple pipe crc based tests.
1088 *
1089 * Returns:
1090 * The kms id of the created framebuffer on success or a negative error code on
1091 * failure.
1092 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01001093unsigned int igt_create_color_fb(int fd, int width, int height,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +00001094 uint32_t format, uint64_t tiling,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001095 double r, double g, double b,
1096 struct igt_fb *fb /* out */)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001097{
1098 unsigned int fb_id;
1099 cairo_t *cr;
1100
Damien Lespiau378e61e2014-06-23 14:53:24 +01001101 fb_id = igt_create_fb(fd, width, height, format, tiling, fb);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001102 igt_assert(fb_id);
1103
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01001104 cr = igt_get_cairo_ctx(fd, fb);
1105 igt_paint_color(cr, 0, 0, width, height, r, g, b);
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +01001106 igt_put_cairo_ctx(fd, fb, cr);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001107
1108 return fb_id;
1109}
1110
Ville Syrjälä5b113d32015-12-17 01:39:31 +02001111/**
1112 * igt_create_pattern_fb:
1113 * @fd: open i915 drm file descriptor
1114 * @width: width of the framebuffer in pixel
1115 * @height: height of the framebuffer in pixel
1116 * @format: drm fourcc pixel format code
1117 * @tiling: tiling layout of the framebuffer
1118 * @fb: pointer to an #igt_fb structure
1119 *
1120 * This function allocates a gem buffer object suitable to back a framebuffer
1121 * with the requested properties and then wraps it up in a drm framebuffer
1122 * object. All metadata is stored in @fb.
1123 *
1124 * Compared to igt_create_fb() this function also draws the standard test pattern
1125 * into the framebuffer.
1126 *
1127 * Returns:
1128 * The kms id of the created framebuffer on success or a negative error code on
1129 * failure.
1130 */
1131unsigned int igt_create_pattern_fb(int fd, int width, int height,
1132 uint32_t format, uint64_t tiling,
1133 struct igt_fb *fb /* out */)
1134{
1135 unsigned int fb_id;
1136 cairo_t *cr;
1137
1138 fb_id = igt_create_fb(fd, width, height, format, tiling, fb);
1139 igt_assert(fb_id);
1140
1141 cr = igt_get_cairo_ctx(fd, fb);
1142 igt_paint_test_pattern(cr, width, height);
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +01001143 igt_put_cairo_ctx(fd, fb, cr);
Ville Syrjälä5b113d32015-12-17 01:39:31 +02001144
1145 return fb_id;
1146}
1147
1148/**
1149 * igt_create_color_pattern_fb:
1150 * @fd: open i915 drm file descriptor
1151 * @width: width of the framebuffer in pixel
1152 * @height: height of the framebuffer in pixel
1153 * @format: drm fourcc pixel format code
1154 * @tiling: tiling layout of the framebuffer
1155 * @r: red value to use as fill color
1156 * @g: green value to use as fill color
1157 * @b: blue value to use as fill color
1158 * @fb: pointer to an #igt_fb structure
1159 *
1160 * This function allocates a gem buffer object suitable to back a framebuffer
1161 * with the requested properties and then wraps it up in a drm framebuffer
1162 * object. All metadata is stored in @fb.
1163 *
1164 * Compared to igt_create_fb() this function also fills the entire framebuffer
1165 * with the given color, and then draws the standard test pattern into the
1166 * framebuffer.
1167 *
1168 * Returns:
1169 * The kms id of the created framebuffer on success or a negative error code on
1170 * failure.
1171 */
1172unsigned int igt_create_color_pattern_fb(int fd, int width, int height,
1173 uint32_t format, uint64_t tiling,
1174 double r, double g, double b,
1175 struct igt_fb *fb /* out */)
1176{
1177 unsigned int fb_id;
1178 cairo_t *cr;
1179
1180 fb_id = igt_create_fb(fd, width, height, format, tiling, fb);
1181 igt_assert(fb_id);
1182
1183 cr = igt_get_cairo_ctx(fd, fb);
1184 igt_paint_color(cr, 0, 0, width, height, r, g, b);
1185 igt_paint_test_pattern(cr, width, height);
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +01001186 igt_put_cairo_ctx(fd, fb, cr);
Ville Syrjälä5b113d32015-12-17 01:39:31 +02001187
1188 return fb_id;
1189}
1190
1191/**
1192 * igt_create_image_fb:
1193 * @drm_fd: open i915 drm file descriptor
1194 * @width: width of the framebuffer in pixel or 0
1195 * @height: height of the framebuffer in pixel or 0
1196 * @format: drm fourcc pixel format code
1197 * @tiling: tiling layout of the framebuffer
1198 * @filename: filename of the png image to draw
1199 * @fb: pointer to an #igt_fb structure
1200 *
1201 * Create a framebuffer with the specified image. If @width is zero the
1202 * image width will be used. If @height is zero the image height will be used.
1203 *
1204 * Returns:
1205 * The kms id of the created framebuffer on success or a negative error code on
1206 * failure.
1207 */
1208unsigned int igt_create_image_fb(int fd, int width, int height,
1209 uint32_t format, uint64_t tiling,
1210 const char *filename,
1211 struct igt_fb *fb /* out */)
1212{
1213 cairo_surface_t *image;
1214 uint32_t fb_id;
1215 cairo_t *cr;
1216
Ville Syrjälä75f320c2017-09-21 15:39:23 +03001217 image = igt_cairo_image_surface_create_from_png(filename);
Ville Syrjälä5b113d32015-12-17 01:39:31 +02001218 igt_assert(cairo_surface_status(image) == CAIRO_STATUS_SUCCESS);
1219 if (width == 0)
1220 width = cairo_image_surface_get_width(image);
1221 if (height == 0)
1222 height = cairo_image_surface_get_height(image);
1223 cairo_surface_destroy(image);
1224
1225 fb_id = igt_create_fb(fd, width, height, format, tiling, fb);
1226
1227 cr = igt_get_cairo_ctx(fd, fb);
1228 igt_paint_image(cr, filename, 0, 0, width, height);
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +01001229 igt_put_cairo_ctx(fd, fb, cr);
Ville Syrjälä5b113d32015-12-17 01:39:31 +02001230
1231 return fb_id;
1232}
1233
Thomas Wood4cb19462014-08-04 16:14:51 +01001234struct box {
1235 int x, y, width, height;
1236};
1237
1238struct stereo_fb_layout {
1239 int fb_width, fb_height;
1240 struct box left, right;
1241};
1242
1243static void box_init(struct box *box, int x, int y, int bwidth, int bheight)
1244{
1245 box->x = x;
1246 box->y = y;
1247 box->width = bwidth;
1248 box->height = bheight;
1249}
1250
1251
1252static void stereo_fb_layout_from_mode(struct stereo_fb_layout *layout,
1253 drmModeModeInfo *mode)
1254{
1255 unsigned int format = mode->flags & DRM_MODE_FLAG_3D_MASK;
1256 const int hdisplay = mode->hdisplay, vdisplay = mode->vdisplay;
1257 int middle;
1258
1259 switch (format) {
1260 case DRM_MODE_FLAG_3D_TOP_AND_BOTTOM:
1261 layout->fb_width = hdisplay;
1262 layout->fb_height = vdisplay;
1263
1264 middle = vdisplay / 2;
1265 box_init(&layout->left, 0, 0, hdisplay, middle);
1266 box_init(&layout->right,
1267 0, middle, hdisplay, vdisplay - middle);
1268 break;
1269 case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF:
1270 layout->fb_width = hdisplay;
1271 layout->fb_height = vdisplay;
1272
1273 middle = hdisplay / 2;
1274 box_init(&layout->left, 0, 0, middle, vdisplay);
1275 box_init(&layout->right,
1276 middle, 0, hdisplay - middle, vdisplay);
1277 break;
1278 case DRM_MODE_FLAG_3D_FRAME_PACKING:
1279 {
1280 int vactive_space = mode->vtotal - vdisplay;
1281
1282 layout->fb_width = hdisplay;
1283 layout->fb_height = 2 * vdisplay + vactive_space;
1284
1285 box_init(&layout->left,
1286 0, 0, hdisplay, vdisplay);
1287 box_init(&layout->right,
1288 0, vdisplay + vactive_space, hdisplay, vdisplay);
1289 break;
1290 }
1291 default:
1292 igt_assert(0);
1293 }
1294}
1295
1296/**
1297 * igt_create_stereo_fb:
1298 * @drm_fd: open i915 drm file descriptor
1299 * @mode: A stereo 3D mode.
1300 * @format: drm fourcc pixel format code
1301 * @tiling: tiling layout of the framebuffer
1302 *
1303 * Create a framebuffer for use with the stereo 3D mode specified by @mode.
1304 *
1305 * Returns:
1306 * The kms id of the created framebuffer on success or a negative error code on
1307 * failure.
1308 */
1309unsigned int igt_create_stereo_fb(int drm_fd, drmModeModeInfo *mode,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +00001310 uint32_t format, uint64_t tiling)
Thomas Wood4cb19462014-08-04 16:14:51 +01001311{
1312 struct stereo_fb_layout layout;
1313 cairo_t *cr;
1314 uint32_t fb_id;
1315 struct igt_fb fb;
1316
1317 stereo_fb_layout_from_mode(&layout, mode);
1318 fb_id = igt_create_fb(drm_fd, layout.fb_width, layout.fb_height, format,
1319 tiling, &fb);
1320 cr = igt_get_cairo_ctx(drm_fd, &fb);
1321
Thomas Woodecb03262015-04-13 17:37:22 +01001322 igt_paint_image(cr, "1080p-left.png",
Thomas Wood4cb19462014-08-04 16:14:51 +01001323 layout.left.x, layout.left.y,
1324 layout.left.width, layout.left.height);
Thomas Woodecb03262015-04-13 17:37:22 +01001325 igt_paint_image(cr, "1080p-right.png",
Thomas Wood4cb19462014-08-04 16:14:51 +01001326 layout.right.x, layout.right.y,
1327 layout.right.width, layout.right.height);
1328
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +01001329 igt_put_cairo_ctx(drm_fd, &fb, cr);
Thomas Wood4cb19462014-08-04 16:14:51 +01001330
1331 return fb_id;
1332}
1333
Maxime Ripard3fa65f42018-10-04 14:39:03 +02001334static pixman_format_code_t drm_format_to_pixman(uint32_t drm_format)
1335{
1336 const struct format_desc_struct *f;
1337
1338 for_each_format(f)
1339 if (f->drm_id == drm_format)
1340 return f->pixman_id;
1341
1342 igt_assert_f(0, "can't find a pixman format for %08x (%s)\n",
1343 drm_format, igt_format_str(drm_format));
1344}
1345
Daniel Vetter57d7db82014-03-26 09:06:11 +01001346static cairo_format_t drm_format_to_cairo(uint32_t drm_format)
1347{
Ville Syrjäläef43fce2018-07-18 20:26:22 +03001348 const struct format_desc_struct *f;
Daniel Vetter57d7db82014-03-26 09:06:11 +01001349
1350 for_each_format(f)
1351 if (f->drm_id == drm_format)
1352 return f->cairo_id;
1353
Damien Lespiau54397ca2014-08-19 11:40:07 +01001354 igt_assert_f(0, "can't find a cairo format for %08x (%s)\n",
1355 drm_format, igt_format_str(drm_format));
Daniel Vetter57d7db82014-03-26 09:06:11 +01001356}
1357
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001358struct fb_blit_linear {
Ville Syrjälä22383612018-07-17 18:32:38 +03001359 struct igt_fb fb;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001360 uint8_t *map;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001361};
1362
Damien Lespiauff451a62015-03-03 14:11:04 +00001363struct fb_blit_upload {
1364 int fd;
1365 struct igt_fb *fb;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001366 struct fb_blit_linear linear;
Damien Lespiauff451a62015-03-03 14:11:04 +00001367};
1368
Ville Syrjälä6f5d6b02018-07-18 20:11:52 +03001369static void blitcopy(const struct igt_fb *dst_fb,
1370 const struct igt_fb *src_fb)
1371{
1372 igt_assert_eq(dst_fb->fd, src_fb->fd);
1373 igt_assert_eq(dst_fb->num_planes, src_fb->num_planes);
1374
1375 for (int i = 0; i < dst_fb->num_planes; i++) {
1376 igt_assert_eq(dst_fb->plane_bpp[i], src_fb->plane_bpp[i]);
1377 igt_assert_eq(dst_fb->plane_width[i], src_fb->plane_width[i]);
1378 igt_assert_eq(dst_fb->plane_height[i], src_fb->plane_height[i]);
1379
1380 igt_blitter_fast_copy__raw(dst_fb->fd,
1381 src_fb->gem_handle,
1382 src_fb->offsets[i],
1383 src_fb->strides[i],
1384 igt_fb_mod_to_tiling(src_fb->tiling),
1385 0, 0, /* src_x, src_y */
1386 dst_fb->plane_width[i], dst_fb->plane_height[i],
1387 dst_fb->plane_bpp[i],
1388 dst_fb->gem_handle,
1389 dst_fb->offsets[i],
1390 dst_fb->strides[i],
1391 igt_fb_mod_to_tiling(dst_fb->tiling),
1392 0, 0 /* dst_x, dst_y */);
1393 }
1394}
1395
Ville Syrjälä74261fd2018-07-17 16:20:34 +03001396static void free_linear_mapping(struct fb_blit_upload *blit)
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001397{
Ville Syrjälä74261fd2018-07-17 16:20:34 +03001398 int fd = blit->fd;
1399 struct igt_fb *fb = blit->fb;
1400 struct fb_blit_linear *linear = &blit->linear;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001401
Ville Syrjälä22383612018-07-17 18:32:38 +03001402 gem_munmap(linear->map, linear->fb.size);
1403 gem_set_domain(fd, linear->fb.gem_handle,
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001404 I915_GEM_DOMAIN_GTT, 0);
1405
Ville Syrjälä6f5d6b02018-07-18 20:11:52 +03001406 blitcopy(fb, &linear->fb);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001407
Ville Syrjälä22383612018-07-17 18:32:38 +03001408 gem_sync(fd, linear->fb.gem_handle);
1409 gem_close(fd, linear->fb.gem_handle);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001410}
1411
Damien Lespiauff451a62015-03-03 14:11:04 +00001412static void destroy_cairo_surface__blit(void *arg)
1413{
1414 struct fb_blit_upload *blit = arg;
Damien Lespiauff451a62015-03-03 14:11:04 +00001415
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001416 blit->fb->cairo_surface = NULL;
Damien Lespiauff451a62015-03-03 14:11:04 +00001417
Ville Syrjälä74261fd2018-07-17 16:20:34 +03001418 free_linear_mapping(blit);
Damien Lespiauff451a62015-03-03 14:11:04 +00001419
1420 free(blit);
1421}
1422
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001423static void setup_linear_mapping(int fd, struct igt_fb *fb, struct fb_blit_linear *linear)
Damien Lespiauff451a62015-03-03 14:11:04 +00001424{
Damien Lespiauff451a62015-03-03 14:11:04 +00001425 /*
1426 * We create a linear BO that we'll map for the CPU to write to (using
1427 * cairo). This linear bo will be then blitted to its final
1428 * destination, tiling it at the same time.
1429 */
Damien Lespiauff451a62015-03-03 14:11:04 +00001430
Ville Syrjälä22383612018-07-17 18:32:38 +03001431 fb_init(&linear->fb, fb->fd, fb->width, fb->height,
1432 fb->drm_format, LOCAL_DRM_FORMAT_MOD_NONE,
1433 fb->color_encoding, fb->color_range);
1434
1435 create_bo_for_fb(&linear->fb);
1436
1437 igt_assert(linear->fb.gem_handle > 0);
Tvrtko Ursulin30a13602015-04-29 13:24:34 +01001438
1439 /* Copy fb content to linear BO */
Ville Syrjälä22383612018-07-17 18:32:38 +03001440 gem_set_domain(fd, linear->fb.gem_handle,
Tvrtko Ursulin30a13602015-04-29 13:24:34 +01001441 I915_GEM_DOMAIN_GTT, 0);
1442
Ville Syrjälä6f5d6b02018-07-18 20:11:52 +03001443 blitcopy(&linear->fb, fb);
Tvrtko Ursulin30a13602015-04-29 13:24:34 +01001444
Ville Syrjälä22383612018-07-17 18:32:38 +03001445 gem_sync(fd, linear->fb.gem_handle);
Tvrtko Ursulin30a13602015-04-29 13:24:34 +01001446
Ville Syrjälä22383612018-07-17 18:32:38 +03001447 gem_set_domain(fd, linear->fb.gem_handle,
Tvrtko Ursulin30a13602015-04-29 13:24:34 +01001448 I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
1449
1450 /* Setup cairo context */
Ville Syrjälä22383612018-07-17 18:32:38 +03001451 linear->map = gem_mmap__cpu(fd, linear->fb.gem_handle,
1452 0, linear->fb.size, PROT_READ | PROT_WRITE);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001453}
1454
1455static void create_cairo_surface__blit(int fd, struct igt_fb *fb)
1456{
1457 struct fb_blit_upload *blit;
1458 cairo_format_t cairo_format;
1459
1460 blit = malloc(sizeof(*blit));
1461 igt_assert(blit);
1462
1463 blit->fd = fd;
1464 blit->fb = fb;
1465 setup_linear_mapping(fd, fb, &blit->linear);
Damien Lespiauff451a62015-03-03 14:11:04 +00001466
Damien Lespiauff451a62015-03-03 14:11:04 +00001467 cairo_format = drm_format_to_cairo(fb->drm_format);
1468 fb->cairo_surface =
1469 cairo_image_surface_create_for_data(blit->linear.map,
1470 cairo_format,
1471 fb->width, fb->height,
Ville Syrjälä22383612018-07-17 18:32:38 +03001472 blit->linear.fb.strides[0]);
Chris Wilson18d0b1e2016-03-02 14:12:12 +00001473 fb->domain = I915_GEM_DOMAIN_GTT;
Damien Lespiauff451a62015-03-03 14:11:04 +00001474
1475 cairo_surface_set_user_data(fb->cairo_surface,
1476 (cairo_user_data_key_t *)create_cairo_surface__blit,
1477 blit, destroy_cairo_surface__blit);
1478}
1479
Tomeu Vizosoa2d5b342016-03-07 16:25:43 +01001480/**
1481 * igt_dirty_fb:
1482 * @fd: open drm file descriptor
1483 * @fb: pointer to an #igt_fb structure
1484 *
1485 * Flushes out the whole framebuffer.
1486 *
1487 * Returns: 0 upon success.
1488 */
1489int igt_dirty_fb(int fd, struct igt_fb *fb)
1490{
1491 return drmModeDirtyFB(fb->fd, fb->fb_id, NULL, 0);
1492}
1493
Maxime Ripard3415b192018-10-04 14:38:54 +02001494static void unmap_bo(struct igt_fb *fb, void *ptr)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001495{
Maxime Ripard3415b192018-10-04 14:38:54 +02001496 gem_munmap(ptr, fb->size);
Tomeu Vizoso89b3ffe2016-02-24 09:04:41 +01001497
1498 if (fb->is_dumb)
1499 igt_dirty_fb(fb->fd, fb);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001500}
1501
Maxime Ripard3415b192018-10-04 14:38:54 +02001502static void destroy_cairo_surface__gtt(void *arg)
1503{
1504 struct igt_fb *fb = arg;
1505
1506 unmap_bo(fb, cairo_image_surface_get_data(fb->cairo_surface));
1507 fb->cairo_surface = NULL;
1508}
1509
1510static void *map_bo(int fd, struct igt_fb *fb)
Damien Lespiau4aadbc82014-06-23 16:41:43 +01001511{
Tomeu Vizoso89b3ffe2016-02-24 09:04:41 +01001512 void *ptr;
1513
Maxime Ripard80bb4432018-10-04 14:38:55 +02001514 if (is_i915_device(fd))
1515 gem_set_domain(fd, fb->gem_handle,
1516 I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
Ville Syrjälä3bd68522018-09-05 19:55:43 +03001517
Tomeu Vizoso89b3ffe2016-02-24 09:04:41 +01001518 if (fb->is_dumb)
1519 ptr = kmstest_dumb_map_buffer(fd, fb->gem_handle, fb->size,
1520 PROT_READ | PROT_WRITE);
1521 else
1522 ptr = gem_mmap__gtt(fd, fb->gem_handle, fb->size,
1523 PROT_READ | PROT_WRITE);
Ville Syrjälä106fe212015-10-09 18:36:24 +03001524
Maxime Ripard3415b192018-10-04 14:38:54 +02001525 return ptr;
1526}
1527
1528static void create_cairo_surface__gtt(int fd, struct igt_fb *fb)
1529{
1530 void *ptr = map_bo(fd, fb);
1531
Damien Lespiau4aadbc82014-06-23 16:41:43 +01001532 fb->cairo_surface =
Ville Syrjälä106fe212015-10-09 18:36:24 +03001533 cairo_image_surface_create_for_data(ptr,
Damien Lespiau4aadbc82014-06-23 16:41:43 +01001534 drm_format_to_cairo(fb->drm_format),
Ville Syrjälä22383612018-07-17 18:32:38 +03001535 fb->width, fb->height, fb->strides[0]);
Deepak Rawatc7034c72018-10-16 15:23:38 -07001536 igt_require_f(cairo_surface_status(fb->cairo_surface) == CAIRO_STATUS_SUCCESS,
1537 "Unable to create a cairo surface: %s\n",
1538 cairo_status_to_string(cairo_surface_status(fb->cairo_surface)));
1539
Chris Wilson18d0b1e2016-03-02 14:12:12 +00001540 fb->domain = I915_GEM_DOMAIN_GTT;
Damien Lespiau4aadbc82014-06-23 16:41:43 +01001541
1542 cairo_surface_set_user_data(fb->cairo_surface,
1543 (cairo_user_data_key_t *)create_cairo_surface__gtt,
1544 fb, destroy_cairo_surface__gtt);
1545}
1546
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001547struct fb_convert_blit_upload {
Ville Syrjälä3ed2a602018-07-17 16:15:34 +03001548 struct fb_blit_upload base;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001549
Maxime Ripardc7128362018-10-04 14:38:57 +02001550 struct igt_fb shadow_fb;
1551 uint8_t *shadow_ptr;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001552};
1553
Maxime Ripardc7128362018-10-04 14:38:57 +02001554static void *igt_fb_create_cairo_shadow_buffer(int fd,
1555 unsigned int width,
1556 unsigned int height,
1557 struct igt_fb *shadow)
1558{
1559 void *ptr;
1560
1561 igt_assert(shadow);
1562
1563 fb_init(shadow, fd, width, height,
Ville Syrjäläe5eb1402018-11-01 22:26:47 +02001564 DRM_FORMAT_XRGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
Maxime Ripardc7128362018-10-04 14:38:57 +02001565 IGT_COLOR_YCBCR_BT709, IGT_COLOR_YCBCR_LIMITED_RANGE);
1566
Maarten Lankhorstb0033d92018-06-07 16:25:22 +02001567 shadow->strides[0] = ALIGN(width * shadow->plane_bpp[0], 16);
Maxime Ripardc7128362018-10-04 14:38:57 +02001568 shadow->size = ALIGN(shadow->strides[0] * height,
1569 sysconf(_SC_PAGESIZE));
1570 ptr = mmap(NULL, shadow->size, PROT_READ | PROT_WRITE,
1571 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
1572 igt_assert(ptr != MAP_FAILED);
1573
1574 return ptr;
1575}
1576
1577static void igt_fb_destroy_cairo_shadow_buffer(struct igt_fb *shadow,
1578 void *ptr)
1579{
1580 munmap(ptr, shadow->size);
1581}
1582
Ville Syrjäläee26fef2018-02-27 22:38:05 +02001583static uint8_t clamprgb(float val)
1584{
Ville Syrjäläd1a93aa2018-06-06 20:36:44 +03001585 return clamp((int)(val + 0.5f), 0, 255);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001586}
1587
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001588static void read_rgb(struct igt_vec4 *rgb, const uint8_t *rgb24)
1589{
1590 rgb->d[0] = rgb24[2];
1591 rgb->d[1] = rgb24[1];
1592 rgb->d[2] = rgb24[0];
1593 rgb->d[3] = 1.0f;
1594}
1595
1596static void write_rgb(uint8_t *rgb24, const struct igt_vec4 *rgb)
1597{
1598 rgb24[2] = clamprgb(rgb->d[0]);
1599 rgb24[1] = clamprgb(rgb->d[1]);
1600 rgb24[0] = clamprgb(rgb->d[2]);
1601}
1602
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001603struct fb_convert_buf {
1604 void *ptr;
1605 struct igt_fb *fb;
Ville Syrjälä737241d2018-11-01 23:31:20 +02001606 bool slow_reads;
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001607};
1608
1609struct fb_convert {
1610 struct fb_convert_buf dst;
1611 struct fb_convert_buf src;
1612};
1613
Ville Syrjälä737241d2018-11-01 23:31:20 +02001614static void *convert_src_get(const struct fb_convert *cvt)
1615{
1616 void *buf;
1617
1618 if (!cvt->src.slow_reads)
1619 return cvt->src.ptr;
1620
1621 /*
1622 * Reading from the BO is awfully slow because of lack of read caching,
1623 * it's faster to copy the whole BO to a temporary buffer and convert
1624 * from there.
1625 */
1626 buf = malloc(cvt->src.fb->size);
1627 if (!buf)
1628 return cvt->src.ptr;
1629
1630 igt_memcpy_from_wc(buf, cvt->src.ptr, cvt->src.fb->size);
1631
1632 return buf;
1633}
1634
1635static void convert_src_put(const struct fb_convert *cvt,
1636 void *src_buf)
1637{
1638 if (src_buf != cvt->src.ptr)
1639 free(src_buf);
1640}
1641
Maxime Ripardde449842019-01-25 15:58:32 +01001642struct yuv_parameters {
1643 unsigned y_inc;
1644 unsigned uv_inc;
1645 unsigned y_stride;
1646 unsigned uv_stride;
1647 unsigned y_offset;
1648 unsigned u_offset;
1649 unsigned v_offset;
1650};
1651
1652static void get_yuv_parameters(struct igt_fb *fb, struct yuv_parameters *params)
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001653{
Maxime Ripardde449842019-01-25 15:58:32 +01001654 igt_assert(igt_format_is_yuv(fb->drm_format));
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001655
Maxime Ripardde449842019-01-25 15:58:32 +01001656 switch (fb->drm_format) {
1657 case DRM_FORMAT_NV12:
Maxime Ripard3b2b80b2019-02-08 14:18:58 +01001658 case DRM_FORMAT_NV16:
1659 case DRM_FORMAT_NV21:
1660 case DRM_FORMAT_NV61:
Maxime Ripardde449842019-01-25 15:58:32 +01001661 params->y_inc = 1;
1662 params->uv_inc = 2;
1663 break;
Ville Syrjälä9c33e5f2018-11-01 22:54:45 +02001664
Maxime Ripard3b2b80b2019-02-08 14:18:58 +01001665 case DRM_FORMAT_YUV420:
1666 case DRM_FORMAT_YUV422:
1667 case DRM_FORMAT_YVU420:
1668 case DRM_FORMAT_YVU422:
1669 params->y_inc = 1;
1670 params->uv_inc = 1;
1671 break;
1672
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001673 case DRM_FORMAT_YUYV:
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001674 case DRM_FORMAT_YVYU:
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001675 case DRM_FORMAT_UYVY:
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001676 case DRM_FORMAT_VYUY:
Maxime Ripardde449842019-01-25 15:58:32 +01001677 params->y_inc = 2;
1678 params->uv_inc = 4;
1679 break;
1680
1681 case DRM_FORMAT_XYUV8888:
1682 params->y_inc = 4;
1683 params->uv_inc = 4;
1684 break;
1685 }
1686
1687 switch (fb->drm_format) {
1688 case DRM_FORMAT_NV12:
Maxime Ripard3b2b80b2019-02-08 14:18:58 +01001689 case DRM_FORMAT_NV16:
1690 case DRM_FORMAT_NV21:
1691 case DRM_FORMAT_NV61:
1692 case DRM_FORMAT_YUV420:
1693 case DRM_FORMAT_YUV422:
1694 case DRM_FORMAT_YVU420:
1695 case DRM_FORMAT_YVU422:
Maxime Ripardde449842019-01-25 15:58:32 +01001696 params->y_stride = fb->strides[0];
1697 params->uv_stride = fb->strides[1];
1698 break;
1699
1700 case DRM_FORMAT_YUYV:
1701 case DRM_FORMAT_YVYU:
1702 case DRM_FORMAT_UYVY:
1703 case DRM_FORMAT_VYUY:
1704 case DRM_FORMAT_XYUV8888:
1705 params->y_stride = fb->strides[0];
1706 params->uv_stride = fb->strides[0];
1707 break;
1708 }
1709
1710 switch (fb->drm_format) {
1711 case DRM_FORMAT_NV12:
Maxime Ripard3b2b80b2019-02-08 14:18:58 +01001712 case DRM_FORMAT_NV16:
Maxime Ripardde449842019-01-25 15:58:32 +01001713 params->y_offset = fb->offsets[0];
1714 params->u_offset = fb->offsets[1];
1715 params->v_offset = fb->offsets[1] + 1;
1716 break;
1717
Maxime Ripard3b2b80b2019-02-08 14:18:58 +01001718 case DRM_FORMAT_NV21:
1719 case DRM_FORMAT_NV61:
1720 params->y_offset = fb->offsets[0];
1721 params->u_offset = fb->offsets[1] + 1;
1722 params->v_offset = fb->offsets[1];
1723 break;
1724
1725 case DRM_FORMAT_YUV420:
1726 case DRM_FORMAT_YUV422:
1727 params->y_offset = fb->offsets[0];
1728 params->u_offset = fb->offsets[1];
1729 params->v_offset = fb->offsets[2];
1730 break;
1731
1732 case DRM_FORMAT_YVU420:
1733 case DRM_FORMAT_YVU422:
1734 params->y_offset = fb->offsets[0];
1735 params->u_offset = fb->offsets[2];
1736 params->v_offset = fb->offsets[1];
1737 break;
1738
Maxime Ripardde449842019-01-25 15:58:32 +01001739 case DRM_FORMAT_YUYV:
1740 params->y_offset = fb->offsets[0];
1741 params->u_offset = fb->offsets[0] + 1;
1742 params->v_offset = fb->offsets[0] + 3;
1743 break;
1744
1745 case DRM_FORMAT_YVYU:
1746 params->y_offset = fb->offsets[0];
1747 params->u_offset = fb->offsets[0] + 3;
1748 params->v_offset = fb->offsets[0] + 1;
1749 break;
1750
1751 case DRM_FORMAT_UYVY:
1752 params->y_offset = fb->offsets[0] + 1;
1753 params->u_offset = fb->offsets[0];
1754 params->v_offset = fb->offsets[0] + 2;
1755 break;
1756
1757 case DRM_FORMAT_VYUY:
1758 params->y_offset = fb->offsets[0] + 1;
1759 params->u_offset = fb->offsets[0] + 2;
1760 params->v_offset = fb->offsets[0];
1761 break;
1762
1763 case DRM_FORMAT_XYUV8888:
1764 params->y_offset = fb->offsets[0] + 1;
1765 params->u_offset = fb->offsets[0] + 2;
1766 params->v_offset = fb->offsets[0] + 3;
1767 break;
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001768 }
1769}
1770
Maxime Ripardde449842019-01-25 15:58:32 +01001771static void convert_yuv_to_rgb24(struct fb_convert *cvt)
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001772{
Maxime Ripardde449842019-01-25 15:58:32 +01001773 const struct format_desc_struct *src_fmt =
1774 lookup_drm_format(cvt->src.fb->drm_format);
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001775 int i, j;
Maxime Ripardde449842019-01-25 15:58:32 +01001776 uint8_t bpp = 4;
1777 uint8_t *y, *u, *v;
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001778 uint8_t *rgb24 = cvt->dst.ptr;
1779 unsigned int rgb24_stride = cvt->dst.fb->strides[0];
Maarten Lankhorstb0033d92018-06-07 16:25:22 +02001780 struct igt_mat4 m = igt_ycbcr_to_rgb_matrix(cvt->src.fb->drm_format,
1781 cvt->dst.fb->drm_format,
1782 cvt->src.fb->color_encoding,
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001783 cvt->src.fb->color_range);
Ville Syrjälä737241d2018-11-01 23:31:20 +02001784 uint8_t *buf;
Maxime Ripardde449842019-01-25 15:58:32 +01001785 struct yuv_parameters params = { };
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001786
Maxime Ripardde449842019-01-25 15:58:32 +01001787 igt_assert(cvt->dst.fb->drm_format == DRM_FORMAT_XRGB8888 &&
1788 igt_format_is_yuv(cvt->src.fb->drm_format));
Ville Syrjälä9c33e5f2018-11-01 22:54:45 +02001789
Ville Syrjälä737241d2018-11-01 23:31:20 +02001790 buf = convert_src_get(cvt);
Maxime Ripardde449842019-01-25 15:58:32 +01001791 get_yuv_parameters(cvt->src.fb, &params);
1792 y = buf + params.y_offset;
1793 u = buf + params.u_offset;
1794 v = buf + params.v_offset;
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001795
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001796 for (i = 0; i < cvt->dst.fb->height; i++) {
Maxime Ripardde449842019-01-25 15:58:32 +01001797 const uint8_t *y_tmp = y;
1798 const uint8_t *u_tmp = u;
1799 const uint8_t *v_tmp = v;
1800 uint8_t *rgb_tmp = rgb24;
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001801
Maxime Ripardde449842019-01-25 15:58:32 +01001802 for (j = 0; j < cvt->dst.fb->width; j++) {
1803 struct igt_vec4 rgb, yuv;
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001804
Maxime Ripardde449842019-01-25 15:58:32 +01001805 yuv.d[0] = *y_tmp;
1806 yuv.d[1] = *u_tmp;
1807 yuv.d[2] = *v_tmp;
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001808 yuv.d[3] = 1.0f;
1809
1810 rgb = igt_matrix_transform(&m, &yuv);
Maxime Ripardde449842019-01-25 15:58:32 +01001811 write_rgb(rgb_tmp, &rgb);
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001812
Maxime Ripardde449842019-01-25 15:58:32 +01001813 rgb_tmp += bpp;
1814 y_tmp += params.y_inc;
1815
1816 if ((src_fmt->hsub == 1) || (j % src_fmt->hsub)) {
1817 u_tmp += params.uv_inc;
1818 v_tmp += params.uv_inc;
1819 }
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001820 }
1821
1822 rgb24 += rgb24_stride;
Maxime Ripardde449842019-01-25 15:58:32 +01001823 y += params.y_stride;
1824
1825 if ((src_fmt->vsub == 1) || (i % src_fmt->vsub)) {
1826 u += params.uv_stride;
1827 v += params.uv_stride;
1828 }
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001829 }
1830
Ville Syrjälä737241d2018-11-01 23:31:20 +02001831 convert_src_put(cvt, buf);
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001832}
1833
Maxime Ripardde449842019-01-25 15:58:32 +01001834static void convert_rgb24_to_yuv(struct fb_convert *cvt)
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001835{
Maxime Ripardde449842019-01-25 15:58:32 +01001836 const struct format_desc_struct *dst_fmt =
1837 lookup_drm_format(cvt->dst.fb->drm_format);
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001838 int i, j;
Maxime Ripardde449842019-01-25 15:58:32 +01001839 uint8_t *y, *u, *v;
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001840 const uint8_t *rgb24 = cvt->src.ptr;
Maxime Ripardde449842019-01-25 15:58:32 +01001841 uint8_t bpp = 4;
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001842 unsigned rgb24_stride = cvt->src.fb->strides[0];
Maarten Lankhorstb0033d92018-06-07 16:25:22 +02001843 struct igt_mat4 m = igt_rgb_to_ycbcr_matrix(cvt->src.fb->drm_format,
1844 cvt->dst.fb->drm_format,
1845 cvt->dst.fb->color_encoding,
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001846 cvt->dst.fb->color_range);
Maxime Ripardde449842019-01-25 15:58:32 +01001847 struct yuv_parameters params = { };
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001848
Ville Syrjälä9c33e5f2018-11-01 22:54:45 +02001849 igt_assert(cvt->src.fb->drm_format == DRM_FORMAT_XRGB8888 &&
Maxime Ripardde449842019-01-25 15:58:32 +01001850 igt_format_is_yuv(cvt->dst.fb->drm_format));
1851
1852 get_yuv_parameters(cvt->dst.fb, &params);
1853 y = cvt->dst.ptr + params.y_offset;
1854 u = cvt->dst.ptr + params.u_offset;
1855 v = cvt->dst.ptr + params.v_offset;
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001856
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001857 for (i = 0; i < cvt->dst.fb->height; i++) {
Maxime Ripardde449842019-01-25 15:58:32 +01001858 const uint8_t *rgb_tmp = rgb24;
1859 uint8_t *y_tmp = y;
1860 uint8_t *u_tmp = u;
1861 uint8_t *v_tmp = v;
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001862
Maxime Ripardde449842019-01-25 15:58:32 +01001863 for (j = 0; j < cvt->dst.fb->width; j++) {
1864 const uint8_t *pair_rgb24 = rgb_tmp;
1865 struct igt_vec4 pair_rgb, rgb;
1866 struct igt_vec4 pair_yuv, yuv;
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001867
Maxime Ripardde449842019-01-25 15:58:32 +01001868 read_rgb(&rgb, rgb_tmp);
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001869 yuv = igt_matrix_transform(&m, &rgb);
1870
Maxime Ripardde449842019-01-25 15:58:32 +01001871 rgb_tmp += bpp;
1872
1873 *y_tmp = yuv.d[0];
1874 y_tmp += params.y_inc;
1875
1876 if ((i % dst_fmt->vsub) || (j % dst_fmt->hsub))
1877 continue;
1878
1879 /*
1880 * We assume the MPEG2 chroma siting convention, where
1881 * pixel center for Cb'Cr' is between the left top and
1882 * bottom pixel in a 2x2 block, so take the average.
1883 *
1884 * Therefore, if we use subsampling, we only really care
1885 * about two pixels all the time, either the two
1886 * subsequent pixels horizontally, vertically, or the
1887 * two corners in a 2x2 block.
1888 *
1889 * The only corner case is when we have an odd number of
1890 * pixels, but this can be handled pretty easily by not
1891 * incrementing the paired pixel pointer in the
1892 * direction it's odd in.
1893 */
1894 if (j != (cvt->dst.fb->width - 1))
1895 pair_rgb24 += (dst_fmt->hsub - 1) * bpp;
1896
1897 if (i != (cvt->dst.fb->height - 1))
1898 pair_rgb24 += rgb24_stride * (dst_fmt->vsub - 1);
1899
1900 read_rgb(&pair_rgb, pair_rgb24);
1901 pair_yuv = igt_matrix_transform(&m, &pair_rgb);
1902
1903 *u_tmp = (yuv.d[1] + pair_yuv.d[1]) / 2.0f;
1904 *v_tmp = (yuv.d[2] + pair_yuv.d[2]) / 2.0f;
1905
1906 u_tmp += params.uv_inc;
1907 v_tmp += params.uv_inc;
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001908 }
1909
1910 rgb24 += rgb24_stride;
Maxime Ripardde449842019-01-25 15:58:32 +01001911 y += params.y_stride;
1912
1913 if ((i % dst_fmt->vsub) == (dst_fmt->vsub - 1)) {
1914 u += params.uv_stride;
1915 v += params.uv_stride;
1916 }
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001917 }
1918}
1919
Maxime Ripard3fa65f42018-10-04 14:39:03 +02001920static void convert_pixman(struct fb_convert *cvt)
1921{
1922 pixman_format_code_t src_pixman = drm_format_to_pixman(cvt->src.fb->drm_format);
1923 pixman_format_code_t dst_pixman = drm_format_to_pixman(cvt->dst.fb->drm_format);
1924 pixman_image_t *dst_image, *src_image;
Ville Syrjälä737241d2018-11-01 23:31:20 +02001925 void *src_ptr;
Maxime Ripard3fa65f42018-10-04 14:39:03 +02001926
1927 igt_assert((src_pixman != PIXMAN_invalid) &&
1928 (dst_pixman != PIXMAN_invalid));
1929
Paul Kocialkowski0ba18cf2018-12-27 15:57:41 +01001930 /* Pixman requires the stride to be aligned to 32 bits. */
1931 igt_assert((cvt->src.fb->strides[0] % sizeof(uint32_t)) == 0);
1932 igt_assert((cvt->dst.fb->strides[0] % sizeof(uint32_t)) == 0);
1933
Ville Syrjälä737241d2018-11-01 23:31:20 +02001934 src_ptr = convert_src_get(cvt);
1935
Maxime Ripard3fa65f42018-10-04 14:39:03 +02001936 src_image = pixman_image_create_bits(src_pixman,
1937 cvt->src.fb->width,
1938 cvt->src.fb->height,
Ville Syrjälä737241d2018-11-01 23:31:20 +02001939 src_ptr,
Maxime Ripard3fa65f42018-10-04 14:39:03 +02001940 cvt->src.fb->strides[0]);
1941 igt_assert(src_image);
1942
1943 dst_image = pixman_image_create_bits(dst_pixman,
1944 cvt->dst.fb->width,
1945 cvt->dst.fb->height,
1946 cvt->dst.ptr,
1947 cvt->dst.fb->strides[0]);
1948 igt_assert(dst_image);
1949
1950 pixman_image_composite(PIXMAN_OP_SRC, src_image, NULL, dst_image,
1951 0, 0, 0, 0, 0, 0,
1952 cvt->dst.fb->width, cvt->dst.fb->height);
1953 pixman_image_unref(dst_image);
1954 pixman_image_unref(src_image);
Ville Syrjälä737241d2018-11-01 23:31:20 +02001955
1956 convert_src_put(cvt, src_ptr);
Maxime Ripard3fa65f42018-10-04 14:39:03 +02001957}
1958
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001959static void fb_convert(struct fb_convert *cvt)
1960{
Maxime Ripard3fa65f42018-10-04 14:39:03 +02001961 if ((drm_format_to_pixman(cvt->src.fb->drm_format) != PIXMAN_invalid) &&
1962 (drm_format_to_pixman(cvt->dst.fb->drm_format) != PIXMAN_invalid)) {
1963 convert_pixman(cvt);
1964 return;
Ville Syrjäläe5eb1402018-11-01 22:26:47 +02001965 } else if (cvt->dst.fb->drm_format == DRM_FORMAT_XRGB8888) {
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001966 switch (cvt->src.fb->drm_format) {
Stanislav Lisovskiyf05c8c22018-12-17 16:30:28 +02001967 case DRM_FORMAT_XYUV8888:
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001968 case DRM_FORMAT_NV12:
Maxime Ripard3b2b80b2019-02-08 14:18:58 +01001969 case DRM_FORMAT_NV16:
1970 case DRM_FORMAT_NV21:
1971 case DRM_FORMAT_NV61:
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001972 case DRM_FORMAT_UYVY:
1973 case DRM_FORMAT_VYUY:
Maxime Ripard3b2b80b2019-02-08 14:18:58 +01001974 case DRM_FORMAT_YUV420:
1975 case DRM_FORMAT_YUV422:
Maxime Ripardde449842019-01-25 15:58:32 +01001976 case DRM_FORMAT_YUYV:
Maxime Ripard3b2b80b2019-02-08 14:18:58 +01001977 case DRM_FORMAT_YVU420:
1978 case DRM_FORMAT_YVU422:
Maxime Ripardde449842019-01-25 15:58:32 +01001979 case DRM_FORMAT_YVYU:
1980 convert_yuv_to_rgb24(cvt);
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001981 return;
1982 }
Ville Syrjäläe5eb1402018-11-01 22:26:47 +02001983 } else if (cvt->src.fb->drm_format == DRM_FORMAT_XRGB8888) {
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001984 switch (cvt->dst.fb->drm_format) {
Stanislav Lisovskiyf05c8c22018-12-17 16:30:28 +02001985 case DRM_FORMAT_XYUV8888:
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001986 case DRM_FORMAT_NV12:
Maxime Ripard3b2b80b2019-02-08 14:18:58 +01001987 case DRM_FORMAT_NV16:
1988 case DRM_FORMAT_NV21:
1989 case DRM_FORMAT_NV61:
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001990 case DRM_FORMAT_UYVY:
1991 case DRM_FORMAT_VYUY:
Maxime Ripard3b2b80b2019-02-08 14:18:58 +01001992 case DRM_FORMAT_YUV420:
1993 case DRM_FORMAT_YUV422:
1994 case DRM_FORMAT_YUYV:
1995 case DRM_FORMAT_YVU420:
1996 case DRM_FORMAT_YVU422:
1997 case DRM_FORMAT_YVYU:
Maxime Ripardde449842019-01-25 15:58:32 +01001998 convert_rgb24_to_yuv(cvt);
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001999 return;
2000 }
2001 }
2002
2003 igt_assert_f(false,
2004 "Conversion not implemented (from format 0x%x to 0x%x)\n",
2005 cvt->src.fb->drm_format, cvt->dst.fb->drm_format);
2006}
2007
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01002008static void destroy_cairo_surface__convert(void *arg)
2009{
2010 struct fb_convert_blit_upload *blit = arg;
Ville Syrjälä3ed2a602018-07-17 16:15:34 +03002011 struct igt_fb *fb = blit->base.fb;
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02002012 struct fb_convert cvt = {
2013 .dst = {
2014 .ptr = blit->base.linear.map,
Ville Syrjäläf3da4192018-11-01 22:55:28 +02002015 .fb = &blit->base.linear.fb,
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02002016 },
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01002017
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02002018 .src = {
2019 .ptr = blit->shadow_ptr,
2020 .fb = &blit->shadow_fb,
2021 },
2022 };
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01002023
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02002024 fb_convert(&cvt);
Maxime Ripardc7128362018-10-04 14:38:57 +02002025 igt_fb_destroy_cairo_shadow_buffer(&blit->shadow_fb, blit->shadow_ptr);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01002026
Ville Syrjälä22383612018-07-17 18:32:38 +03002027 if (blit->base.linear.fb.gem_handle)
Ville Syrjälä74261fd2018-07-17 16:20:34 +03002028 free_linear_mapping(&blit->base);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01002029 else
Maxime Ripard3415b192018-10-04 14:38:54 +02002030 unmap_bo(fb, blit->base.linear.map);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01002031
2032 free(blit);
2033
2034 fb->cairo_surface = NULL;
2035}
2036
2037static void create_cairo_surface__convert(int fd, struct igt_fb *fb)
2038{
2039 struct fb_convert_blit_upload *blit = malloc(sizeof(*blit));
Maarten Lankhorst8b354102018-11-19 11:59:55 +01002040 struct fb_convert cvt = { };
Maxime Ripardc7128362018-10-04 14:38:57 +02002041
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01002042 igt_assert(blit);
2043
Ville Syrjälä3ed2a602018-07-17 16:15:34 +03002044 blit->base.fd = fd;
2045 blit->base.fb = fb;
Maxime Ripardc7128362018-10-04 14:38:57 +02002046 blit->shadow_ptr = igt_fb_create_cairo_shadow_buffer(fd,
2047 fb->width,
2048 fb->height,
2049 &blit->shadow_fb);
2050 igt_assert(blit->shadow_ptr);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01002051
2052 if (fb->tiling == LOCAL_I915_FORMAT_MOD_Y_TILED ||
2053 fb->tiling == LOCAL_I915_FORMAT_MOD_Yf_TILED) {
Ville Syrjälä3ed2a602018-07-17 16:15:34 +03002054 setup_linear_mapping(fd, fb, &blit->base.linear);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01002055 } else {
Ville Syrjäläf3da4192018-11-01 22:55:28 +02002056 blit->base.linear.fb = *fb;
Ville Syrjälä22383612018-07-17 18:32:38 +03002057 blit->base.linear.fb.gem_handle = 0;
Maxime Ripard3415b192018-10-04 14:38:54 +02002058 blit->base.linear.map = map_bo(fd, fb);
Ville Syrjälä3ed2a602018-07-17 16:15:34 +03002059 igt_assert(blit->base.linear.map);
Ville Syrjälä737241d2018-11-01 23:31:20 +02002060
2061 /* reading via gtt mmap is slow */
2062 cvt.src.slow_reads = is_i915_device(fd);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01002063 }
2064
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02002065 cvt.dst.ptr = blit->shadow_ptr;
2066 cvt.dst.fb = &blit->shadow_fb;
2067 cvt.src.ptr = blit->base.linear.map;
Ville Syrjäläf3da4192018-11-01 22:55:28 +02002068 cvt.src.fb = &blit->base.linear.fb;
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02002069 fb_convert(&cvt);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01002070
2071 fb->cairo_surface =
Maxime Ripardc7128362018-10-04 14:38:57 +02002072 cairo_image_surface_create_for_data(blit->shadow_ptr,
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01002073 CAIRO_FORMAT_RGB24,
2074 fb->width, fb->height,
Maxime Ripardc7128362018-10-04 14:38:57 +02002075 blit->shadow_fb.strides[0]);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01002076
2077 cairo_surface_set_user_data(fb->cairo_surface,
2078 (cairo_user_data_key_t *)create_cairo_surface__convert,
2079 blit, destroy_cairo_surface__convert);
2080}
2081
Stanislav Lisovskiyf05c8c22018-12-17 16:30:28 +02002082
Paul Kocialkowskib4ad3972017-07-19 16:46:04 +03002083/**
Maxime Ripard3415b192018-10-04 14:38:54 +02002084 * igt_fb_map_buffer:
2085 * @fd: open drm file descriptor
2086 * @fb: pointer to an #igt_fb structure
2087 *
2088 * This function will creating a new mapping of the buffer and return a pointer
2089 * to the content of the supplied framebuffer's plane. This mapping needs to be
2090 * deleted using igt_fb_unmap_buffer().
2091 *
2092 * Returns:
2093 * A pointer to a buffer with the contents of the framebuffer
2094 */
2095void *igt_fb_map_buffer(int fd, struct igt_fb *fb)
2096{
2097 return map_bo(fd, fb);
2098}
2099
2100/**
2101 * igt_fb_unmap_buffer:
2102 * @fb: pointer to the backing igt_fb structure
2103 * @buffer: pointer to the buffer previously mappped
2104 *
2105 * This function will unmap a buffer mapped previously with
2106 * igt_fb_map_buffer().
2107 */
2108void igt_fb_unmap_buffer(struct igt_fb *fb, void *buffer)
2109{
2110 return unmap_bo(fb, buffer);
2111}
2112
2113/**
Paul Kocialkowskib4ad3972017-07-19 16:46:04 +03002114 * igt_get_cairo_surface:
2115 * @fd: open drm file descriptor
2116 * @fb: pointer to an #igt_fb structure
2117 *
Maarten Lankhorst918ea422018-01-19 12:47:11 +01002118 * This function stores the contents of the supplied framebuffer's plane
2119 * into a cairo surface and returns it.
Paul Kocialkowskib4ad3972017-07-19 16:46:04 +03002120 *
2121 * Returns:
2122 * A pointer to a cairo surface with the contents of the framebuffer.
2123 */
2124cairo_surface_t *igt_get_cairo_surface(int fd, struct igt_fb *fb)
Daniel Vetter57d7db82014-03-26 09:06:11 +01002125{
Maxime Ripard3fa65f42018-10-04 14:39:03 +02002126 const struct format_desc_struct *f = lookup_drm_format(fb->drm_format);
2127
Damien Lespiauff451a62015-03-03 14:11:04 +00002128 if (fb->cairo_surface == NULL) {
Maxime Ripard3fa65f42018-10-04 14:39:03 +02002129 if (igt_format_is_yuv(fb->drm_format) ||
2130 ((f->cairo_id == CAIRO_FORMAT_INVALID) &&
2131 (f->pixman_id != PIXMAN_invalid)))
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01002132 create_cairo_surface__convert(fd, fb);
2133 else if (fb->tiling == LOCAL_I915_FORMAT_MOD_Y_TILED ||
Damien Lespiauff451a62015-03-03 14:11:04 +00002134 fb->tiling == LOCAL_I915_FORMAT_MOD_Yf_TILED)
2135 create_cairo_surface__blit(fd, fb);
2136 else
2137 create_cairo_surface__gtt(fd, fb);
2138 }
Daniel Vetter57d7db82014-03-26 09:06:11 +01002139
Daniel Vetter57d7db82014-03-26 09:06:11 +01002140 igt_assert(cairo_surface_status(fb->cairo_surface) == CAIRO_STATUS_SUCCESS);
Damien Lespiau0db75bb2014-06-30 16:34:20 +01002141 return fb->cairo_surface;
Daniel Vetter57d7db82014-03-26 09:06:11 +01002142}
2143
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01002144/**
2145 * igt_get_cairo_ctx:
2146 * @fd: open i915 drm file descriptor
2147 * @fb: pointer to an #igt_fb structure
2148 *
2149 * This initializes a cairo surface for @fb and then allocates a drawing context
2150 * for it. The return cairo drawing context should be released by calling
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +01002151 * igt_put_cairo_ctx(). This also sets a default font for drawing text on
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01002152 * framebuffers.
2153 *
2154 * Returns:
2155 * The created cairo drawing context.
2156 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01002157cairo_t *igt_get_cairo_ctx(int fd, struct igt_fb *fb)
Daniel Vetter57d7db82014-03-26 09:06:11 +01002158{
2159 cairo_surface_t *surface;
2160 cairo_t *cr;
2161
Paul Kocialkowskib4ad3972017-07-19 16:46:04 +03002162 surface = igt_get_cairo_surface(fd, fb);
Daniel Vetter57d7db82014-03-26 09:06:11 +01002163 cr = cairo_create(surface);
2164 cairo_surface_destroy(surface);
Daniel Vetter7568edf2014-03-26 16:36:46 +01002165 igt_assert(cairo_status(cr) == CAIRO_STATUS_SUCCESS);
Daniel Vetter57d7db82014-03-26 09:06:11 +01002166
Daniel Vetter7568edf2014-03-26 16:36:46 +01002167 cairo_select_font_face(cr, "Helvetica", CAIRO_FONT_SLANT_NORMAL,
2168 CAIRO_FONT_WEIGHT_NORMAL);
Daniel Vetter57d7db82014-03-26 09:06:11 +01002169 igt_assert(cairo_status(cr) == CAIRO_STATUS_SUCCESS);
2170
2171 return cr;
2172}
2173
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01002174/**
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +01002175 * igt_put_cairo_ctx:
2176 * @fd: open i915 drm file descriptor
2177 * @fb: pointer to an #igt_fb structure
2178 * @cr: the cairo context returned by igt_get_cairo_ctx.
2179 *
2180 * This releases the cairo surface @cr returned by igt_get_cairo_ctx()
2181 * for @fb, and writes the changes out to the framebuffer if cairo doesn't
2182 * have native support for the format.
2183 */
2184void igt_put_cairo_ctx(int fd, struct igt_fb *fb, cairo_t *cr)
2185{
2186 cairo_status_t ret = cairo_status(cr);
2187 igt_assert_f(ret == CAIRO_STATUS_SUCCESS, "Cairo failed to draw with %s\n", cairo_status_to_string(ret));
2188
2189 cairo_destroy(cr);
2190}
2191
2192/**
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01002193 * igt_remove_fb:
2194 * @fd: open i915 drm file descriptor
2195 * @fb: pointer to an #igt_fb structure
2196 *
2197 * This function releases all resources allocated in igt_create_fb() for @fb.
2198 * Note that if this framebuffer is still in use on a primary plane the kernel
2199 * will disable the corresponding crtc.
2200 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01002201void igt_remove_fb(int fd, struct igt_fb *fb)
Daniel Vetter57d7db82014-03-26 09:06:11 +01002202{
Maarten Lankhorste62de1c2018-02-02 10:58:42 +01002203 if (!fb || !fb->fb_id)
2204 return;
2205
Daniel Vetter57d7db82014-03-26 09:06:11 +01002206 cairo_surface_destroy(fb->cairo_surface);
2207 do_or_die(drmModeRmFB(fd, fb->fb_id));
Deepak Rawat4ca3d1d2018-10-16 15:23:37 -07002208 if (fb->is_dumb)
2209 kmstest_dumb_destroy(fd, fb->gem_handle);
2210 else
2211 gem_close(fd, fb->gem_handle);
Maarten Lankhorste62de1c2018-02-02 10:58:42 +01002212 fb->fb_id = 0;
Daniel Vetter57d7db82014-03-26 09:06:11 +01002213}
2214
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01002215/**
Maxime Riparde3b1c342018-10-04 14:39:00 +02002216 * igt_fb_convert:
2217 * @dst: pointer to the #igt_fb structure that will store the conversion result
2218 * @src: pointer to the #igt_fb structure that stores the frame we convert
2219 * @dst_fourcc: DRM format specifier to convert to
2220 *
2221 * This will convert a given @src content to the @dst_fourcc format,
2222 * storing the result in the @dst fb, allocating the @dst fb
2223 * underlying buffer.
2224 *
2225 * Once done with @dst, the caller will have to call igt_remove_fb()
2226 * on it to free the associated resources.
2227 *
2228 * Returns:
2229 * The kms id of the created framebuffer.
2230 */
2231unsigned int igt_fb_convert(struct igt_fb *dst, struct igt_fb *src,
2232 uint32_t dst_fourcc)
2233{
Maarten Lankhorst8b354102018-11-19 11:59:55 +01002234 struct fb_convert cvt = { };
Maxime Riparde3b1c342018-10-04 14:39:00 +02002235 void *dst_ptr, *src_ptr;
2236 int fb_id;
2237
2238 fb_id = igt_create_fb(src->fd, src->width, src->height,
2239 dst_fourcc, LOCAL_DRM_FORMAT_MOD_NONE, dst);
2240 igt_assert(fb_id > 0);
2241
2242 src_ptr = igt_fb_map_buffer(src->fd, src);
2243 igt_assert(src_ptr);
2244
2245 dst_ptr = igt_fb_map_buffer(dst->fd, dst);
2246 igt_assert(dst_ptr);
2247
2248 cvt.dst.ptr = dst_ptr;
2249 cvt.dst.fb = dst;
2250 cvt.src.ptr = src_ptr;
2251 cvt.src.fb = src;
2252 fb_convert(&cvt);
2253
2254 igt_fb_unmap_buffer(dst, dst_ptr);
2255 igt_fb_unmap_buffer(src, src_ptr);
2256
2257 return fb_id;
2258}
2259
2260/**
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01002261 * igt_bpp_depth_to_drm_format:
2262 * @bpp: desired bits per pixel
2263 * @depth: desired depth
2264 *
2265 * Returns:
2266 * The rgb drm fourcc pixel format code corresponding to the given @bpp and
2267 * @depth values. Fails hard if no match was found.
2268 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01002269uint32_t igt_bpp_depth_to_drm_format(int bpp, int depth)
Daniel Vetter57d7db82014-03-26 09:06:11 +01002270{
Ville Syrjäläef43fce2018-07-18 20:26:22 +03002271 const struct format_desc_struct *f;
Daniel Vetter57d7db82014-03-26 09:06:11 +01002272
2273 for_each_format(f)
Ville Syrjäläe556d852018-02-27 22:48:46 +02002274 if (f->plane_bpp[0] == bpp && f->depth == depth)
Daniel Vetter57d7db82014-03-26 09:06:11 +01002275 return f->drm_id;
2276
Damien Lespiau54397ca2014-08-19 11:40:07 +01002277
2278 igt_assert_f(0, "can't find drm format with bpp=%d, depth=%d\n", bpp,
2279 depth);
Daniel Vetter57d7db82014-03-26 09:06:11 +01002280}
2281
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01002282/**
2283 * igt_drm_format_to_bpp:
2284 * @drm_format: drm fourcc pixel format code
2285 *
2286 * Returns:
2287 * The bits per pixel for the given drm fourcc pixel format code. Fails hard if
2288 * no match was found.
2289 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01002290uint32_t igt_drm_format_to_bpp(uint32_t drm_format)
Daniel Vetter57d7db82014-03-26 09:06:11 +01002291{
Ville Syrjäläef43fce2018-07-18 20:26:22 +03002292 const struct format_desc_struct *f = lookup_drm_format(drm_format);
Daniel Vetter57d7db82014-03-26 09:06:11 +01002293
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +01002294 igt_assert_f(f, "can't find a bpp format for %08x (%s)\n",
Damien Lespiau54397ca2014-08-19 11:40:07 +01002295 drm_format, igt_format_str(drm_format));
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +01002296
Ville Syrjäläe556d852018-02-27 22:48:46 +02002297 return f->plane_bpp[0];
Daniel Vetter57d7db82014-03-26 09:06:11 +01002298}
2299
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01002300/**
2301 * igt_format_str:
2302 * @drm_format: drm fourcc pixel format code
2303 *
2304 * Returns:
2305 * Human-readable fourcc pixel format code for @drm_format or "invalid" no match
2306 * was found.
2307 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01002308const char *igt_format_str(uint32_t drm_format)
Daniel Vetter57d7db82014-03-26 09:06:11 +01002309{
Ville Syrjäläef43fce2018-07-18 20:26:22 +03002310 const struct format_desc_struct *f = lookup_drm_format(drm_format);
Daniel Vetter57d7db82014-03-26 09:06:11 +01002311
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +01002312 return f ? f->name : "invalid";
Daniel Vetter57d7db82014-03-26 09:06:11 +01002313}
2314
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01002315/**
Maarten Lankhorstc60cf3b2018-02-02 11:32:40 +01002316 * igt_fb_supported_format:
2317 * @drm_format: drm fourcc to test.
2318 *
2319 * This functions returns whether @drm_format can be succesfully created by
2320 * igt_create_fb() and drawn to by igt_get_cairo_ctx().
2321 */
2322bool igt_fb_supported_format(uint32_t drm_format)
2323{
Ville Syrjäläef43fce2018-07-18 20:26:22 +03002324 const struct format_desc_struct *f;
Maarten Lankhorstc60cf3b2018-02-02 11:32:40 +01002325
2326 for_each_format(f)
2327 if (f->drm_id == drm_format)
Maxime Ripard3fa65f42018-10-04 14:39:03 +02002328 return (f->cairo_id != CAIRO_FORMAT_INVALID) ||
2329 (f->pixman_id != PIXMAN_invalid);
Maarten Lankhorstc60cf3b2018-02-02 11:32:40 +01002330
2331 return false;
2332}
Ville Syrjälä40bf6d02018-05-18 23:32:32 +03002333
2334/**
2335 * igt_format_is_yuv:
2336 * @drm_format: drm fourcc
2337 *
2338 * This functions returns whether @drm_format is YUV (as opposed to RGB).
2339 */
2340bool igt_format_is_yuv(uint32_t drm_format)
2341{
2342 switch (drm_format) {
2343 case DRM_FORMAT_NV12:
Maxime Ripard3b2b80b2019-02-08 14:18:58 +01002344 case DRM_FORMAT_NV16:
2345 case DRM_FORMAT_NV21:
2346 case DRM_FORMAT_NV61:
2347 case DRM_FORMAT_YUV420:
2348 case DRM_FORMAT_YUV422:
2349 case DRM_FORMAT_YVU420:
2350 case DRM_FORMAT_YVU422:
Ville Syrjälä40bf6d02018-05-18 23:32:32 +03002351 case DRM_FORMAT_YUYV:
2352 case DRM_FORMAT_YVYU:
2353 case DRM_FORMAT_UYVY:
2354 case DRM_FORMAT_VYUY:
Stanislav Lisovskiyf05c8c22018-12-17 16:30:28 +02002355 case DRM_FORMAT_XYUV8888:
Ville Syrjälä40bf6d02018-05-18 23:32:32 +03002356 return true;
2357 default:
2358 return false;
2359 }
2360}