blob: 25a07b0dfa3909793b2ed349ea35b5e00242dc66 [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"
Paul Kocialkowski08c9cc02019-01-09 17:55:59 +010040#include "igt_vc4.h"
Chris Wilson6a06d012018-02-27 21:45:14 +000041#include "igt_x86.h"
Daniel Vetter57d7db82014-03-26 09:06:11 +010042#include "ioctl_wrappers.h"
Lionel Landwerlin8bde13a2018-05-06 23:08:46 +010043#include "intel_batchbuffer.h"
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -020044#include "intel_chipset.h"
Daniel Vetter57d7db82014-03-26 09:06:11 +010045
Daniel Vetterc6c2b2b2014-03-26 15:15:49 +010046/**
47 * SECTION:igt_fb
48 * @short_description: Framebuffer handling and drawing library
Damien Lespiau6ebd8c22015-06-26 14:28:41 +010049 * @title: Framebuffer
Thomas Woodf0381d12015-09-07 09:26:01 +010050 * @include: igt.h
Daniel Vetter3d9e63f2014-03-26 16:37:15 +010051 *
52 * This library contains helper functions for handling kms framebuffer objects
53 * using #igt_fb structures to track all the metadata. igt_create_fb() creates
Thomas Woodd01ebbd2015-06-29 16:47:14 +010054 * a basic framebuffer and igt_remove_fb() cleans everything up again.
Daniel Vetter3d9e63f2014-03-26 16:37:15 +010055 *
56 * It also supports drawing using the cairo library and provides some simplified
57 * helper functions to easily draw test patterns. The main function to create a
58 * cairo drawing context for a framebuffer object is igt_get_cairo_ctx().
59 *
60 * Finally it also pulls in the drm fourcc headers and provides some helper
61 * functions to work with these pixel format codes.
Daniel Vetterc6c2b2b2014-03-26 15:15:49 +010062 */
63
Maxime Ripard3fa65f42018-10-04 14:39:03 +020064#define PIXMAN_invalid 0
65
Maarten Lankhorstcb8e45a2019-02-01 11:13:59 +010066#if CAIRO_VERSION < CAIRO_VERSION_ENCODE(1, 17, 2)
67/*
68 * We need cairo 1.17.2 to use HDR formats, but the only thing added is a value
69 * to cairo_format_t.
70 *
71 * To prevent going outside the enum, make cairo_format_t an int and define
72 * ourselves.
73 */
74
75#define CAIRO_FORMAT_RGB96F (6)
76#define CAIRO_FORMAT_RGBA128F (7)
77#define cairo_format_t int
78#endif
79
Daniel Vetter57d7db82014-03-26 09:06:11 +010080/* drm fourcc/cairo format maps */
Ville Syrjäläef43fce2018-07-18 20:26:22 +030081static const struct format_desc_struct {
Ville Syrjäläe556d852018-02-27 22:48:46 +020082 const char *name;
Daniel Vetter57d7db82014-03-26 09:06:11 +010083 uint32_t drm_id;
84 cairo_format_t cairo_id;
Maxime Ripard3fa65f42018-10-04 14:39:03 +020085 pixman_format_code_t pixman_id;
Daniel Vetter57d7db82014-03-26 09:06:11 +010086 int depth;
Ville Syrjäläe556d852018-02-27 22:48:46 +020087 int num_planes;
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +010088 int plane_bpp[4];
Maxime Ripard915c58a2019-01-25 15:58:30 +010089 uint8_t hsub;
90 uint8_t vsub;
Daniel Vetter57d7db82014-03-26 09:06:11 +010091} format_desc[] = {
Maxime Ripardaedb0442018-10-04 14:39:04 +020092 { .name = "ARGB1555", .depth = -1, .drm_id = DRM_FORMAT_ARGB1555,
93 .cairo_id = CAIRO_FORMAT_INVALID,
94 .pixman_id = PIXMAN_a1r5g5b5,
95 .num_planes = 1, .plane_bpp = { 16, },
Maxime Ripard915c58a2019-01-25 15:58:30 +010096 .hsub = 1, .vsub = 1,
Maxime Ripardaedb0442018-10-04 14:39:04 +020097 },
98 { .name = "XRGB1555", .depth = -1, .drm_id = DRM_FORMAT_XRGB1555,
99 .cairo_id = CAIRO_FORMAT_INVALID,
100 .pixman_id = PIXMAN_x1r5g5b5,
101 .num_planes = 1, .plane_bpp = { 16, },
Maxime Ripard915c58a2019-01-25 15:58:30 +0100102 .hsub = 1, .vsub = 1,
Maxime Ripardaedb0442018-10-04 14:39:04 +0200103 },
Ville Syrjäläe556d852018-02-27 22:48:46 +0200104 { .name = "RGB565", .depth = 16, .drm_id = DRM_FORMAT_RGB565,
105 .cairo_id = CAIRO_FORMAT_RGB16_565,
Maxime Ripard3fa65f42018-10-04 14:39:03 +0200106 .pixman_id = PIXMAN_r5g6b5,
Ville Syrjäläe556d852018-02-27 22:48:46 +0200107 .num_planes = 1, .plane_bpp = { 16, },
Maxime Ripard915c58a2019-01-25 15:58:30 +0100108 .hsub = 1, .vsub = 1,
Ville Syrjäläe556d852018-02-27 22:48:46 +0200109 },
Maxime Ripardaedb0442018-10-04 14:39:04 +0200110 { .name = "BGR565", .depth = -1, .drm_id = DRM_FORMAT_BGR565,
111 .cairo_id = CAIRO_FORMAT_INVALID,
112 .pixman_id = PIXMAN_b5g6r5,
113 .num_planes = 1, .plane_bpp = { 16, },
Maxime Ripard915c58a2019-01-25 15:58:30 +0100114 .hsub = 1, .vsub = 1,
Maxime Ripardaedb0442018-10-04 14:39:04 +0200115 },
116 { .name = "BGR888", .depth = -1, .drm_id = DRM_FORMAT_BGR888,
117 .cairo_id = CAIRO_FORMAT_INVALID,
118 .pixman_id = PIXMAN_b8g8r8,
119 .num_planes = 1, .plane_bpp = { 24, },
Maxime Ripard915c58a2019-01-25 15:58:30 +0100120 .hsub = 1, .vsub = 1,
Maxime Ripardaedb0442018-10-04 14:39:04 +0200121 },
Maxime Riparda3d88d32018-10-04 14:38:56 +0200122 { .name = "RGB888", .depth = -1, .drm_id = DRM_FORMAT_RGB888,
123 .cairo_id = CAIRO_FORMAT_INVALID,
Maxime Ripard3fa65f42018-10-04 14:39:03 +0200124 .pixman_id = PIXMAN_r8g8b8,
Maxime Riparda3d88d32018-10-04 14:38:56 +0200125 .num_planes = 1, .plane_bpp = { 24, },
Maxime Ripard915c58a2019-01-25 15:58:30 +0100126 .hsub = 1, .vsub = 1,
Maxime Riparda3d88d32018-10-04 14:38:56 +0200127 },
Stanislav Lisovskiyf05c8c22018-12-17 16:30:28 +0200128 { .name = "XYUV8888", .depth = -1, .drm_id = DRM_FORMAT_XYUV8888,
129 .cairo_id = CAIRO_FORMAT_RGB24,
130 .num_planes = 1, .plane_bpp = { 32, },
Maxime Ripard915c58a2019-01-25 15:58:30 +0100131 .hsub = 1, .vsub = 1,
Stanislav Lisovskiyf05c8c22018-12-17 16:30:28 +0200132 },
Ville Syrjäläe556d852018-02-27 22:48:46 +0200133 { .name = "XRGB8888", .depth = 24, .drm_id = DRM_FORMAT_XRGB8888,
134 .cairo_id = CAIRO_FORMAT_RGB24,
Maxime Ripard3fa65f42018-10-04 14:39:03 +0200135 .pixman_id = PIXMAN_x8r8g8b8,
Ville Syrjäläe556d852018-02-27 22:48:46 +0200136 .num_planes = 1, .plane_bpp = { 32, },
Maxime Ripard915c58a2019-01-25 15:58:30 +0100137 .hsub = 1, .vsub = 1,
Ville Syrjäläe556d852018-02-27 22:48:46 +0200138 },
Maxime Ripardaedb0442018-10-04 14:39:04 +0200139 { .name = "XBGR8888", .depth = -1, .drm_id = DRM_FORMAT_XBGR8888,
140 .cairo_id = CAIRO_FORMAT_INVALID,
141 .pixman_id = PIXMAN_x8b8g8r8,
142 .num_planes = 1, .plane_bpp = { 32, },
Maxime Ripard915c58a2019-01-25 15:58:30 +0100143 .hsub = 1, .vsub = 1,
Maxime Ripardaedb0442018-10-04 14:39:04 +0200144 },
Ville Syrjäläe556d852018-02-27 22:48:46 +0200145 { .name = "XRGB2101010", .depth = 30, .drm_id = DRM_FORMAT_XRGB2101010,
146 .cairo_id = CAIRO_FORMAT_RGB30,
Maxime Ripard3fa65f42018-10-04 14:39:03 +0200147 .pixman_id = PIXMAN_x2r10g10b10,
Ville Syrjäläe556d852018-02-27 22:48:46 +0200148 .num_planes = 1, .plane_bpp = { 32, },
Maxime Ripard915c58a2019-01-25 15:58:30 +0100149 .hsub = 1, .vsub = 1,
Ville Syrjäläe556d852018-02-27 22:48:46 +0200150 },
151 { .name = "ARGB8888", .depth = 32, .drm_id = DRM_FORMAT_ARGB8888,
152 .cairo_id = CAIRO_FORMAT_ARGB32,
Maxime Ripard3fa65f42018-10-04 14:39:03 +0200153 .pixman_id = PIXMAN_a8r8g8b8,
Ville Syrjäläe556d852018-02-27 22:48:46 +0200154 .num_planes = 1, .plane_bpp = { 32, },
Maxime Ripard915c58a2019-01-25 15:58:30 +0100155 .hsub = 1, .vsub = 1,
Ville Syrjäläe556d852018-02-27 22:48:46 +0200156 },
Maxime Ripardaedb0442018-10-04 14:39:04 +0200157 { .name = "ABGR8888", .depth = -1, .drm_id = DRM_FORMAT_ABGR8888,
158 .cairo_id = CAIRO_FORMAT_INVALID,
159 .pixman_id = PIXMAN_a8b8g8r8,
160 .num_planes = 1, .plane_bpp = { 32, },
Maxime Ripard915c58a2019-01-25 15:58:30 +0100161 .hsub = 1, .vsub = 1,
Maxime Ripardaedb0442018-10-04 14:39:04 +0200162 },
Ville Syrjäläe556d852018-02-27 22:48:46 +0200163 { .name = "NV12", .depth = -1, .drm_id = DRM_FORMAT_NV12,
164 .cairo_id = CAIRO_FORMAT_RGB24,
165 .num_planes = 2, .plane_bpp = { 8, 16, },
Maxime Ripard915c58a2019-01-25 15:58:30 +0100166 .hsub = 2, .vsub = 2,
Ville Syrjäläe556d852018-02-27 22:48:46 +0200167 },
Maxime Ripard3b2b80b2019-02-08 14:18:58 +0100168 { .name = "NV16", .depth = -1, .drm_id = DRM_FORMAT_NV16,
169 .cairo_id = CAIRO_FORMAT_RGB24,
170 .num_planes = 2, .plane_bpp = { 8, 16, },
171 .hsub = 2, .vsub = 1,
172 },
173 { .name = "NV21", .depth = -1, .drm_id = DRM_FORMAT_NV21,
174 .cairo_id = CAIRO_FORMAT_RGB24,
175 .num_planes = 2, .plane_bpp = { 8, 16, },
176 .hsub = 2, .vsub = 2,
177 },
178 { .name = "NV61", .depth = -1, .drm_id = DRM_FORMAT_NV61,
179 .cairo_id = CAIRO_FORMAT_RGB24,
180 .num_planes = 2, .plane_bpp = { 8, 16, },
181 .hsub = 2, .vsub = 1,
182 },
Ville Syrjäläfed97c42018-02-27 22:58:01 +0200183 { .name = "YUYV", .depth = -1, .drm_id = DRM_FORMAT_YUYV,
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 },
188 { .name = "YVYU", .depth = -1, .drm_id = DRM_FORMAT_YVYU,
189 .cairo_id = CAIRO_FORMAT_RGB24,
190 .num_planes = 1, .plane_bpp = { 16, },
Maxime Ripard915c58a2019-01-25 15:58:30 +0100191 .hsub = 2, .vsub = 1,
Ville Syrjäläfed97c42018-02-27 22:58:01 +0200192 },
193 { .name = "UYVY", .depth = -1, .drm_id = DRM_FORMAT_UYVY,
194 .cairo_id = CAIRO_FORMAT_RGB24,
195 .num_planes = 1, .plane_bpp = { 16, },
Maxime Ripard915c58a2019-01-25 15:58:30 +0100196 .hsub = 2, .vsub = 1,
Ville Syrjäläfed97c42018-02-27 22:58:01 +0200197 },
198 { .name = "VYUY", .depth = -1, .drm_id = DRM_FORMAT_VYUY,
199 .cairo_id = CAIRO_FORMAT_RGB24,
200 .num_planes = 1, .plane_bpp = { 16, },
Maxime Ripard915c58a2019-01-25 15:58:30 +0100201 .hsub = 2, .vsub = 1,
Ville Syrjäläfed97c42018-02-27 22:58:01 +0200202 },
Maxime Ripard3b2b80b2019-02-08 14:18:58 +0100203 { .name = "YU12", .depth = -1, .drm_id = DRM_FORMAT_YUV420,
204 .cairo_id = CAIRO_FORMAT_RGB24,
205 .num_planes = 3, .plane_bpp = { 8, 8, 8, },
206 .hsub = 2, .vsub = 2,
207 },
208 { .name = "YU16", .depth = -1, .drm_id = DRM_FORMAT_YUV422,
209 .cairo_id = CAIRO_FORMAT_RGB24,
210 .num_planes = 3, .plane_bpp = { 8, 8, 8, },
211 .hsub = 2, .vsub = 1,
212 },
213 { .name = "YV12", .depth = -1, .drm_id = DRM_FORMAT_YVU420,
214 .cairo_id = CAIRO_FORMAT_RGB24,
215 .num_planes = 3, .plane_bpp = { 8, 8, 8, },
216 .hsub = 2, .vsub = 2,
217 },
218 { .name = "YV16", .depth = -1, .drm_id = DRM_FORMAT_YVU422,
219 .cairo_id = CAIRO_FORMAT_RGB24,
220 .num_planes = 3, .plane_bpp = { 8, 8, 8, },
221 .hsub = 2, .vsub = 1,
222 },
Maarten Lankhorstcb8e45a2019-02-01 11:13:59 +0100223 { .name = "P010", .depth = -1, .drm_id = DRM_FORMAT_P010,
224 .cairo_id = CAIRO_FORMAT_RGB96F,
225 .num_planes = 2, .plane_bpp = { 16, 32 },
226 .vsub = 2, .hsub = 2,
227 },
228 { .name = "P012", .depth = -1, .drm_id = DRM_FORMAT_P012,
229 .cairo_id = CAIRO_FORMAT_RGB96F,
230 .num_planes = 2, .plane_bpp = { 16, 32 },
231 .vsub = 2, .hsub = 2,
232 },
233 { .name = "P016", .depth = -1, .drm_id = DRM_FORMAT_P016,
234 .cairo_id = CAIRO_FORMAT_RGB96F,
235 .num_planes = 2, .plane_bpp = { 16, 32 },
236 .vsub = 2, .hsub = 2,
237 },
238 { .name = "IGT-FLOAT", .depth = -1, .drm_id = IGT_FORMAT_FLOAT,
239 .cairo_id = CAIRO_FORMAT_INVALID,
240 .num_planes = 1, .plane_bpp = { 128 },
241 },
Daniel Vetter57d7db82014-03-26 09:06:11 +0100242};
Daniel Vetter57d7db82014-03-26 09:06:11 +0100243#define for_each_format(f) \
244 for (f = format_desc; f - format_desc < ARRAY_SIZE(format_desc); f++)
245
Ville Syrjäläef43fce2018-07-18 20:26:22 +0300246static const struct format_desc_struct *lookup_drm_format(uint32_t drm_format)
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100247{
Ville Syrjäläef43fce2018-07-18 20:26:22 +0300248 const struct format_desc_struct *format;
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100249
250 for_each_format(format) {
251 if (format->drm_id != drm_format)
252 continue;
253
254 return format;
255 }
256
257 return NULL;
258}
259
Praveen Paneri4bb45412017-07-18 22:52:56 +0530260/**
261 * igt_get_fb_tile_size:
262 * @fd: the DRM file descriptor
263 * @tiling: tiling layout of the framebuffer (as framebuffer modifier)
264 * @fb_bpp: bits per pixel of the framebuffer
265 * @width_ret: width of the tile in bytes
266 * @height_ret: height of the tile in lines
267 *
268 * This function returns width and height of a tile based on the given tiling
269 * format.
270 */
271void igt_get_fb_tile_size(int fd, uint64_t tiling, int fb_bpp,
272 unsigned *width_ret, unsigned *height_ret)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100273{
Paul Kocialkowski9f9e7c42018-12-28 11:18:19 +0100274 uint32_t vc4_tiling_param = 0;
275
276 if (is_vc4_device(fd)) {
277 vc4_tiling_param = fourcc_mod_broadcom_param(tiling);
Paul Kocialkowski08c9cc02019-01-09 17:55:59 +0100278 tiling = fourcc_mod_broadcom_mod(tiling);
Paul Kocialkowski9f9e7c42018-12-28 11:18:19 +0100279 }
Paul Kocialkowski08c9cc02019-01-09 17:55:59 +0100280
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200281 switch (tiling) {
282 case LOCAL_DRM_FORMAT_MOD_NONE:
Maxime Ripard6112f952019-01-25 15:58:31 +0100283 if (is_i915_device(fd))
284 *width_ret = 64;
285 else
286 *width_ret = 1;
287
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200288 *height_ret = 1;
289 break;
290 case LOCAL_I915_FORMAT_MOD_X_TILED:
Tomeu Vizoso85a1d452016-02-24 08:39:53 +0100291 igt_require_intel(fd);
292 if (intel_gen(intel_get_drm_devid(fd)) == 2) {
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200293 *width_ret = 128;
294 *height_ret = 16;
295 } else {
296 *width_ret = 512;
297 *height_ret = 8;
298 }
299 break;
300 case LOCAL_I915_FORMAT_MOD_Y_TILED:
Tomeu Vizoso85a1d452016-02-24 08:39:53 +0100301 igt_require_intel(fd);
302 if (intel_gen(intel_get_drm_devid(fd)) == 2) {
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200303 *width_ret = 128;
Ville Syrjälä037bc692016-02-12 21:28:54 +0200304 *height_ret = 16;
Tomeu Vizoso85a1d452016-02-24 08:39:53 +0100305 } else if (IS_915(intel_get_drm_devid(fd))) {
Ville Syrjälä037bc692016-02-12 21:28:54 +0200306 *width_ret = 512;
307 *height_ret = 8;
308 } else {
309 *width_ret = 128;
310 *height_ret = 32;
311 }
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200312 break;
313 case LOCAL_I915_FORMAT_MOD_Yf_TILED:
Tomeu Vizoso85a1d452016-02-24 08:39:53 +0100314 igt_require_intel(fd);
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200315 switch (fb_bpp) {
316 case 8:
317 *width_ret = 64;
318 *height_ret = 64;
319 break;
320 case 16:
321 case 32:
322 *width_ret = 128;
323 *height_ret = 32;
324 break;
325 case 64:
326 case 128:
327 *width_ret = 256;
328 *height_ret = 16;
329 break;
330 default:
331 igt_assert(false);
332 }
333 break;
Paul Kocialkowski08c9cc02019-01-09 17:55:59 +0100334 case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
335 igt_require_vc4(fd);
336 *width_ret = 128;
337 *height_ret = 32;
338 break;
Paul Kocialkowski9f9e7c42018-12-28 11:18:19 +0100339 case DRM_FORMAT_MOD_BROADCOM_SAND32:
340 igt_require_vc4(fd);
341 *width_ret = 32;
342 *height_ret = vc4_tiling_param;
343 break;
344 case DRM_FORMAT_MOD_BROADCOM_SAND64:
345 igt_require_vc4(fd);
346 *width_ret = 64;
347 *height_ret = vc4_tiling_param;
348 break;
349 case DRM_FORMAT_MOD_BROADCOM_SAND128:
350 igt_require_vc4(fd);
351 *width_ret = 128;
352 *height_ret = vc4_tiling_param;
353 break;
354 case DRM_FORMAT_MOD_BROADCOM_SAND256:
355 igt_require_vc4(fd);
356 *width_ret = 256;
357 *height_ret = vc4_tiling_param;
358 break;
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200359 default:
360 igt_assert(false);
361 }
362}
363
Ville Syrjälä22383612018-07-17 18:32:38 +0300364static unsigned fb_plane_width(const struct igt_fb *fb, int plane)
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100365{
Maxime Ripard915c58a2019-01-25 15:58:30 +0100366 const struct format_desc_struct *format = lookup_drm_format(fb->drm_format);
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100367
Maxime Ripard915c58a2019-01-25 15:58:30 +0100368 if (plane == 0)
369 return fb->width;
370
371 return DIV_ROUND_UP(fb->width, format->hsub);
Maarten Lankhorst918ea422018-01-19 12:47:11 +0100372}
373
Ville Syrjälä22383612018-07-17 18:32:38 +0300374static unsigned fb_plane_bpp(const struct igt_fb *fb, int plane)
Ville Syrjälä72bf5972018-07-17 18:11:40 +0300375{
Ville Syrjälä22383612018-07-17 18:32:38 +0300376 const struct format_desc_struct *format = lookup_drm_format(fb->drm_format);
377
Ville Syrjälä72bf5972018-07-17 18:11:40 +0300378 return format->plane_bpp[plane];
379}
380
Ville Syrjälä22383612018-07-17 18:32:38 +0300381static unsigned fb_plane_height(const struct igt_fb *fb, int plane)
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100382{
Maxime Ripard915c58a2019-01-25 15:58:30 +0100383 const struct format_desc_struct *format = lookup_drm_format(fb->drm_format);
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100384
Maxime Ripard915c58a2019-01-25 15:58:30 +0100385 if (plane == 0)
386 return fb->height;
387
388 return DIV_ROUND_UP(fb->height, format->vsub);
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100389}
390
Ville Syrjälä22383612018-07-17 18:32:38 +0300391static int fb_num_planes(const struct igt_fb *fb)
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100392{
Ville Syrjälä22383612018-07-17 18:32:38 +0300393 const struct format_desc_struct *format = lookup_drm_format(fb->drm_format);
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100394
Ville Syrjäläb7298a72018-07-17 18:25:34 +0300395 return format->num_planes;
396}
397
Ville Syrjälä22383612018-07-17 18:32:38 +0300398static void fb_init(struct igt_fb *fb,
399 int fd, int width, int height,
400 uint32_t drm_format,
401 uint64_t modifier,
402 enum igt_color_encoding color_encoding,
403 enum igt_color_range color_range)
Ville Syrjäläc3edd792018-07-17 18:18:14 +0300404{
Ville Syrjälä22383612018-07-17 18:32:38 +0300405 const struct format_desc_struct *f = lookup_drm_format(drm_format);
Ville Syrjäläc3edd792018-07-17 18:18:14 +0300406
Ville Syrjälä22383612018-07-17 18:32:38 +0300407 igt_assert_f(f, "DRM format %08x not found\n", drm_format);
408
409 memset(fb, 0, sizeof(*fb));
410
411 fb->width = width;
412 fb->height = height;
413 fb->tiling = modifier;
414 fb->drm_format = drm_format;
415 fb->fd = fd;
416 fb->num_planes = fb_num_planes(fb);
417 fb->color_encoding = color_encoding;
418 fb->color_range = color_range;
419
420 for (int i = 0; i < fb->num_planes; i++) {
421 fb->plane_bpp[i] = fb_plane_bpp(fb, i);
422 fb->plane_height[i] = fb_plane_height(fb, i);
423 fb->plane_width[i] = fb_plane_width(fb, i);
424 }
425}
426
427static uint32_t calc_plane_stride(struct igt_fb *fb, int plane)
428{
429 uint32_t min_stride = fb->plane_width[plane] *
430 (fb->plane_bpp[plane] / 8);
431
432 if (fb->tiling != LOCAL_DRM_FORMAT_MOD_NONE &&
Paul Kocialkowskie1092cb2018-12-05 11:14:37 +0100433 is_i915_device(fb->fd) &&
Ville Syrjälä22383612018-07-17 18:32:38 +0300434 intel_gen(intel_get_drm_devid(fb->fd)) <= 3) {
Ville Syrjäläc3edd792018-07-17 18:18:14 +0300435 uint32_t stride;
436
437 /* Round the tiling up to the next power-of-two and the region
438 * up to the next pot fence size so that this works on all
439 * generations.
440 *
441 * This can still fail if the framebuffer is too large to be
442 * tiled. But then that failure is expected.
443 */
444
445 stride = max(min_stride, 512);
446 stride = roundup_power_of_two(stride);
447
448 return stride;
449 } else {
450 unsigned int tile_width, tile_height;
451
Ville Syrjälä22383612018-07-17 18:32:38 +0300452 igt_get_fb_tile_size(fb->fd, fb->tiling, fb->plane_bpp[plane],
Ville Syrjäläc3edd792018-07-17 18:18:14 +0300453 &tile_width, &tile_height);
454
455 return ALIGN(min_stride, tile_width);
456 }
457}
458
Ville Syrjälä22383612018-07-17 18:32:38 +0300459static uint64_t calc_plane_size(struct igt_fb *fb, int plane)
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100460{
Ville Syrjälä22383612018-07-17 18:32:38 +0300461 if (fb->tiling != LOCAL_DRM_FORMAT_MOD_NONE &&
Paul Kocialkowskie1092cb2018-12-05 11:14:37 +0100462 is_i915_device(fb->fd) &&
Ville Syrjälä22383612018-07-17 18:32:38 +0300463 intel_gen(intel_get_drm_devid(fb->fd)) <= 3) {
464 uint64_t min_size = (uint64_t) fb->strides[plane] *
465 fb->plane_height[plane];
Ville Syrjälä4d2598f2018-07-18 17:56:56 +0300466 uint64_t size;
467
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200468 /* Round the tiling up to the next power-of-two and the region
469 * up to the next pot fence size so that this works on all
470 * generations.
Daniel Vetter57d7db82014-03-26 09:06:11 +0100471 *
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200472 * This can still fail if the framebuffer is too large to be
473 * tiled. But then that failure is expected.
Daniel Vetter57d7db82014-03-26 09:06:11 +0100474 */
475
Ville Syrjälä4d2598f2018-07-18 17:56:56 +0300476 size = max(min_size, 1024*1024);
Ville Syrjälä20a7ead2018-09-07 22:12:26 +0300477 size = roundup_power_of_two(size);
Ville Syrjälä4d2598f2018-07-18 17:56:56 +0300478
479 return size;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100480 } else {
Ville Syrjäläc3edd792018-07-17 18:18:14 +0300481 unsigned int tile_width, tile_height;
482
Ville Syrjälä22383612018-07-17 18:32:38 +0300483 igt_get_fb_tile_size(fb->fd, fb->tiling, fb->plane_bpp[plane],
Ville Syrjäläc3edd792018-07-17 18:18:14 +0300484 &tile_width, &tile_height);
Ville Syrjälä94540e32018-07-18 21:17:05 +0300485
Paul Kocialkowski3fa19532018-12-28 10:59:05 +0100486 /* Special case where the "tile height" represents a
487 * height-based stride, such as with VC4 SAND tiling modes.
488 */
489
490 if (tile_height > fb->plane_height[plane])
491 return fb->strides[plane] * tile_height;
492
Ville Syrjälä22383612018-07-17 18:32:38 +0300493 return (uint64_t) fb->strides[plane] *
494 ALIGN(fb->plane_height[plane], tile_height);
Ville Syrjälä4d2598f2018-07-18 17:56:56 +0300495 }
496}
497
Ville Syrjälä22383612018-07-17 18:32:38 +0300498static uint64_t calc_fb_size(struct igt_fb *fb)
Ville Syrjälä4d2598f2018-07-18 17:56:56 +0300499{
500 uint64_t size = 0;
501 int plane;
502
Ville Syrjälä22383612018-07-17 18:32:38 +0300503 for (plane = 0; plane < fb->num_planes; plane++) {
504 /* respect the stride requested by the caller */
505 if (!fb->strides[plane])
506 fb->strides[plane] = calc_plane_stride(fb, plane);
Ville Syrjälä4d2598f2018-07-18 17:56:56 +0300507
Ville Syrjälä22383612018-07-17 18:32:38 +0300508 fb->offsets[plane] = size;
Ville Syrjälä4d2598f2018-07-18 17:56:56 +0300509
Ville Syrjälä22383612018-07-17 18:32:38 +0300510 size += calc_plane_size(fb, plane);
Ville Syrjälä4d2598f2018-07-18 17:56:56 +0300511 }
512
513 return size;
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200514}
515
Tomeu Vizosoae649632016-11-10 10:25:24 +0100516/**
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100517 * igt_calc_fb_size:
518 * @fd: the DRM file descriptor
519 * @width: width of the framebuffer in pixels
520 * @height: height of the framebuffer in pixels
521 * @format: drm fourcc pixel format code
522 * @tiling: tiling layout of the framebuffer (as framebuffer modifier)
523 * @size_ret: returned size for the framebuffer
524 * @stride_ret: returned stride for the framebuffer
525 *
526 * This function returns valid stride and size values for a framebuffer with the
527 * specified parameters.
528 */
529void 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 +0300530 uint64_t *size_ret, unsigned *stride_ret)
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100531{
Ville Syrjälä22383612018-07-17 18:32:38 +0300532 struct igt_fb fb;
Ville Syrjälä4d2598f2018-07-18 17:56:56 +0300533
Ville Syrjälä22383612018-07-17 18:32:38 +0300534 fb_init(&fb, fd, width, height, drm_format, tiling,
535 IGT_COLOR_YCBCR_BT709, IGT_COLOR_YCBCR_LIMITED_RANGE);
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100536
Ville Syrjälä22383612018-07-17 18:32:38 +0300537 fb.size = calc_fb_size(&fb);
538
539 if (size_ret)
540 *size_ret = fb.size;
541 if (stride_ret)
542 *stride_ret = fb.strides[0];
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +0100543}
544
545/**
Tomeu Vizosoae649632016-11-10 10:25:24 +0100546 * igt_fb_mod_to_tiling:
547 * @modifier: DRM framebuffer modifier
548 *
549 * This function converts a DRM framebuffer modifier to its corresponding
550 * tiling constant.
551 *
552 * Returns:
553 * A tiling constant
554 */
555uint64_t igt_fb_mod_to_tiling(uint64_t modifier)
556{
557 switch (modifier) {
558 case LOCAL_DRM_FORMAT_MOD_NONE:
559 return I915_TILING_NONE;
560 case LOCAL_I915_FORMAT_MOD_X_TILED:
561 return I915_TILING_X;
562 case LOCAL_I915_FORMAT_MOD_Y_TILED:
563 return I915_TILING_Y;
564 case LOCAL_I915_FORMAT_MOD_Yf_TILED:
565 return I915_TILING_Yf;
566 default:
567 igt_assert(0);
568 }
569}
570
Praveen Paneri4437e212017-07-18 22:52:57 +0530571/**
572 * igt_fb_tiling_to_mod:
573 * @tiling: DRM framebuffer tiling
574 *
575 * This function converts a DRM framebuffer tiling to its corresponding
576 * modifier constant.
577 *
578 * Returns:
579 * A modifier constant
580 */
581uint64_t igt_fb_tiling_to_mod(uint64_t tiling)
582{
583 switch (tiling) {
584 case I915_TILING_NONE:
585 return LOCAL_DRM_FORMAT_MOD_NONE;
586 case I915_TILING_X:
587 return LOCAL_I915_FORMAT_MOD_X_TILED;
588 case I915_TILING_Y:
589 return LOCAL_I915_FORMAT_MOD_Y_TILED;
590 case I915_TILING_Yf:
591 return LOCAL_I915_FORMAT_MOD_Yf_TILED;
592 default:
593 igt_assert(0);
594 }
595}
596
Maxime Ripard49e44e82019-01-25 15:58:33 +0100597static void clear_yuv_buffer(struct igt_fb *fb)
598{
599 bool full_range = fb->color_range == IGT_COLOR_YCBCR_FULL_RANGE;
600 void *ptr;
601
602 igt_assert(igt_format_is_yuv(fb->drm_format));
603
604 /* Ensure the framebuffer is preallocated */
605 ptr = igt_fb_map_buffer(fb->fd, fb);
606 igt_assert(*(uint32_t *)ptr == 0);
607
608 switch (fb->drm_format) {
609 case DRM_FORMAT_NV12:
610 memset(ptr + fb->offsets[0],
611 full_range ? 0x00 : 0x10,
612 fb->strides[0] * fb->plane_height[0]);
613 memset(ptr + fb->offsets[1],
614 0x80,
615 fb->strides[1] * fb->plane_height[1]);
616 break;
617 case DRM_FORMAT_XYUV8888:
618 wmemset(ptr + fb->offsets[0], full_range ? 0x00008080 : 0x00108080,
619 fb->strides[0] * fb->plane_height[0] / sizeof(wchar_t));
620 break;
621 case DRM_FORMAT_YUYV:
622 case DRM_FORMAT_YVYU:
623 wmemset(ptr + fb->offsets[0],
624 full_range ? 0x80008000 : 0x80108010,
625 fb->strides[0] * fb->plane_height[0] / sizeof(wchar_t));
626 break;
627 case DRM_FORMAT_UYVY:
628 case DRM_FORMAT_VYUY:
629 wmemset(ptr + fb->offsets[0],
630 full_range ? 0x00800080 : 0x10801080,
631 fb->strides[0] * fb->plane_height[0] / sizeof(wchar_t));
632 break;
Maarten Lankhorstcb8e45a2019-02-01 11:13:59 +0100633 case DRM_FORMAT_P010:
634 case DRM_FORMAT_P012:
635 case DRM_FORMAT_P016:
636 wmemset(ptr, full_range ? 0 : 0x10001000,
637 fb->offsets[1] / sizeof(wchar_t));
638 wmemset(ptr + fb->offsets[1], 0x80008000,
639 fb->strides[1] * fb->plane_height[1] / sizeof(wchar_t));
640 break;
Maxime Ripard49e44e82019-01-25 15:58:33 +0100641 }
642
643 igt_fb_unmap_buffer(fb, ptr);
644}
645
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200646/* helpers to create nice-looking framebuffers */
Ville Syrjälä22383612018-07-17 18:32:38 +0300647static int create_bo_for_fb(struct igt_fb *fb)
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200648{
Maxime Ripardd6e79072019-02-08 14:18:54 +0100649 const struct format_desc_struct *fmt = lookup_drm_format(fb->drm_format);
650 unsigned int bpp = 0;
651 unsigned int plane;
Maxime Ripard91c95152019-02-08 14:18:55 +0100652 unsigned *strides = &fb->strides[0];
Paul Kocialkowski9e0c8392019-02-20 16:11:16 +0100653 bool device_bo = false;
Ville Syrjälä22383612018-07-17 18:32:38 +0300654 int fd = fb->fd;
Paul Kocialkowski9e0c8392019-02-20 16:11:16 +0100655 uint64_t size;
Maxime Ripardad6e1db2019-02-08 14:18:52 +0100656
Maxime Ripard77c6f0a2019-02-08 14:18:53 +0100657 /*
658 * The current dumb buffer allocation API doesn't really allow to
659 * specify a custom size or stride. Yet the caller is free to specify
Paul Kocialkowski9e0c8392019-02-20 16:11:16 +0100660 * them, so we need to make sure to use a device BO then.
Maxime Ripard77c6f0a2019-02-08 14:18:53 +0100661 */
Paul Kocialkowski9e0c8392019-02-20 16:11:16 +0100662 if (fb->tiling || fb->size || fb->strides[0] ||
663 (is_i915_device(fd) && igt_format_is_yuv(fb->drm_format)))
664 device_bo = true;
Maxime Ripard77c6f0a2019-02-08 14:18:53 +0100665
Paul Kocialkowski9e0c8392019-02-20 16:11:16 +0100666 /* Sets offets and stride if necessary. */
667 size = calc_fb_size(fb);
668
669 /* Respect the size requested by the caller. */
670 if (fb->size == 0)
671 fb->size = size;
672
673 if (device_bo) {
674 fb->is_dumb = false;
675
676 if (is_i915_device(fd)) {
677 fb->gem_handle = gem_create(fd, fb->size);
678 gem_set_tiling(fd, fb->gem_handle,
679 igt_fb_mod_to_tiling(fb->tiling),
680 fb->strides[0]);
Paul Kocialkowski08c9cc02019-01-09 17:55:59 +0100681 } else if (is_vc4_device(fd)) {
682 fb->gem_handle = igt_vc4_create_bo(fd, fb->size);
683
684 if (fb->tiling == DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED)
685 igt_vc4_set_tiling(fd, fb->gem_handle,
686 fb->tiling);
Paul Kocialkowski9e0c8392019-02-20 16:11:16 +0100687 } else {
688 igt_assert(false);
689 }
690
691 goto out;
692 }
693
Maxime Ripardd6e79072019-02-08 14:18:54 +0100694 for (plane = 0; plane < fb->num_planes; plane++)
695 bpp += DIV_ROUND_UP(fb->plane_bpp[plane],
696 plane ? fmt->hsub * fmt->vsub : 1);
Maxime Ripard77c6f0a2019-02-08 14:18:53 +0100697
Maxime Ripardad6e1db2019-02-08 14:18:52 +0100698 fb->is_dumb = true;
Maxime Ripard91c95152019-02-08 14:18:55 +0100699
700 /*
701 * We can't really pass the stride array here since the dumb
702 * buffer allocation is assuming that it operates on one
703 * plane, and therefore will calculate the stride as if each
704 * pixel was stored on a single plane.
705 *
706 * This might cause issues at some point on drivers that would
707 * change the stride of YUV buffers, but we haven't
708 * encountered any yet.
709 */
710 if (fb->num_planes > 1)
711 strides = NULL;
712
Maxime Ripardad6e1db2019-02-08 14:18:52 +0100713 fb->gem_handle = kmstest_dumb_create(fd, fb->width, fb->height,
Maxime Ripard91c95152019-02-08 14:18:55 +0100714 bpp, strides, &fb->size);
Maxime Ripardad6e1db2019-02-08 14:18:52 +0100715
Maxime Ripard270e8222019-02-08 14:18:57 +0100716out:
Maxime Ripard062508c2019-02-08 14:18:56 +0100717 if (igt_format_is_yuv(fb->drm_format))
718 clear_yuv_buffer(fb);
719
Maxime Ripardad6e1db2019-02-08 14:18:52 +0100720 return fb->gem_handle;
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200721}
722
Tomeu Vizoso8a1a3862016-02-24 09:04:04 +0100723/**
724 * igt_create_bo_with_dimensions:
725 * @fd: open drm file descriptor
726 * @width: width of the buffer object in pixels
727 * @height: height of the buffer object in pixels
728 * @format: drm fourcc pixel format code
729 * @modifier: modifier corresponding to the tiling layout of the buffer object
730 * @stride: stride of the buffer object in bytes (0 for automatic stride)
731 * @size_ret: size of the buffer object as created by the kernel
732 * @stride_ret: stride of the buffer object as created by the kernel
733 * @is_dumb: whether the created buffer object is a dumb buffer or not
734 *
735 * This function allocates a gem buffer object matching the requested
736 * properties.
737 *
738 * Returns:
739 * The kms id of the created buffer object.
740 */
741int igt_create_bo_with_dimensions(int fd, int width, int height,
742 uint32_t format, uint64_t modifier,
Ville Syrjälä5f8a33a2018-09-06 16:34:15 +0300743 unsigned stride, uint64_t *size_ret,
Tomeu Vizoso8a1a3862016-02-24 09:04:04 +0100744 unsigned *stride_ret, bool *is_dumb)
745{
Ville Syrjälä22383612018-07-17 18:32:38 +0300746 struct igt_fb fb;
747
748 fb_init(&fb, fd, width, height, format, modifier,
749 IGT_COLOR_YCBCR_BT709, IGT_COLOR_YCBCR_LIMITED_RANGE);
750
751 for (int i = 0; i < fb.num_planes; i++)
752 fb.strides[i] = stride;
753
754 create_bo_for_fb(&fb);
755
756 if (size_ret)
757 *size_ret = fb.size;
758 if (stride_ret)
759 *stride_ret = fb.strides[0];
760 if (is_dumb)
761 *is_dumb = fb.is_dumb;
762
763 return fb.gem_handle;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100764}
765
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100766/**
767 * igt_paint_color:
768 * @cr: cairo drawing context
769 * @x: pixel x-coordination of the fill rectangle
770 * @y: pixel y-coordination of the fill rectangle
771 * @w: width of the fill rectangle
772 * @h: height of the fill rectangle
773 * @r: red value to use as fill color
Thomas Woodd01ebbd2015-06-29 16:47:14 +0100774 * @g: green value to use as fill color
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100775 * @b: blue value to use as fill color
776 *
777 * This functions draws a solid rectangle with the given color using the drawing
778 * context @cr.
779 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100780void igt_paint_color(cairo_t *cr, int x, int y, int w, int h,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100781 double r, double g, double b)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100782{
783 cairo_rectangle(cr, x, y, w, h);
784 cairo_set_source_rgb(cr, r, g, b);
785 cairo_fill(cr);
786}
787
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100788/**
789 * igt_paint_color_alpha:
790 * @cr: cairo drawing context
791 * @x: pixel x-coordination of the fill rectangle
792 * @y: pixel y-coordination of the fill rectangle
793 * @w: width of the fill rectangle
794 * @h: height of the fill rectangle
795 * @r: red value to use as fill color
Thomas Woodd01ebbd2015-06-29 16:47:14 +0100796 * @g: green value to use as fill color
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100797 * @b: blue value to use as fill color
798 * @a: alpha value to use as fill color
799 *
800 * This functions draws a rectangle with the given color and alpha values using
801 * the drawing context @cr.
802 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100803void igt_paint_color_alpha(cairo_t *cr, int x, int y, int w, int h,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100804 double r, double g, double b, double a)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100805{
806 cairo_rectangle(cr, x, y, w, h);
807 cairo_set_source_rgba(cr, r, g, b, a);
808 cairo_fill(cr);
809}
810
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100811/**
812 * igt_paint_color_gradient:
813 * @cr: cairo drawing context
814 * @x: pixel x-coordination of the fill rectangle
815 * @y: pixel y-coordination of the fill rectangle
816 * @w: width of the fill rectangle
817 * @h: height of the fill rectangle
818 * @r: red value to use as fill color
Thomas Woodd01ebbd2015-06-29 16:47:14 +0100819 * @g: green value to use as fill color
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100820 * @b: blue value to use as fill color
821 *
822 * This functions draws a gradient into the rectangle which fades in from black
823 * to the given values using the drawing context @cr.
824 */
Daniel Vetter57d7db82014-03-26 09:06:11 +0100825void
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100826igt_paint_color_gradient(cairo_t *cr, int x, int y, int w, int h,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100827 int r, int g, int b)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100828{
829 cairo_pattern_t *pat;
830
831 pat = cairo_pattern_create_linear(x, y, x + w, y + h);
832 cairo_pattern_add_color_stop_rgba(pat, 1, 0, 0, 0, 1);
833 cairo_pattern_add_color_stop_rgba(pat, 0, r, g, b, 1);
834
835 cairo_rectangle(cr, x, y, w, h);
836 cairo_set_source(cr, pat);
837 cairo_fill(cr);
838 cairo_pattern_destroy(pat);
839}
840
Lionel Landwerlina5113102016-03-18 17:33:02 +0000841/**
842 * igt_paint_color_gradient_range:
843 * @cr: cairo drawing context
844 * @x: pixel x-coordination of the fill rectangle
845 * @y: pixel y-coordination of the fill rectangle
846 * @w: width of the fill rectangle
847 * @h: height of the fill rectangle
848 * @sr: red value to use as start gradient color
849 * @sg: green value to use as start gradient color
850 * @sb: blue value to use as start gradient color
851 * @er: red value to use as end gradient color
852 * @eg: green value to use as end gradient color
853 * @eb: blue value to use as end gradient color
854 *
855 * This functions draws a gradient into the rectangle which fades in
856 * from one color to the other using the drawing context @cr.
857 */
858void
859igt_paint_color_gradient_range(cairo_t *cr, int x, int y, int w, int h,
860 double sr, double sg, double sb,
861 double er, double eg, double eb)
862{
863 cairo_pattern_t *pat;
864
865 pat = cairo_pattern_create_linear(x, y, x + w, y + h);
866 cairo_pattern_add_color_stop_rgba(pat, 1, sr, sg, sb, 1);
867 cairo_pattern_add_color_stop_rgba(pat, 0, er, eg, eb, 1);
868
869 cairo_rectangle(cr, x, y, w, h);
870 cairo_set_source(cr, pat);
871 cairo_fill(cr);
872 cairo_pattern_destroy(pat);
873}
874
Daniel Vetter57d7db82014-03-26 09:06:11 +0100875static void
876paint_test_patterns(cairo_t *cr, int width, int height)
877{
878 double gr_height, gr_width;
879 int x, y;
880
881 y = height * 0.10;
882 gr_width = width * 0.75;
883 gr_height = height * 0.08;
884 x = (width / 2) - (gr_width / 2);
885
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100886 igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 1, 0, 0);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100887
888 y += gr_height;
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100889 igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 0, 1, 0);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100890
891 y += gr_height;
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100892 igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 0, 0, 1);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100893
894 y += gr_height;
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100895 igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 1, 1, 1);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100896}
897
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100898/**
899 * igt_cairo_printf_line:
900 * @cr: cairo drawing context
901 * @align: text alignment
902 * @yspacing: additional y-direction feed after this line
903 * @fmt: format string
904 * @...: optional arguments used in the format string
905 *
906 * This is a little helper to draw text onto framebuffers. All the initial setup
907 * (like setting the font size and the moving to the starting position) still
908 * needs to be done manually with explicit cairo calls on @cr.
909 *
910 * Returns:
911 * The width of the drawn text.
912 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100913int igt_cairo_printf_line(cairo_t *cr, enum igt_text_align align,
Daniel Vetter57d7db82014-03-26 09:06:11 +0100914 double yspacing, const char *fmt, ...)
915{
916 double x, y, xofs, yofs;
917 cairo_text_extents_t extents;
918 char *text;
919 va_list ap;
920 int ret;
921
922 va_start(ap, fmt);
923 ret = vasprintf(&text, fmt, ap);
924 igt_assert(ret >= 0);
925 va_end(ap);
926
927 cairo_text_extents(cr, text, &extents);
928
929 xofs = yofs = 0;
930 if (align & align_right)
931 xofs = -extents.width;
932 else if (align & align_hcenter)
933 xofs = -extents.width / 2;
934
935 if (align & align_top)
936 yofs = extents.height;
937 else if (align & align_vcenter)
938 yofs = extents.height / 2;
939
940 cairo_get_current_point(cr, &x, &y);
941 if (xofs || yofs)
942 cairo_rel_move_to(cr, xofs, yofs);
943
944 cairo_text_path(cr, text);
945 cairo_set_source_rgb(cr, 0, 0, 0);
946 cairo_stroke_preserve(cr);
947 cairo_set_source_rgb(cr, 1, 1, 1);
948 cairo_fill(cr);
949
950 cairo_move_to(cr, x, y + extents.height + yspacing);
951
952 free(text);
953
954 return extents.width;
955}
956
957static void
958paint_marker(cairo_t *cr, int x, int y)
959{
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100960 enum igt_text_align align;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100961 int xoff, yoff;
962
963 cairo_move_to(cr, x, y - 20);
964 cairo_line_to(cr, x, y + 20);
965 cairo_move_to(cr, x - 20, y);
966 cairo_line_to(cr, x + 20, y);
967 cairo_new_sub_path(cr);
968 cairo_arc(cr, x, y, 10, 0, M_PI * 2);
969 cairo_set_line_width(cr, 4);
970 cairo_set_source_rgb(cr, 0, 0, 0);
971 cairo_stroke_preserve(cr);
972 cairo_set_source_rgb(cr, 1, 1, 1);
973 cairo_set_line_width(cr, 2);
974 cairo_stroke(cr);
975
976 xoff = x ? -20 : 20;
977 align = x ? align_right : align_left;
978
979 yoff = y ? -20 : 20;
980 align |= y ? align_bottom : align_top;
981
982 cairo_move_to(cr, x + xoff, y + yoff);
983 cairo_set_font_size(cr, 18);
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100984 igt_cairo_printf_line(cr, align, 0, "(%d, %d)", x, y);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100985}
986
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100987/**
988 * igt_paint_test_pattern:
989 * @cr: cairo drawing context
990 * @width: width of the visible area
991 * @height: height of the visible area
992 *
993 * This functions draws an entire set of test patterns for the given visible
994 * area using the drawing context @cr. This is useful for manual visual
995 * inspection of displayed framebuffers.
996 *
997 * The test patterns include
998 * - corner markers to check for over/underscan and
999 * - a set of color and b/w gradients.
1000 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01001001void igt_paint_test_pattern(cairo_t *cr, int width, int height)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001002{
1003 paint_test_patterns(cr, width, height);
1004
1005 cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
1006
1007 /* Paint corner markers */
1008 paint_marker(cr, 0, 0);
1009 paint_marker(cr, width, 0);
1010 paint_marker(cr, 0, height);
1011 paint_marker(cr, width, height);
1012
1013 igt_assert(!cairo_status(cr));
1014}
1015
Thomas Woodecb03262015-04-13 17:37:22 +01001016static cairo_status_t
1017stdio_read_func(void *closure, unsigned char* data, unsigned int size)
1018{
1019 if (fread(data, 1, size, (FILE*)closure) != size)
1020 return CAIRO_STATUS_READ_ERROR;
1021
1022 return CAIRO_STATUS_SUCCESS;
1023}
1024
Ville Syrjälä75f320c2017-09-21 15:39:23 +03001025cairo_surface_t *igt_cairo_image_surface_create_from_png(const char *filename)
1026{
1027 cairo_surface_t *image;
1028 FILE *f;
1029
1030 f = igt_fopen_data(filename);
1031 image = cairo_image_surface_create_from_png_stream(&stdio_read_func, f);
1032 fclose(f);
1033
1034 return image;
1035}
1036
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001037/**
1038 * igt_paint_image:
1039 * @cr: cairo drawing context
1040 * @filename: filename of the png image to draw
1041 * @dst_x: pixel x-coordination of the destination rectangle
1042 * @dst_y: pixel y-coordination of the destination rectangle
1043 * @dst_width: width of the destination rectangle
1044 * @dst_height: height of the destination rectangle
1045 *
Thomas Woodecb03262015-04-13 17:37:22 +01001046 * This function can be used to draw a scaled version of the supplied png image,
1047 * which is loaded from the package data directory.
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001048 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01001049void igt_paint_image(cairo_t *cr, const char *filename,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001050 int dst_x, int dst_y, int dst_width, int dst_height)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001051{
1052 cairo_surface_t *image;
1053 int img_width, img_height;
1054 double scale_x, scale_y;
1055
Ville Syrjälä75f320c2017-09-21 15:39:23 +03001056 image = igt_cairo_image_surface_create_from_png(filename);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001057 igt_assert(cairo_surface_status(image) == CAIRO_STATUS_SUCCESS);
1058
1059 img_width = cairo_image_surface_get_width(image);
1060 img_height = cairo_image_surface_get_height(image);
1061
1062 scale_x = (double)dst_width / img_width;
1063 scale_y = (double)dst_height / img_height;
1064
1065 cairo_save(cr);
1066
1067 cairo_translate(cr, dst_x, dst_y);
1068 cairo_scale(cr, scale_x, scale_y);
1069 cairo_set_source_surface(cr, image, 0, 0);
1070 cairo_paint(cr);
1071
1072 cairo_surface_destroy(image);
1073
1074 cairo_restore(cr);
1075}
1076
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001077/**
Oscar Mateo5bdd4d92014-05-16 14:07:11 +01001078 * igt_create_fb_with_bo_size:
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001079 * @fd: open i915 drm file descriptor
1080 * @width: width of the framebuffer in pixel
1081 * @height: height of the framebuffer in pixel
1082 * @format: drm fourcc pixel format code
Tvrtko Ursuline36091d2015-03-03 14:11:01 +00001083 * @tiling: tiling layout of the framebuffer (as framebuffer modifier)
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001084 * @fb: pointer to an #igt_fb structure
Paulo Zanonicb7dd5d2015-11-05 16:18:55 -02001085 * @bo_size: size of the backing bo (0 for automatic size)
Paulo Zanonid6341372015-11-05 16:39:00 -02001086 * @bo_stride: stride of the backing bo (0 for automatic stride)
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001087 *
1088 * This function allocates a gem buffer object suitable to back a framebuffer
1089 * with the requested properties and then wraps it up in a drm framebuffer
Oscar Mateo5bdd4d92014-05-16 14:07:11 +01001090 * object of the requested size. All metadata is stored in @fb.
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001091 *
1092 * The backing storage of the framebuffer is filled with all zeros, i.e. black
1093 * for rgb pixel formats.
1094 *
1095 * Returns:
Damien Lespiau50166d22014-08-19 11:55:22 +01001096 * The kms id of the created framebuffer.
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001097 */
Damien Lespiau378e61e2014-06-23 14:53:24 +01001098unsigned int
1099igt_create_fb_with_bo_size(int fd, int width, int height,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +00001100 uint32_t format, uint64_t tiling,
Ville Syrjälä5f8a33a2018-09-06 16:34:15 +03001101 struct igt_fb *fb, uint64_t bo_size,
Paulo Zanonid6341372015-11-05 16:39:00 -02001102 unsigned bo_stride)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001103{
Ville Syrjäläb6975342018-03-06 20:01:22 +02001104 /* FIXME allow the caller to pass these in */
1105 enum igt_color_encoding color_encoding = IGT_COLOR_YCBCR_BT709;
1106 enum igt_color_range color_range = IGT_COLOR_YCBCR_LIMITED_RANGE;
Deepak Rawat759af702018-10-16 15:23:39 -07001107 uint32_t flags = 0;
Maarten Lankhorst918ea422018-01-19 12:47:11 +01001108
Ville Syrjälä22383612018-07-17 18:32:38 +03001109 fb_init(fb, fd, width, height, format, tiling,
1110 color_encoding, color_range);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001111
Ville Syrjälä22383612018-07-17 18:32:38 +03001112 for (int i = 0; i < fb->num_planes; i++)
1113 fb->strides[i] = bo_stride;
1114
1115 fb->size = bo_size;
Daniel Vetter57d7db82014-03-26 09:06:11 +01001116
Ville Syrjälä5f8a33a2018-09-06 16:34:15 +03001117 igt_debug("%s(width=%d, height=%d, format=0x%x, tiling=0x%"PRIx64", size=%"PRIu64")\n",
Tomeu Vizoso8a1a3862016-02-24 09:04:04 +01001118 __func__, width, height, format, tiling, bo_size);
Ville Syrjälä22383612018-07-17 18:32:38 +03001119
1120 create_bo_for_fb(fb);
Tomeu Vizoso7be235c2016-04-22 11:08:45 +02001121 igt_assert(fb->gem_handle > 0);
Chris Wilsondb4cc742014-09-06 12:07:49 +01001122
Chris Wilsondb4cc742014-09-06 12:07:49 +01001123 igt_debug("%s(handle=%d, pitch=%d)\n",
Ville Syrjälä22383612018-07-17 18:32:38 +03001124 __func__, fb->gem_handle, fb->strides[0]);
Tvrtko Ursulineb93c1b2015-03-03 14:11:03 +00001125
Deepak Rawat759af702018-10-16 15:23:39 -07001126 if (fb->tiling || igt_has_fb_modifiers(fd))
1127 flags = LOCAL_DRM_MODE_FB_MODIFIERS;
1128
Ville Syrjälä22383612018-07-17 18:32:38 +03001129 do_or_die(__kms_addfb(fb->fd, fb->gem_handle,
1130 fb->width, fb->height,
1131 fb->drm_format, fb->tiling,
Deepak Rawat759af702018-10-16 15:23:39 -07001132 fb->strides, fb->offsets, fb->num_planes, flags,
Ville Syrjälä22383612018-07-17 18:32:38 +03001133 &fb->fb_id));
Ville Syrjälä42359ed2018-07-17 18:50:13 +03001134
Ville Syrjälä22383612018-07-17 18:32:38 +03001135 return fb->fb_id;
Daniel Vetter57d7db82014-03-26 09:06:11 +01001136}
1137
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001138/**
Oscar Mateo5bdd4d92014-05-16 14:07:11 +01001139 * igt_create_fb:
1140 * @fd: open i915 drm file descriptor
1141 * @width: width of the framebuffer in pixel
1142 * @height: height of the framebuffer in pixel
1143 * @format: drm fourcc pixel format code
Damien Lespiau378e61e2014-06-23 14:53:24 +01001144 * @tiling: tiling layout of the framebuffer
Oscar Mateo5bdd4d92014-05-16 14:07:11 +01001145 * @fb: pointer to an #igt_fb structure
1146 *
1147 * This function allocates a gem buffer object suitable to back a framebuffer
1148 * with the requested properties and then wraps it up in a drm framebuffer
1149 * object. All metadata is stored in @fb.
1150 *
1151 * The backing storage of the framebuffer is filled with all zeros, i.e. black
1152 * for rgb pixel formats.
1153 *
1154 * Returns:
Damien Lespiau50166d22014-08-19 11:55:22 +01001155 * The kms id of the created framebuffer.
Oscar Mateo5bdd4d92014-05-16 14:07:11 +01001156 */
1157unsigned int igt_create_fb(int fd, int width, int height, uint32_t format,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +00001158 uint64_t tiling, struct igt_fb *fb)
Oscar Mateo5bdd4d92014-05-16 14:07:11 +01001159{
Paulo Zanonid6341372015-11-05 16:39:00 -02001160 return igt_create_fb_with_bo_size(fd, width, height, format, tiling, fb,
1161 0, 0);
Oscar Mateo5bdd4d92014-05-16 14:07:11 +01001162}
1163
1164/**
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001165 * igt_create_color_fb:
1166 * @fd: open i915 drm file descriptor
1167 * @width: width of the framebuffer in pixel
1168 * @height: height of the framebuffer in pixel
1169 * @format: drm fourcc pixel format code
Damien Lespiau378e61e2014-06-23 14:53:24 +01001170 * @tiling: tiling layout of the framebuffer
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001171 * @r: red value to use as fill color
Ville Syrjälä5b113d32015-12-17 01:39:31 +02001172 * @g: green value to use as fill color
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001173 * @b: blue value to use as fill color
1174 * @fb: pointer to an #igt_fb structure
1175 *
1176 * This function allocates a gem buffer object suitable to back a framebuffer
1177 * with the requested properties and then wraps it up in a drm framebuffer
1178 * object. All metadata is stored in @fb.
1179 *
1180 * Compared to igt_create_fb() this function also fills the entire framebuffer
1181 * with the given color, which is useful for some simple pipe crc based tests.
1182 *
1183 * Returns:
1184 * The kms id of the created framebuffer on success or a negative error code on
1185 * failure.
1186 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01001187unsigned int igt_create_color_fb(int fd, int width, int height,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +00001188 uint32_t format, uint64_t tiling,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001189 double r, double g, double b,
1190 struct igt_fb *fb /* out */)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001191{
1192 unsigned int fb_id;
1193 cairo_t *cr;
1194
Damien Lespiau378e61e2014-06-23 14:53:24 +01001195 fb_id = igt_create_fb(fd, width, height, format, tiling, fb);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001196 igt_assert(fb_id);
1197
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01001198 cr = igt_get_cairo_ctx(fd, fb);
1199 igt_paint_color(cr, 0, 0, width, height, r, g, b);
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +01001200 igt_put_cairo_ctx(fd, fb, cr);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001201
1202 return fb_id;
1203}
1204
Ville Syrjälä5b113d32015-12-17 01:39:31 +02001205/**
1206 * igt_create_pattern_fb:
1207 * @fd: open i915 drm file descriptor
1208 * @width: width of the framebuffer in pixel
1209 * @height: height of the framebuffer in pixel
1210 * @format: drm fourcc pixel format code
1211 * @tiling: tiling layout of the framebuffer
1212 * @fb: pointer to an #igt_fb structure
1213 *
1214 * This function allocates a gem buffer object suitable to back a framebuffer
1215 * with the requested properties and then wraps it up in a drm framebuffer
1216 * object. All metadata is stored in @fb.
1217 *
1218 * Compared to igt_create_fb() this function also draws the standard test pattern
1219 * into the framebuffer.
1220 *
1221 * Returns:
1222 * The kms id of the created framebuffer on success or a negative error code on
1223 * failure.
1224 */
1225unsigned int igt_create_pattern_fb(int fd, int width, int height,
1226 uint32_t format, uint64_t tiling,
1227 struct igt_fb *fb /* out */)
1228{
1229 unsigned int fb_id;
1230 cairo_t *cr;
1231
1232 fb_id = igt_create_fb(fd, width, height, format, tiling, fb);
1233 igt_assert(fb_id);
1234
1235 cr = igt_get_cairo_ctx(fd, fb);
1236 igt_paint_test_pattern(cr, width, height);
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +01001237 igt_put_cairo_ctx(fd, fb, cr);
Ville Syrjälä5b113d32015-12-17 01:39:31 +02001238
1239 return fb_id;
1240}
1241
1242/**
1243 * igt_create_color_pattern_fb:
1244 * @fd: open i915 drm file descriptor
1245 * @width: width of the framebuffer in pixel
1246 * @height: height of the framebuffer in pixel
1247 * @format: drm fourcc pixel format code
1248 * @tiling: tiling layout of the framebuffer
1249 * @r: red value to use as fill color
1250 * @g: green value to use as fill color
1251 * @b: blue value to use as fill color
1252 * @fb: pointer to an #igt_fb structure
1253 *
1254 * This function allocates a gem buffer object suitable to back a framebuffer
1255 * with the requested properties and then wraps it up in a drm framebuffer
1256 * object. All metadata is stored in @fb.
1257 *
1258 * Compared to igt_create_fb() this function also fills the entire framebuffer
1259 * with the given color, and then draws the standard test pattern into the
1260 * framebuffer.
1261 *
1262 * Returns:
1263 * The kms id of the created framebuffer on success or a negative error code on
1264 * failure.
1265 */
1266unsigned int igt_create_color_pattern_fb(int fd, int width, int height,
1267 uint32_t format, uint64_t tiling,
1268 double r, double g, double b,
1269 struct igt_fb *fb /* out */)
1270{
1271 unsigned int fb_id;
1272 cairo_t *cr;
1273
1274 fb_id = igt_create_fb(fd, width, height, format, tiling, fb);
1275 igt_assert(fb_id);
1276
1277 cr = igt_get_cairo_ctx(fd, fb);
1278 igt_paint_color(cr, 0, 0, width, height, r, g, b);
1279 igt_paint_test_pattern(cr, width, height);
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +01001280 igt_put_cairo_ctx(fd, fb, cr);
Ville Syrjälä5b113d32015-12-17 01:39:31 +02001281
1282 return fb_id;
1283}
1284
1285/**
1286 * igt_create_image_fb:
1287 * @drm_fd: open i915 drm file descriptor
1288 * @width: width of the framebuffer in pixel or 0
1289 * @height: height of the framebuffer in pixel or 0
1290 * @format: drm fourcc pixel format code
1291 * @tiling: tiling layout of the framebuffer
1292 * @filename: filename of the png image to draw
1293 * @fb: pointer to an #igt_fb structure
1294 *
1295 * Create a framebuffer with the specified image. If @width is zero the
1296 * image width will be used. If @height is zero the image height will be used.
1297 *
1298 * Returns:
1299 * The kms id of the created framebuffer on success or a negative error code on
1300 * failure.
1301 */
1302unsigned int igt_create_image_fb(int fd, int width, int height,
1303 uint32_t format, uint64_t tiling,
1304 const char *filename,
1305 struct igt_fb *fb /* out */)
1306{
1307 cairo_surface_t *image;
1308 uint32_t fb_id;
1309 cairo_t *cr;
1310
Ville Syrjälä75f320c2017-09-21 15:39:23 +03001311 image = igt_cairo_image_surface_create_from_png(filename);
Ville Syrjälä5b113d32015-12-17 01:39:31 +02001312 igt_assert(cairo_surface_status(image) == CAIRO_STATUS_SUCCESS);
1313 if (width == 0)
1314 width = cairo_image_surface_get_width(image);
1315 if (height == 0)
1316 height = cairo_image_surface_get_height(image);
1317 cairo_surface_destroy(image);
1318
1319 fb_id = igt_create_fb(fd, width, height, format, tiling, fb);
1320
1321 cr = igt_get_cairo_ctx(fd, fb);
1322 igt_paint_image(cr, filename, 0, 0, width, height);
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +01001323 igt_put_cairo_ctx(fd, fb, cr);
Ville Syrjälä5b113d32015-12-17 01:39:31 +02001324
1325 return fb_id;
1326}
1327
Thomas Wood4cb19462014-08-04 16:14:51 +01001328struct box {
1329 int x, y, width, height;
1330};
1331
1332struct stereo_fb_layout {
1333 int fb_width, fb_height;
1334 struct box left, right;
1335};
1336
1337static void box_init(struct box *box, int x, int y, int bwidth, int bheight)
1338{
1339 box->x = x;
1340 box->y = y;
1341 box->width = bwidth;
1342 box->height = bheight;
1343}
1344
1345
1346static void stereo_fb_layout_from_mode(struct stereo_fb_layout *layout,
1347 drmModeModeInfo *mode)
1348{
1349 unsigned int format = mode->flags & DRM_MODE_FLAG_3D_MASK;
1350 const int hdisplay = mode->hdisplay, vdisplay = mode->vdisplay;
1351 int middle;
1352
1353 switch (format) {
1354 case DRM_MODE_FLAG_3D_TOP_AND_BOTTOM:
1355 layout->fb_width = hdisplay;
1356 layout->fb_height = vdisplay;
1357
1358 middle = vdisplay / 2;
1359 box_init(&layout->left, 0, 0, hdisplay, middle);
1360 box_init(&layout->right,
1361 0, middle, hdisplay, vdisplay - middle);
1362 break;
1363 case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF:
1364 layout->fb_width = hdisplay;
1365 layout->fb_height = vdisplay;
1366
1367 middle = hdisplay / 2;
1368 box_init(&layout->left, 0, 0, middle, vdisplay);
1369 box_init(&layout->right,
1370 middle, 0, hdisplay - middle, vdisplay);
1371 break;
1372 case DRM_MODE_FLAG_3D_FRAME_PACKING:
1373 {
1374 int vactive_space = mode->vtotal - vdisplay;
1375
1376 layout->fb_width = hdisplay;
1377 layout->fb_height = 2 * vdisplay + vactive_space;
1378
1379 box_init(&layout->left,
1380 0, 0, hdisplay, vdisplay);
1381 box_init(&layout->right,
1382 0, vdisplay + vactive_space, hdisplay, vdisplay);
1383 break;
1384 }
1385 default:
1386 igt_assert(0);
1387 }
1388}
1389
1390/**
1391 * igt_create_stereo_fb:
1392 * @drm_fd: open i915 drm file descriptor
1393 * @mode: A stereo 3D mode.
1394 * @format: drm fourcc pixel format code
1395 * @tiling: tiling layout of the framebuffer
1396 *
1397 * Create a framebuffer for use with the stereo 3D mode specified by @mode.
1398 *
1399 * Returns:
1400 * The kms id of the created framebuffer on success or a negative error code on
1401 * failure.
1402 */
1403unsigned int igt_create_stereo_fb(int drm_fd, drmModeModeInfo *mode,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +00001404 uint32_t format, uint64_t tiling)
Thomas Wood4cb19462014-08-04 16:14:51 +01001405{
1406 struct stereo_fb_layout layout;
1407 cairo_t *cr;
1408 uint32_t fb_id;
1409 struct igt_fb fb;
1410
1411 stereo_fb_layout_from_mode(&layout, mode);
1412 fb_id = igt_create_fb(drm_fd, layout.fb_width, layout.fb_height, format,
1413 tiling, &fb);
1414 cr = igt_get_cairo_ctx(drm_fd, &fb);
1415
Thomas Woodecb03262015-04-13 17:37:22 +01001416 igt_paint_image(cr, "1080p-left.png",
Thomas Wood4cb19462014-08-04 16:14:51 +01001417 layout.left.x, layout.left.y,
1418 layout.left.width, layout.left.height);
Thomas Woodecb03262015-04-13 17:37:22 +01001419 igt_paint_image(cr, "1080p-right.png",
Thomas Wood4cb19462014-08-04 16:14:51 +01001420 layout.right.x, layout.right.y,
1421 layout.right.width, layout.right.height);
1422
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +01001423 igt_put_cairo_ctx(drm_fd, &fb, cr);
Thomas Wood4cb19462014-08-04 16:14:51 +01001424
1425 return fb_id;
1426}
1427
Maxime Ripard3fa65f42018-10-04 14:39:03 +02001428static pixman_format_code_t drm_format_to_pixman(uint32_t drm_format)
1429{
1430 const struct format_desc_struct *f;
1431
1432 for_each_format(f)
1433 if (f->drm_id == drm_format)
1434 return f->pixman_id;
1435
1436 igt_assert_f(0, "can't find a pixman format for %08x (%s)\n",
1437 drm_format, igt_format_str(drm_format));
1438}
1439
Daniel Vetter57d7db82014-03-26 09:06:11 +01001440static cairo_format_t drm_format_to_cairo(uint32_t drm_format)
1441{
Ville Syrjäläef43fce2018-07-18 20:26:22 +03001442 const struct format_desc_struct *f;
Daniel Vetter57d7db82014-03-26 09:06:11 +01001443
1444 for_each_format(f)
1445 if (f->drm_id == drm_format)
1446 return f->cairo_id;
1447
Damien Lespiau54397ca2014-08-19 11:40:07 +01001448 igt_assert_f(0, "can't find a cairo format for %08x (%s)\n",
1449 drm_format, igt_format_str(drm_format));
Daniel Vetter57d7db82014-03-26 09:06:11 +01001450}
1451
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001452struct fb_blit_linear {
Ville Syrjälä22383612018-07-17 18:32:38 +03001453 struct igt_fb fb;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001454 uint8_t *map;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001455};
1456
Damien Lespiauff451a62015-03-03 14:11:04 +00001457struct fb_blit_upload {
1458 int fd;
1459 struct igt_fb *fb;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001460 struct fb_blit_linear linear;
Damien Lespiauff451a62015-03-03 14:11:04 +00001461};
1462
Ville Syrjälä6f5d6b02018-07-18 20:11:52 +03001463static void blitcopy(const struct igt_fb *dst_fb,
1464 const struct igt_fb *src_fb)
1465{
1466 igt_assert_eq(dst_fb->fd, src_fb->fd);
1467 igt_assert_eq(dst_fb->num_planes, src_fb->num_planes);
1468
1469 for (int i = 0; i < dst_fb->num_planes; i++) {
1470 igt_assert_eq(dst_fb->plane_bpp[i], src_fb->plane_bpp[i]);
1471 igt_assert_eq(dst_fb->plane_width[i], src_fb->plane_width[i]);
1472 igt_assert_eq(dst_fb->plane_height[i], src_fb->plane_height[i]);
1473
1474 igt_blitter_fast_copy__raw(dst_fb->fd,
1475 src_fb->gem_handle,
1476 src_fb->offsets[i],
1477 src_fb->strides[i],
1478 igt_fb_mod_to_tiling(src_fb->tiling),
1479 0, 0, /* src_x, src_y */
1480 dst_fb->plane_width[i], dst_fb->plane_height[i],
1481 dst_fb->plane_bpp[i],
1482 dst_fb->gem_handle,
1483 dst_fb->offsets[i],
1484 dst_fb->strides[i],
1485 igt_fb_mod_to_tiling(dst_fb->tiling),
1486 0, 0 /* dst_x, dst_y */);
1487 }
1488}
1489
Ville Syrjälä74261fd2018-07-17 16:20:34 +03001490static void free_linear_mapping(struct fb_blit_upload *blit)
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001491{
Ville Syrjälä74261fd2018-07-17 16:20:34 +03001492 int fd = blit->fd;
1493 struct igt_fb *fb = blit->fb;
1494 struct fb_blit_linear *linear = &blit->linear;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001495
Ville Syrjälä22383612018-07-17 18:32:38 +03001496 gem_munmap(linear->map, linear->fb.size);
1497 gem_set_domain(fd, linear->fb.gem_handle,
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001498 I915_GEM_DOMAIN_GTT, 0);
1499
Ville Syrjälä6f5d6b02018-07-18 20:11:52 +03001500 blitcopy(fb, &linear->fb);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001501
Ville Syrjälä22383612018-07-17 18:32:38 +03001502 gem_sync(fd, linear->fb.gem_handle);
1503 gem_close(fd, linear->fb.gem_handle);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001504}
1505
Damien Lespiauff451a62015-03-03 14:11:04 +00001506static void destroy_cairo_surface__blit(void *arg)
1507{
1508 struct fb_blit_upload *blit = arg;
Damien Lespiauff451a62015-03-03 14:11:04 +00001509
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001510 blit->fb->cairo_surface = NULL;
Damien Lespiauff451a62015-03-03 14:11:04 +00001511
Ville Syrjälä74261fd2018-07-17 16:20:34 +03001512 free_linear_mapping(blit);
Damien Lespiauff451a62015-03-03 14:11:04 +00001513
1514 free(blit);
1515}
1516
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001517static void setup_linear_mapping(int fd, struct igt_fb *fb, struct fb_blit_linear *linear)
Damien Lespiauff451a62015-03-03 14:11:04 +00001518{
Damien Lespiauff451a62015-03-03 14:11:04 +00001519 /*
1520 * We create a linear BO that we'll map for the CPU to write to (using
1521 * cairo). This linear bo will be then blitted to its final
1522 * destination, tiling it at the same time.
1523 */
Damien Lespiauff451a62015-03-03 14:11:04 +00001524
Ville Syrjälä22383612018-07-17 18:32:38 +03001525 fb_init(&linear->fb, fb->fd, fb->width, fb->height,
1526 fb->drm_format, LOCAL_DRM_FORMAT_MOD_NONE,
1527 fb->color_encoding, fb->color_range);
1528
1529 create_bo_for_fb(&linear->fb);
1530
1531 igt_assert(linear->fb.gem_handle > 0);
Tvrtko Ursulin30a13602015-04-29 13:24:34 +01001532
1533 /* Copy fb content to linear BO */
Ville Syrjälä22383612018-07-17 18:32:38 +03001534 gem_set_domain(fd, linear->fb.gem_handle,
Tvrtko Ursulin30a13602015-04-29 13:24:34 +01001535 I915_GEM_DOMAIN_GTT, 0);
1536
Ville Syrjälä6f5d6b02018-07-18 20:11:52 +03001537 blitcopy(&linear->fb, fb);
Tvrtko Ursulin30a13602015-04-29 13:24:34 +01001538
Ville Syrjälä22383612018-07-17 18:32:38 +03001539 gem_sync(fd, linear->fb.gem_handle);
Tvrtko Ursulin30a13602015-04-29 13:24:34 +01001540
Ville Syrjälä22383612018-07-17 18:32:38 +03001541 gem_set_domain(fd, linear->fb.gem_handle,
Tvrtko Ursulin30a13602015-04-29 13:24:34 +01001542 I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
1543
1544 /* Setup cairo context */
Ville Syrjälä22383612018-07-17 18:32:38 +03001545 linear->map = gem_mmap__cpu(fd, linear->fb.gem_handle,
1546 0, linear->fb.size, PROT_READ | PROT_WRITE);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001547}
1548
1549static void create_cairo_surface__blit(int fd, struct igt_fb *fb)
1550{
1551 struct fb_blit_upload *blit;
1552 cairo_format_t cairo_format;
1553
1554 blit = malloc(sizeof(*blit));
1555 igt_assert(blit);
1556
1557 blit->fd = fd;
1558 blit->fb = fb;
1559 setup_linear_mapping(fd, fb, &blit->linear);
Damien Lespiauff451a62015-03-03 14:11:04 +00001560
Damien Lespiauff451a62015-03-03 14:11:04 +00001561 cairo_format = drm_format_to_cairo(fb->drm_format);
1562 fb->cairo_surface =
1563 cairo_image_surface_create_for_data(blit->linear.map,
1564 cairo_format,
1565 fb->width, fb->height,
Ville Syrjälä22383612018-07-17 18:32:38 +03001566 blit->linear.fb.strides[0]);
Chris Wilson18d0b1e2016-03-02 14:12:12 +00001567 fb->domain = I915_GEM_DOMAIN_GTT;
Damien Lespiauff451a62015-03-03 14:11:04 +00001568
1569 cairo_surface_set_user_data(fb->cairo_surface,
1570 (cairo_user_data_key_t *)create_cairo_surface__blit,
1571 blit, destroy_cairo_surface__blit);
1572}
1573
Tomeu Vizosoa2d5b342016-03-07 16:25:43 +01001574/**
1575 * igt_dirty_fb:
1576 * @fd: open drm file descriptor
1577 * @fb: pointer to an #igt_fb structure
1578 *
1579 * Flushes out the whole framebuffer.
1580 *
1581 * Returns: 0 upon success.
1582 */
1583int igt_dirty_fb(int fd, struct igt_fb *fb)
1584{
1585 return drmModeDirtyFB(fb->fd, fb->fb_id, NULL, 0);
1586}
1587
Maxime Ripard3415b192018-10-04 14:38:54 +02001588static void unmap_bo(struct igt_fb *fb, void *ptr)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001589{
Maxime Ripard3415b192018-10-04 14:38:54 +02001590 gem_munmap(ptr, fb->size);
Tomeu Vizoso89b3ffe2016-02-24 09:04:41 +01001591
1592 if (fb->is_dumb)
1593 igt_dirty_fb(fb->fd, fb);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001594}
1595
Maxime Ripard3415b192018-10-04 14:38:54 +02001596static void destroy_cairo_surface__gtt(void *arg)
1597{
1598 struct igt_fb *fb = arg;
1599
1600 unmap_bo(fb, cairo_image_surface_get_data(fb->cairo_surface));
1601 fb->cairo_surface = NULL;
1602}
1603
1604static void *map_bo(int fd, struct igt_fb *fb)
Damien Lespiau4aadbc82014-06-23 16:41:43 +01001605{
Tomeu Vizoso89b3ffe2016-02-24 09:04:41 +01001606 void *ptr;
1607
Maxime Ripard80bb4432018-10-04 14:38:55 +02001608 if (is_i915_device(fd))
1609 gem_set_domain(fd, fb->gem_handle,
1610 I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
Ville Syrjälä3bd68522018-09-05 19:55:43 +03001611
Tomeu Vizoso89b3ffe2016-02-24 09:04:41 +01001612 if (fb->is_dumb)
1613 ptr = kmstest_dumb_map_buffer(fd, fb->gem_handle, fb->size,
1614 PROT_READ | PROT_WRITE);
Paul Kocialkowskie1092cb2018-12-05 11:14:37 +01001615 else if (is_i915_device(fd))
Tomeu Vizoso89b3ffe2016-02-24 09:04:41 +01001616 ptr = gem_mmap__gtt(fd, fb->gem_handle, fb->size,
1617 PROT_READ | PROT_WRITE);
Paul Kocialkowski08c9cc02019-01-09 17:55:59 +01001618 else if (is_vc4_device(fd))
1619 ptr = igt_vc4_mmap_bo(fd, fb->gem_handle, fb->size,
1620 PROT_READ | PROT_WRITE);
Paul Kocialkowskie1092cb2018-12-05 11:14:37 +01001621 else
1622 igt_assert(false);
Ville Syrjälä106fe212015-10-09 18:36:24 +03001623
Maxime Ripard3415b192018-10-04 14:38:54 +02001624 return ptr;
1625}
1626
1627static void create_cairo_surface__gtt(int fd, struct igt_fb *fb)
1628{
1629 void *ptr = map_bo(fd, fb);
1630
Damien Lespiau4aadbc82014-06-23 16:41:43 +01001631 fb->cairo_surface =
Ville Syrjälä106fe212015-10-09 18:36:24 +03001632 cairo_image_surface_create_for_data(ptr,
Damien Lespiau4aadbc82014-06-23 16:41:43 +01001633 drm_format_to_cairo(fb->drm_format),
Ville Syrjälä22383612018-07-17 18:32:38 +03001634 fb->width, fb->height, fb->strides[0]);
Deepak Rawatc7034c72018-10-16 15:23:38 -07001635 igt_require_f(cairo_surface_status(fb->cairo_surface) == CAIRO_STATUS_SUCCESS,
1636 "Unable to create a cairo surface: %s\n",
1637 cairo_status_to_string(cairo_surface_status(fb->cairo_surface)));
1638
Chris Wilson18d0b1e2016-03-02 14:12:12 +00001639 fb->domain = I915_GEM_DOMAIN_GTT;
Damien Lespiau4aadbc82014-06-23 16:41:43 +01001640
1641 cairo_surface_set_user_data(fb->cairo_surface,
1642 (cairo_user_data_key_t *)create_cairo_surface__gtt,
1643 fb, destroy_cairo_surface__gtt);
1644}
1645
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001646struct fb_convert_blit_upload {
Ville Syrjälä3ed2a602018-07-17 16:15:34 +03001647 struct fb_blit_upload base;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001648
Maxime Ripardc7128362018-10-04 14:38:57 +02001649 struct igt_fb shadow_fb;
1650 uint8_t *shadow_ptr;
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001651};
1652
Maxime Ripardc7128362018-10-04 14:38:57 +02001653static void *igt_fb_create_cairo_shadow_buffer(int fd,
Maarten Lankhorstcb8e45a2019-02-01 11:13:59 +01001654 unsigned drm_format,
Maxime Ripardc7128362018-10-04 14:38:57 +02001655 unsigned int width,
1656 unsigned int height,
1657 struct igt_fb *shadow)
1658{
1659 void *ptr;
1660
1661 igt_assert(shadow);
1662
1663 fb_init(shadow, fd, width, height,
Maarten Lankhorstcb8e45a2019-02-01 11:13:59 +01001664 drm_format, LOCAL_DRM_FORMAT_MOD_NONE,
Maxime Ripardc7128362018-10-04 14:38:57 +02001665 IGT_COLOR_YCBCR_BT709, IGT_COLOR_YCBCR_LIMITED_RANGE);
1666
Maarten Lankhorstb0033d92018-06-07 16:25:22 +02001667 shadow->strides[0] = ALIGN(width * shadow->plane_bpp[0], 16);
Maxime Ripardc7128362018-10-04 14:38:57 +02001668 shadow->size = ALIGN(shadow->strides[0] * height,
1669 sysconf(_SC_PAGESIZE));
1670 ptr = mmap(NULL, shadow->size, PROT_READ | PROT_WRITE,
1671 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
1672 igt_assert(ptr != MAP_FAILED);
1673
1674 return ptr;
1675}
1676
1677static void igt_fb_destroy_cairo_shadow_buffer(struct igt_fb *shadow,
1678 void *ptr)
1679{
1680 munmap(ptr, shadow->size);
1681}
1682
Ville Syrjäläee26fef2018-02-27 22:38:05 +02001683static uint8_t clamprgb(float val)
1684{
Ville Syrjäläd1a93aa2018-06-06 20:36:44 +03001685 return clamp((int)(val + 0.5f), 0, 255);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001686}
1687
Ville Syrjälä1c7ef382018-02-27 22:59:25 +02001688static void read_rgb(struct igt_vec4 *rgb, const uint8_t *rgb24)
1689{
1690 rgb->d[0] = rgb24[2];
1691 rgb->d[1] = rgb24[1];
1692 rgb->d[2] = rgb24[0];
1693 rgb->d[3] = 1.0f;
1694}
1695
1696static void write_rgb(uint8_t *rgb24, const struct igt_vec4 *rgb)
1697{
1698 rgb24[2] = clamprgb(rgb->d[0]);
1699 rgb24[1] = clamprgb(rgb->d[1]);
1700 rgb24[0] = clamprgb(rgb->d[2]);
1701}
1702
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001703struct fb_convert_buf {
1704 void *ptr;
1705 struct igt_fb *fb;
Ville Syrjälä737241d2018-11-01 23:31:20 +02001706 bool slow_reads;
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001707};
1708
1709struct fb_convert {
1710 struct fb_convert_buf dst;
1711 struct fb_convert_buf src;
1712};
1713
Ville Syrjälä737241d2018-11-01 23:31:20 +02001714static void *convert_src_get(const struct fb_convert *cvt)
1715{
1716 void *buf;
1717
1718 if (!cvt->src.slow_reads)
1719 return cvt->src.ptr;
1720
1721 /*
1722 * Reading from the BO is awfully slow because of lack of read caching,
1723 * it's faster to copy the whole BO to a temporary buffer and convert
1724 * from there.
1725 */
1726 buf = malloc(cvt->src.fb->size);
1727 if (!buf)
1728 return cvt->src.ptr;
1729
1730 igt_memcpy_from_wc(buf, cvt->src.ptr, cvt->src.fb->size);
1731
1732 return buf;
1733}
1734
1735static void convert_src_put(const struct fb_convert *cvt,
1736 void *src_buf)
1737{
1738 if (src_buf != cvt->src.ptr)
1739 free(src_buf);
1740}
1741
Maxime Ripardde449842019-01-25 15:58:32 +01001742struct yuv_parameters {
1743 unsigned y_inc;
1744 unsigned uv_inc;
1745 unsigned y_stride;
1746 unsigned uv_stride;
1747 unsigned y_offset;
1748 unsigned u_offset;
1749 unsigned v_offset;
1750};
1751
1752static void get_yuv_parameters(struct igt_fb *fb, struct yuv_parameters *params)
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001753{
Maxime Ripardde449842019-01-25 15:58:32 +01001754 igt_assert(igt_format_is_yuv(fb->drm_format));
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01001755
Maxime Ripardde449842019-01-25 15:58:32 +01001756 switch (fb->drm_format) {
1757 case DRM_FORMAT_NV12:
Maxime Ripard3b2b80b2019-02-08 14:18:58 +01001758 case DRM_FORMAT_NV16:
1759 case DRM_FORMAT_NV21:
1760 case DRM_FORMAT_NV61:
Maarten Lankhorstcb8e45a2019-02-01 11:13:59 +01001761 case DRM_FORMAT_P010:
1762 case DRM_FORMAT_P012:
1763 case DRM_FORMAT_P016:
Maxime Ripardde449842019-01-25 15:58:32 +01001764 params->y_inc = 1;
1765 params->uv_inc = 2;
1766 break;
Ville Syrjälä9c33e5f2018-11-01 22:54:45 +02001767
Maxime Ripard3b2b80b2019-02-08 14:18:58 +01001768 case DRM_FORMAT_YUV420:
1769 case DRM_FORMAT_YUV422:
1770 case DRM_FORMAT_YVU420:
1771 case DRM_FORMAT_YVU422:
1772 params->y_inc = 1;
1773 params->uv_inc = 1;
1774 break;
1775
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001776 case DRM_FORMAT_YUYV:
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001777 case DRM_FORMAT_YVYU:
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001778 case DRM_FORMAT_UYVY:
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001779 case DRM_FORMAT_VYUY:
Maxime Ripardde449842019-01-25 15:58:32 +01001780 params->y_inc = 2;
1781 params->uv_inc = 4;
1782 break;
1783
1784 case DRM_FORMAT_XYUV8888:
1785 params->y_inc = 4;
1786 params->uv_inc = 4;
1787 break;
1788 }
1789
1790 switch (fb->drm_format) {
1791 case DRM_FORMAT_NV12:
Maxime Ripard3b2b80b2019-02-08 14:18:58 +01001792 case DRM_FORMAT_NV16:
1793 case DRM_FORMAT_NV21:
1794 case DRM_FORMAT_NV61:
1795 case DRM_FORMAT_YUV420:
1796 case DRM_FORMAT_YUV422:
1797 case DRM_FORMAT_YVU420:
1798 case DRM_FORMAT_YVU422:
Maarten Lankhorstcb8e45a2019-02-01 11:13:59 +01001799 case DRM_FORMAT_P010:
1800 case DRM_FORMAT_P012:
1801 case DRM_FORMAT_P016:
Maxime Ripardde449842019-01-25 15:58:32 +01001802 params->y_stride = fb->strides[0];
1803 params->uv_stride = fb->strides[1];
1804 break;
1805
1806 case DRM_FORMAT_YUYV:
1807 case DRM_FORMAT_YVYU:
1808 case DRM_FORMAT_UYVY:
1809 case DRM_FORMAT_VYUY:
1810 case DRM_FORMAT_XYUV8888:
1811 params->y_stride = fb->strides[0];
1812 params->uv_stride = fb->strides[0];
1813 break;
1814 }
1815
1816 switch (fb->drm_format) {
1817 case DRM_FORMAT_NV12:
Maxime Ripard3b2b80b2019-02-08 14:18:58 +01001818 case DRM_FORMAT_NV16:
Maxime Ripardde449842019-01-25 15:58:32 +01001819 params->y_offset = fb->offsets[0];
1820 params->u_offset = fb->offsets[1];
1821 params->v_offset = fb->offsets[1] + 1;
1822 break;
1823
Maxime Ripard3b2b80b2019-02-08 14:18:58 +01001824 case DRM_FORMAT_NV21:
1825 case DRM_FORMAT_NV61:
1826 params->y_offset = fb->offsets[0];
1827 params->u_offset = fb->offsets[1] + 1;
1828 params->v_offset = fb->offsets[1];
1829 break;
1830
1831 case DRM_FORMAT_YUV420:
1832 case DRM_FORMAT_YUV422:
1833 params->y_offset = fb->offsets[0];
1834 params->u_offset = fb->offsets[1];
1835 params->v_offset = fb->offsets[2];
1836 break;
1837
1838 case DRM_FORMAT_YVU420:
1839 case DRM_FORMAT_YVU422:
1840 params->y_offset = fb->offsets[0];
1841 params->u_offset = fb->offsets[2];
1842 params->v_offset = fb->offsets[1];
Maarten Lankhorstcb8e45a2019-02-01 11:13:59 +01001843 case DRM_FORMAT_P010:
1844 case DRM_FORMAT_P012:
1845 case DRM_FORMAT_P016:
1846 params->y_offset = fb->offsets[0];
1847 params->u_offset = fb->offsets[1];
1848 params->v_offset = fb->offsets[1] + 2;
Maxime Ripard3b2b80b2019-02-08 14:18:58 +01001849 break;
1850
Maxime Ripardde449842019-01-25 15:58:32 +01001851 case DRM_FORMAT_YUYV:
1852 params->y_offset = fb->offsets[0];
1853 params->u_offset = fb->offsets[0] + 1;
1854 params->v_offset = fb->offsets[0] + 3;
1855 break;
1856
1857 case DRM_FORMAT_YVYU:
1858 params->y_offset = fb->offsets[0];
1859 params->u_offset = fb->offsets[0] + 3;
1860 params->v_offset = fb->offsets[0] + 1;
1861 break;
1862
1863 case DRM_FORMAT_UYVY:
1864 params->y_offset = fb->offsets[0] + 1;
1865 params->u_offset = fb->offsets[0];
1866 params->v_offset = fb->offsets[0] + 2;
1867 break;
1868
1869 case DRM_FORMAT_VYUY:
1870 params->y_offset = fb->offsets[0] + 1;
1871 params->u_offset = fb->offsets[0] + 2;
1872 params->v_offset = fb->offsets[0];
1873 break;
1874
1875 case DRM_FORMAT_XYUV8888:
1876 params->y_offset = fb->offsets[0] + 1;
1877 params->u_offset = fb->offsets[0] + 2;
1878 params->v_offset = fb->offsets[0] + 3;
1879 break;
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001880 }
1881}
1882
Maxime Ripardde449842019-01-25 15:58:32 +01001883static void convert_yuv_to_rgb24(struct fb_convert *cvt)
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001884{
Maxime Ripardde449842019-01-25 15:58:32 +01001885 const struct format_desc_struct *src_fmt =
1886 lookup_drm_format(cvt->src.fb->drm_format);
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001887 int i, j;
Maxime Ripardde449842019-01-25 15:58:32 +01001888 uint8_t bpp = 4;
1889 uint8_t *y, *u, *v;
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001890 uint8_t *rgb24 = cvt->dst.ptr;
1891 unsigned int rgb24_stride = cvt->dst.fb->strides[0];
Maarten Lankhorstb0033d92018-06-07 16:25:22 +02001892 struct igt_mat4 m = igt_ycbcr_to_rgb_matrix(cvt->src.fb->drm_format,
1893 cvt->dst.fb->drm_format,
1894 cvt->src.fb->color_encoding,
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001895 cvt->src.fb->color_range);
Ville Syrjälä737241d2018-11-01 23:31:20 +02001896 uint8_t *buf;
Maxime Ripardde449842019-01-25 15:58:32 +01001897 struct yuv_parameters params = { };
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001898
Maxime Ripardde449842019-01-25 15:58:32 +01001899 igt_assert(cvt->dst.fb->drm_format == DRM_FORMAT_XRGB8888 &&
1900 igt_format_is_yuv(cvt->src.fb->drm_format));
Ville Syrjälä9c33e5f2018-11-01 22:54:45 +02001901
Ville Syrjälä737241d2018-11-01 23:31:20 +02001902 buf = convert_src_get(cvt);
Maxime Ripardde449842019-01-25 15:58:32 +01001903 get_yuv_parameters(cvt->src.fb, &params);
1904 y = buf + params.y_offset;
1905 u = buf + params.u_offset;
1906 v = buf + params.v_offset;
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001907
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001908 for (i = 0; i < cvt->dst.fb->height; i++) {
Maxime Ripardde449842019-01-25 15:58:32 +01001909 const uint8_t *y_tmp = y;
1910 const uint8_t *u_tmp = u;
1911 const uint8_t *v_tmp = v;
1912 uint8_t *rgb_tmp = rgb24;
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001913
Maxime Ripardde449842019-01-25 15:58:32 +01001914 for (j = 0; j < cvt->dst.fb->width; j++) {
1915 struct igt_vec4 rgb, yuv;
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001916
Maxime Ripardde449842019-01-25 15:58:32 +01001917 yuv.d[0] = *y_tmp;
1918 yuv.d[1] = *u_tmp;
1919 yuv.d[2] = *v_tmp;
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001920 yuv.d[3] = 1.0f;
1921
1922 rgb = igt_matrix_transform(&m, &yuv);
Maxime Ripardde449842019-01-25 15:58:32 +01001923 write_rgb(rgb_tmp, &rgb);
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001924
Maxime Ripardde449842019-01-25 15:58:32 +01001925 rgb_tmp += bpp;
1926 y_tmp += params.y_inc;
1927
1928 if ((src_fmt->hsub == 1) || (j % src_fmt->hsub)) {
1929 u_tmp += params.uv_inc;
1930 v_tmp += params.uv_inc;
1931 }
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001932 }
1933
1934 rgb24 += rgb24_stride;
Maxime Ripardde449842019-01-25 15:58:32 +01001935 y += params.y_stride;
1936
1937 if ((src_fmt->vsub == 1) || (i % src_fmt->vsub)) {
1938 u += params.uv_stride;
1939 v += params.uv_stride;
1940 }
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001941 }
1942
Ville Syrjälä737241d2018-11-01 23:31:20 +02001943 convert_src_put(cvt, buf);
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001944}
1945
Maxime Ripardde449842019-01-25 15:58:32 +01001946static void convert_rgb24_to_yuv(struct fb_convert *cvt)
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001947{
Maxime Ripardde449842019-01-25 15:58:32 +01001948 const struct format_desc_struct *dst_fmt =
1949 lookup_drm_format(cvt->dst.fb->drm_format);
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001950 int i, j;
Maxime Ripardde449842019-01-25 15:58:32 +01001951 uint8_t *y, *u, *v;
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001952 const uint8_t *rgb24 = cvt->src.ptr;
Maxime Ripardde449842019-01-25 15:58:32 +01001953 uint8_t bpp = 4;
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001954 unsigned rgb24_stride = cvt->src.fb->strides[0];
Maarten Lankhorstb0033d92018-06-07 16:25:22 +02001955 struct igt_mat4 m = igt_rgb_to_ycbcr_matrix(cvt->src.fb->drm_format,
1956 cvt->dst.fb->drm_format,
1957 cvt->dst.fb->color_encoding,
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001958 cvt->dst.fb->color_range);
Maxime Ripardde449842019-01-25 15:58:32 +01001959 struct yuv_parameters params = { };
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001960
Ville Syrjälä9c33e5f2018-11-01 22:54:45 +02001961 igt_assert(cvt->src.fb->drm_format == DRM_FORMAT_XRGB8888 &&
Maxime Ripardde449842019-01-25 15:58:32 +01001962 igt_format_is_yuv(cvt->dst.fb->drm_format));
1963
1964 get_yuv_parameters(cvt->dst.fb, &params);
1965 y = cvt->dst.ptr + params.y_offset;
1966 u = cvt->dst.ptr + params.u_offset;
1967 v = cvt->dst.ptr + params.v_offset;
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001968
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02001969 for (i = 0; i < cvt->dst.fb->height; i++) {
Maxime Ripardde449842019-01-25 15:58:32 +01001970 const uint8_t *rgb_tmp = rgb24;
1971 uint8_t *y_tmp = y;
1972 uint8_t *u_tmp = u;
1973 uint8_t *v_tmp = v;
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001974
Maxime Ripardde449842019-01-25 15:58:32 +01001975 for (j = 0; j < cvt->dst.fb->width; j++) {
1976 const uint8_t *pair_rgb24 = rgb_tmp;
1977 struct igt_vec4 pair_rgb, rgb;
1978 struct igt_vec4 pair_yuv, yuv;
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001979
Maxime Ripardde449842019-01-25 15:58:32 +01001980 read_rgb(&rgb, rgb_tmp);
Ville Syrjäläfed97c42018-02-27 22:58:01 +02001981 yuv = igt_matrix_transform(&m, &rgb);
1982
Maxime Ripardde449842019-01-25 15:58:32 +01001983 rgb_tmp += bpp;
1984
1985 *y_tmp = yuv.d[0];
1986 y_tmp += params.y_inc;
1987
1988 if ((i % dst_fmt->vsub) || (j % dst_fmt->hsub))
1989 continue;
1990
1991 /*
1992 * We assume the MPEG2 chroma siting convention, where
1993 * pixel center for Cb'Cr' is between the left top and
1994 * bottom pixel in a 2x2 block, so take the average.
1995 *
1996 * Therefore, if we use subsampling, we only really care
1997 * about two pixels all the time, either the two
1998 * subsequent pixels horizontally, vertically, or the
1999 * two corners in a 2x2 block.
2000 *
2001 * The only corner case is when we have an odd number of
2002 * pixels, but this can be handled pretty easily by not
2003 * incrementing the paired pixel pointer in the
2004 * direction it's odd in.
2005 */
2006 if (j != (cvt->dst.fb->width - 1))
2007 pair_rgb24 += (dst_fmt->hsub - 1) * bpp;
2008
2009 if (i != (cvt->dst.fb->height - 1))
2010 pair_rgb24 += rgb24_stride * (dst_fmt->vsub - 1);
2011
2012 read_rgb(&pair_rgb, pair_rgb24);
2013 pair_yuv = igt_matrix_transform(&m, &pair_rgb);
2014
2015 *u_tmp = (yuv.d[1] + pair_yuv.d[1]) / 2.0f;
2016 *v_tmp = (yuv.d[2] + pair_yuv.d[2]) / 2.0f;
2017
2018 u_tmp += params.uv_inc;
2019 v_tmp += params.uv_inc;
Ville Syrjäläfed97c42018-02-27 22:58:01 +02002020 }
2021
2022 rgb24 += rgb24_stride;
Maxime Ripardde449842019-01-25 15:58:32 +01002023 y += params.y_stride;
2024
2025 if ((i % dst_fmt->vsub) == (dst_fmt->vsub - 1)) {
2026 u += params.uv_stride;
2027 v += params.uv_stride;
2028 }
Ville Syrjäläfed97c42018-02-27 22:58:01 +02002029 }
2030}
2031
Maarten Lankhorstcb8e45a2019-02-01 11:13:59 +01002032static void read_rgbf(struct igt_vec4 *rgb, const float *rgb24)
2033{
2034 rgb->d[0] = rgb24[0];
2035 rgb->d[1] = rgb24[1];
2036 rgb->d[2] = rgb24[2];
2037 rgb->d[3] = 1.0f;
2038}
2039
2040static void write_rgbf(float *rgb24, const struct igt_vec4 *rgb)
2041{
2042 rgb24[0] = rgb->d[0];
2043 rgb24[1] = rgb->d[1];
2044 rgb24[2] = rgb->d[2];
2045}
2046
2047static void convert_yuv16_to_float(struct fb_convert *cvt)
2048{
2049 const struct format_desc_struct *src_fmt =
2050 lookup_drm_format(cvt->src.fb->drm_format);
2051 int i, j;
2052 uint8_t fpp = 3;
2053 uint16_t *y, *u, *v;
2054 float *ptr = cvt->dst.ptr;
2055 unsigned int float_stride = cvt->dst.fb->strides[0] / sizeof(*ptr);
2056 struct igt_mat4 m = igt_ycbcr_to_rgb_matrix(cvt->src.fb->drm_format,
2057 cvt->dst.fb->drm_format,
2058 cvt->src.fb->color_encoding,
2059 cvt->src.fb->color_range);
2060 uint16_t *buf;
2061 struct yuv_parameters params = { };
2062
2063 igt_assert(cvt->dst.fb->drm_format == IGT_FORMAT_FLOAT &&
2064 igt_format_is_yuv(cvt->src.fb->drm_format));
2065
2066 buf = convert_src_get(cvt);
2067 get_yuv_parameters(cvt->src.fb, &params);
2068 igt_assert(!(params.y_offset % sizeof(*buf)) &&
2069 !(params.u_offset % sizeof(*buf)) &&
2070 !(params.v_offset % sizeof(*buf)));
2071
2072 y = buf + params.y_offset / sizeof(*buf);
2073 u = buf + params.u_offset / sizeof(*buf);
2074 v = buf + params.v_offset / sizeof(*buf);
2075
2076 for (i = 0; i < cvt->dst.fb->height; i++) {
2077 const uint16_t *y_tmp = y;
2078 const uint16_t *u_tmp = u;
2079 const uint16_t *v_tmp = v;
2080 float *rgb_tmp = ptr;
2081
2082 for (j = 0; j < cvt->dst.fb->width; j++) {
2083 struct igt_vec4 rgb, yuv;
2084
2085 yuv.d[0] = *y_tmp;
2086 yuv.d[1] = *u_tmp;
2087 yuv.d[2] = *v_tmp;
2088 yuv.d[3] = 1.0f;
2089
2090 rgb = igt_matrix_transform(&m, &yuv);
2091 write_rgbf(rgb_tmp, &rgb);
2092
2093 rgb_tmp += fpp;
2094 y_tmp += params.y_inc;
2095
2096 if ((src_fmt->hsub == 1) || (j % src_fmt->hsub)) {
2097 u_tmp += params.uv_inc;
2098 v_tmp += params.uv_inc;
2099 }
2100 }
2101
2102 ptr += float_stride;
2103 y += params.y_stride / sizeof(*y);
2104
2105 if ((src_fmt->vsub == 1) || (i % src_fmt->vsub)) {
2106 u += params.uv_stride / sizeof(*u);
2107 v += params.uv_stride / sizeof(*v);
2108 }
2109 }
2110
2111 convert_src_put(cvt, buf);
2112}
2113
2114static void convert_float_to_yuv16(struct fb_convert *cvt)
2115{
2116 const struct format_desc_struct *dst_fmt =
2117 lookup_drm_format(cvt->dst.fb->drm_format);
2118 int i, j;
2119 uint16_t *y, *u, *v;
2120 const float *ptr = cvt->src.ptr;
2121 uint8_t fpp = 3;
2122 unsigned float_stride = cvt->src.fb->strides[0] / sizeof(*ptr);
2123 struct igt_mat4 m = igt_rgb_to_ycbcr_matrix(cvt->src.fb->drm_format,
2124 cvt->dst.fb->drm_format,
2125 cvt->dst.fb->color_encoding,
2126 cvt->dst.fb->color_range);
2127 struct yuv_parameters params = { };
2128
2129 igt_assert(cvt->src.fb->drm_format == IGT_FORMAT_FLOAT &&
2130 igt_format_is_yuv(cvt->dst.fb->drm_format));
2131
2132 get_yuv_parameters(cvt->dst.fb, &params);
2133 igt_assert(!(params.y_offset % sizeof(*y)) &&
2134 !(params.u_offset % sizeof(*u)) &&
2135 !(params.v_offset % sizeof(*v)));
2136
2137 y = cvt->dst.ptr + params.y_offset;
2138 u = cvt->dst.ptr + params.u_offset;
2139 v = cvt->dst.ptr + params.v_offset;
2140
2141 for (i = 0; i < cvt->dst.fb->height; i++) {
2142 const float *rgb_tmp = ptr;
2143 uint16_t *y_tmp = y;
2144 uint16_t *u_tmp = u;
2145 uint16_t *v_tmp = v;
2146
2147 for (j = 0; j < cvt->dst.fb->width; j++) {
2148 const float *pair_float = rgb_tmp;
2149 struct igt_vec4 pair_rgb, rgb;
2150 struct igt_vec4 pair_yuv, yuv;
2151
2152 read_rgbf(&rgb, rgb_tmp);
2153 yuv = igt_matrix_transform(&m, &rgb);
2154
2155 rgb_tmp += fpp;
2156
2157 *y_tmp = yuv.d[0];
2158 y_tmp += params.y_inc;
2159
2160 if ((i % dst_fmt->vsub) || (j % dst_fmt->hsub))
2161 continue;
2162
2163 /*
2164 * We assume the MPEG2 chroma siting convention, where
2165 * pixel center for Cb'Cr' is between the left top and
2166 * bottom pixel in a 2x2 block, so take the average.
2167 *
2168 * Therefore, if we use subsampling, we only really care
2169 * about two pixels all the time, either the two
2170 * subsequent pixels horizontally, vertically, or the
2171 * two corners in a 2x2 block.
2172 *
2173 * The only corner case is when we have an odd number of
2174 * pixels, but this can be handled pretty easily by not
2175 * incrementing the paired pixel pointer in the
2176 * direction it's odd in.
2177 */
2178 if (j != (cvt->dst.fb->width - 1))
2179 pair_float += (dst_fmt->hsub - 1) * fpp;
2180
2181 if (i != (cvt->dst.fb->height - 1))
2182 pair_float += float_stride * (dst_fmt->vsub - 1);
2183
2184 read_rgbf(&pair_rgb, pair_float);
2185 pair_yuv = igt_matrix_transform(&m, &pair_rgb);
2186
2187 *u_tmp = (yuv.d[1] + pair_yuv.d[1]) / 2.0f;
2188 *v_tmp = (yuv.d[2] + pair_yuv.d[2]) / 2.0f;
2189
2190 u_tmp += params.uv_inc;
2191 v_tmp += params.uv_inc;
2192 }
2193
2194 ptr += float_stride;
2195 y += params.y_stride / sizeof(*y);
2196
2197 if ((i % dst_fmt->vsub) == (dst_fmt->vsub - 1)) {
2198 u += params.uv_stride / sizeof(*u);
2199 v += params.uv_stride / sizeof(*v);
2200 }
2201 }
2202}
2203
Maxime Ripard3fa65f42018-10-04 14:39:03 +02002204static void convert_pixman(struct fb_convert *cvt)
2205{
2206 pixman_format_code_t src_pixman = drm_format_to_pixman(cvt->src.fb->drm_format);
2207 pixman_format_code_t dst_pixman = drm_format_to_pixman(cvt->dst.fb->drm_format);
2208 pixman_image_t *dst_image, *src_image;
Ville Syrjälä737241d2018-11-01 23:31:20 +02002209 void *src_ptr;
Maxime Ripard3fa65f42018-10-04 14:39:03 +02002210
2211 igt_assert((src_pixman != PIXMAN_invalid) &&
2212 (dst_pixman != PIXMAN_invalid));
2213
Paul Kocialkowski0ba18cf2018-12-27 15:57:41 +01002214 /* Pixman requires the stride to be aligned to 32 bits. */
2215 igt_assert((cvt->src.fb->strides[0] % sizeof(uint32_t)) == 0);
2216 igt_assert((cvt->dst.fb->strides[0] % sizeof(uint32_t)) == 0);
2217
Ville Syrjälä737241d2018-11-01 23:31:20 +02002218 src_ptr = convert_src_get(cvt);
2219
Maxime Ripard3fa65f42018-10-04 14:39:03 +02002220 src_image = pixman_image_create_bits(src_pixman,
2221 cvt->src.fb->width,
2222 cvt->src.fb->height,
Ville Syrjälä737241d2018-11-01 23:31:20 +02002223 src_ptr,
Maxime Ripard3fa65f42018-10-04 14:39:03 +02002224 cvt->src.fb->strides[0]);
2225 igt_assert(src_image);
2226
2227 dst_image = pixman_image_create_bits(dst_pixman,
2228 cvt->dst.fb->width,
2229 cvt->dst.fb->height,
2230 cvt->dst.ptr,
2231 cvt->dst.fb->strides[0]);
2232 igt_assert(dst_image);
2233
2234 pixman_image_composite(PIXMAN_OP_SRC, src_image, NULL, dst_image,
2235 0, 0, 0, 0, 0, 0,
2236 cvt->dst.fb->width, cvt->dst.fb->height);
2237 pixman_image_unref(dst_image);
2238 pixman_image_unref(src_image);
Ville Syrjälä737241d2018-11-01 23:31:20 +02002239
2240 convert_src_put(cvt, src_ptr);
Maxime Ripard3fa65f42018-10-04 14:39:03 +02002241}
2242
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02002243static void fb_convert(struct fb_convert *cvt)
2244{
Maxime Ripard3fa65f42018-10-04 14:39:03 +02002245 if ((drm_format_to_pixman(cvt->src.fb->drm_format) != PIXMAN_invalid) &&
2246 (drm_format_to_pixman(cvt->dst.fb->drm_format) != PIXMAN_invalid)) {
2247 convert_pixman(cvt);
2248 return;
Ville Syrjäläe5eb1402018-11-01 22:26:47 +02002249 } else if (cvt->dst.fb->drm_format == DRM_FORMAT_XRGB8888) {
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02002250 switch (cvt->src.fb->drm_format) {
Stanislav Lisovskiyf05c8c22018-12-17 16:30:28 +02002251 case DRM_FORMAT_XYUV8888:
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02002252 case DRM_FORMAT_NV12:
Maxime Ripard3b2b80b2019-02-08 14:18:58 +01002253 case DRM_FORMAT_NV16:
2254 case DRM_FORMAT_NV21:
2255 case DRM_FORMAT_NV61:
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02002256 case DRM_FORMAT_UYVY:
2257 case DRM_FORMAT_VYUY:
Maxime Ripard3b2b80b2019-02-08 14:18:58 +01002258 case DRM_FORMAT_YUV420:
2259 case DRM_FORMAT_YUV422:
Maxime Ripardde449842019-01-25 15:58:32 +01002260 case DRM_FORMAT_YUYV:
Maxime Ripard3b2b80b2019-02-08 14:18:58 +01002261 case DRM_FORMAT_YVU420:
2262 case DRM_FORMAT_YVU422:
Maxime Ripardde449842019-01-25 15:58:32 +01002263 case DRM_FORMAT_YVYU:
2264 convert_yuv_to_rgb24(cvt);
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02002265 return;
2266 }
Ville Syrjäläe5eb1402018-11-01 22:26:47 +02002267 } else if (cvt->src.fb->drm_format == DRM_FORMAT_XRGB8888) {
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02002268 switch (cvt->dst.fb->drm_format) {
Stanislav Lisovskiyf05c8c22018-12-17 16:30:28 +02002269 case DRM_FORMAT_XYUV8888:
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02002270 case DRM_FORMAT_NV12:
Maxime Ripard3b2b80b2019-02-08 14:18:58 +01002271 case DRM_FORMAT_NV16:
2272 case DRM_FORMAT_NV21:
2273 case DRM_FORMAT_NV61:
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02002274 case DRM_FORMAT_UYVY:
2275 case DRM_FORMAT_VYUY:
Maxime Ripard3b2b80b2019-02-08 14:18:58 +01002276 case DRM_FORMAT_YUV420:
2277 case DRM_FORMAT_YUV422:
2278 case DRM_FORMAT_YUYV:
2279 case DRM_FORMAT_YVU420:
2280 case DRM_FORMAT_YVU422:
2281 case DRM_FORMAT_YVYU:
Maxime Ripardde449842019-01-25 15:58:32 +01002282 convert_rgb24_to_yuv(cvt);
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02002283 return;
2284 }
Maarten Lankhorstcb8e45a2019-02-01 11:13:59 +01002285 } else if (cvt->dst.fb->drm_format == IGT_FORMAT_FLOAT) {
2286 switch (cvt->src.fb->drm_format) {
2287 case DRM_FORMAT_P010:
2288 case DRM_FORMAT_P012:
2289 case DRM_FORMAT_P016:
2290 convert_yuv16_to_float(cvt);
2291 return;
2292 }
2293 } else if (cvt->src.fb->drm_format == IGT_FORMAT_FLOAT) {
2294 switch (cvt->dst.fb->drm_format) {
2295 case DRM_FORMAT_P010:
2296 case DRM_FORMAT_P012:
2297 case DRM_FORMAT_P016:
2298 convert_float_to_yuv16(cvt);
2299 return;
2300 }
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02002301 }
2302
2303 igt_assert_f(false,
2304 "Conversion not implemented (from format 0x%x to 0x%x)\n",
2305 cvt->src.fb->drm_format, cvt->dst.fb->drm_format);
2306}
2307
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01002308static void destroy_cairo_surface__convert(void *arg)
2309{
2310 struct fb_convert_blit_upload *blit = arg;
Ville Syrjälä3ed2a602018-07-17 16:15:34 +03002311 struct igt_fb *fb = blit->base.fb;
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02002312 struct fb_convert cvt = {
2313 .dst = {
2314 .ptr = blit->base.linear.map,
Ville Syrjäläf3da4192018-11-01 22:55:28 +02002315 .fb = &blit->base.linear.fb,
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02002316 },
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01002317
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02002318 .src = {
2319 .ptr = blit->shadow_ptr,
2320 .fb = &blit->shadow_fb,
2321 },
2322 };
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01002323
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02002324 fb_convert(&cvt);
Maxime Ripardc7128362018-10-04 14:38:57 +02002325 igt_fb_destroy_cairo_shadow_buffer(&blit->shadow_fb, blit->shadow_ptr);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01002326
Ville Syrjälä22383612018-07-17 18:32:38 +03002327 if (blit->base.linear.fb.gem_handle)
Ville Syrjälä74261fd2018-07-17 16:20:34 +03002328 free_linear_mapping(&blit->base);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01002329 else
Maxime Ripard3415b192018-10-04 14:38:54 +02002330 unmap_bo(fb, blit->base.linear.map);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01002331
2332 free(blit);
2333
2334 fb->cairo_surface = NULL;
2335}
2336
2337static void create_cairo_surface__convert(int fd, struct igt_fb *fb)
2338{
2339 struct fb_convert_blit_upload *blit = malloc(sizeof(*blit));
Maarten Lankhorst8b354102018-11-19 11:59:55 +01002340 struct fb_convert cvt = { };
Maarten Lankhorstcb8e45a2019-02-01 11:13:59 +01002341 const struct format_desc_struct *f = lookup_drm_format(fb->drm_format);
2342 unsigned drm_format;
2343 cairo_format_t cairo_id;
2344
2345 if (f->cairo_id != CAIRO_FORMAT_INVALID) {
2346 cairo_id = f->cairo_id;
2347
2348 switch (f->cairo_id) {
2349 case CAIRO_FORMAT_RGB96F:
2350 case CAIRO_FORMAT_RGBA128F:
2351 drm_format = IGT_FORMAT_FLOAT;
2352 break;
2353 case CAIRO_FORMAT_RGB24:
2354 drm_format = DRM_FORMAT_XRGB8888;
2355 break;
2356 default:
2357 igt_assert_f(0, "Unsupported format %u", f->cairo_id);
2358 }
2359 } else if (PIXMAN_FORMAT_A(f->pixman_id)) {
2360 cairo_id = CAIRO_FORMAT_ARGB32;
2361 drm_format = DRM_FORMAT_ARGB8888;
2362 } else {
2363 cairo_id = CAIRO_FORMAT_RGB24;
2364 drm_format = DRM_FORMAT_XRGB8888;
2365 }
Maxime Ripardc7128362018-10-04 14:38:57 +02002366
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01002367 igt_assert(blit);
2368
Ville Syrjälä3ed2a602018-07-17 16:15:34 +03002369 blit->base.fd = fd;
2370 blit->base.fb = fb;
Maarten Lankhorstcb8e45a2019-02-01 11:13:59 +01002371 blit->shadow_ptr = igt_fb_create_cairo_shadow_buffer(fd, drm_format,
Maxime Ripardc7128362018-10-04 14:38:57 +02002372 fb->width,
2373 fb->height,
2374 &blit->shadow_fb);
2375 igt_assert(blit->shadow_ptr);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01002376
2377 if (fb->tiling == LOCAL_I915_FORMAT_MOD_Y_TILED ||
2378 fb->tiling == LOCAL_I915_FORMAT_MOD_Yf_TILED) {
Ville Syrjälä3ed2a602018-07-17 16:15:34 +03002379 setup_linear_mapping(fd, fb, &blit->base.linear);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01002380 } else {
Ville Syrjäläf3da4192018-11-01 22:55:28 +02002381 blit->base.linear.fb = *fb;
Ville Syrjälä22383612018-07-17 18:32:38 +03002382 blit->base.linear.fb.gem_handle = 0;
Maxime Ripard3415b192018-10-04 14:38:54 +02002383 blit->base.linear.map = map_bo(fd, fb);
Ville Syrjälä3ed2a602018-07-17 16:15:34 +03002384 igt_assert(blit->base.linear.map);
Ville Syrjälä737241d2018-11-01 23:31:20 +02002385
2386 /* reading via gtt mmap is slow */
2387 cvt.src.slow_reads = is_i915_device(fd);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01002388 }
2389
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02002390 cvt.dst.ptr = blit->shadow_ptr;
2391 cvt.dst.fb = &blit->shadow_fb;
2392 cvt.src.ptr = blit->base.linear.map;
Ville Syrjäläf3da4192018-11-01 22:55:28 +02002393 cvt.src.fb = &blit->base.linear.fb;
Maxime Ripard5a8de8a2018-10-04 14:38:59 +02002394 fb_convert(&cvt);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01002395
2396 fb->cairo_surface =
Maxime Ripardc7128362018-10-04 14:38:57 +02002397 cairo_image_surface_create_for_data(blit->shadow_ptr,
Maarten Lankhorstcb8e45a2019-02-01 11:13:59 +01002398 cairo_id,
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01002399 fb->width, fb->height,
Maxime Ripardc7128362018-10-04 14:38:57 +02002400 blit->shadow_fb.strides[0]);
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01002401
2402 cairo_surface_set_user_data(fb->cairo_surface,
2403 (cairo_user_data_key_t *)create_cairo_surface__convert,
2404 blit, destroy_cairo_surface__convert);
2405}
2406
Stanislav Lisovskiyf05c8c22018-12-17 16:30:28 +02002407
Paul Kocialkowskib4ad3972017-07-19 16:46:04 +03002408/**
Maxime Ripard3415b192018-10-04 14:38:54 +02002409 * igt_fb_map_buffer:
2410 * @fd: open drm file descriptor
2411 * @fb: pointer to an #igt_fb structure
2412 *
2413 * This function will creating a new mapping of the buffer and return a pointer
2414 * to the content of the supplied framebuffer's plane. This mapping needs to be
2415 * deleted using igt_fb_unmap_buffer().
2416 *
2417 * Returns:
2418 * A pointer to a buffer with the contents of the framebuffer
2419 */
2420void *igt_fb_map_buffer(int fd, struct igt_fb *fb)
2421{
2422 return map_bo(fd, fb);
2423}
2424
2425/**
2426 * igt_fb_unmap_buffer:
2427 * @fb: pointer to the backing igt_fb structure
2428 * @buffer: pointer to the buffer previously mappped
2429 *
2430 * This function will unmap a buffer mapped previously with
2431 * igt_fb_map_buffer().
2432 */
2433void igt_fb_unmap_buffer(struct igt_fb *fb, void *buffer)
2434{
2435 return unmap_bo(fb, buffer);
2436}
2437
2438/**
Paul Kocialkowskib4ad3972017-07-19 16:46:04 +03002439 * igt_get_cairo_surface:
2440 * @fd: open drm file descriptor
2441 * @fb: pointer to an #igt_fb structure
2442 *
Maarten Lankhorst918ea422018-01-19 12:47:11 +01002443 * This function stores the contents of the supplied framebuffer's plane
2444 * into a cairo surface and returns it.
Paul Kocialkowskib4ad3972017-07-19 16:46:04 +03002445 *
2446 * Returns:
2447 * A pointer to a cairo surface with the contents of the framebuffer.
2448 */
2449cairo_surface_t *igt_get_cairo_surface(int fd, struct igt_fb *fb)
Daniel Vetter57d7db82014-03-26 09:06:11 +01002450{
Maxime Ripard3fa65f42018-10-04 14:39:03 +02002451 const struct format_desc_struct *f = lookup_drm_format(fb->drm_format);
2452
Damien Lespiauff451a62015-03-03 14:11:04 +00002453 if (fb->cairo_surface == NULL) {
Maxime Ripard3fa65f42018-10-04 14:39:03 +02002454 if (igt_format_is_yuv(fb->drm_format) ||
2455 ((f->cairo_id == CAIRO_FORMAT_INVALID) &&
2456 (f->pixman_id != PIXMAN_invalid)))
Maarten Lankhorst4452dcb2018-01-22 12:21:34 +01002457 create_cairo_surface__convert(fd, fb);
2458 else if (fb->tiling == LOCAL_I915_FORMAT_MOD_Y_TILED ||
Damien Lespiauff451a62015-03-03 14:11:04 +00002459 fb->tiling == LOCAL_I915_FORMAT_MOD_Yf_TILED)
2460 create_cairo_surface__blit(fd, fb);
2461 else
2462 create_cairo_surface__gtt(fd, fb);
Maarten Lankhorstcb8e45a2019-02-01 11:13:59 +01002463
2464 if (f->cairo_id == CAIRO_FORMAT_RGB96F ||
2465 f->cairo_id == CAIRO_FORMAT_RGBA128F) {
2466 cairo_status_t status = cairo_surface_status(fb->cairo_surface);
2467
2468 igt_skip_on_f(status == CAIRO_STATUS_INVALID_FORMAT &&
2469 cairo_version() < CAIRO_VERSION_ENCODE(1, 17, 2),
2470 "Cairo version too old, need 1.17.2, have %s\n",
2471 cairo_version_string());
2472
2473 igt_skip_on_f(status == CAIRO_STATUS_NO_MEMORY &&
2474 pixman_version() < PIXMAN_VERSION_ENCODE(0, 36, 0),
2475 "Pixman version too old, need 0.36.0, have %s\n",
2476 pixman_version_string());
2477 }
Damien Lespiauff451a62015-03-03 14:11:04 +00002478 }
Daniel Vetter57d7db82014-03-26 09:06:11 +01002479
Daniel Vetter57d7db82014-03-26 09:06:11 +01002480 igt_assert(cairo_surface_status(fb->cairo_surface) == CAIRO_STATUS_SUCCESS);
Damien Lespiau0db75bb2014-06-30 16:34:20 +01002481 return fb->cairo_surface;
Daniel Vetter57d7db82014-03-26 09:06:11 +01002482}
2483
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01002484/**
2485 * igt_get_cairo_ctx:
2486 * @fd: open i915 drm file descriptor
2487 * @fb: pointer to an #igt_fb structure
2488 *
2489 * This initializes a cairo surface for @fb and then allocates a drawing context
2490 * for it. The return cairo drawing context should be released by calling
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +01002491 * igt_put_cairo_ctx(). This also sets a default font for drawing text on
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01002492 * framebuffers.
2493 *
2494 * Returns:
2495 * The created cairo drawing context.
2496 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01002497cairo_t *igt_get_cairo_ctx(int fd, struct igt_fb *fb)
Daniel Vetter57d7db82014-03-26 09:06:11 +01002498{
2499 cairo_surface_t *surface;
2500 cairo_t *cr;
2501
Paul Kocialkowskib4ad3972017-07-19 16:46:04 +03002502 surface = igt_get_cairo_surface(fd, fb);
Daniel Vetter57d7db82014-03-26 09:06:11 +01002503 cr = cairo_create(surface);
2504 cairo_surface_destroy(surface);
Daniel Vetter7568edf2014-03-26 16:36:46 +01002505 igt_assert(cairo_status(cr) == CAIRO_STATUS_SUCCESS);
Daniel Vetter57d7db82014-03-26 09:06:11 +01002506
Daniel Vetter7568edf2014-03-26 16:36:46 +01002507 cairo_select_font_face(cr, "Helvetica", CAIRO_FONT_SLANT_NORMAL,
2508 CAIRO_FONT_WEIGHT_NORMAL);
Daniel Vetter57d7db82014-03-26 09:06:11 +01002509 igt_assert(cairo_status(cr) == CAIRO_STATUS_SUCCESS);
2510
2511 return cr;
2512}
2513
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01002514/**
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +01002515 * igt_put_cairo_ctx:
2516 * @fd: open i915 drm file descriptor
2517 * @fb: pointer to an #igt_fb structure
2518 * @cr: the cairo context returned by igt_get_cairo_ctx.
2519 *
2520 * This releases the cairo surface @cr returned by igt_get_cairo_ctx()
2521 * for @fb, and writes the changes out to the framebuffer if cairo doesn't
2522 * have native support for the format.
2523 */
2524void igt_put_cairo_ctx(int fd, struct igt_fb *fb, cairo_t *cr)
2525{
2526 cairo_status_t ret = cairo_status(cr);
2527 igt_assert_f(ret == CAIRO_STATUS_SUCCESS, "Cairo failed to draw with %s\n", cairo_status_to_string(ret));
2528
2529 cairo_destroy(cr);
2530}
2531
2532/**
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01002533 * igt_remove_fb:
2534 * @fd: open i915 drm file descriptor
2535 * @fb: pointer to an #igt_fb structure
2536 *
2537 * This function releases all resources allocated in igt_create_fb() for @fb.
2538 * Note that if this framebuffer is still in use on a primary plane the kernel
2539 * will disable the corresponding crtc.
2540 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01002541void igt_remove_fb(int fd, struct igt_fb *fb)
Daniel Vetter57d7db82014-03-26 09:06:11 +01002542{
Maarten Lankhorste62de1c2018-02-02 10:58:42 +01002543 if (!fb || !fb->fb_id)
2544 return;
2545
Daniel Vetter57d7db82014-03-26 09:06:11 +01002546 cairo_surface_destroy(fb->cairo_surface);
2547 do_or_die(drmModeRmFB(fd, fb->fb_id));
Deepak Rawat4ca3d1d2018-10-16 15:23:37 -07002548 if (fb->is_dumb)
2549 kmstest_dumb_destroy(fd, fb->gem_handle);
2550 else
2551 gem_close(fd, fb->gem_handle);
Maarten Lankhorste62de1c2018-02-02 10:58:42 +01002552 fb->fb_id = 0;
Daniel Vetter57d7db82014-03-26 09:06:11 +01002553}
2554
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01002555/**
Paul Kocialkowski6e227182018-12-05 16:10:35 +01002556 * igt_fb_convert_with_stride:
Maxime Riparde3b1c342018-10-04 14:39:00 +02002557 * @dst: pointer to the #igt_fb structure that will store the conversion result
2558 * @src: pointer to the #igt_fb structure that stores the frame we convert
2559 * @dst_fourcc: DRM format specifier to convert to
Paul Kocialkowskicf8438a2019-01-24 16:30:48 +01002560 * @dst_modifier: DRM format modifier to convert to
Paul Kocialkowski6e227182018-12-05 16:10:35 +01002561 * @dst_stride: Stride for the resulting framebuffer (0 for automatic stride)
Maxime Riparde3b1c342018-10-04 14:39:00 +02002562 *
2563 * This will convert a given @src content to the @dst_fourcc format,
2564 * storing the result in the @dst fb, allocating the @dst fb
Paul Kocialkowski6e227182018-12-05 16:10:35 +01002565 * underlying buffer with a stride of @dst_stride stride.
Maxime Riparde3b1c342018-10-04 14:39:00 +02002566 *
2567 * Once done with @dst, the caller will have to call igt_remove_fb()
2568 * on it to free the associated resources.
2569 *
2570 * Returns:
2571 * The kms id of the created framebuffer.
2572 */
Paul Kocialkowski6e227182018-12-05 16:10:35 +01002573unsigned int igt_fb_convert_with_stride(struct igt_fb *dst, struct igt_fb *src,
2574 uint32_t dst_fourcc,
Paul Kocialkowskicf8438a2019-01-24 16:30:48 +01002575 uint64_t dst_modifier,
Paul Kocialkowski6e227182018-12-05 16:10:35 +01002576 unsigned int dst_stride)
Maxime Riparde3b1c342018-10-04 14:39:00 +02002577{
Maarten Lankhorst8b354102018-11-19 11:59:55 +01002578 struct fb_convert cvt = { };
Maxime Riparde3b1c342018-10-04 14:39:00 +02002579 void *dst_ptr, *src_ptr;
2580 int fb_id;
2581
Paul Kocialkowski6e227182018-12-05 16:10:35 +01002582 fb_id = igt_create_fb_with_bo_size(src->fd, src->width, src->height,
2583 dst_fourcc,
Paul Kocialkowskicf8438a2019-01-24 16:30:48 +01002584 LOCAL_DRM_FORMAT_MOD_NONE, dst, 0,
2585 dst_stride);
Maxime Riparde3b1c342018-10-04 14:39:00 +02002586 igt_assert(fb_id > 0);
2587
2588 src_ptr = igt_fb_map_buffer(src->fd, src);
2589 igt_assert(src_ptr);
2590
2591 dst_ptr = igt_fb_map_buffer(dst->fd, dst);
2592 igt_assert(dst_ptr);
2593
2594 cvt.dst.ptr = dst_ptr;
2595 cvt.dst.fb = dst;
2596 cvt.src.ptr = src_ptr;
2597 cvt.src.fb = src;
2598 fb_convert(&cvt);
2599
2600 igt_fb_unmap_buffer(dst, dst_ptr);
2601 igt_fb_unmap_buffer(src, src_ptr);
2602
Paul Kocialkowskicf8438a2019-01-24 16:30:48 +01002603 igt_assert(dst_modifier == LOCAL_DRM_FORMAT_MOD_NONE);
2604
Maxime Riparde3b1c342018-10-04 14:39:00 +02002605 return fb_id;
2606}
2607
2608/**
Paul Kocialkowski6e227182018-12-05 16:10:35 +01002609 * igt_fb_convert:
2610 * @dst: pointer to the #igt_fb structure that will store the conversion result
2611 * @src: pointer to the #igt_fb structure that stores the frame we convert
2612 * @dst_fourcc: DRM format specifier to convert to
Paul Kocialkowskicf8438a2019-01-24 16:30:48 +01002613 * @dst_modifier: DRM format modifier to convert to
Paul Kocialkowski6e227182018-12-05 16:10:35 +01002614 *
2615 * This will convert a given @src content to the @dst_fourcc format,
2616 * storing the result in the @dst fb, allocating the @dst fb
2617 * underlying buffer.
2618 *
2619 * Once done with @dst, the caller will have to call igt_remove_fb()
2620 * on it to free the associated resources.
2621 *
2622 * Returns:
2623 * The kms id of the created framebuffer.
2624 */
2625unsigned int igt_fb_convert(struct igt_fb *dst, struct igt_fb *src,
Paul Kocialkowskicf8438a2019-01-24 16:30:48 +01002626 uint32_t dst_fourcc, uint64_t dst_modifier)
Paul Kocialkowski6e227182018-12-05 16:10:35 +01002627{
Paul Kocialkowskicf8438a2019-01-24 16:30:48 +01002628 return igt_fb_convert_with_stride(dst, src, dst_fourcc, dst_modifier,
2629 0);
Paul Kocialkowski6e227182018-12-05 16:10:35 +01002630}
2631
2632/**
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01002633 * igt_bpp_depth_to_drm_format:
2634 * @bpp: desired bits per pixel
2635 * @depth: desired depth
2636 *
2637 * Returns:
2638 * The rgb drm fourcc pixel format code corresponding to the given @bpp and
2639 * @depth values. Fails hard if no match was found.
2640 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01002641uint32_t igt_bpp_depth_to_drm_format(int bpp, int depth)
Daniel Vetter57d7db82014-03-26 09:06:11 +01002642{
Ville Syrjäläef43fce2018-07-18 20:26:22 +03002643 const struct format_desc_struct *f;
Daniel Vetter57d7db82014-03-26 09:06:11 +01002644
2645 for_each_format(f)
Ville Syrjäläe556d852018-02-27 22:48:46 +02002646 if (f->plane_bpp[0] == bpp && f->depth == depth)
Daniel Vetter57d7db82014-03-26 09:06:11 +01002647 return f->drm_id;
2648
Damien Lespiau54397ca2014-08-19 11:40:07 +01002649
2650 igt_assert_f(0, "can't find drm format with bpp=%d, depth=%d\n", bpp,
2651 depth);
Daniel Vetter57d7db82014-03-26 09:06:11 +01002652}
2653
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01002654/**
2655 * igt_drm_format_to_bpp:
2656 * @drm_format: drm fourcc pixel format code
2657 *
2658 * Returns:
2659 * The bits per pixel for the given drm fourcc pixel format code. Fails hard if
2660 * no match was found.
2661 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01002662uint32_t igt_drm_format_to_bpp(uint32_t drm_format)
Daniel Vetter57d7db82014-03-26 09:06:11 +01002663{
Ville Syrjäläef43fce2018-07-18 20:26:22 +03002664 const struct format_desc_struct *f = lookup_drm_format(drm_format);
Daniel Vetter57d7db82014-03-26 09:06:11 +01002665
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +01002666 igt_assert_f(f, "can't find a bpp format for %08x (%s)\n",
Damien Lespiau54397ca2014-08-19 11:40:07 +01002667 drm_format, igt_format_str(drm_format));
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +01002668
Ville Syrjäläe556d852018-02-27 22:48:46 +02002669 return f->plane_bpp[0];
Daniel Vetter57d7db82014-03-26 09:06:11 +01002670}
2671
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01002672/**
2673 * igt_format_str:
2674 * @drm_format: drm fourcc pixel format code
2675 *
2676 * Returns:
2677 * Human-readable fourcc pixel format code for @drm_format or "invalid" no match
2678 * was found.
2679 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01002680const char *igt_format_str(uint32_t drm_format)
Daniel Vetter57d7db82014-03-26 09:06:11 +01002681{
Ville Syrjäläef43fce2018-07-18 20:26:22 +03002682 const struct format_desc_struct *f = lookup_drm_format(drm_format);
Daniel Vetter57d7db82014-03-26 09:06:11 +01002683
Maarten Lankhorst01ef9f82018-01-19 11:01:35 +01002684 return f ? f->name : "invalid";
Daniel Vetter57d7db82014-03-26 09:06:11 +01002685}
2686
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01002687/**
Maarten Lankhorstc60cf3b2018-02-02 11:32:40 +01002688 * igt_fb_supported_format:
2689 * @drm_format: drm fourcc to test.
2690 *
2691 * This functions returns whether @drm_format can be succesfully created by
2692 * igt_create_fb() and drawn to by igt_get_cairo_ctx().
2693 */
2694bool igt_fb_supported_format(uint32_t drm_format)
2695{
Ville Syrjäläef43fce2018-07-18 20:26:22 +03002696 const struct format_desc_struct *f;
Maarten Lankhorstc60cf3b2018-02-02 11:32:40 +01002697
2698 for_each_format(f)
2699 if (f->drm_id == drm_format)
Maxime Ripard3fa65f42018-10-04 14:39:03 +02002700 return (f->cairo_id != CAIRO_FORMAT_INVALID) ||
2701 (f->pixman_id != PIXMAN_invalid);
Maarten Lankhorstc60cf3b2018-02-02 11:32:40 +01002702
2703 return false;
2704}
Ville Syrjälä40bf6d02018-05-18 23:32:32 +03002705
2706/**
2707 * igt_format_is_yuv:
2708 * @drm_format: drm fourcc
2709 *
2710 * This functions returns whether @drm_format is YUV (as opposed to RGB).
2711 */
2712bool igt_format_is_yuv(uint32_t drm_format)
2713{
2714 switch (drm_format) {
2715 case DRM_FORMAT_NV12:
Maxime Ripard3b2b80b2019-02-08 14:18:58 +01002716 case DRM_FORMAT_NV16:
2717 case DRM_FORMAT_NV21:
2718 case DRM_FORMAT_NV61:
2719 case DRM_FORMAT_YUV420:
2720 case DRM_FORMAT_YUV422:
2721 case DRM_FORMAT_YVU420:
2722 case DRM_FORMAT_YVU422:
Maarten Lankhorstcb8e45a2019-02-01 11:13:59 +01002723 case DRM_FORMAT_P010:
2724 case DRM_FORMAT_P012:
2725 case DRM_FORMAT_P016:
Ville Syrjälä40bf6d02018-05-18 23:32:32 +03002726 case DRM_FORMAT_YUYV:
2727 case DRM_FORMAT_YVYU:
2728 case DRM_FORMAT_UYVY:
2729 case DRM_FORMAT_VYUY:
Stanislav Lisovskiyf05c8c22018-12-17 16:30:28 +02002730 case DRM_FORMAT_XYUV8888:
Ville Syrjälä40bf6d02018-05-18 23:32:32 +03002731 return true;
2732 default:
2733 return false;
2734 }
2735}
Paul Kocialkowski34a21df2018-12-05 16:14:59 +01002736
2737/**
2738 * igt_format_plane_bpp:
2739 * @drm_format: drm fourcc
2740 * @plane: format plane index
2741 *
2742 * This functions returns the number of bits per pixel for the given @plane
2743 * index of the @drm_format.
2744 */
2745int igt_format_plane_bpp(uint32_t drm_format, int plane)
2746{
2747 const struct format_desc_struct *format =
2748 lookup_drm_format(drm_format);
2749
2750 return format->plane_bpp[plane];
2751}
Paul Kocialkowski7a8456b2019-01-10 17:33:52 +01002752
2753/**
2754 * igt_format_array_fill:
2755 * @formats_array: a pointer to the formats array pointer to be allocated
2756 * @count: a pointer to the number of elements contained in the allocated array
2757 * @allow_yuv: a boolean indicating whether YUV formats should be included
2758 *
2759 * This functions allocates and fills a @formats_array that lists the DRM
2760 * formats current available.
2761 */
2762void igt_format_array_fill(uint32_t **formats_array, unsigned int *count,
2763 bool allow_yuv)
2764{
2765 const struct format_desc_struct *format;
2766 unsigned int index = 0;
2767
2768 *count = 0;
2769
2770 for_each_format(format) {
2771 if (!allow_yuv && igt_format_is_yuv(format->drm_id))
2772 continue;
2773
2774 (*count)++;
2775 }
2776
2777 *formats_array = calloc(*count, sizeof(uint32_t));
2778 igt_assert(*formats_array);
2779
2780 for_each_format(format) {
2781 if (!allow_yuv && igt_format_is_yuv(format->drm_id))
2782 continue;
2783
2784 (*formats_array)[index++] = format->drm_id;
2785 }
2786}