blob: d4eaed71acefad58433226840d7a77fc6bdf49ba [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>
30
31#include "drmtest.h"
32#include "igt_fb.h"
Tomeu Vizoso8a1a3862016-02-24 09:04:04 +010033#include "igt_kms.h"
Daniel Vetter57d7db82014-03-26 09:06:11 +010034#include "ioctl_wrappers.h"
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -020035#include "intel_chipset.h"
Daniel Vetter57d7db82014-03-26 09:06:11 +010036
Daniel Vetterc6c2b2b2014-03-26 15:15:49 +010037/**
38 * SECTION:igt_fb
39 * @short_description: Framebuffer handling and drawing library
Damien Lespiau6ebd8c22015-06-26 14:28:41 +010040 * @title: Framebuffer
Thomas Woodf0381d12015-09-07 09:26:01 +010041 * @include: igt.h
Daniel Vetter3d9e63f2014-03-26 16:37:15 +010042 *
43 * This library contains helper functions for handling kms framebuffer objects
44 * using #igt_fb structures to track all the metadata. igt_create_fb() creates
Thomas Woodd01ebbd2015-06-29 16:47:14 +010045 * a basic framebuffer and igt_remove_fb() cleans everything up again.
Daniel Vetter3d9e63f2014-03-26 16:37:15 +010046 *
47 * It also supports drawing using the cairo library and provides some simplified
48 * helper functions to easily draw test patterns. The main function to create a
49 * cairo drawing context for a framebuffer object is igt_get_cairo_ctx().
50 *
51 * Finally it also pulls in the drm fourcc headers and provides some helper
52 * functions to work with these pixel format codes.
Daniel Vetterc6c2b2b2014-03-26 15:15:49 +010053 */
54
Daniel Vetter57d7db82014-03-26 09:06:11 +010055/* drm fourcc/cairo format maps */
56#define DF(did, cid, _bpp, _depth) \
57 { DRM_FORMAT_##did, CAIRO_FORMAT_##cid, # did, _bpp, _depth }
58static struct format_desc_struct {
59 uint32_t drm_id;
60 cairo_format_t cairo_id;
61 const char *name;
62 int bpp;
63 int depth;
64} format_desc[] = {
65 DF(RGB565, RGB16_565, 16, 16),
Chris Wilson9df77d52014-09-06 12:08:13 +010066 //DF(RGB888, INVALID, 24, 24),
Daniel Vetter57d7db82014-03-26 09:06:11 +010067 DF(XRGB8888, RGB24, 32, 24),
68 DF(XRGB2101010, RGB30, 32, 30),
69 DF(ARGB8888, ARGB32, 32, 32),
70};
71#undef DF
72
73#define for_each_format(f) \
74 for (f = format_desc; f - format_desc < ARRAY_SIZE(format_desc); f++)
75
Praveen Paneri4bb45412017-07-18 22:52:56 +053076/**
77 * igt_get_fb_tile_size:
78 * @fd: the DRM file descriptor
79 * @tiling: tiling layout of the framebuffer (as framebuffer modifier)
80 * @fb_bpp: bits per pixel of the framebuffer
81 * @width_ret: width of the tile in bytes
82 * @height_ret: height of the tile in lines
83 *
84 * This function returns width and height of a tile based on the given tiling
85 * format.
86 */
87void igt_get_fb_tile_size(int fd, uint64_t tiling, int fb_bpp,
88 unsigned *width_ret, unsigned *height_ret)
Daniel Vetter57d7db82014-03-26 09:06:11 +010089{
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -020090 switch (tiling) {
91 case LOCAL_DRM_FORMAT_MOD_NONE:
92 *width_ret = 64;
93 *height_ret = 1;
94 break;
95 case LOCAL_I915_FORMAT_MOD_X_TILED:
Tomeu Vizoso85a1d452016-02-24 08:39:53 +010096 igt_require_intel(fd);
97 if (intel_gen(intel_get_drm_devid(fd)) == 2) {
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -020098 *width_ret = 128;
99 *height_ret = 16;
100 } else {
101 *width_ret = 512;
102 *height_ret = 8;
103 }
104 break;
105 case LOCAL_I915_FORMAT_MOD_Y_TILED:
Tomeu Vizoso85a1d452016-02-24 08:39:53 +0100106 igt_require_intel(fd);
107 if (intel_gen(intel_get_drm_devid(fd)) == 2) {
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200108 *width_ret = 128;
Ville Syrjälä037bc692016-02-12 21:28:54 +0200109 *height_ret = 16;
Tomeu Vizoso85a1d452016-02-24 08:39:53 +0100110 } else if (IS_915(intel_get_drm_devid(fd))) {
Ville Syrjälä037bc692016-02-12 21:28:54 +0200111 *width_ret = 512;
112 *height_ret = 8;
113 } else {
114 *width_ret = 128;
115 *height_ret = 32;
116 }
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200117 break;
118 case LOCAL_I915_FORMAT_MOD_Yf_TILED:
Tomeu Vizoso85a1d452016-02-24 08:39:53 +0100119 igt_require_intel(fd);
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200120 switch (fb_bpp) {
121 case 8:
122 *width_ret = 64;
123 *height_ret = 64;
124 break;
125 case 16:
126 case 32:
127 *width_ret = 128;
128 *height_ret = 32;
129 break;
130 case 64:
131 case 128:
132 *width_ret = 256;
133 *height_ret = 16;
134 break;
135 default:
136 igt_assert(false);
137 }
138 break;
139 default:
140 igt_assert(false);
141 }
142}
143
144/**
145 * igt_calc_fb_size:
146 * @fd: the DRM file descriptor
147 * @width: width of the framebuffer in pixels
148 * @height: height of the framebuffer in pixels
149 * @bpp: bytes per pixel of the framebuffer
150 * @tiling: tiling layout of the framebuffer (as framebuffer modifier)
151 * @size_ret: returned size for the framebuffer
152 * @stride_ret: returned stride for the framebuffer
153 *
154 * This function returns valid stride and size values for a framebuffer with the
155 * specified parameters.
156 */
157void igt_calc_fb_size(int fd, int width, int height, int bpp, uint64_t tiling,
158 unsigned *size_ret, unsigned *stride_ret)
159{
160 unsigned int tile_width, tile_height, stride, size;
161 int byte_width = width * (bpp / 8);
162
163 igt_get_fb_tile_size(fd, tiling, bpp, &tile_width, &tile_height);
164
Tomeu Vizoso85a1d452016-02-24 08:39:53 +0100165 if (tiling != LOCAL_DRM_FORMAT_MOD_NONE &&
166 intel_gen(intel_get_drm_devid(fd)) <= 3) {
Daniel Vetter57d7db82014-03-26 09:06:11 +0100167 int v;
168
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200169 /* Round the tiling up to the next power-of-two and the region
170 * up to the next pot fence size so that this works on all
171 * generations.
Daniel Vetter57d7db82014-03-26 09:06:11 +0100172 *
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200173 * This can still fail if the framebuffer is too large to be
174 * tiled. But then that failure is expected.
Daniel Vetter57d7db82014-03-26 09:06:11 +0100175 */
176
177 v = width * bpp / 8;
178 for (stride = 512; stride < v; stride *= 2)
179 ;
180
181 v = stride * height;
182 for (size = 1024*1024; size < v; size *= 2)
183 ;
184 } else {
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200185 stride = ALIGN(byte_width, tile_width);
186 size = stride * ALIGN(height, tile_height);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100187 }
188
Paulo Zanonibe6f3fa2015-11-27 12:13:41 -0200189 *stride_ret = stride;
190 *size_ret = size;
191}
192
Tomeu Vizosoae649632016-11-10 10:25:24 +0100193/**
194 * igt_fb_mod_to_tiling:
195 * @modifier: DRM framebuffer modifier
196 *
197 * This function converts a DRM framebuffer modifier to its corresponding
198 * tiling constant.
199 *
200 * Returns:
201 * A tiling constant
202 */
203uint64_t igt_fb_mod_to_tiling(uint64_t modifier)
204{
205 switch (modifier) {
206 case LOCAL_DRM_FORMAT_MOD_NONE:
207 return I915_TILING_NONE;
208 case LOCAL_I915_FORMAT_MOD_X_TILED:
209 return I915_TILING_X;
210 case LOCAL_I915_FORMAT_MOD_Y_TILED:
211 return I915_TILING_Y;
212 case LOCAL_I915_FORMAT_MOD_Yf_TILED:
213 return I915_TILING_Yf;
214 default:
215 igt_assert(0);
216 }
217}
218
Praveen Paneri4437e212017-07-18 22:52:57 +0530219/**
220 * igt_fb_tiling_to_mod:
221 * @tiling: DRM framebuffer tiling
222 *
223 * This function converts a DRM framebuffer tiling to its corresponding
224 * modifier constant.
225 *
226 * Returns:
227 * A modifier constant
228 */
229uint64_t igt_fb_tiling_to_mod(uint64_t tiling)
230{
231 switch (tiling) {
232 case I915_TILING_NONE:
233 return LOCAL_DRM_FORMAT_MOD_NONE;
234 case I915_TILING_X:
235 return LOCAL_I915_FORMAT_MOD_X_TILED;
236 case I915_TILING_Y:
237 return LOCAL_I915_FORMAT_MOD_Y_TILED;
238 case I915_TILING_Yf:
239 return LOCAL_I915_FORMAT_MOD_Yf_TILED;
240 default:
241 igt_assert(0);
242 }
243}
244
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200245/* helpers to create nice-looking framebuffers */
246static int create_bo_for_fb(int fd, int width, int height, uint32_t format,
247 uint64_t tiling, unsigned size, unsigned stride,
248 unsigned *size_ret, unsigned *stride_ret,
249 bool *is_dumb)
250{
251 int bpp = igt_drm_format_to_bpp(format);
252 int bo;
253
254 if (tiling || size || stride) {
255 unsigned calculated_size, calculated_stride;
256
257 igt_calc_fb_size(fd, width, height, bpp, tiling,
258 &calculated_size, &calculated_stride);
259 if (stride == 0)
260 stride = calculated_stride;
261 if (size == 0)
262 size = calculated_size;
263
264 if (is_dumb)
265 *is_dumb = false;
266
267 if (is_i915_device(fd)) {
Chris Wilsond2805062016-08-18 13:56:18 +0100268 uint32_t *ptr;
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200269
270 bo = gem_create(fd, size);
Tomeu Vizosoae649632016-11-10 10:25:24 +0100271 gem_set_tiling(fd, bo, igt_fb_mod_to_tiling(tiling), stride);
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200272
Chris Wilsond2805062016-08-18 13:56:18 +0100273 /* Ensure the framebuffer is preallocated */
274 ptr = gem_mmap__gtt(fd, bo, size, PROT_READ);
275 igt_assert(*ptr == 0);
Maarten Lankhorstd930b642017-02-09 10:42:01 +0100276 gem_munmap(ptr, size);
Chris Wilsond2805062016-08-18 13:56:18 +0100277
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200278 if (size_ret)
279 *size_ret = size;
280
281 if (stride_ret)
282 *stride_ret = stride;
283
284 return bo;
285 } else {
286 bool driver_has_gem_api = false;
287
288 igt_require(driver_has_gem_api);
289 return -EINVAL;
290 }
291 } else {
292 if (is_dumb)
293 *is_dumb = true;
294
295 return kmstest_dumb_create(fd, width, height, bpp, stride_ret,
296 size_ret);
297 }
298}
299
Tomeu Vizoso8a1a3862016-02-24 09:04:04 +0100300/**
301 * igt_create_bo_with_dimensions:
302 * @fd: open drm file descriptor
303 * @width: width of the buffer object in pixels
304 * @height: height of the buffer object in pixels
305 * @format: drm fourcc pixel format code
306 * @modifier: modifier corresponding to the tiling layout of the buffer object
307 * @stride: stride of the buffer object in bytes (0 for automatic stride)
308 * @size_ret: size of the buffer object as created by the kernel
309 * @stride_ret: stride of the buffer object as created by the kernel
310 * @is_dumb: whether the created buffer object is a dumb buffer or not
311 *
312 * This function allocates a gem buffer object matching the requested
313 * properties.
314 *
315 * Returns:
316 * The kms id of the created buffer object.
317 */
318int igt_create_bo_with_dimensions(int fd, int width, int height,
319 uint32_t format, uint64_t modifier,
320 unsigned stride, unsigned *size_ret,
321 unsigned *stride_ret, bool *is_dumb)
322{
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200323 return create_bo_for_fb(fd, width, height, format, modifier, 0, stride,
324 size_ret, stride_ret, is_dumb);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100325}
326
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100327/**
328 * igt_paint_color:
329 * @cr: cairo drawing context
330 * @x: pixel x-coordination of the fill rectangle
331 * @y: pixel y-coordination of the fill rectangle
332 * @w: width of the fill rectangle
333 * @h: height of the fill rectangle
334 * @r: red value to use as fill color
Thomas Woodd01ebbd2015-06-29 16:47:14 +0100335 * @g: green value to use as fill color
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100336 * @b: blue value to use as fill color
337 *
338 * This functions draws a solid rectangle with the given color using the drawing
339 * context @cr.
340 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100341void igt_paint_color(cairo_t *cr, int x, int y, int w, int h,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100342 double r, double g, double b)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100343{
344 cairo_rectangle(cr, x, y, w, h);
345 cairo_set_source_rgb(cr, r, g, b);
346 cairo_fill(cr);
347}
348
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100349/**
350 * igt_paint_color_alpha:
351 * @cr: cairo drawing context
352 * @x: pixel x-coordination of the fill rectangle
353 * @y: pixel y-coordination of the fill rectangle
354 * @w: width of the fill rectangle
355 * @h: height of the fill rectangle
356 * @r: red value to use as fill color
Thomas Woodd01ebbd2015-06-29 16:47:14 +0100357 * @g: green value to use as fill color
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100358 * @b: blue value to use as fill color
359 * @a: alpha value to use as fill color
360 *
361 * This functions draws a rectangle with the given color and alpha values using
362 * the drawing context @cr.
363 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100364void igt_paint_color_alpha(cairo_t *cr, int x, int y, int w, int h,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100365 double r, double g, double b, double a)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100366{
367 cairo_rectangle(cr, x, y, w, h);
368 cairo_set_source_rgba(cr, r, g, b, a);
369 cairo_fill(cr);
370}
371
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100372/**
373 * igt_paint_color_gradient:
374 * @cr: cairo drawing context
375 * @x: pixel x-coordination of the fill rectangle
376 * @y: pixel y-coordination of the fill rectangle
377 * @w: width of the fill rectangle
378 * @h: height of the fill rectangle
379 * @r: red value to use as fill color
Thomas Woodd01ebbd2015-06-29 16:47:14 +0100380 * @g: green value to use as fill color
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100381 * @b: blue value to use as fill color
382 *
383 * This functions draws a gradient into the rectangle which fades in from black
384 * to the given values using the drawing context @cr.
385 */
Daniel Vetter57d7db82014-03-26 09:06:11 +0100386void
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100387igt_paint_color_gradient(cairo_t *cr, int x, int y, int w, int h,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100388 int r, int g, int b)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100389{
390 cairo_pattern_t *pat;
391
392 pat = cairo_pattern_create_linear(x, y, x + w, y + h);
393 cairo_pattern_add_color_stop_rgba(pat, 1, 0, 0, 0, 1);
394 cairo_pattern_add_color_stop_rgba(pat, 0, r, g, b, 1);
395
396 cairo_rectangle(cr, x, y, w, h);
397 cairo_set_source(cr, pat);
398 cairo_fill(cr);
399 cairo_pattern_destroy(pat);
400}
401
Lionel Landwerlina5113102016-03-18 17:33:02 +0000402/**
403 * igt_paint_color_gradient_range:
404 * @cr: cairo drawing context
405 * @x: pixel x-coordination of the fill rectangle
406 * @y: pixel y-coordination of the fill rectangle
407 * @w: width of the fill rectangle
408 * @h: height of the fill rectangle
409 * @sr: red value to use as start gradient color
410 * @sg: green value to use as start gradient color
411 * @sb: blue value to use as start gradient color
412 * @er: red value to use as end gradient color
413 * @eg: green value to use as end gradient color
414 * @eb: blue value to use as end gradient color
415 *
416 * This functions draws a gradient into the rectangle which fades in
417 * from one color to the other using the drawing context @cr.
418 */
419void
420igt_paint_color_gradient_range(cairo_t *cr, int x, int y, int w, int h,
421 double sr, double sg, double sb,
422 double er, double eg, double eb)
423{
424 cairo_pattern_t *pat;
425
426 pat = cairo_pattern_create_linear(x, y, x + w, y + h);
427 cairo_pattern_add_color_stop_rgba(pat, 1, sr, sg, sb, 1);
428 cairo_pattern_add_color_stop_rgba(pat, 0, er, eg, eb, 1);
429
430 cairo_rectangle(cr, x, y, w, h);
431 cairo_set_source(cr, pat);
432 cairo_fill(cr);
433 cairo_pattern_destroy(pat);
434}
435
Daniel Vetter57d7db82014-03-26 09:06:11 +0100436static void
437paint_test_patterns(cairo_t *cr, int width, int height)
438{
439 double gr_height, gr_width;
440 int x, y;
441
442 y = height * 0.10;
443 gr_width = width * 0.75;
444 gr_height = height * 0.08;
445 x = (width / 2) - (gr_width / 2);
446
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100447 igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 1, 0, 0);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100448
449 y += gr_height;
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100450 igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 0, 1, 0);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100451
452 y += gr_height;
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100453 igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 0, 0, 1);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100454
455 y += gr_height;
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100456 igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 1, 1, 1);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100457}
458
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100459/**
460 * igt_cairo_printf_line:
461 * @cr: cairo drawing context
462 * @align: text alignment
463 * @yspacing: additional y-direction feed after this line
464 * @fmt: format string
465 * @...: optional arguments used in the format string
466 *
467 * This is a little helper to draw text onto framebuffers. All the initial setup
468 * (like setting the font size and the moving to the starting position) still
469 * needs to be done manually with explicit cairo calls on @cr.
470 *
471 * Returns:
472 * The width of the drawn text.
473 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100474int igt_cairo_printf_line(cairo_t *cr, enum igt_text_align align,
Daniel Vetter57d7db82014-03-26 09:06:11 +0100475 double yspacing, const char *fmt, ...)
476{
477 double x, y, xofs, yofs;
478 cairo_text_extents_t extents;
479 char *text;
480 va_list ap;
481 int ret;
482
483 va_start(ap, fmt);
484 ret = vasprintf(&text, fmt, ap);
485 igt_assert(ret >= 0);
486 va_end(ap);
487
488 cairo_text_extents(cr, text, &extents);
489
490 xofs = yofs = 0;
491 if (align & align_right)
492 xofs = -extents.width;
493 else if (align & align_hcenter)
494 xofs = -extents.width / 2;
495
496 if (align & align_top)
497 yofs = extents.height;
498 else if (align & align_vcenter)
499 yofs = extents.height / 2;
500
501 cairo_get_current_point(cr, &x, &y);
502 if (xofs || yofs)
503 cairo_rel_move_to(cr, xofs, yofs);
504
505 cairo_text_path(cr, text);
506 cairo_set_source_rgb(cr, 0, 0, 0);
507 cairo_stroke_preserve(cr);
508 cairo_set_source_rgb(cr, 1, 1, 1);
509 cairo_fill(cr);
510
511 cairo_move_to(cr, x, y + extents.height + yspacing);
512
513 free(text);
514
515 return extents.width;
516}
517
518static void
519paint_marker(cairo_t *cr, int x, int y)
520{
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100521 enum igt_text_align align;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100522 int xoff, yoff;
523
524 cairo_move_to(cr, x, y - 20);
525 cairo_line_to(cr, x, y + 20);
526 cairo_move_to(cr, x - 20, y);
527 cairo_line_to(cr, x + 20, y);
528 cairo_new_sub_path(cr);
529 cairo_arc(cr, x, y, 10, 0, M_PI * 2);
530 cairo_set_line_width(cr, 4);
531 cairo_set_source_rgb(cr, 0, 0, 0);
532 cairo_stroke_preserve(cr);
533 cairo_set_source_rgb(cr, 1, 1, 1);
534 cairo_set_line_width(cr, 2);
535 cairo_stroke(cr);
536
537 xoff = x ? -20 : 20;
538 align = x ? align_right : align_left;
539
540 yoff = y ? -20 : 20;
541 align |= y ? align_bottom : align_top;
542
543 cairo_move_to(cr, x + xoff, y + yoff);
544 cairo_set_font_size(cr, 18);
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100545 igt_cairo_printf_line(cr, align, 0, "(%d, %d)", x, y);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100546}
547
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100548/**
549 * igt_paint_test_pattern:
550 * @cr: cairo drawing context
551 * @width: width of the visible area
552 * @height: height of the visible area
553 *
554 * This functions draws an entire set of test patterns for the given visible
555 * area using the drawing context @cr. This is useful for manual visual
556 * inspection of displayed framebuffers.
557 *
558 * The test patterns include
559 * - corner markers to check for over/underscan and
560 * - a set of color and b/w gradients.
561 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100562void igt_paint_test_pattern(cairo_t *cr, int width, int height)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100563{
564 paint_test_patterns(cr, width, height);
565
566 cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
567
568 /* Paint corner markers */
569 paint_marker(cr, 0, 0);
570 paint_marker(cr, width, 0);
571 paint_marker(cr, 0, height);
572 paint_marker(cr, width, height);
573
574 igt_assert(!cairo_status(cr));
575}
576
Thomas Woodecb03262015-04-13 17:37:22 +0100577static cairo_status_t
578stdio_read_func(void *closure, unsigned char* data, unsigned int size)
579{
580 if (fread(data, 1, size, (FILE*)closure) != size)
581 return CAIRO_STATUS_READ_ERROR;
582
583 return CAIRO_STATUS_SUCCESS;
584}
585
Ville Syrjälä75f320c2017-09-21 15:39:23 +0300586cairo_surface_t *igt_cairo_image_surface_create_from_png(const char *filename)
587{
588 cairo_surface_t *image;
589 FILE *f;
590
591 f = igt_fopen_data(filename);
592 image = cairo_image_surface_create_from_png_stream(&stdio_read_func, f);
593 fclose(f);
594
595 return image;
596}
597
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100598/**
599 * igt_paint_image:
600 * @cr: cairo drawing context
601 * @filename: filename of the png image to draw
602 * @dst_x: pixel x-coordination of the destination rectangle
603 * @dst_y: pixel y-coordination of the destination rectangle
604 * @dst_width: width of the destination rectangle
605 * @dst_height: height of the destination rectangle
606 *
Thomas Woodecb03262015-04-13 17:37:22 +0100607 * This function can be used to draw a scaled version of the supplied png image,
608 * which is loaded from the package data directory.
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100609 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100610void igt_paint_image(cairo_t *cr, const char *filename,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100611 int dst_x, int dst_y, int dst_width, int dst_height)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100612{
613 cairo_surface_t *image;
614 int img_width, img_height;
615 double scale_x, scale_y;
616
Ville Syrjälä75f320c2017-09-21 15:39:23 +0300617 image = igt_cairo_image_surface_create_from_png(filename);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100618 igt_assert(cairo_surface_status(image) == CAIRO_STATUS_SUCCESS);
619
620 img_width = cairo_image_surface_get_width(image);
621 img_height = cairo_image_surface_get_height(image);
622
623 scale_x = (double)dst_width / img_width;
624 scale_y = (double)dst_height / img_height;
625
626 cairo_save(cr);
627
628 cairo_translate(cr, dst_x, dst_y);
629 cairo_scale(cr, scale_x, scale_y);
630 cairo_set_source_surface(cr, image, 0, 0);
631 cairo_paint(cr);
632
633 cairo_surface_destroy(image);
634
635 cairo_restore(cr);
636}
637
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100638/**
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100639 * igt_create_fb_with_bo_size:
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100640 * @fd: open i915 drm file descriptor
641 * @width: width of the framebuffer in pixel
642 * @height: height of the framebuffer in pixel
643 * @format: drm fourcc pixel format code
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000644 * @tiling: tiling layout of the framebuffer (as framebuffer modifier)
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100645 * @fb: pointer to an #igt_fb structure
Paulo Zanonicb7dd5d2015-11-05 16:18:55 -0200646 * @bo_size: size of the backing bo (0 for automatic size)
Paulo Zanonid6341372015-11-05 16:39:00 -0200647 * @bo_stride: stride of the backing bo (0 for automatic stride)
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100648 *
649 * This function allocates a gem buffer object suitable to back a framebuffer
650 * with the requested properties and then wraps it up in a drm framebuffer
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100651 * object of the requested size. All metadata is stored in @fb.
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100652 *
653 * The backing storage of the framebuffer is filled with all zeros, i.e. black
654 * for rgb pixel formats.
655 *
656 * Returns:
Damien Lespiau50166d22014-08-19 11:55:22 +0100657 * The kms id of the created framebuffer.
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100658 */
Damien Lespiau378e61e2014-06-23 14:53:24 +0100659unsigned int
660igt_create_fb_with_bo_size(int fd, int width, int height,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000661 uint32_t format, uint64_t tiling,
Paulo Zanonid6341372015-11-05 16:39:00 -0200662 struct igt_fb *fb, unsigned bo_size,
663 unsigned bo_stride)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100664{
Daniel Vetter57d7db82014-03-26 09:06:11 +0100665 uint32_t fb_id;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100666
667 memset(fb, 0, sizeof(*fb));
668
Tomeu Vizoso8a1a3862016-02-24 09:04:04 +0100669 igt_debug("%s(width=%d, height=%d, format=0x%x, tiling=0x%"PRIx64", size=%d)\n",
670 __func__, width, height, format, tiling, bo_size);
Tomeu Vizoso7be235c2016-04-22 11:08:45 +0200671 fb->gem_handle = create_bo_for_fb(fd, width, height, format, tiling,
672 bo_size, bo_stride, &fb->size,
673 &fb->stride, &fb->is_dumb);
674 igt_assert(fb->gem_handle > 0);
Chris Wilsondb4cc742014-09-06 12:07:49 +0100675
Chris Wilsondb4cc742014-09-06 12:07:49 +0100676 igt_debug("%s(handle=%d, pitch=%d)\n",
Tvrtko Ursulineb93c1b2015-03-03 14:11:03 +0000677 __func__, fb->gem_handle, fb->stride);
678
679 if (tiling != LOCAL_DRM_FORMAT_MOD_NONE &&
680 tiling != LOCAL_I915_FORMAT_MOD_X_TILED) {
681 do_or_die(__kms_addfb(fd, fb->gem_handle, width, height,
682 fb->stride, format, tiling,
683 LOCAL_DRM_MODE_FB_MODIFIERS, &fb_id));
684 } else {
685 uint32_t handles[4];
686 uint32_t pitches[4];
687 uint32_t offsets[4];
688
689 memset(handles, 0, sizeof(handles));
690 memset(pitches, 0, sizeof(pitches));
691 memset(offsets, 0, sizeof(offsets));
692
693 handles[0] = fb->gem_handle;
694 pitches[0] = fb->stride;
695
696 do_or_die(drmModeAddFB2(fd, width, height, format,
697 handles, pitches, offsets,
698 &fb_id, 0));
699 }
Daniel Vetter57d7db82014-03-26 09:06:11 +0100700
701 fb->width = width;
702 fb->height = height;
Damien Lespiau378e61e2014-06-23 14:53:24 +0100703 fb->tiling = tiling;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100704 fb->drm_format = format;
705 fb->fb_id = fb_id;
Tomeu Vizoso89b3ffe2016-02-24 09:04:41 +0100706 fb->fd = fd;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100707
708 return fb_id;
709}
710
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100711/**
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100712 * igt_create_fb:
713 * @fd: open i915 drm file descriptor
714 * @width: width of the framebuffer in pixel
715 * @height: height of the framebuffer in pixel
716 * @format: drm fourcc pixel format code
Damien Lespiau378e61e2014-06-23 14:53:24 +0100717 * @tiling: tiling layout of the framebuffer
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100718 * @fb: pointer to an #igt_fb structure
719 *
720 * This function allocates a gem buffer object suitable to back a framebuffer
721 * with the requested properties and then wraps it up in a drm framebuffer
722 * object. All metadata is stored in @fb.
723 *
724 * The backing storage of the framebuffer is filled with all zeros, i.e. black
725 * for rgb pixel formats.
726 *
727 * Returns:
Damien Lespiau50166d22014-08-19 11:55:22 +0100728 * The kms id of the created framebuffer.
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100729 */
730unsigned int igt_create_fb(int fd, int width, int height, uint32_t format,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000731 uint64_t tiling, struct igt_fb *fb)
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100732{
Paulo Zanonid6341372015-11-05 16:39:00 -0200733 return igt_create_fb_with_bo_size(fd, width, height, format, tiling, fb,
734 0, 0);
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100735}
736
737/**
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100738 * igt_create_color_fb:
739 * @fd: open i915 drm file descriptor
740 * @width: width of the framebuffer in pixel
741 * @height: height of the framebuffer in pixel
742 * @format: drm fourcc pixel format code
Damien Lespiau378e61e2014-06-23 14:53:24 +0100743 * @tiling: tiling layout of the framebuffer
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100744 * @r: red value to use as fill color
Ville Syrjälä5b113d32015-12-17 01:39:31 +0200745 * @g: green value to use as fill color
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100746 * @b: blue value to use as fill color
747 * @fb: pointer to an #igt_fb structure
748 *
749 * This function allocates a gem buffer object suitable to back a framebuffer
750 * with the requested properties and then wraps it up in a drm framebuffer
751 * object. All metadata is stored in @fb.
752 *
753 * Compared to igt_create_fb() this function also fills the entire framebuffer
754 * with the given color, which is useful for some simple pipe crc based tests.
755 *
756 * Returns:
757 * The kms id of the created framebuffer on success or a negative error code on
758 * failure.
759 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100760unsigned int igt_create_color_fb(int fd, int width, int height,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000761 uint32_t format, uint64_t tiling,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100762 double r, double g, double b,
763 struct igt_fb *fb /* out */)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100764{
765 unsigned int fb_id;
766 cairo_t *cr;
767
Damien Lespiau378e61e2014-06-23 14:53:24 +0100768 fb_id = igt_create_fb(fd, width, height, format, tiling, fb);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100769 igt_assert(fb_id);
770
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100771 cr = igt_get_cairo_ctx(fd, fb);
772 igt_paint_color(cr, 0, 0, width, height, r, g, b);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100773 igt_assert(cairo_status(cr) == 0);
774 cairo_destroy(cr);
775
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);
811 igt_assert(cairo_status(cr) == 0);
812 cairo_destroy(cr);
813
814 return fb_id;
815}
816
817/**
818 * igt_create_color_pattern_fb:
819 * @fd: open i915 drm file descriptor
820 * @width: width of the framebuffer in pixel
821 * @height: height of the framebuffer in pixel
822 * @format: drm fourcc pixel format code
823 * @tiling: tiling layout of the framebuffer
824 * @r: red value to use as fill color
825 * @g: green value to use as fill color
826 * @b: blue value to use as fill color
827 * @fb: pointer to an #igt_fb structure
828 *
829 * This function allocates a gem buffer object suitable to back a framebuffer
830 * with the requested properties and then wraps it up in a drm framebuffer
831 * object. All metadata is stored in @fb.
832 *
833 * Compared to igt_create_fb() this function also fills the entire framebuffer
834 * with the given color, and then draws the standard test pattern into the
835 * framebuffer.
836 *
837 * Returns:
838 * The kms id of the created framebuffer on success or a negative error code on
839 * failure.
840 */
841unsigned int igt_create_color_pattern_fb(int fd, int width, int height,
842 uint32_t format, uint64_t tiling,
843 double r, double g, double b,
844 struct igt_fb *fb /* out */)
845{
846 unsigned int fb_id;
847 cairo_t *cr;
848
849 fb_id = igt_create_fb(fd, width, height, format, tiling, fb);
850 igt_assert(fb_id);
851
852 cr = igt_get_cairo_ctx(fd, fb);
853 igt_paint_color(cr, 0, 0, width, height, r, g, b);
854 igt_paint_test_pattern(cr, width, height);
855 igt_assert(cairo_status(cr) == 0);
856 cairo_destroy(cr);
857
858 return fb_id;
859}
860
861/**
862 * igt_create_image_fb:
863 * @drm_fd: open i915 drm file descriptor
864 * @width: width of the framebuffer in pixel or 0
865 * @height: height of the framebuffer in pixel or 0
866 * @format: drm fourcc pixel format code
867 * @tiling: tiling layout of the framebuffer
868 * @filename: filename of the png image to draw
869 * @fb: pointer to an #igt_fb structure
870 *
871 * Create a framebuffer with the specified image. If @width is zero the
872 * image width will be used. If @height is zero the image height will be used.
873 *
874 * Returns:
875 * The kms id of the created framebuffer on success or a negative error code on
876 * failure.
877 */
878unsigned int igt_create_image_fb(int fd, int width, int height,
879 uint32_t format, uint64_t tiling,
880 const char *filename,
881 struct igt_fb *fb /* out */)
882{
883 cairo_surface_t *image;
884 uint32_t fb_id;
885 cairo_t *cr;
886
Ville Syrjälä75f320c2017-09-21 15:39:23 +0300887 image = igt_cairo_image_surface_create_from_png(filename);
Ville Syrjälä5b113d32015-12-17 01:39:31 +0200888 igt_assert(cairo_surface_status(image) == CAIRO_STATUS_SUCCESS);
889 if (width == 0)
890 width = cairo_image_surface_get_width(image);
891 if (height == 0)
892 height = cairo_image_surface_get_height(image);
893 cairo_surface_destroy(image);
894
895 fb_id = igt_create_fb(fd, width, height, format, tiling, fb);
896
897 cr = igt_get_cairo_ctx(fd, fb);
898 igt_paint_image(cr, filename, 0, 0, width, height);
899 igt_assert(cairo_status(cr) == 0);
900 cairo_destroy(cr);
901
902 return fb_id;
903}
904
Thomas Wood4cb19462014-08-04 16:14:51 +0100905struct box {
906 int x, y, width, height;
907};
908
909struct stereo_fb_layout {
910 int fb_width, fb_height;
911 struct box left, right;
912};
913
914static void box_init(struct box *box, int x, int y, int bwidth, int bheight)
915{
916 box->x = x;
917 box->y = y;
918 box->width = bwidth;
919 box->height = bheight;
920}
921
922
923static void stereo_fb_layout_from_mode(struct stereo_fb_layout *layout,
924 drmModeModeInfo *mode)
925{
926 unsigned int format = mode->flags & DRM_MODE_FLAG_3D_MASK;
927 const int hdisplay = mode->hdisplay, vdisplay = mode->vdisplay;
928 int middle;
929
930 switch (format) {
931 case DRM_MODE_FLAG_3D_TOP_AND_BOTTOM:
932 layout->fb_width = hdisplay;
933 layout->fb_height = vdisplay;
934
935 middle = vdisplay / 2;
936 box_init(&layout->left, 0, 0, hdisplay, middle);
937 box_init(&layout->right,
938 0, middle, hdisplay, vdisplay - middle);
939 break;
940 case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF:
941 layout->fb_width = hdisplay;
942 layout->fb_height = vdisplay;
943
944 middle = hdisplay / 2;
945 box_init(&layout->left, 0, 0, middle, vdisplay);
946 box_init(&layout->right,
947 middle, 0, hdisplay - middle, vdisplay);
948 break;
949 case DRM_MODE_FLAG_3D_FRAME_PACKING:
950 {
951 int vactive_space = mode->vtotal - vdisplay;
952
953 layout->fb_width = hdisplay;
954 layout->fb_height = 2 * vdisplay + vactive_space;
955
956 box_init(&layout->left,
957 0, 0, hdisplay, vdisplay);
958 box_init(&layout->right,
959 0, vdisplay + vactive_space, hdisplay, vdisplay);
960 break;
961 }
962 default:
963 igt_assert(0);
964 }
965}
966
967/**
968 * igt_create_stereo_fb:
969 * @drm_fd: open i915 drm file descriptor
970 * @mode: A stereo 3D mode.
971 * @format: drm fourcc pixel format code
972 * @tiling: tiling layout of the framebuffer
973 *
974 * Create a framebuffer for use with the stereo 3D mode specified by @mode.
975 *
976 * Returns:
977 * The kms id of the created framebuffer on success or a negative error code on
978 * failure.
979 */
980unsigned int igt_create_stereo_fb(int drm_fd, drmModeModeInfo *mode,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000981 uint32_t format, uint64_t tiling)
Thomas Wood4cb19462014-08-04 16:14:51 +0100982{
983 struct stereo_fb_layout layout;
984 cairo_t *cr;
985 uint32_t fb_id;
986 struct igt_fb fb;
987
988 stereo_fb_layout_from_mode(&layout, mode);
989 fb_id = igt_create_fb(drm_fd, layout.fb_width, layout.fb_height, format,
990 tiling, &fb);
991 cr = igt_get_cairo_ctx(drm_fd, &fb);
992
Thomas Woodecb03262015-04-13 17:37:22 +0100993 igt_paint_image(cr, "1080p-left.png",
Thomas Wood4cb19462014-08-04 16:14:51 +0100994 layout.left.x, layout.left.y,
995 layout.left.width, layout.left.height);
Thomas Woodecb03262015-04-13 17:37:22 +0100996 igt_paint_image(cr, "1080p-right.png",
Thomas Wood4cb19462014-08-04 16:14:51 +0100997 layout.right.x, layout.right.y,
998 layout.right.width, layout.right.height);
999
1000 cairo_destroy(cr);
1001
1002 return fb_id;
1003}
1004
Daniel Vetter57d7db82014-03-26 09:06:11 +01001005static cairo_format_t drm_format_to_cairo(uint32_t drm_format)
1006{
1007 struct format_desc_struct *f;
1008
1009 for_each_format(f)
1010 if (f->drm_id == drm_format)
1011 return f->cairo_id;
1012
Damien Lespiau54397ca2014-08-19 11:40:07 +01001013 igt_assert_f(0, "can't find a cairo format for %08x (%s)\n",
1014 drm_format, igt_format_str(drm_format));
Daniel Vetter57d7db82014-03-26 09:06:11 +01001015}
1016
Damien Lespiauff451a62015-03-03 14:11:04 +00001017struct fb_blit_upload {
1018 int fd;
1019 struct igt_fb *fb;
1020 struct {
1021 uint32_t handle;
1022 unsigned size, stride;
1023 uint8_t *map;
Tomeu Vizoso8a1a3862016-02-24 09:04:04 +01001024 bool is_dumb;
Damien Lespiauff451a62015-03-03 14:11:04 +00001025 } linear;
1026};
1027
1028static void destroy_cairo_surface__blit(void *arg)
1029{
1030 struct fb_blit_upload *blit = arg;
1031 struct igt_fb *fb = blit->fb;
Tomeu Vizosoae649632016-11-10 10:25:24 +01001032 unsigned int obj_tiling = igt_fb_mod_to_tiling(fb->tiling);
Damien Lespiauff451a62015-03-03 14:11:04 +00001033
Maarten Lankhorstd930b642017-02-09 10:42:01 +01001034 gem_munmap(blit->linear.map, blit->linear.size);
Damien Lespiauff451a62015-03-03 14:11:04 +00001035 fb->cairo_surface = NULL;
1036
1037 gem_set_domain(blit->fd, blit->linear.handle,
1038 I915_GEM_DOMAIN_GTT, 0);
1039
Damien Lespiauff451a62015-03-03 14:11:04 +00001040 igt_blitter_fast_copy__raw(blit->fd,
1041 blit->linear.handle,
1042 blit->linear.stride,
1043 I915_TILING_NONE,
1044 0, 0, /* src_x, src_y */
1045 fb->width, fb->height,
1046 fb->gem_handle,
1047 fb->stride,
1048 obj_tiling,
1049 0, 0 /* dst_x, dst_y */);
1050
1051 gem_sync(blit->fd, blit->linear.handle);
1052 gem_close(blit->fd, blit->linear.handle);
1053
1054 free(blit);
1055}
1056
1057static void create_cairo_surface__blit(int fd, struct igt_fb *fb)
1058{
1059 struct fb_blit_upload *blit;
1060 cairo_format_t cairo_format;
Tomeu Vizosoae649632016-11-10 10:25:24 +01001061 unsigned int obj_tiling = igt_fb_mod_to_tiling(fb->tiling);
Damien Lespiauff451a62015-03-03 14:11:04 +00001062
1063 blit = malloc(sizeof(*blit));
1064 igt_assert(blit);
1065
1066 /*
1067 * We create a linear BO that we'll map for the CPU to write to (using
1068 * cairo). This linear bo will be then blitted to its final
1069 * destination, tiling it at the same time.
1070 */
Tomeu Vizoso7be235c2016-04-22 11:08:45 +02001071 blit->linear.handle = create_bo_for_fb(fd, fb->width, fb->height,
1072 fb->drm_format,
1073 LOCAL_DRM_FORMAT_MOD_NONE, 0,
1074 0, &blit->linear.size,
1075 &blit->linear.stride,
1076 &blit->linear.is_dumb);
Damien Lespiauff451a62015-03-03 14:11:04 +00001077
Tomeu Vizoso7be235c2016-04-22 11:08:45 +02001078 igt_assert(blit->linear.handle > 0);
Damien Lespiauff451a62015-03-03 14:11:04 +00001079
1080 blit->fd = fd;
1081 blit->fb = fb;
Tvrtko Ursulin30a13602015-04-29 13:24:34 +01001082
1083 /* Copy fb content to linear BO */
1084 gem_set_domain(fd, blit->linear.handle,
1085 I915_GEM_DOMAIN_GTT, 0);
1086
1087 igt_blitter_fast_copy__raw(fd,
1088 fb->gem_handle,
1089 fb->stride,
1090 obj_tiling,
1091 0, 0, /* src_x, src_y */
1092 fb->width, fb->height,
1093 blit->linear.handle,
1094 blit->linear.stride,
1095 I915_TILING_NONE,
1096 0, 0 /* dst_x, dst_y */);
1097
1098 gem_sync(fd, blit->linear.handle);
1099
1100 gem_set_domain(fd, blit->linear.handle,
1101 I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
1102
1103 /* Setup cairo context */
Ville Syrjäläf52e7ec2015-10-09 19:11:39 +03001104 blit->linear.map = gem_mmap__cpu(fd,
Damien Lespiauff451a62015-03-03 14:11:04 +00001105 blit->linear.handle,
1106 0,
1107 blit->linear.size,
1108 PROT_READ | PROT_WRITE);
Damien Lespiauff451a62015-03-03 14:11:04 +00001109
Damien Lespiauff451a62015-03-03 14:11:04 +00001110 cairo_format = drm_format_to_cairo(fb->drm_format);
1111 fb->cairo_surface =
1112 cairo_image_surface_create_for_data(blit->linear.map,
1113 cairo_format,
1114 fb->width, fb->height,
1115 blit->linear.stride);
Chris Wilson18d0b1e2016-03-02 14:12:12 +00001116 fb->domain = I915_GEM_DOMAIN_GTT;
Damien Lespiauff451a62015-03-03 14:11:04 +00001117
1118 cairo_surface_set_user_data(fb->cairo_surface,
1119 (cairo_user_data_key_t *)create_cairo_surface__blit,
1120 blit, destroy_cairo_surface__blit);
1121}
1122
Tomeu Vizosoa2d5b342016-03-07 16:25:43 +01001123/**
1124 * igt_dirty_fb:
1125 * @fd: open drm file descriptor
1126 * @fb: pointer to an #igt_fb structure
1127 *
1128 * Flushes out the whole framebuffer.
1129 *
1130 * Returns: 0 upon success.
1131 */
1132int igt_dirty_fb(int fd, struct igt_fb *fb)
1133{
1134 return drmModeDirtyFB(fb->fd, fb->fb_id, NULL, 0);
1135}
1136
Damien Lespiau4aadbc82014-06-23 16:41:43 +01001137static void destroy_cairo_surface__gtt(void *arg)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001138{
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01001139 struct igt_fb *fb = arg;
Damien Lespiau72357f32014-07-11 14:45:37 +01001140
Maarten Lankhorstd930b642017-02-09 10:42:01 +01001141 gem_munmap(cairo_image_surface_get_data(fb->cairo_surface), fb->size);
Damien Lespiau72357f32014-07-11 14:45:37 +01001142 fb->cairo_surface = NULL;
Tomeu Vizoso89b3ffe2016-02-24 09:04:41 +01001143
1144 if (fb->is_dumb)
1145 igt_dirty_fb(fb->fd, fb);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001146}
1147
Damien Lespiau4aadbc82014-06-23 16:41:43 +01001148static void create_cairo_surface__gtt(int fd, struct igt_fb *fb)
1149{
Tomeu Vizoso89b3ffe2016-02-24 09:04:41 +01001150 void *ptr;
1151
1152 if (fb->is_dumb)
1153 ptr = kmstest_dumb_map_buffer(fd, fb->gem_handle, fb->size,
1154 PROT_READ | PROT_WRITE);
1155 else
1156 ptr = gem_mmap__gtt(fd, fb->gem_handle, fb->size,
1157 PROT_READ | PROT_WRITE);
Ville Syrjälä106fe212015-10-09 18:36:24 +03001158
Damien Lespiau4aadbc82014-06-23 16:41:43 +01001159 fb->cairo_surface =
Ville Syrjälä106fe212015-10-09 18:36:24 +03001160 cairo_image_surface_create_for_data(ptr,
Damien Lespiau4aadbc82014-06-23 16:41:43 +01001161 drm_format_to_cairo(fb->drm_format),
1162 fb->width, fb->height, fb->stride);
Chris Wilson18d0b1e2016-03-02 14:12:12 +00001163 fb->domain = I915_GEM_DOMAIN_GTT;
Damien Lespiau4aadbc82014-06-23 16:41:43 +01001164
1165 cairo_surface_set_user_data(fb->cairo_surface,
1166 (cairo_user_data_key_t *)create_cairo_surface__gtt,
1167 fb, destroy_cairo_surface__gtt);
1168}
1169
Paul Kocialkowskib4ad3972017-07-19 16:46:04 +03001170/**
1171 * igt_get_cairo_surface:
1172 * @fd: open drm file descriptor
1173 * @fb: pointer to an #igt_fb structure
1174 *
1175 * This function stores the contents of the supplied framebuffer into a cairo
1176 * surface and returns it.
1177 *
1178 * Returns:
1179 * A pointer to a cairo surface with the contents of the framebuffer.
1180 */
1181cairo_surface_t *igt_get_cairo_surface(int fd, struct igt_fb *fb)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001182{
Damien Lespiauff451a62015-03-03 14:11:04 +00001183 if (fb->cairo_surface == NULL) {
1184 if (fb->tiling == LOCAL_I915_FORMAT_MOD_Y_TILED ||
1185 fb->tiling == LOCAL_I915_FORMAT_MOD_Yf_TILED)
1186 create_cairo_surface__blit(fd, fb);
1187 else
1188 create_cairo_surface__gtt(fd, fb);
1189 }
Daniel Vetter57d7db82014-03-26 09:06:11 +01001190
Tomeu Vizoso89b3ffe2016-02-24 09:04:41 +01001191 if (!fb->is_dumb)
1192 gem_set_domain(fd, fb->gem_handle, I915_GEM_DOMAIN_CPU,
1193 I915_GEM_DOMAIN_CPU);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001194
1195 igt_assert(cairo_surface_status(fb->cairo_surface) == CAIRO_STATUS_SUCCESS);
Damien Lespiau0db75bb2014-06-30 16:34:20 +01001196 return fb->cairo_surface;
Daniel Vetter57d7db82014-03-26 09:06:11 +01001197}
1198
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001199/**
1200 * igt_get_cairo_ctx:
1201 * @fd: open i915 drm file descriptor
1202 * @fb: pointer to an #igt_fb structure
1203 *
1204 * This initializes a cairo surface for @fb and then allocates a drawing context
1205 * for it. The return cairo drawing context should be released by calling
1206 * cairo_destroy(). This also sets a default font for drawing text on
1207 * framebuffers.
1208 *
1209 * Returns:
1210 * The created cairo drawing context.
1211 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01001212cairo_t *igt_get_cairo_ctx(int fd, struct igt_fb *fb)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001213{
1214 cairo_surface_t *surface;
1215 cairo_t *cr;
1216
Paul Kocialkowskib4ad3972017-07-19 16:46:04 +03001217 surface = igt_get_cairo_surface(fd, fb);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001218 cr = cairo_create(surface);
1219 cairo_surface_destroy(surface);
Daniel Vetter7568edf2014-03-26 16:36:46 +01001220 igt_assert(cairo_status(cr) == CAIRO_STATUS_SUCCESS);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001221
Daniel Vetter7568edf2014-03-26 16:36:46 +01001222 cairo_select_font_face(cr, "Helvetica", CAIRO_FONT_SLANT_NORMAL,
1223 CAIRO_FONT_WEIGHT_NORMAL);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001224 igt_assert(cairo_status(cr) == CAIRO_STATUS_SUCCESS);
1225
1226 return cr;
1227}
1228
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001229/**
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001230 * igt_remove_fb:
1231 * @fd: open i915 drm file descriptor
1232 * @fb: pointer to an #igt_fb structure
1233 *
1234 * This function releases all resources allocated in igt_create_fb() for @fb.
1235 * Note that if this framebuffer is still in use on a primary plane the kernel
1236 * will disable the corresponding crtc.
1237 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01001238void igt_remove_fb(int fd, struct igt_fb *fb)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001239{
1240 cairo_surface_destroy(fb->cairo_surface);
1241 do_or_die(drmModeRmFB(fd, fb->fb_id));
1242 gem_close(fd, fb->gem_handle);
1243}
1244
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001245/**
1246 * igt_bpp_depth_to_drm_format:
1247 * @bpp: desired bits per pixel
1248 * @depth: desired depth
1249 *
1250 * Returns:
1251 * The rgb drm fourcc pixel format code corresponding to the given @bpp and
1252 * @depth values. Fails hard if no match was found.
1253 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01001254uint32_t igt_bpp_depth_to_drm_format(int bpp, int depth)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001255{
1256 struct format_desc_struct *f;
1257
1258 for_each_format(f)
1259 if (f->bpp == bpp && f->depth == depth)
1260 return f->drm_id;
1261
Damien Lespiau54397ca2014-08-19 11:40:07 +01001262
1263 igt_assert_f(0, "can't find drm format with bpp=%d, depth=%d\n", bpp,
1264 depth);
Daniel Vetter57d7db82014-03-26 09:06:11 +01001265}
1266
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001267/**
1268 * igt_drm_format_to_bpp:
1269 * @drm_format: drm fourcc pixel format code
1270 *
1271 * Returns:
1272 * The bits per pixel for the given drm fourcc pixel format code. Fails hard if
1273 * no match was found.
1274 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01001275uint32_t igt_drm_format_to_bpp(uint32_t drm_format)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001276{
1277 struct format_desc_struct *f;
1278
1279 for_each_format(f)
1280 if (f->drm_id == drm_format)
1281 return f->bpp;
1282
Damien Lespiau54397ca2014-08-19 11:40:07 +01001283 igt_assert_f(0, "can't find a bpp format for %08x (%s)\n",
1284 drm_format, igt_format_str(drm_format));
Daniel Vetter57d7db82014-03-26 09:06:11 +01001285}
1286
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001287/**
1288 * igt_format_str:
1289 * @drm_format: drm fourcc pixel format code
1290 *
1291 * Returns:
1292 * Human-readable fourcc pixel format code for @drm_format or "invalid" no match
1293 * was found.
1294 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +01001295const char *igt_format_str(uint32_t drm_format)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001296{
1297 struct format_desc_struct *f;
1298
1299 for_each_format(f)
1300 if (f->drm_id == drm_format)
1301 return f->name;
1302
1303 return "invalid";
1304}
1305
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001306/**
Paulo Zanoni7ca55f42016-01-26 10:52:29 -02001307 * igt_get_all_cairo_formats:
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001308 * @formats: pointer to pointer to store the allocated formats array
1309 * @format_count: pointer to integer to store the size of the allocated array
1310 *
Paulo Zanoni7ca55f42016-01-26 10:52:29 -02001311 * This functions returns an array of all the drm fourcc codes supported by
1312 * cairo and this library.
Daniel Vetter3d9e63f2014-03-26 16:37:15 +01001313 */
Paulo Zanoni7ca55f42016-01-26 10:52:29 -02001314void igt_get_all_cairo_formats(const uint32_t **formats, int *format_count)
Daniel Vetter57d7db82014-03-26 09:06:11 +01001315{
1316 static uint32_t *drm_formats;
Paulo Zanoni7ca55f42016-01-26 10:52:29 -02001317 static int n_formats;
Daniel Vetter57d7db82014-03-26 09:06:11 +01001318
1319 if (!drm_formats) {
1320 struct format_desc_struct *f;
1321 uint32_t *format;
1322
Paulo Zanoni7ca55f42016-01-26 10:52:29 -02001323 n_formats = 0;
1324 for_each_format(f)
1325 if (f->cairo_id != CAIRO_FORMAT_INVALID)
1326 n_formats++;
1327
1328 drm_formats = calloc(n_formats, sizeof(*drm_formats));
Daniel Vetter57d7db82014-03-26 09:06:11 +01001329 format = &drm_formats[0];
1330 for_each_format(f)
Paulo Zanoni7ca55f42016-01-26 10:52:29 -02001331 if (f->cairo_id != CAIRO_FORMAT_INVALID)
1332 *format++ = f->drm_id;
Daniel Vetter57d7db82014-03-26 09:06:11 +01001333 }
1334
1335 *formats = drm_formats;
Paulo Zanoni7ca55f42016-01-26 10:52:29 -02001336 *format_count = n_formats;
Daniel Vetter57d7db82014-03-26 09:06:11 +01001337}