blob: 39a83bae178a30c445c3dc3d10569ac3d12bc88a [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>
Mike Frysinger030977e2018-01-10 17:12:15 -050030#include <inttypes.h>
Daniel Vetter57d7db82014-03-26 09:06:11 +010031
32#include "drmtest.h"
33#include "igt_fb.h"
Tomeu Vizoso8a1a3862016-02-24 09:04:04 +010034#include "igt_kms.h"
Daniel Vetter57d7db82014-03-26 09:06:11 +010035#include "ioctl_wrappers.h"
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -020036#include "intel_chipset.h"
Daniel Vetter57d7db82014-03-26 09:06:11 +010037
Daniel Vetterc6c2b2b2014-03-26 15:15:49 +010038/**
39 * SECTION:igt_fb
40 * @short_description: Framebuffer handling and drawing library
Damien Lespiau6ebd8c22015-06-26 14:28:41 +010041 * @title: Framebuffer
Thomas Woodf0381d12015-09-07 09:26:01 +010042 * @include: igt.h
Daniel Vetter3d9e63f2014-03-26 16:37:15 +010043 *
44 * This library contains helper functions for handling kms framebuffer objects
45 * using #igt_fb structures to track all the metadata. igt_create_fb() creates
Thomas Woodd01ebbd2015-06-29 16:47:14 +010046 * a basic framebuffer and igt_remove_fb() cleans everything up again.
Daniel Vetter3d9e63f2014-03-26 16:37:15 +010047 *
48 * It also supports drawing using the cairo library and provides some simplified
49 * helper functions to easily draw test patterns. The main function to create a
50 * cairo drawing context for a framebuffer object is igt_get_cairo_ctx().
51 *
52 * Finally it also pulls in the drm fourcc headers and provides some helper
53 * functions to work with these pixel format codes.
Daniel Vetterc6c2b2b2014-03-26 15:15:49 +010054 */
55
Daniel Vetter57d7db82014-03-26 09:06:11 +010056/* drm fourcc/cairo format maps */
57#define DF(did, cid, _bpp, _depth) \
58 { DRM_FORMAT_##did, CAIRO_FORMAT_##cid, # did, _bpp, _depth }
59static struct format_desc_struct {
60 uint32_t drm_id;
61 cairo_format_t cairo_id;
62 const char *name;
63 int bpp;
64 int depth;
65} format_desc[] = {
66 DF(RGB565, RGB16_565, 16, 16),
Chris Wilson9df77d52014-09-06 12:08:13 +010067 //DF(RGB888, INVALID, 24, 24),
Daniel Vetter57d7db82014-03-26 09:06:11 +010068 DF(XRGB8888, RGB24, 32, 24),
69 DF(XRGB2101010, RGB30, 32, 30),
70 DF(ARGB8888, ARGB32, 32, 32),
71};
72#undef DF
73
74#define for_each_format(f) \
75 for (f = format_desc; f - format_desc < ARRAY_SIZE(format_desc); f++)
76
Praveen Paneri4bb45412017-07-18 22:52:56 +053077/**
78 * igt_get_fb_tile_size:
79 * @fd: the DRM file descriptor
80 * @tiling: tiling layout of the framebuffer (as framebuffer modifier)
81 * @fb_bpp: bits per pixel of the framebuffer
82 * @width_ret: width of the tile in bytes
83 * @height_ret: height of the tile in lines
84 *
85 * This function returns width and height of a tile based on the given tiling
86 * format.
87 */
88void igt_get_fb_tile_size(int fd, uint64_t tiling, int fb_bpp,
89 unsigned *width_ret, unsigned *height_ret)
Daniel Vetter57d7db82014-03-26 09:06:11 +010090{
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -020091 switch (tiling) {
92 case LOCAL_DRM_FORMAT_MOD_NONE:
93 *width_ret = 64;
94 *height_ret = 1;
95 break;
96 case LOCAL_I915_FORMAT_MOD_X_TILED:
Tomeu Vizoso85a1d452016-02-24 08:39:53 +010097 igt_require_intel(fd);
98 if (intel_gen(intel_get_drm_devid(fd)) == 2) {
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -020099 *width_ret = 128;
100 *height_ret = 16;
101 } else {
102 *width_ret = 512;
103 *height_ret = 8;
104 }
105 break;
106 case LOCAL_I915_FORMAT_MOD_Y_TILED:
Tomeu Vizoso85a1d452016-02-24 08:39:53 +0100107 igt_require_intel(fd);
108 if (intel_gen(intel_get_drm_devid(fd)) == 2) {
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200109 *width_ret = 128;
Ville Syrjälä037bc692016-02-12 21:28:54 +0200110 *height_ret = 16;
Tomeu Vizoso85a1d452016-02-24 08:39:53 +0100111 } else if (IS_915(intel_get_drm_devid(fd))) {
Ville Syrjälä037bc692016-02-12 21:28:54 +0200112 *width_ret = 512;
113 *height_ret = 8;
114 } else {
115 *width_ret = 128;
116 *height_ret = 32;
117 }
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200118 break;
119 case LOCAL_I915_FORMAT_MOD_Yf_TILED:
Tomeu Vizoso85a1d452016-02-24 08:39:53 +0100120 igt_require_intel(fd);
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200121 switch (fb_bpp) {
122 case 8:
123 *width_ret = 64;
124 *height_ret = 64;
125 break;
126 case 16:
127 case 32:
128 *width_ret = 128;
129 *height_ret = 32;
130 break;
131 case 64:
132 case 128:
133 *width_ret = 256;
134 *height_ret = 16;
135 break;
136 default:
137 igt_assert(false);
138 }
139 break;
140 default:
141 igt_assert(false);
142 }
143}
144
145/**
146 * igt_calc_fb_size:
147 * @fd: the DRM file descriptor
148 * @width: width of the framebuffer in pixels
149 * @height: height of the framebuffer in pixels
150 * @bpp: bytes per pixel of the framebuffer
151 * @tiling: tiling layout of the framebuffer (as framebuffer modifier)
152 * @size_ret: returned size for the framebuffer
153 * @stride_ret: returned stride for the framebuffer
154 *
155 * This function returns valid stride and size values for a framebuffer with the
156 * specified parameters.
157 */
158void igt_calc_fb_size(int fd, int width, int height, int bpp, uint64_t tiling,
159 unsigned *size_ret, unsigned *stride_ret)
160{
161 unsigned int tile_width, tile_height, stride, size;
162 int byte_width = width * (bpp / 8);
163
164 igt_get_fb_tile_size(fd, tiling, bpp, &tile_width, &tile_height);
165
Tomeu Vizoso85a1d452016-02-24 08:39:53 +0100166 if (tiling != LOCAL_DRM_FORMAT_MOD_NONE &&
167 intel_gen(intel_get_drm_devid(fd)) <= 3) {
Daniel Vetter57d7db82014-03-26 09:06:11 +0100168 int v;
169
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200170 /* Round the tiling up to the next power-of-two and the region
171 * up to the next pot fence size so that this works on all
172 * generations.
Daniel Vetter57d7db82014-03-26 09:06:11 +0100173 *
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200174 * This can still fail if the framebuffer is too large to be
175 * tiled. But then that failure is expected.
Daniel Vetter57d7db82014-03-26 09:06:11 +0100176 */
177
178 v = width * bpp / 8;
179 for (stride = 512; stride < v; stride *= 2)
180 ;
181
182 v = stride * height;
183 for (size = 1024*1024; size < v; size *= 2)
184 ;
185 } else {
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200186 stride = ALIGN(byte_width, tile_width);
187 size = stride * ALIGN(height, tile_height);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100188 }
189
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200190 *stride_ret = stride;
191 *size_ret = size;
192}
193
Tomeu Vizosoae649632016-11-10 10:25:24 +0100194/**
195 * igt_fb_mod_to_tiling:
196 * @modifier: DRM framebuffer modifier
197 *
198 * This function converts a DRM framebuffer modifier to its corresponding
199 * tiling constant.
200 *
201 * Returns:
202 * A tiling constant
203 */
204uint64_t igt_fb_mod_to_tiling(uint64_t modifier)
205{
206 switch (modifier) {
207 case LOCAL_DRM_FORMAT_MOD_NONE:
208 return I915_TILING_NONE;
209 case LOCAL_I915_FORMAT_MOD_X_TILED:
210 return I915_TILING_X;
211 case LOCAL_I915_FORMAT_MOD_Y_TILED:
212 return I915_TILING_Y;
213 case LOCAL_I915_FORMAT_MOD_Yf_TILED:
214 return I915_TILING_Yf;
215 default:
216 igt_assert(0);
217 }
218}
219
Praveen Paneri4437e212017-07-18 22:52:57 +0530220/**
221 * igt_fb_tiling_to_mod:
222 * @tiling: DRM framebuffer tiling
223 *
224 * This function converts a DRM framebuffer tiling to its corresponding
225 * modifier constant.
226 *
227 * Returns:
228 * A modifier constant
229 */
230uint64_t igt_fb_tiling_to_mod(uint64_t tiling)
231{
232 switch (tiling) {
233 case I915_TILING_NONE:
234 return LOCAL_DRM_FORMAT_MOD_NONE;
235 case I915_TILING_X:
236 return LOCAL_I915_FORMAT_MOD_X_TILED;
237 case I915_TILING_Y:
238 return LOCAL_I915_FORMAT_MOD_Y_TILED;
239 case I915_TILING_Yf:
240 return LOCAL_I915_FORMAT_MOD_Yf_TILED;
241 default:
242 igt_assert(0);
243 }
244}
245
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200246/* helpers to create nice-looking framebuffers */
247static int create_bo_for_fb(int fd, int width, int height, uint32_t format,
248 uint64_t tiling, unsigned size, unsigned stride,
249 unsigned *size_ret, unsigned *stride_ret,
250 bool *is_dumb)
251{
252 int bpp = igt_drm_format_to_bpp(format);
253 int bo;
254
255 if (tiling || size || stride) {
256 unsigned calculated_size, calculated_stride;
257
258 igt_calc_fb_size(fd, width, height, bpp, tiling,
259 &calculated_size, &calculated_stride);
260 if (stride == 0)
261 stride = calculated_stride;
262 if (size == 0)
263 size = calculated_size;
264
265 if (is_dumb)
266 *is_dumb = false;
267
268 if (is_i915_device(fd)) {
Chris Wilsond2805062016-08-18 13:56:18 +0100269 uint32_t *ptr;
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200270
271 bo = gem_create(fd, size);
Tomeu Vizosoae649632016-11-10 10:25:24 +0100272 gem_set_tiling(fd, bo, igt_fb_mod_to_tiling(tiling), stride);
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200273
Chris Wilsond2805062016-08-18 13:56:18 +0100274 /* Ensure the framebuffer is preallocated */
275 ptr = gem_mmap__gtt(fd, bo, size, PROT_READ);
276 igt_assert(*ptr == 0);
Maarten Lankhorstd930b642017-02-09 10:42:01 +0100277 gem_munmap(ptr, size);
Chris Wilsond2805062016-08-18 13:56:18 +0100278
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200279 if (size_ret)
280 *size_ret = size;
281
282 if (stride_ret)
283 *stride_ret = stride;
284
285 return bo;
286 } else {
287 bool driver_has_gem_api = false;
288
289 igt_require(driver_has_gem_api);
290 return -EINVAL;
291 }
292 } else {
293 if (is_dumb)
294 *is_dumb = true;
295
296 return kmstest_dumb_create(fd, width, height, bpp, stride_ret,
297 size_ret);
298 }
299}
300
Tomeu Vizoso8a1a3862016-02-24 09:04:04 +0100301/**
302 * igt_create_bo_with_dimensions:
303 * @fd: open drm file descriptor
304 * @width: width of the buffer object in pixels
305 * @height: height of the buffer object in pixels
306 * @format: drm fourcc pixel format code
307 * @modifier: modifier corresponding to the tiling layout of the buffer object
308 * @stride: stride of the buffer object in bytes (0 for automatic stride)
309 * @size_ret: size of the buffer object as created by the kernel
310 * @stride_ret: stride of the buffer object as created by the kernel
311 * @is_dumb: whether the created buffer object is a dumb buffer or not
312 *
313 * This function allocates a gem buffer object matching the requested
314 * properties.
315 *
316 * Returns:
317 * The kms id of the created buffer object.
318 */
319int igt_create_bo_with_dimensions(int fd, int width, int height,
320 uint32_t format, uint64_t modifier,
321 unsigned stride, unsigned *size_ret,
322 unsigned *stride_ret, bool *is_dumb)
323{
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200324 return create_bo_for_fb(fd, width, height, format, modifier, 0, stride,
325 size_ret, stride_ret, is_dumb);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100326}
327
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100328/**
329 * igt_paint_color:
330 * @cr: cairo drawing context
331 * @x: pixel x-coordination of the fill rectangle
332 * @y: pixel y-coordination of the fill rectangle
333 * @w: width of the fill rectangle
334 * @h: height of the fill rectangle
335 * @r: red value to use as fill color
Thomas Woodd01ebbd2015-06-29 16:47:14 +0100336 * @g: green value to use as fill color
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100337 * @b: blue value to use as fill color
338 *
339 * This functions draws a solid rectangle with the given color using the drawing
340 * context @cr.
341 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100342void igt_paint_color(cairo_t *cr, int x, int y, int w, int h,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100343 double r, double g, double b)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100344{
345 cairo_rectangle(cr, x, y, w, h);
346 cairo_set_source_rgb(cr, r, g, b);
347 cairo_fill(cr);
348}
349
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100350/**
351 * igt_paint_color_alpha:
352 * @cr: cairo drawing context
353 * @x: pixel x-coordination of the fill rectangle
354 * @y: pixel y-coordination of the fill rectangle
355 * @w: width of the fill rectangle
356 * @h: height of the fill rectangle
357 * @r: red value to use as fill color
Thomas Woodd01ebbd2015-06-29 16:47:14 +0100358 * @g: green value to use as fill color
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100359 * @b: blue value to use as fill color
360 * @a: alpha value to use as fill color
361 *
362 * This functions draws a rectangle with the given color and alpha values using
363 * the drawing context @cr.
364 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100365void igt_paint_color_alpha(cairo_t *cr, int x, int y, int w, int h,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100366 double r, double g, double b, double a)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100367{
368 cairo_rectangle(cr, x, y, w, h);
369 cairo_set_source_rgba(cr, r, g, b, a);
370 cairo_fill(cr);
371}
372
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100373/**
374 * igt_paint_color_gradient:
375 * @cr: cairo drawing context
376 * @x: pixel x-coordination of the fill rectangle
377 * @y: pixel y-coordination of the fill rectangle
378 * @w: width of the fill rectangle
379 * @h: height of the fill rectangle
380 * @r: red value to use as fill color
Thomas Woodd01ebbd2015-06-29 16:47:14 +0100381 * @g: green value to use as fill color
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100382 * @b: blue value to use as fill color
383 *
384 * This functions draws a gradient into the rectangle which fades in from black
385 * to the given values using the drawing context @cr.
386 */
Daniel Vetter57d7db82014-03-26 09:06:11 +0100387void
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100388igt_paint_color_gradient(cairo_t *cr, int x, int y, int w, int h,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100389 int r, int g, int b)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100390{
391 cairo_pattern_t *pat;
392
393 pat = cairo_pattern_create_linear(x, y, x + w, y + h);
394 cairo_pattern_add_color_stop_rgba(pat, 1, 0, 0, 0, 1);
395 cairo_pattern_add_color_stop_rgba(pat, 0, r, g, b, 1);
396
397 cairo_rectangle(cr, x, y, w, h);
398 cairo_set_source(cr, pat);
399 cairo_fill(cr);
400 cairo_pattern_destroy(pat);
401}
402
Lionel Landwerlina5113102016-03-18 17:33:02 +0000403/**
404 * igt_paint_color_gradient_range:
405 * @cr: cairo drawing context
406 * @x: pixel x-coordination of the fill rectangle
407 * @y: pixel y-coordination of the fill rectangle
408 * @w: width of the fill rectangle
409 * @h: height of the fill rectangle
410 * @sr: red value to use as start gradient color
411 * @sg: green value to use as start gradient color
412 * @sb: blue value to use as start gradient color
413 * @er: red value to use as end gradient color
414 * @eg: green value to use as end gradient color
415 * @eb: blue value to use as end gradient color
416 *
417 * This functions draws a gradient into the rectangle which fades in
418 * from one color to the other using the drawing context @cr.
419 */
420void
421igt_paint_color_gradient_range(cairo_t *cr, int x, int y, int w, int h,
422 double sr, double sg, double sb,
423 double er, double eg, double eb)
424{
425 cairo_pattern_t *pat;
426
427 pat = cairo_pattern_create_linear(x, y, x + w, y + h);
428 cairo_pattern_add_color_stop_rgba(pat, 1, sr, sg, sb, 1);
429 cairo_pattern_add_color_stop_rgba(pat, 0, er, eg, eb, 1);
430
431 cairo_rectangle(cr, x, y, w, h);
432 cairo_set_source(cr, pat);
433 cairo_fill(cr);
434 cairo_pattern_destroy(pat);
435}
436
Daniel Vetter57d7db82014-03-26 09:06:11 +0100437static void
438paint_test_patterns(cairo_t *cr, int width, int height)
439{
440 double gr_height, gr_width;
441 int x, y;
442
443 y = height * 0.10;
444 gr_width = width * 0.75;
445 gr_height = height * 0.08;
446 x = (width / 2) - (gr_width / 2);
447
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100448 igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 1, 0, 0);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100449
450 y += gr_height;
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100451 igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 0, 1, 0);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100452
453 y += gr_height;
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100454 igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 0, 0, 1);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100455
456 y += gr_height;
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100457 igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 1, 1, 1);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100458}
459
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100460/**
461 * igt_cairo_printf_line:
462 * @cr: cairo drawing context
463 * @align: text alignment
464 * @yspacing: additional y-direction feed after this line
465 * @fmt: format string
466 * @...: optional arguments used in the format string
467 *
468 * This is a little helper to draw text onto framebuffers. All the initial setup
469 * (like setting the font size and the moving to the starting position) still
470 * needs to be done manually with explicit cairo calls on @cr.
471 *
472 * Returns:
473 * The width of the drawn text.
474 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100475int igt_cairo_printf_line(cairo_t *cr, enum igt_text_align align,
Daniel Vetter57d7db82014-03-26 09:06:11 +0100476 double yspacing, const char *fmt, ...)
477{
478 double x, y, xofs, yofs;
479 cairo_text_extents_t extents;
480 char *text;
481 va_list ap;
482 int ret;
483
484 va_start(ap, fmt);
485 ret = vasprintf(&text, fmt, ap);
486 igt_assert(ret >= 0);
487 va_end(ap);
488
489 cairo_text_extents(cr, text, &extents);
490
491 xofs = yofs = 0;
492 if (align & align_right)
493 xofs = -extents.width;
494 else if (align & align_hcenter)
495 xofs = -extents.width / 2;
496
497 if (align & align_top)
498 yofs = extents.height;
499 else if (align & align_vcenter)
500 yofs = extents.height / 2;
501
502 cairo_get_current_point(cr, &x, &y);
503 if (xofs || yofs)
504 cairo_rel_move_to(cr, xofs, yofs);
505
506 cairo_text_path(cr, text);
507 cairo_set_source_rgb(cr, 0, 0, 0);
508 cairo_stroke_preserve(cr);
509 cairo_set_source_rgb(cr, 1, 1, 1);
510 cairo_fill(cr);
511
512 cairo_move_to(cr, x, y + extents.height + yspacing);
513
514 free(text);
515
516 return extents.width;
517}
518
519static void
520paint_marker(cairo_t *cr, int x, int y)
521{
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100522 enum igt_text_align align;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100523 int xoff, yoff;
524
525 cairo_move_to(cr, x, y - 20);
526 cairo_line_to(cr, x, y + 20);
527 cairo_move_to(cr, x - 20, y);
528 cairo_line_to(cr, x + 20, y);
529 cairo_new_sub_path(cr);
530 cairo_arc(cr, x, y, 10, 0, M_PI * 2);
531 cairo_set_line_width(cr, 4);
532 cairo_set_source_rgb(cr, 0, 0, 0);
533 cairo_stroke_preserve(cr);
534 cairo_set_source_rgb(cr, 1, 1, 1);
535 cairo_set_line_width(cr, 2);
536 cairo_stroke(cr);
537
538 xoff = x ? -20 : 20;
539 align = x ? align_right : align_left;
540
541 yoff = y ? -20 : 20;
542 align |= y ? align_bottom : align_top;
543
544 cairo_move_to(cr, x + xoff, y + yoff);
545 cairo_set_font_size(cr, 18);
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100546 igt_cairo_printf_line(cr, align, 0, "(%d, %d)", x, y);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100547}
548
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100549/**
550 * igt_paint_test_pattern:
551 * @cr: cairo drawing context
552 * @width: width of the visible area
553 * @height: height of the visible area
554 *
555 * This functions draws an entire set of test patterns for the given visible
556 * area using the drawing context @cr. This is useful for manual visual
557 * inspection of displayed framebuffers.
558 *
559 * The test patterns include
560 * - corner markers to check for over/underscan and
561 * - a set of color and b/w gradients.
562 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100563void igt_paint_test_pattern(cairo_t *cr, int width, int height)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100564{
565 paint_test_patterns(cr, width, height);
566
567 cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
568
569 /* Paint corner markers */
570 paint_marker(cr, 0, 0);
571 paint_marker(cr, width, 0);
572 paint_marker(cr, 0, height);
573 paint_marker(cr, width, height);
574
575 igt_assert(!cairo_status(cr));
576}
577
Thomas Woodecb03262015-04-13 17:37:22 +0100578static cairo_status_t
579stdio_read_func(void *closure, unsigned char* data, unsigned int size)
580{
581 if (fread(data, 1, size, (FILE*)closure) != size)
582 return CAIRO_STATUS_READ_ERROR;
583
584 return CAIRO_STATUS_SUCCESS;
585}
586
Ville Syrjälä75f320c2017-09-21 15:39:23 +0300587cairo_surface_t *igt_cairo_image_surface_create_from_png(const char *filename)
588{
589 cairo_surface_t *image;
590 FILE *f;
591
592 f = igt_fopen_data(filename);
593 image = cairo_image_surface_create_from_png_stream(&stdio_read_func, f);
594 fclose(f);
595
596 return image;
597}
598
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100599/**
600 * igt_paint_image:
601 * @cr: cairo drawing context
602 * @filename: filename of the png image to draw
603 * @dst_x: pixel x-coordination of the destination rectangle
604 * @dst_y: pixel y-coordination of the destination rectangle
605 * @dst_width: width of the destination rectangle
606 * @dst_height: height of the destination rectangle
607 *
Thomas Woodecb03262015-04-13 17:37:22 +0100608 * This function can be used to draw a scaled version of the supplied png image,
609 * which is loaded from the package data directory.
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100610 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100611void igt_paint_image(cairo_t *cr, const char *filename,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100612 int dst_x, int dst_y, int dst_width, int dst_height)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100613{
614 cairo_surface_t *image;
615 int img_width, img_height;
616 double scale_x, scale_y;
617
Ville Syrjälä75f320c2017-09-21 15:39:23 +0300618 image = igt_cairo_image_surface_create_from_png(filename);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100619 igt_assert(cairo_surface_status(image) == CAIRO_STATUS_SUCCESS);
620
621 img_width = cairo_image_surface_get_width(image);
622 img_height = cairo_image_surface_get_height(image);
623
624 scale_x = (double)dst_width / img_width;
625 scale_y = (double)dst_height / img_height;
626
627 cairo_save(cr);
628
629 cairo_translate(cr, dst_x, dst_y);
630 cairo_scale(cr, scale_x, scale_y);
631 cairo_set_source_surface(cr, image, 0, 0);
632 cairo_paint(cr);
633
634 cairo_surface_destroy(image);
635
636 cairo_restore(cr);
637}
638
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100639/**
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100640 * igt_create_fb_with_bo_size:
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100641 * @fd: open i915 drm file descriptor
642 * @width: width of the framebuffer in pixel
643 * @height: height of the framebuffer in pixel
644 * @format: drm fourcc pixel format code
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000645 * @tiling: tiling layout of the framebuffer (as framebuffer modifier)
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100646 * @fb: pointer to an #igt_fb structure
Paulo Zanonicb7dd5d2015-11-05 16:18:55 -0200647 * @bo_size: size of the backing bo (0 for automatic size)
Paulo Zanonid6341372015-11-05 16:39:00 -0200648 * @bo_stride: stride of the backing bo (0 for automatic stride)
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100649 *
650 * This function allocates a gem buffer object suitable to back a framebuffer
651 * with the requested properties and then wraps it up in a drm framebuffer
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100652 * object of the requested size. All metadata is stored in @fb.
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100653 *
654 * The backing storage of the framebuffer is filled with all zeros, i.e. black
655 * for rgb pixel formats.
656 *
657 * Returns:
Damien Lespiau50166d22014-08-19 11:55:22 +0100658 * The kms id of the created framebuffer.
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100659 */
Damien Lespiau378e61e2014-06-23 14:53:24 +0100660unsigned int
661igt_create_fb_with_bo_size(int fd, int width, int height,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000662 uint32_t format, uint64_t tiling,
Paulo Zanonid6341372015-11-05 16:39:00 -0200663 struct igt_fb *fb, unsigned bo_size,
664 unsigned bo_stride)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100665{
Daniel Vetter57d7db82014-03-26 09:06:11 +0100666 uint32_t fb_id;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100667
668 memset(fb, 0, sizeof(*fb));
669
Tomeu Vizoso8a1a3862016-02-24 09:04:04 +0100670 igt_debug("%s(width=%d, height=%d, format=0x%x, tiling=0x%"PRIx64", size=%d)\n",
671 __func__, width, height, format, tiling, bo_size);
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200672 fb->gem_handle = create_bo_for_fb(fd, width, height, format, tiling,
673 bo_size, bo_stride, &fb->size,
674 &fb->stride, &fb->is_dumb);
675 igt_assert(fb->gem_handle > 0);
Chris Wilsondb4cc742014-09-06 12:07:49 +0100676
Chris Wilsondb4cc742014-09-06 12:07:49 +0100677 igt_debug("%s(handle=%d, pitch=%d)\n",
Tvrtko Ursulineb93c1b2015-03-03 14:11:03 +0000678 __func__, fb->gem_handle, fb->stride);
679
680 if (tiling != LOCAL_DRM_FORMAT_MOD_NONE &&
681 tiling != LOCAL_I915_FORMAT_MOD_X_TILED) {
682 do_or_die(__kms_addfb(fd, fb->gem_handle, width, height,
683 fb->stride, format, tiling,
684 LOCAL_DRM_MODE_FB_MODIFIERS, &fb_id));
685 } else {
686 uint32_t handles[4];
687 uint32_t pitches[4];
688 uint32_t offsets[4];
689
690 memset(handles, 0, sizeof(handles));
691 memset(pitches, 0, sizeof(pitches));
692 memset(offsets, 0, sizeof(offsets));
693
694 handles[0] = fb->gem_handle;
695 pitches[0] = fb->stride;
696
697 do_or_die(drmModeAddFB2(fd, width, height, format,
698 handles, pitches, offsets,
699 &fb_id, 0));
700 }
Daniel Vetter57d7db82014-03-26 09:06:11 +0100701
702 fb->width = width;
703 fb->height = height;
Damien Lespiau378e61e2014-06-23 14:53:24 +0100704 fb->tiling = tiling;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100705 fb->drm_format = format;
706 fb->fb_id = fb_id;
Tomeu Vizoso89b3ffe2016-02-24 09:04:41 +0100707 fb->fd = fd;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100708
709 return fb_id;
710}
711
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100712/**
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100713 * igt_create_fb:
714 * @fd: open i915 drm file descriptor
715 * @width: width of the framebuffer in pixel
716 * @height: height of the framebuffer in pixel
717 * @format: drm fourcc pixel format code
Damien Lespiau378e61e2014-06-23 14:53:24 +0100718 * @tiling: tiling layout of the framebuffer
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100719 * @fb: pointer to an #igt_fb structure
720 *
721 * This function allocates a gem buffer object suitable to back a framebuffer
722 * with the requested properties and then wraps it up in a drm framebuffer
723 * object. All metadata is stored in @fb.
724 *
725 * The backing storage of the framebuffer is filled with all zeros, i.e. black
726 * for rgb pixel formats.
727 *
728 * Returns:
Damien Lespiau50166d22014-08-19 11:55:22 +0100729 * The kms id of the created framebuffer.
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100730 */
731unsigned int igt_create_fb(int fd, int width, int height, uint32_t format,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000732 uint64_t tiling, struct igt_fb *fb)
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100733{
Paulo Zanonid6341372015-11-05 16:39:00 -0200734 return igt_create_fb_with_bo_size(fd, width, height, format, tiling, fb,
735 0, 0);
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100736}
737
738/**
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100739 * igt_create_color_fb:
740 * @fd: open i915 drm file descriptor
741 * @width: width of the framebuffer in pixel
742 * @height: height of the framebuffer in pixel
743 * @format: drm fourcc pixel format code
Damien Lespiau378e61e2014-06-23 14:53:24 +0100744 * @tiling: tiling layout of the framebuffer
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100745 * @r: red value to use as fill color
Ville Syrjälä5b113d32015-12-17 01:39:31 +0200746 * @g: green value to use as fill color
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100747 * @b: blue value to use as fill color
748 * @fb: pointer to an #igt_fb structure
749 *
750 * This function allocates a gem buffer object suitable to back a framebuffer
751 * with the requested properties and then wraps it up in a drm framebuffer
752 * object. All metadata is stored in @fb.
753 *
754 * Compared to igt_create_fb() this function also fills the entire framebuffer
755 * with the given color, which is useful for some simple pipe crc based tests.
756 *
757 * Returns:
758 * The kms id of the created framebuffer on success or a negative error code on
759 * failure.
760 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100761unsigned int igt_create_color_fb(int fd, int width, int height,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000762 uint32_t format, uint64_t tiling,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100763 double r, double g, double b,
764 struct igt_fb *fb /* out */)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100765{
766 unsigned int fb_id;
767 cairo_t *cr;
768
Damien Lespiau378e61e2014-06-23 14:53:24 +0100769 fb_id = igt_create_fb(fd, width, height, format, tiling, fb);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100770 igt_assert(fb_id);
771
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100772 cr = igt_get_cairo_ctx(fd, fb);
773 igt_paint_color(cr, 0, 0, width, height, r, g, b);
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +0100774 igt_put_cairo_ctx(fd, fb, cr);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100775
776 return fb_id;
777}
778
Ville Syrjälä5b113d32015-12-17 01:39:31 +0200779/**
780 * igt_create_pattern_fb:
781 * @fd: open i915 drm file descriptor
782 * @width: width of the framebuffer in pixel
783 * @height: height of the framebuffer in pixel
784 * @format: drm fourcc pixel format code
785 * @tiling: tiling layout of the framebuffer
786 * @fb: pointer to an #igt_fb structure
787 *
788 * This function allocates a gem buffer object suitable to back a framebuffer
789 * with the requested properties and then wraps it up in a drm framebuffer
790 * object. All metadata is stored in @fb.
791 *
792 * Compared to igt_create_fb() this function also draws the standard test pattern
793 * into the framebuffer.
794 *
795 * Returns:
796 * The kms id of the created framebuffer on success or a negative error code on
797 * failure.
798 */
799unsigned int igt_create_pattern_fb(int fd, int width, int height,
800 uint32_t format, uint64_t tiling,
801 struct igt_fb *fb /* out */)
802{
803 unsigned int fb_id;
804 cairo_t *cr;
805
806 fb_id = igt_create_fb(fd, width, height, format, tiling, fb);
807 igt_assert(fb_id);
808
809 cr = igt_get_cairo_ctx(fd, fb);
810 igt_paint_test_pattern(cr, width, height);
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +0100811 igt_put_cairo_ctx(fd, fb, cr);
Ville Syrjälä5b113d32015-12-17 01:39:31 +0200812
813 return fb_id;
814}
815
816/**
817 * igt_create_color_pattern_fb:
818 * @fd: open i915 drm file descriptor
819 * @width: width of the framebuffer in pixel
820 * @height: height of the framebuffer in pixel
821 * @format: drm fourcc pixel format code
822 * @tiling: tiling layout of the framebuffer
823 * @r: red value to use as fill color
824 * @g: green value to use as fill color
825 * @b: blue value to use as fill color
826 * @fb: pointer to an #igt_fb structure
827 *
828 * This function allocates a gem buffer object suitable to back a framebuffer
829 * with the requested properties and then wraps it up in a drm framebuffer
830 * object. All metadata is stored in @fb.
831 *
832 * Compared to igt_create_fb() this function also fills the entire framebuffer
833 * with the given color, and then draws the standard test pattern into the
834 * framebuffer.
835 *
836 * Returns:
837 * The kms id of the created framebuffer on success or a negative error code on
838 * failure.
839 */
840unsigned int igt_create_color_pattern_fb(int fd, int width, int height,
841 uint32_t format, uint64_t tiling,
842 double r, double g, double b,
843 struct igt_fb *fb /* out */)
844{
845 unsigned int fb_id;
846 cairo_t *cr;
847
848 fb_id = igt_create_fb(fd, width, height, format, tiling, fb);
849 igt_assert(fb_id);
850
851 cr = igt_get_cairo_ctx(fd, fb);
852 igt_paint_color(cr, 0, 0, width, height, r, g, b);
853 igt_paint_test_pattern(cr, width, height);
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +0100854 igt_put_cairo_ctx(fd, fb, cr);
Ville Syrjälä5b113d32015-12-17 01:39:31 +0200855
856 return fb_id;
857}
858
859/**
860 * igt_create_image_fb:
861 * @drm_fd: open i915 drm file descriptor
862 * @width: width of the framebuffer in pixel or 0
863 * @height: height of the framebuffer in pixel or 0
864 * @format: drm fourcc pixel format code
865 * @tiling: tiling layout of the framebuffer
866 * @filename: filename of the png image to draw
867 * @fb: pointer to an #igt_fb structure
868 *
869 * Create a framebuffer with the specified image. If @width is zero the
870 * image width will be used. If @height is zero the image height will be used.
871 *
872 * Returns:
873 * The kms id of the created framebuffer on success or a negative error code on
874 * failure.
875 */
876unsigned int igt_create_image_fb(int fd, int width, int height,
877 uint32_t format, uint64_t tiling,
878 const char *filename,
879 struct igt_fb *fb /* out */)
880{
881 cairo_surface_t *image;
882 uint32_t fb_id;
883 cairo_t *cr;
884
Ville Syrjälä75f320c2017-09-21 15:39:23 +0300885 image = igt_cairo_image_surface_create_from_png(filename);
Ville Syrjälä5b113d32015-12-17 01:39:31 +0200886 igt_assert(cairo_surface_status(image) == CAIRO_STATUS_SUCCESS);
887 if (width == 0)
888 width = cairo_image_surface_get_width(image);
889 if (height == 0)
890 height = cairo_image_surface_get_height(image);
891 cairo_surface_destroy(image);
892
893 fb_id = igt_create_fb(fd, width, height, format, tiling, fb);
894
895 cr = igt_get_cairo_ctx(fd, fb);
896 igt_paint_image(cr, filename, 0, 0, width, height);
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +0100897 igt_put_cairo_ctx(fd, fb, cr);
Ville Syrjälä5b113d32015-12-17 01:39:31 +0200898
899 return fb_id;
900}
901
Thomas Wood4cb19462014-08-04 16:14:51 +0100902struct box {
903 int x, y, width, height;
904};
905
906struct stereo_fb_layout {
907 int fb_width, fb_height;
908 struct box left, right;
909};
910
911static void box_init(struct box *box, int x, int y, int bwidth, int bheight)
912{
913 box->x = x;
914 box->y = y;
915 box->width = bwidth;
916 box->height = bheight;
917}
918
919
920static void stereo_fb_layout_from_mode(struct stereo_fb_layout *layout,
921 drmModeModeInfo *mode)
922{
923 unsigned int format = mode->flags & DRM_MODE_FLAG_3D_MASK;
924 const int hdisplay = mode->hdisplay, vdisplay = mode->vdisplay;
925 int middle;
926
927 switch (format) {
928 case DRM_MODE_FLAG_3D_TOP_AND_BOTTOM:
929 layout->fb_width = hdisplay;
930 layout->fb_height = vdisplay;
931
932 middle = vdisplay / 2;
933 box_init(&layout->left, 0, 0, hdisplay, middle);
934 box_init(&layout->right,
935 0, middle, hdisplay, vdisplay - middle);
936 break;
937 case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF:
938 layout->fb_width = hdisplay;
939 layout->fb_height = vdisplay;
940
941 middle = hdisplay / 2;
942 box_init(&layout->left, 0, 0, middle, vdisplay);
943 box_init(&layout->right,
944 middle, 0, hdisplay - middle, vdisplay);
945 break;
946 case DRM_MODE_FLAG_3D_FRAME_PACKING:
947 {
948 int vactive_space = mode->vtotal - vdisplay;
949
950 layout->fb_width = hdisplay;
951 layout->fb_height = 2 * vdisplay + vactive_space;
952
953 box_init(&layout->left,
954 0, 0, hdisplay, vdisplay);
955 box_init(&layout->right,
956 0, vdisplay + vactive_space, hdisplay, vdisplay);
957 break;
958 }
959 default:
960 igt_assert(0);
961 }
962}
963
964/**
965 * igt_create_stereo_fb:
966 * @drm_fd: open i915 drm file descriptor
967 * @mode: A stereo 3D mode.
968 * @format: drm fourcc pixel format code
969 * @tiling: tiling layout of the framebuffer
970 *
971 * Create a framebuffer for use with the stereo 3D mode specified by @mode.
972 *
973 * Returns:
974 * The kms id of the created framebuffer on success or a negative error code on
975 * failure.
976 */
977unsigned int igt_create_stereo_fb(int drm_fd, drmModeModeInfo *mode,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000978 uint32_t format, uint64_t tiling)
Thomas Wood4cb19462014-08-04 16:14:51 +0100979{
980 struct stereo_fb_layout layout;
981 cairo_t *cr;
982 uint32_t fb_id;
983 struct igt_fb fb;
984
985 stereo_fb_layout_from_mode(&layout, mode);
986 fb_id = igt_create_fb(drm_fd, layout.fb_width, layout.fb_height, format,
987 tiling, &fb);
988 cr = igt_get_cairo_ctx(drm_fd, &fb);
989
Thomas Woodecb03262015-04-13 17:37:22 +0100990 igt_paint_image(cr, "1080p-left.png",
Thomas Wood4cb19462014-08-04 16:14:51 +0100991 layout.left.x, layout.left.y,
992 layout.left.width, layout.left.height);
Thomas Woodecb03262015-04-13 17:37:22 +0100993 igt_paint_image(cr, "1080p-right.png",
Thomas Wood4cb19462014-08-04 16:14:51 +0100994 layout.right.x, layout.right.y,
995 layout.right.width, layout.right.height);
996
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +0100997 igt_put_cairo_ctx(drm_fd, &fb, cr);
Thomas Wood4cb19462014-08-04 16:14:51 +0100998
999 return fb_id;
1000}
1001
Daniel Vetter57d7db82014-03-26 09:06:11 +01001002static cairo_format_t drm_format_to_cairo(uint32_t drm_format)
1003{
1004 struct format_desc_struct *f;
1005
1006 for_each_format(f)
1007 if (f->drm_id == drm_format)
1008 return f->cairo_id;
1009
Damien Lespiau54397ca2014-08-19 11:40:07 +01001010 igt_assert_f(0, "can't find a cairo format for %08x (%s)\n",
1011 drm_format, igt_format_str(drm_format));
Daniel Vetter57d7db82014-03-26 09:06:11 +01001012}
1013
Damien Lespiauff451a62015-03-03 14:11:04 +00001014struct fb_blit_upload {
1015 int fd;
1016 struct igt_fb *fb;
1017 struct {
1018 uint32_t handle;
1019 unsigned size, stride;
1020 uint8_t *map;
Tomeu Vizoso8a1a3862016-02-24 09:04:04 +01001021 bool is_dumb;
Damien Lespiauff451a62015-03-03 14:11:04 +00001022 } linear;
1023};
1024
1025static void destroy_cairo_surface__blit(void *arg)
1026{
1027 struct fb_blit_upload *blit = arg;
1028 struct igt_fb *fb = blit->fb;
Tomeu Vizosoae649632016-11-10 10:25:24 +01001029 unsigned int obj_tiling = igt_fb_mod_to_tiling(fb->tiling);
Damien Lespiauff451a62015-03-03 14:11:04 +00001030
Maarten Lankhorstd930b642017-02-09 10:42:01 +01001031 gem_munmap(blit->linear.map, blit->linear.size);
Damien Lespiauff451a62015-03-03 14:11:04 +00001032 fb->cairo_surface = NULL;
1033
1034 gem_set_domain(blit->fd, blit->linear.handle,
1035 I915_GEM_DOMAIN_GTT, 0);
1036
Damien Lespiauff451a62015-03-03 14:11:04 +00001037 igt_blitter_fast_copy__raw(blit->fd,
1038 blit->linear.handle,
1039 blit->linear.stride,
1040 I915_TILING_NONE,
1041 0, 0, /* src_x, src_y */
1042 fb->width, fb->height,
Imre Deak4d40a672017-12-08 16:43:05 +02001043 igt_drm_format_to_bpp(fb->drm_format),
Damien Lespiauff451a62015-03-03 14:11:04 +00001044 fb->gem_handle,
1045 fb->stride,
1046 obj_tiling,
1047 0, 0 /* dst_x, dst_y */);
1048
1049 gem_sync(blit->fd, blit->linear.handle);
1050 gem_close(blit->fd, blit->linear.handle);
1051
1052 free(blit);
1053}
1054
1055static void create_cairo_surface__blit(int fd, struct igt_fb *fb)
1056{
1057 struct fb_blit_upload *blit;
1058 cairo_format_t cairo_format;
Tomeu Vizosoae649632016-11-10 10:25:24 +01001059 unsigned int obj_tiling = igt_fb_mod_to_tiling(fb->tiling);
Damien Lespiauff451a62015-03-03 14:11:04 +00001060
1061 blit = malloc(sizeof(*blit));
1062 igt_assert(blit);
1063
1064 /*
1065 * We create a linear BO that we'll map for the CPU to write to (using
1066 * cairo). This linear bo will be then blitted to its final
1067 * destination, tiling it at the same time.
1068 */
Tomeu Vizoso7be235c2016-04-22 11:08:45 +02001069 blit->linear.handle = create_bo_for_fb(fd, fb->width, fb->height,
1070 fb->drm_format,
1071 LOCAL_DRM_FORMAT_MOD_NONE, 0,
1072 0, &blit->linear.size,
1073 &blit->linear.stride,
1074 &blit->linear.is_dumb);
Damien Lespiauff451a62015-03-03 14:11:04 +00001075
Tomeu Vizoso7be235c2016-04-22 11:08:45 +02001076 igt_assert(blit->linear.handle > 0);
Damien Lespiauff451a62015-03-03 14:11:04 +00001077
1078 blit->fd = fd;
1079 blit->fb = fb;
Tvrtko Ursulin30a13602015-04-29 13:24:34 +01001080
1081 /* Copy fb content to linear BO */
1082 gem_set_domain(fd, blit->linear.handle,
1083 I915_GEM_DOMAIN_GTT, 0);
1084
1085 igt_blitter_fast_copy__raw(fd,
1086 fb->gem_handle,
1087 fb->stride,
1088 obj_tiling,
1089 0, 0, /* src_x, src_y */
1090 fb->width, fb->height,
Imre Deak4d40a672017-12-08 16:43:05 +02001091 igt_drm_format_to_bpp(fb->drm_format),
Tvrtko Ursulin30a13602015-04-29 13:24:34 +01001092 blit->linear.handle,
1093 blit->linear.stride,
1094 I915_TILING_NONE,
1095 0, 0 /* dst_x, dst_y */);
1096
1097 gem_sync(fd, blit->linear.handle);
1098
1099 gem_set_domain(fd, blit->linear.handle,
1100 I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
1101
1102 /* Setup cairo context */
Ville Syrjäläf52e7ec2015-10-09 19:11:39 +03001103 blit->linear.map = gem_mmap__cpu(fd,
Damien Lespiauff451a62015-03-03 14:11:04 +00001104 blit->linear.handle,
1105 0,
1106 blit->linear.size,
1107 PROT_READ | PROT_WRITE);
Damien Lespiauff451a62015-03-03 14:11:04 +00001108
Damien Lespiauff451a62015-03-03 14:11:04 +00001109 cairo_format = drm_format_to_cairo(fb->drm_format);
1110 fb->cairo_surface =
1111 cairo_image_surface_create_for_data(blit->linear.map,
1112 cairo_format,
1113 fb->width, fb->height,
1114 blit->linear.stride);
Chris Wilson18d0b1e2016-03-02 14:12:12 +00001115 fb->domain = I915_GEM_DOMAIN_GTT;
Damien Lespiauff451a62015-03-03 14:11:04 +00001116
1117 cairo_surface_set_user_data(fb->cairo_surface,
1118 (cairo_user_data_key_t *)create_cairo_surface__blit,
1119 blit, destroy_cairo_surface__blit);
1120}
1121
Tomeu Vizosoa2d5b342016-03-07 16:25:43 +01001122/**
1123 * igt_dirty_fb:
1124 * @fd: open drm file descriptor
1125 * @fb: pointer to an #igt_fb structure
1126 *
1127 * Flushes out the whole framebuffer.
1128 *
1129 * Returns: 0 upon success.
1130 */
1131int igt_dirty_fb(int fd, struct igt_fb *fb)
1132{
1133 return drmModeDirtyFB(fb->fd, fb->fb_id, NULL, 0);
1134}
1135
Damien Lespiau4aadbc82014-06-23 16:41:43 +01001136static void destroy_cairo_surface__gtt(void *arg)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001137{
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01001138 struct igt_fb *fb = arg;
Damien Lespiau72357f32014-07-11 14:45:37 +01001139
Maarten Lankhorstd930b642017-02-09 10:42:01 +01001140 gem_munmap(cairo_image_surface_get_data(fb->cairo_surface), fb->size);
Damien Lespiau72357f32014-07-11 14:45:37 +01001141 fb->cairo_surface = NULL;
Tomeu Vizoso89b3ffe2016-02-24 09:04:41 +01001142
1143 if (fb->is_dumb)
1144 igt_dirty_fb(fb->fd, fb);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001145}
1146
Damien Lespiau4aadbc82014-06-23 16:41:43 +01001147static void create_cairo_surface__gtt(int fd, struct igt_fb *fb)
1148{
Tomeu Vizoso89b3ffe2016-02-24 09:04:41 +01001149 void *ptr;
1150
1151 if (fb->is_dumb)
1152 ptr = kmstest_dumb_map_buffer(fd, fb->gem_handle, fb->size,
1153 PROT_READ | PROT_WRITE);
1154 else
1155 ptr = gem_mmap__gtt(fd, fb->gem_handle, fb->size,
1156 PROT_READ | PROT_WRITE);
Ville Syrjälä106fe212015-10-09 18:36:24 +03001157
Damien Lespiau4aadbc82014-06-23 16:41:43 +01001158 fb->cairo_surface =
Ville Syrjälä106fe212015-10-09 18:36:24 +03001159 cairo_image_surface_create_for_data(ptr,
Damien Lespiau4aadbc82014-06-23 16:41:43 +01001160 drm_format_to_cairo(fb->drm_format),
1161 fb->width, fb->height, fb->stride);
Chris Wilson18d0b1e2016-03-02 14:12:12 +00001162 fb->domain = I915_GEM_DOMAIN_GTT;
Damien Lespiau4aadbc82014-06-23 16:41:43 +01001163
1164 cairo_surface_set_user_data(fb->cairo_surface,
1165 (cairo_user_data_key_t *)create_cairo_surface__gtt,
1166 fb, destroy_cairo_surface__gtt);
1167}
1168
Paul Kocialkowskib4ad3972017-07-19 16:46:04 +03001169/**
1170 * igt_get_cairo_surface:
1171 * @fd: open drm file descriptor
1172 * @fb: pointer to an #igt_fb structure
1173 *
1174 * This function stores the contents of the supplied framebuffer into a cairo
1175 * surface and returns it.
1176 *
1177 * Returns:
1178 * A pointer to a cairo surface with the contents of the framebuffer.
1179 */
1180cairo_surface_t *igt_get_cairo_surface(int fd, struct igt_fb *fb)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001181{
Damien Lespiauff451a62015-03-03 14:11:04 +00001182 if (fb->cairo_surface == NULL) {
1183 if (fb->tiling == LOCAL_I915_FORMAT_MOD_Y_TILED ||
1184 fb->tiling == LOCAL_I915_FORMAT_MOD_Yf_TILED)
1185 create_cairo_surface__blit(fd, fb);
1186 else
1187 create_cairo_surface__gtt(fd, fb);
1188 }
Daniel Vetter57d7db82014-03-26 09:06:11 +01001189
Tomeu Vizoso89b3ffe2016-02-24 09:04:41 +01001190 if (!fb->is_dumb)
1191 gem_set_domain(fd, fb->gem_handle, I915_GEM_DOMAIN_CPU,
1192 I915_GEM_DOMAIN_CPU);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001193
1194 igt_assert(cairo_surface_status(fb->cairo_surface) == CAIRO_STATUS_SUCCESS);
Damien Lespiau0db75bb2014-06-30 16:34:20 +01001195 return fb->cairo_surface;
Daniel Vetter57d7db82014-03-26 09:06:11 +01001196}
1197
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001198/**
1199 * igt_get_cairo_ctx:
1200 * @fd: open i915 drm file descriptor
1201 * @fb: pointer to an #igt_fb structure
1202 *
1203 * This initializes a cairo surface for @fb and then allocates a drawing context
1204 * for it. The return cairo drawing context should be released by calling
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +01001205 * igt_put_cairo_ctx(). This also sets a default font for drawing text on
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001206 * framebuffers.
1207 *
1208 * Returns:
1209 * The created cairo drawing context.
1210 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01001211cairo_t *igt_get_cairo_ctx(int fd, struct igt_fb *fb)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001212{
1213 cairo_surface_t *surface;
1214 cairo_t *cr;
1215
Paul Kocialkowskib4ad3972017-07-19 16:46:04 +03001216 surface = igt_get_cairo_surface(fd, fb);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001217 cr = cairo_create(surface);
1218 cairo_surface_destroy(surface);
Daniel Vetter7568edf2014-03-26 16:36:46 +01001219 igt_assert(cairo_status(cr) == CAIRO_STATUS_SUCCESS);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001220
Daniel Vetter7568edf2014-03-26 16:36:46 +01001221 cairo_select_font_face(cr, "Helvetica", CAIRO_FONT_SLANT_NORMAL,
1222 CAIRO_FONT_WEIGHT_NORMAL);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001223 igt_assert(cairo_status(cr) == CAIRO_STATUS_SUCCESS);
1224
1225 return cr;
1226}
1227
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001228/**
Maarten Lankhorstbe2f6fc2018-02-01 12:48:45 +01001229 * igt_put_cairo_ctx:
1230 * @fd: open i915 drm file descriptor
1231 * @fb: pointer to an #igt_fb structure
1232 * @cr: the cairo context returned by igt_get_cairo_ctx.
1233 *
1234 * This releases the cairo surface @cr returned by igt_get_cairo_ctx()
1235 * for @fb, and writes the changes out to the framebuffer if cairo doesn't
1236 * have native support for the format.
1237 */
1238void igt_put_cairo_ctx(int fd, struct igt_fb *fb, cairo_t *cr)
1239{
1240 cairo_status_t ret = cairo_status(cr);
1241 igt_assert_f(ret == CAIRO_STATUS_SUCCESS, "Cairo failed to draw with %s\n", cairo_status_to_string(ret));
1242
1243 cairo_destroy(cr);
1244}
1245
1246/**
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001247 * igt_remove_fb:
1248 * @fd: open i915 drm file descriptor
1249 * @fb: pointer to an #igt_fb structure
1250 *
1251 * This function releases all resources allocated in igt_create_fb() for @fb.
1252 * Note that if this framebuffer is still in use on a primary plane the kernel
1253 * will disable the corresponding crtc.
1254 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01001255void igt_remove_fb(int fd, struct igt_fb *fb)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001256{
1257 cairo_surface_destroy(fb->cairo_surface);
1258 do_or_die(drmModeRmFB(fd, fb->fb_id));
1259 gem_close(fd, fb->gem_handle);
1260}
1261
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001262/**
1263 * igt_bpp_depth_to_drm_format:
1264 * @bpp: desired bits per pixel
1265 * @depth: desired depth
1266 *
1267 * Returns:
1268 * The rgb drm fourcc pixel format code corresponding to the given @bpp and
1269 * @depth values. Fails hard if no match was found.
1270 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01001271uint32_t igt_bpp_depth_to_drm_format(int bpp, int depth)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001272{
1273 struct format_desc_struct *f;
1274
1275 for_each_format(f)
1276 if (f->bpp == bpp && f->depth == depth)
1277 return f->drm_id;
1278
Damien Lespiau54397ca2014-08-19 11:40:07 +01001279
1280 igt_assert_f(0, "can't find drm format with bpp=%d, depth=%d\n", bpp,
1281 depth);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001282}
1283
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001284/**
1285 * igt_drm_format_to_bpp:
1286 * @drm_format: drm fourcc pixel format code
1287 *
1288 * Returns:
1289 * The bits per pixel for the given drm fourcc pixel format code. Fails hard if
1290 * no match was found.
1291 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01001292uint32_t igt_drm_format_to_bpp(uint32_t drm_format)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001293{
1294 struct format_desc_struct *f;
1295
1296 for_each_format(f)
1297 if (f->drm_id == drm_format)
1298 return f->bpp;
1299
Damien Lespiau54397ca2014-08-19 11:40:07 +01001300 igt_assert_f(0, "can't find a bpp format for %08x (%s)\n",
1301 drm_format, igt_format_str(drm_format));
Daniel Vetter57d7db82014-03-26 09:06:11 +01001302}
1303
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001304/**
1305 * igt_format_str:
1306 * @drm_format: drm fourcc pixel format code
1307 *
1308 * Returns:
1309 * Human-readable fourcc pixel format code for @drm_format or "invalid" no match
1310 * was found.
1311 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01001312const char *igt_format_str(uint32_t drm_format)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001313{
1314 struct format_desc_struct *f;
1315
1316 for_each_format(f)
1317 if (f->drm_id == drm_format)
1318 return f->name;
1319
1320 return "invalid";
1321}
1322
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001323/**
Paulo Zanoni7ca55f42016-01-26 10:52:29 -02001324 * igt_get_all_cairo_formats:
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001325 * @formats: pointer to pointer to store the allocated formats array
1326 * @format_count: pointer to integer to store the size of the allocated array
1327 *
Paulo Zanoni7ca55f42016-01-26 10:52:29 -02001328 * This functions returns an array of all the drm fourcc codes supported by
1329 * cairo and this library.
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001330 */
Paulo Zanoni7ca55f42016-01-26 10:52:29 -02001331void igt_get_all_cairo_formats(const uint32_t **formats, int *format_count)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001332{
1333 static uint32_t *drm_formats;
Paulo Zanoni7ca55f42016-01-26 10:52:29 -02001334 static int n_formats;
Daniel Vetter57d7db82014-03-26 09:06:11 +01001335
1336 if (!drm_formats) {
1337 struct format_desc_struct *f;
1338 uint32_t *format;
1339
Paulo Zanoni7ca55f42016-01-26 10:52:29 -02001340 n_formats = 0;
1341 for_each_format(f)
1342 if (f->cairo_id != CAIRO_FORMAT_INVALID)
1343 n_formats++;
1344
1345 drm_formats = calloc(n_formats, sizeof(*drm_formats));
Daniel Vetter57d7db82014-03-26 09:06:11 +01001346 format = &drm_formats[0];
1347 for_each_format(f)
Paulo Zanoni7ca55f42016-01-26 10:52:29 -02001348 if (f->cairo_id != CAIRO_FORMAT_INVALID)
1349 *format++ = f->drm_id;
Daniel Vetter57d7db82014-03-26 09:06:11 +01001350 }
1351
1352 *formats = drm_formats;
Paulo Zanoni7ca55f42016-01-26 10:52:29 -02001353 *format_count = n_formats;
Daniel Vetter57d7db82014-03-26 09:06:11 +01001354}