blob: 3ea9915c42c446f7332de694ff080fe6643da40d [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
28#define _GNU_SOURCE
29#include <stdio.h>
30#include <math.h>
31
32#include "drmtest.h"
33#include "igt_fb.h"
34#include "ioctl_wrappers.h"
35
Daniel Vetterc6c2b2b2014-03-26 15:15:49 +010036/**
37 * SECTION:igt_fb
38 * @short_description: Framebuffer handling and drawing library
Damien Lespiau6ebd8c22015-06-26 14:28:41 +010039 * @title: Framebuffer
Thomas Woodf0381d12015-09-07 09:26:01 +010040 * @include: igt.h
Daniel Vetter3d9e63f2014-03-26 16:37:15 +010041 *
42 * This library contains helper functions for handling kms framebuffer objects
43 * using #igt_fb structures to track all the metadata. igt_create_fb() creates
Thomas Woodd01ebbd2015-06-29 16:47:14 +010044 * a basic framebuffer and igt_remove_fb() cleans everything up again.
Daniel Vetter3d9e63f2014-03-26 16:37:15 +010045 *
46 * It also supports drawing using the cairo library and provides some simplified
47 * helper functions to easily draw test patterns. The main function to create a
48 * cairo drawing context for a framebuffer object is igt_get_cairo_ctx().
49 *
50 * Finally it also pulls in the drm fourcc headers and provides some helper
51 * functions to work with these pixel format codes.
Daniel Vetterc6c2b2b2014-03-26 15:15:49 +010052 */
53
Daniel Vetter57d7db82014-03-26 09:06:11 +010054/* drm fourcc/cairo format maps */
55#define DF(did, cid, _bpp, _depth) \
56 { DRM_FORMAT_##did, CAIRO_FORMAT_##cid, # did, _bpp, _depth }
57static struct format_desc_struct {
58 uint32_t drm_id;
59 cairo_format_t cairo_id;
60 const char *name;
61 int bpp;
62 int depth;
63} format_desc[] = {
64 DF(RGB565, RGB16_565, 16, 16),
Chris Wilson9df77d52014-09-06 12:08:13 +010065 //DF(RGB888, INVALID, 24, 24),
Daniel Vetter57d7db82014-03-26 09:06:11 +010066 DF(XRGB8888, RGB24, 32, 24),
67 DF(XRGB2101010, RGB30, 32, 30),
68 DF(ARGB8888, ARGB32, 32, 32),
69};
70#undef DF
71
72#define for_each_format(f) \
73 for (f = format_desc; f - format_desc < ARRAY_SIZE(format_desc); f++)
74
75
76/* helpers to create nice-looking framebuffers */
77static int create_bo_for_fb(int fd, int width, int height, int bpp,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +000078 uint64_t tiling, unsigned bo_size,
Paulo Zanonid6341372015-11-05 16:39:00 -020079 unsigned bo_stride, uint32_t *gem_handle_ret,
80 unsigned *size_ret, unsigned *stride_ret)
Daniel Vetter57d7db82014-03-26 09:06:11 +010081{
82 uint32_t gem_handle;
Daniel Vettercc730c42014-03-11 16:14:33 +010083 int size, ret = 0;
Daniel Vetter57d7db82014-03-26 09:06:11 +010084 unsigned stride;
85
Tvrtko Ursuline36091d2015-03-03 14:11:01 +000086 if (tiling != LOCAL_DRM_FORMAT_MOD_NONE) {
Daniel Vetter57d7db82014-03-26 09:06:11 +010087 int v;
88
89 /* Round the tiling up to the next power-of-two and the
90 * region up to the next pot fence size so that this works
91 * on all generations.
92 *
93 * This can still fail if the framebuffer is too large to
94 * be tiled. But then that failure is expected.
95 */
96
97 v = width * bpp / 8;
98 for (stride = 512; stride < v; stride *= 2)
99 ;
100
101 v = stride * height;
102 for (size = 1024*1024; size < v; size *= 2)
103 ;
104 } else {
105 /* Scan-out has a 64 byte alignment restriction */
Paulo Zanoni1c68a712015-11-05 16:24:06 -0200106 stride = ALIGN(width * (bpp / 8), 64);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100107 size = stride * height;
108 }
109
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100110 if (bo_size == 0)
111 bo_size = size;
Paulo Zanonid6341372015-11-05 16:39:00 -0200112 if (bo_stride == 0)
113 bo_stride = stride;
114
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100115 gem_handle = gem_create(fd, bo_size);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100116
Damien Lespiauff451a62015-03-03 14:11:04 +0000117 if (tiling == LOCAL_I915_FORMAT_MOD_X_TILED)
Paulo Zanonid6341372015-11-05 16:39:00 -0200118 ret = __gem_set_tiling(fd, gem_handle, I915_TILING_X,
119 bo_stride);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100120
Paulo Zanonid6341372015-11-05 16:39:00 -0200121 *stride_ret = bo_stride;
Paulo Zanoni5cfc4e72015-11-05 10:42:49 -0200122 *size_ret = bo_size;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100123 *gem_handle_ret = gem_handle;
124
Daniel Vettercc730c42014-03-11 16:14:33 +0100125 return ret;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100126}
127
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100128/**
129 * igt_paint_color:
130 * @cr: cairo drawing context
131 * @x: pixel x-coordination of the fill rectangle
132 * @y: pixel y-coordination of the fill rectangle
133 * @w: width of the fill rectangle
134 * @h: height of the fill rectangle
135 * @r: red value to use as fill color
Thomas Woodd01ebbd2015-06-29 16:47:14 +0100136 * @g: green value to use as fill color
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100137 * @b: blue value to use as fill color
138 *
139 * This functions draws a solid rectangle with the given color using the drawing
140 * context @cr.
141 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100142void igt_paint_color(cairo_t *cr, int x, int y, int w, int h,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100143 double r, double g, double b)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100144{
145 cairo_rectangle(cr, x, y, w, h);
146 cairo_set_source_rgb(cr, r, g, b);
147 cairo_fill(cr);
148}
149
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100150/**
151 * igt_paint_color_alpha:
152 * @cr: cairo drawing context
153 * @x: pixel x-coordination of the fill rectangle
154 * @y: pixel y-coordination of the fill rectangle
155 * @w: width of the fill rectangle
156 * @h: height of the fill rectangle
157 * @r: red value to use as fill color
Thomas Woodd01ebbd2015-06-29 16:47:14 +0100158 * @g: green value to use as fill color
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100159 * @b: blue value to use as fill color
160 * @a: alpha value to use as fill color
161 *
162 * This functions draws a rectangle with the given color and alpha values using
163 * the drawing context @cr.
164 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100165void igt_paint_color_alpha(cairo_t *cr, int x, int y, int w, int h,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100166 double r, double g, double b, double a)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100167{
168 cairo_rectangle(cr, x, y, w, h);
169 cairo_set_source_rgba(cr, r, g, b, a);
170 cairo_fill(cr);
171}
172
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100173/**
174 * igt_paint_color_gradient:
175 * @cr: cairo drawing context
176 * @x: pixel x-coordination of the fill rectangle
177 * @y: pixel y-coordination of the fill rectangle
178 * @w: width of the fill rectangle
179 * @h: height of the fill rectangle
180 * @r: red value to use as fill color
Thomas Woodd01ebbd2015-06-29 16:47:14 +0100181 * @g: green value to use as fill color
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100182 * @b: blue value to use as fill color
183 *
184 * This functions draws a gradient into the rectangle which fades in from black
185 * to the given values using the drawing context @cr.
186 */
Daniel Vetter57d7db82014-03-26 09:06:11 +0100187void
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100188igt_paint_color_gradient(cairo_t *cr, int x, int y, int w, int h,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100189 int r, int g, int b)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100190{
191 cairo_pattern_t *pat;
192
193 pat = cairo_pattern_create_linear(x, y, x + w, y + h);
194 cairo_pattern_add_color_stop_rgba(pat, 1, 0, 0, 0, 1);
195 cairo_pattern_add_color_stop_rgba(pat, 0, r, g, b, 1);
196
197 cairo_rectangle(cr, x, y, w, h);
198 cairo_set_source(cr, pat);
199 cairo_fill(cr);
200 cairo_pattern_destroy(pat);
201}
202
203static void
204paint_test_patterns(cairo_t *cr, int width, int height)
205{
206 double gr_height, gr_width;
207 int x, y;
208
209 y = height * 0.10;
210 gr_width = width * 0.75;
211 gr_height = height * 0.08;
212 x = (width / 2) - (gr_width / 2);
213
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100214 igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 1, 0, 0);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100215
216 y += gr_height;
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100217 igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 0, 1, 0);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100218
219 y += gr_height;
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100220 igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 0, 0, 1);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100221
222 y += gr_height;
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100223 igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 1, 1, 1);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100224}
225
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100226/**
227 * igt_cairo_printf_line:
228 * @cr: cairo drawing context
229 * @align: text alignment
230 * @yspacing: additional y-direction feed after this line
231 * @fmt: format string
232 * @...: optional arguments used in the format string
233 *
234 * This is a little helper to draw text onto framebuffers. All the initial setup
235 * (like setting the font size and the moving to the starting position) still
236 * needs to be done manually with explicit cairo calls on @cr.
237 *
238 * Returns:
239 * The width of the drawn text.
240 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100241int igt_cairo_printf_line(cairo_t *cr, enum igt_text_align align,
Daniel Vetter57d7db82014-03-26 09:06:11 +0100242 double yspacing, const char *fmt, ...)
243{
244 double x, y, xofs, yofs;
245 cairo_text_extents_t extents;
246 char *text;
247 va_list ap;
248 int ret;
249
250 va_start(ap, fmt);
251 ret = vasprintf(&text, fmt, ap);
252 igt_assert(ret >= 0);
253 va_end(ap);
254
255 cairo_text_extents(cr, text, &extents);
256
257 xofs = yofs = 0;
258 if (align & align_right)
259 xofs = -extents.width;
260 else if (align & align_hcenter)
261 xofs = -extents.width / 2;
262
263 if (align & align_top)
264 yofs = extents.height;
265 else if (align & align_vcenter)
266 yofs = extents.height / 2;
267
268 cairo_get_current_point(cr, &x, &y);
269 if (xofs || yofs)
270 cairo_rel_move_to(cr, xofs, yofs);
271
272 cairo_text_path(cr, text);
273 cairo_set_source_rgb(cr, 0, 0, 0);
274 cairo_stroke_preserve(cr);
275 cairo_set_source_rgb(cr, 1, 1, 1);
276 cairo_fill(cr);
277
278 cairo_move_to(cr, x, y + extents.height + yspacing);
279
280 free(text);
281
282 return extents.width;
283}
284
285static void
286paint_marker(cairo_t *cr, int x, int y)
287{
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100288 enum igt_text_align align;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100289 int xoff, yoff;
290
291 cairo_move_to(cr, x, y - 20);
292 cairo_line_to(cr, x, y + 20);
293 cairo_move_to(cr, x - 20, y);
294 cairo_line_to(cr, x + 20, y);
295 cairo_new_sub_path(cr);
296 cairo_arc(cr, x, y, 10, 0, M_PI * 2);
297 cairo_set_line_width(cr, 4);
298 cairo_set_source_rgb(cr, 0, 0, 0);
299 cairo_stroke_preserve(cr);
300 cairo_set_source_rgb(cr, 1, 1, 1);
301 cairo_set_line_width(cr, 2);
302 cairo_stroke(cr);
303
304 xoff = x ? -20 : 20;
305 align = x ? align_right : align_left;
306
307 yoff = y ? -20 : 20;
308 align |= y ? align_bottom : align_top;
309
310 cairo_move_to(cr, x + xoff, y + yoff);
311 cairo_set_font_size(cr, 18);
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100312 igt_cairo_printf_line(cr, align, 0, "(%d, %d)", x, y);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100313}
314
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100315/**
316 * igt_paint_test_pattern:
317 * @cr: cairo drawing context
318 * @width: width of the visible area
319 * @height: height of the visible area
320 *
321 * This functions draws an entire set of test patterns for the given visible
322 * area using the drawing context @cr. This is useful for manual visual
323 * inspection of displayed framebuffers.
324 *
325 * The test patterns include
326 * - corner markers to check for over/underscan and
327 * - a set of color and b/w gradients.
328 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100329void igt_paint_test_pattern(cairo_t *cr, int width, int height)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100330{
331 paint_test_patterns(cr, width, height);
332
333 cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
334
335 /* Paint corner markers */
336 paint_marker(cr, 0, 0);
337 paint_marker(cr, width, 0);
338 paint_marker(cr, 0, height);
339 paint_marker(cr, width, height);
340
341 igt_assert(!cairo_status(cr));
342}
343
Thomas Woodecb03262015-04-13 17:37:22 +0100344static cairo_status_t
345stdio_read_func(void *closure, unsigned char* data, unsigned int size)
346{
347 if (fread(data, 1, size, (FILE*)closure) != size)
348 return CAIRO_STATUS_READ_ERROR;
349
350 return CAIRO_STATUS_SUCCESS;
351}
352
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100353/**
354 * igt_paint_image:
355 * @cr: cairo drawing context
356 * @filename: filename of the png image to draw
357 * @dst_x: pixel x-coordination of the destination rectangle
358 * @dst_y: pixel y-coordination of the destination rectangle
359 * @dst_width: width of the destination rectangle
360 * @dst_height: height of the destination rectangle
361 *
Thomas Woodecb03262015-04-13 17:37:22 +0100362 * This function can be used to draw a scaled version of the supplied png image,
363 * which is loaded from the package data directory.
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100364 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100365void igt_paint_image(cairo_t *cr, const char *filename,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100366 int dst_x, int dst_y, int dst_width, int dst_height)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100367{
368 cairo_surface_t *image;
369 int img_width, img_height;
370 double scale_x, scale_y;
Thomas Woodecb03262015-04-13 17:37:22 +0100371 FILE* f;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100372
Thomas Woodecb03262015-04-13 17:37:22 +0100373 f = igt_fopen_data(filename);
374
375 image = cairo_image_surface_create_from_png_stream(&stdio_read_func, f);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100376 igt_assert(cairo_surface_status(image) == CAIRO_STATUS_SUCCESS);
377
378 img_width = cairo_image_surface_get_width(image);
379 img_height = cairo_image_surface_get_height(image);
380
381 scale_x = (double)dst_width / img_width;
382 scale_y = (double)dst_height / img_height;
383
384 cairo_save(cr);
385
386 cairo_translate(cr, dst_x, dst_y);
387 cairo_scale(cr, scale_x, scale_y);
388 cairo_set_source_surface(cr, image, 0, 0);
389 cairo_paint(cr);
390
391 cairo_surface_destroy(image);
392
393 cairo_restore(cr);
Tvrtko Ursulinc317b782015-04-30 12:27:54 +0100394
395 fclose(f);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100396}
397
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100398/**
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100399 * igt_create_fb_with_bo_size:
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100400 * @fd: open i915 drm file descriptor
401 * @width: width of the framebuffer in pixel
402 * @height: height of the framebuffer in pixel
403 * @format: drm fourcc pixel format code
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000404 * @tiling: tiling layout of the framebuffer (as framebuffer modifier)
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100405 * @fb: pointer to an #igt_fb structure
Paulo Zanonicb7dd5d2015-11-05 16:18:55 -0200406 * @bo_size: size of the backing bo (0 for automatic size)
Paulo Zanonid6341372015-11-05 16:39:00 -0200407 * @bo_stride: stride of the backing bo (0 for automatic stride)
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100408 *
409 * This function allocates a gem buffer object suitable to back a framebuffer
410 * with the requested properties and then wraps it up in a drm framebuffer
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100411 * object of the requested size. All metadata is stored in @fb.
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100412 *
413 * The backing storage of the framebuffer is filled with all zeros, i.e. black
414 * for rgb pixel formats.
415 *
416 * Returns:
Damien Lespiau50166d22014-08-19 11:55:22 +0100417 * The kms id of the created framebuffer.
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100418 */
Damien Lespiau378e61e2014-06-23 14:53:24 +0100419unsigned int
420igt_create_fb_with_bo_size(int fd, int width, int height,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000421 uint32_t format, uint64_t tiling,
Paulo Zanonid6341372015-11-05 16:39:00 -0200422 struct igt_fb *fb, unsigned bo_size,
423 unsigned bo_stride)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100424{
Daniel Vetter57d7db82014-03-26 09:06:11 +0100425 uint32_t fb_id;
426 int bpp;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100427
428 memset(fb, 0, sizeof(*fb));
429
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100430 bpp = igt_drm_format_to_bpp(format);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100431
Paulo Zanonif9744222015-08-24 16:30:04 -0300432 igt_debug("%s(width=%d, height=%d, format=0x%x [bpp=%d], tiling=0x%"PRIx64", size=%d)\n",
Chris Wilsondb4cc742014-09-06 12:07:49 +0100433 __func__, width, height, format, bpp, tiling, bo_size);
434 do_or_die(create_bo_for_fb(fd, width, height, bpp, tiling, bo_size,
Paulo Zanonid6341372015-11-05 16:39:00 -0200435 bo_stride, &fb->gem_handle, &fb->size,
436 &fb->stride));
Chris Wilsondb4cc742014-09-06 12:07:49 +0100437
Chris Wilsondb4cc742014-09-06 12:07:49 +0100438 igt_debug("%s(handle=%d, pitch=%d)\n",
Tvrtko Ursulineb93c1b2015-03-03 14:11:03 +0000439 __func__, fb->gem_handle, fb->stride);
440
441 if (tiling != LOCAL_DRM_FORMAT_MOD_NONE &&
442 tiling != LOCAL_I915_FORMAT_MOD_X_TILED) {
443 do_or_die(__kms_addfb(fd, fb->gem_handle, width, height,
444 fb->stride, format, tiling,
445 LOCAL_DRM_MODE_FB_MODIFIERS, &fb_id));
446 } else {
447 uint32_t handles[4];
448 uint32_t pitches[4];
449 uint32_t offsets[4];
450
451 memset(handles, 0, sizeof(handles));
452 memset(pitches, 0, sizeof(pitches));
453 memset(offsets, 0, sizeof(offsets));
454
455 handles[0] = fb->gem_handle;
456 pitches[0] = fb->stride;
457
458 do_or_die(drmModeAddFB2(fd, width, height, format,
459 handles, pitches, offsets,
460 &fb_id, 0));
461 }
Daniel Vetter57d7db82014-03-26 09:06:11 +0100462
463 fb->width = width;
464 fb->height = height;
Damien Lespiau378e61e2014-06-23 14:53:24 +0100465 fb->tiling = tiling;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100466 fb->drm_format = format;
467 fb->fb_id = fb_id;
468
469 return fb_id;
470}
471
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100472/**
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100473 * igt_create_fb:
474 * @fd: open i915 drm file descriptor
475 * @width: width of the framebuffer in pixel
476 * @height: height of the framebuffer in pixel
477 * @format: drm fourcc pixel format code
Damien Lespiau378e61e2014-06-23 14:53:24 +0100478 * @tiling: tiling layout of the framebuffer
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100479 * @fb: pointer to an #igt_fb structure
480 *
481 * This function allocates a gem buffer object suitable to back a framebuffer
482 * with the requested properties and then wraps it up in a drm framebuffer
483 * object. All metadata is stored in @fb.
484 *
485 * The backing storage of the framebuffer is filled with all zeros, i.e. black
486 * for rgb pixel formats.
487 *
488 * Returns:
Damien Lespiau50166d22014-08-19 11:55:22 +0100489 * The kms id of the created framebuffer.
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100490 */
491unsigned int igt_create_fb(int fd, int width, int height, uint32_t format,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000492 uint64_t tiling, struct igt_fb *fb)
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100493{
Paulo Zanonid6341372015-11-05 16:39:00 -0200494 return igt_create_fb_with_bo_size(fd, width, height, format, tiling, fb,
495 0, 0);
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100496}
497
498/**
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100499 * igt_create_color_fb:
500 * @fd: open i915 drm file descriptor
501 * @width: width of the framebuffer in pixel
502 * @height: height of the framebuffer in pixel
503 * @format: drm fourcc pixel format code
Damien Lespiau378e61e2014-06-23 14:53:24 +0100504 * @tiling: tiling layout of the framebuffer
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100505 * @r: red value to use as fill color
506 * @g: gree value to use as fill color
507 * @b: blue value to use as fill color
508 * @fb: pointer to an #igt_fb structure
509 *
510 * This function allocates a gem buffer object suitable to back a framebuffer
511 * with the requested properties and then wraps it up in a drm framebuffer
512 * object. All metadata is stored in @fb.
513 *
514 * Compared to igt_create_fb() this function also fills the entire framebuffer
515 * with the given color, which is useful for some simple pipe crc based tests.
516 *
517 * Returns:
518 * The kms id of the created framebuffer on success or a negative error code on
519 * failure.
520 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100521unsigned int igt_create_color_fb(int fd, int width, int height,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000522 uint32_t format, uint64_t tiling,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100523 double r, double g, double b,
524 struct igt_fb *fb /* out */)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100525{
526 unsigned int fb_id;
527 cairo_t *cr;
528
Damien Lespiau378e61e2014-06-23 14:53:24 +0100529 fb_id = igt_create_fb(fd, width, height, format, tiling, fb);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100530 igt_assert(fb_id);
531
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100532 cr = igt_get_cairo_ctx(fd, fb);
533 igt_paint_color(cr, 0, 0, width, height, r, g, b);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100534 igt_assert(cairo_status(cr) == 0);
535 cairo_destroy(cr);
536
537 return fb_id;
538}
539
Thomas Wood4cb19462014-08-04 16:14:51 +0100540struct box {
541 int x, y, width, height;
542};
543
544struct stereo_fb_layout {
545 int fb_width, fb_height;
546 struct box left, right;
547};
548
549static void box_init(struct box *box, int x, int y, int bwidth, int bheight)
550{
551 box->x = x;
552 box->y = y;
553 box->width = bwidth;
554 box->height = bheight;
555}
556
557
558static void stereo_fb_layout_from_mode(struct stereo_fb_layout *layout,
559 drmModeModeInfo *mode)
560{
561 unsigned int format = mode->flags & DRM_MODE_FLAG_3D_MASK;
562 const int hdisplay = mode->hdisplay, vdisplay = mode->vdisplay;
563 int middle;
564
565 switch (format) {
566 case DRM_MODE_FLAG_3D_TOP_AND_BOTTOM:
567 layout->fb_width = hdisplay;
568 layout->fb_height = vdisplay;
569
570 middle = vdisplay / 2;
571 box_init(&layout->left, 0, 0, hdisplay, middle);
572 box_init(&layout->right,
573 0, middle, hdisplay, vdisplay - middle);
574 break;
575 case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF:
576 layout->fb_width = hdisplay;
577 layout->fb_height = vdisplay;
578
579 middle = hdisplay / 2;
580 box_init(&layout->left, 0, 0, middle, vdisplay);
581 box_init(&layout->right,
582 middle, 0, hdisplay - middle, vdisplay);
583 break;
584 case DRM_MODE_FLAG_3D_FRAME_PACKING:
585 {
586 int vactive_space = mode->vtotal - vdisplay;
587
588 layout->fb_width = hdisplay;
589 layout->fb_height = 2 * vdisplay + vactive_space;
590
591 box_init(&layout->left,
592 0, 0, hdisplay, vdisplay);
593 box_init(&layout->right,
594 0, vdisplay + vactive_space, hdisplay, vdisplay);
595 break;
596 }
597 default:
598 igt_assert(0);
599 }
600}
601
602/**
603 * igt_create_stereo_fb:
604 * @drm_fd: open i915 drm file descriptor
605 * @mode: A stereo 3D mode.
606 * @format: drm fourcc pixel format code
607 * @tiling: tiling layout of the framebuffer
608 *
609 * Create a framebuffer for use with the stereo 3D mode specified by @mode.
610 *
611 * Returns:
612 * The kms id of the created framebuffer on success or a negative error code on
613 * failure.
614 */
615unsigned int igt_create_stereo_fb(int drm_fd, drmModeModeInfo *mode,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000616 uint32_t format, uint64_t tiling)
Thomas Wood4cb19462014-08-04 16:14:51 +0100617{
618 struct stereo_fb_layout layout;
619 cairo_t *cr;
620 uint32_t fb_id;
621 struct igt_fb fb;
622
623 stereo_fb_layout_from_mode(&layout, mode);
624 fb_id = igt_create_fb(drm_fd, layout.fb_width, layout.fb_height, format,
625 tiling, &fb);
626 cr = igt_get_cairo_ctx(drm_fd, &fb);
627
Thomas Woodecb03262015-04-13 17:37:22 +0100628 igt_paint_image(cr, "1080p-left.png",
Thomas Wood4cb19462014-08-04 16:14:51 +0100629 layout.left.x, layout.left.y,
630 layout.left.width, layout.left.height);
Thomas Woodecb03262015-04-13 17:37:22 +0100631 igt_paint_image(cr, "1080p-right.png",
Thomas Wood4cb19462014-08-04 16:14:51 +0100632 layout.right.x, layout.right.y,
633 layout.right.width, layout.right.height);
634
635 cairo_destroy(cr);
636
637 return fb_id;
638}
639
Daniel Vetter57d7db82014-03-26 09:06:11 +0100640static cairo_format_t drm_format_to_cairo(uint32_t drm_format)
641{
642 struct format_desc_struct *f;
643
644 for_each_format(f)
645 if (f->drm_id == drm_format)
646 return f->cairo_id;
647
Damien Lespiau54397ca2014-08-19 11:40:07 +0100648 igt_assert_f(0, "can't find a cairo format for %08x (%s)\n",
649 drm_format, igt_format_str(drm_format));
Daniel Vetter57d7db82014-03-26 09:06:11 +0100650}
651
Damien Lespiauff451a62015-03-03 14:11:04 +0000652struct fb_blit_upload {
653 int fd;
654 struct igt_fb *fb;
655 struct {
656 uint32_t handle;
657 unsigned size, stride;
658 uint8_t *map;
659 } linear;
660};
661
Tvrtko Ursulin30a13602015-04-29 13:24:34 +0100662static unsigned int fb_mod_to_obj_tiling(uint64_t fb_mod)
663{
664 switch (fb_mod) {
665 case LOCAL_DRM_FORMAT_MOD_NONE:
666 return I915_TILING_NONE;
667 case LOCAL_I915_FORMAT_MOD_X_TILED:
668 return I915_TILING_X;
669 case LOCAL_I915_FORMAT_MOD_Y_TILED:
670 return I915_TILING_Y;
671 case LOCAL_I915_FORMAT_MOD_Yf_TILED:
672 return I915_TILING_Yf;
673 default:
674 igt_assert(0);
675 }
676}
677
Damien Lespiauff451a62015-03-03 14:11:04 +0000678static void destroy_cairo_surface__blit(void *arg)
679{
680 struct fb_blit_upload *blit = arg;
681 struct igt_fb *fb = blit->fb;
Tvrtko Ursulin30a13602015-04-29 13:24:34 +0100682 unsigned int obj_tiling = fb_mod_to_obj_tiling(fb->tiling);
Damien Lespiauff451a62015-03-03 14:11:04 +0000683
684 munmap(blit->linear.map, blit->linear.size);
685 fb->cairo_surface = NULL;
686
687 gem_set_domain(blit->fd, blit->linear.handle,
688 I915_GEM_DOMAIN_GTT, 0);
689
Damien Lespiauff451a62015-03-03 14:11:04 +0000690 igt_blitter_fast_copy__raw(blit->fd,
691 blit->linear.handle,
692 blit->linear.stride,
693 I915_TILING_NONE,
694 0, 0, /* src_x, src_y */
695 fb->width, fb->height,
696 fb->gem_handle,
697 fb->stride,
698 obj_tiling,
699 0, 0 /* dst_x, dst_y */);
700
701 gem_sync(blit->fd, blit->linear.handle);
702 gem_close(blit->fd, blit->linear.handle);
703
704 free(blit);
705}
706
707static void create_cairo_surface__blit(int fd, struct igt_fb *fb)
708{
709 struct fb_blit_upload *blit;
710 cairo_format_t cairo_format;
Tvrtko Ursulin30a13602015-04-29 13:24:34 +0100711 unsigned int obj_tiling = fb_mod_to_obj_tiling(fb->tiling);
Damien Lespiauff451a62015-03-03 14:11:04 +0000712 int bpp, ret;
713
714 blit = malloc(sizeof(*blit));
715 igt_assert(blit);
716
717 /*
718 * We create a linear BO that we'll map for the CPU to write to (using
719 * cairo). This linear bo will be then blitted to its final
720 * destination, tiling it at the same time.
721 */
722 bpp = igt_drm_format_to_bpp(fb->drm_format);
723 ret = create_bo_for_fb(fd, fb->width, fb->height, bpp,
Paulo Zanonid6341372015-11-05 16:39:00 -0200724 LOCAL_DRM_FORMAT_MOD_NONE, 0, 0,
Damien Lespiauff451a62015-03-03 14:11:04 +0000725 &blit->linear.handle,
726 &blit->linear.size,
727 &blit->linear.stride);
728
729 igt_assert(ret == 0);
730
731 blit->fd = fd;
732 blit->fb = fb;
Tvrtko Ursulin30a13602015-04-29 13:24:34 +0100733
734 /* Copy fb content to linear BO */
735 gem_set_domain(fd, blit->linear.handle,
736 I915_GEM_DOMAIN_GTT, 0);
737
738 igt_blitter_fast_copy__raw(fd,
739 fb->gem_handle,
740 fb->stride,
741 obj_tiling,
742 0, 0, /* src_x, src_y */
743 fb->width, fb->height,
744 blit->linear.handle,
745 blit->linear.stride,
746 I915_TILING_NONE,
747 0, 0 /* dst_x, dst_y */);
748
749 gem_sync(fd, blit->linear.handle);
750
751 gem_set_domain(fd, blit->linear.handle,
752 I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
753
754 /* Setup cairo context */
Ville Syrjäläf52e7ec2015-10-09 19:11:39 +0300755 blit->linear.map = gem_mmap__cpu(fd,
Damien Lespiauff451a62015-03-03 14:11:04 +0000756 blit->linear.handle,
757 0,
758 blit->linear.size,
759 PROT_READ | PROT_WRITE);
Damien Lespiauff451a62015-03-03 14:11:04 +0000760
Damien Lespiauff451a62015-03-03 14:11:04 +0000761 cairo_format = drm_format_to_cairo(fb->drm_format);
762 fb->cairo_surface =
763 cairo_image_surface_create_for_data(blit->linear.map,
764 cairo_format,
765 fb->width, fb->height,
766 blit->linear.stride);
767
768 cairo_surface_set_user_data(fb->cairo_surface,
769 (cairo_user_data_key_t *)create_cairo_surface__blit,
770 blit, destroy_cairo_surface__blit);
771}
772
Damien Lespiau4aadbc82014-06-23 16:41:43 +0100773static void destroy_cairo_surface__gtt(void *arg)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100774{
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100775 struct igt_fb *fb = arg;
Damien Lespiau72357f32014-07-11 14:45:37 +0100776
Daniel Vetter57d7db82014-03-26 09:06:11 +0100777 munmap(cairo_image_surface_get_data(fb->cairo_surface), fb->size);
Damien Lespiau72357f32014-07-11 14:45:37 +0100778 fb->cairo_surface = NULL;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100779}
780
Damien Lespiau4aadbc82014-06-23 16:41:43 +0100781static void create_cairo_surface__gtt(int fd, struct igt_fb *fb)
782{
Ville Syrjäläf52e7ec2015-10-09 19:11:39 +0300783 void *ptr = gem_mmap__gtt(fd, fb->gem_handle, fb->size, PROT_READ | PROT_WRITE);
Ville Syrjälä106fe212015-10-09 18:36:24 +0300784
Damien Lespiau4aadbc82014-06-23 16:41:43 +0100785 fb->cairo_surface =
Ville Syrjälä106fe212015-10-09 18:36:24 +0300786 cairo_image_surface_create_for_data(ptr,
Damien Lespiau4aadbc82014-06-23 16:41:43 +0100787 drm_format_to_cairo(fb->drm_format),
788 fb->width, fb->height, fb->stride);
789
790 cairo_surface_set_user_data(fb->cairo_surface,
791 (cairo_user_data_key_t *)create_cairo_surface__gtt,
792 fb, destroy_cairo_surface__gtt);
793}
794
Daniel Vetterae461e62014-03-26 16:09:27 +0100795static cairo_surface_t *get_cairo_surface(int fd, struct igt_fb *fb)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100796{
Damien Lespiauff451a62015-03-03 14:11:04 +0000797 if (fb->cairo_surface == NULL) {
798 if (fb->tiling == LOCAL_I915_FORMAT_MOD_Y_TILED ||
799 fb->tiling == LOCAL_I915_FORMAT_MOD_Yf_TILED)
800 create_cairo_surface__blit(fd, fb);
801 else
802 create_cairo_surface__gtt(fd, fb);
803 }
Daniel Vetter57d7db82014-03-26 09:06:11 +0100804
805 gem_set_domain(fd, fb->gem_handle,
806 I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
807
808 igt_assert(cairo_surface_status(fb->cairo_surface) == CAIRO_STATUS_SUCCESS);
Damien Lespiau0db75bb2014-06-30 16:34:20 +0100809 return fb->cairo_surface;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100810}
811
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100812/**
813 * igt_get_cairo_ctx:
814 * @fd: open i915 drm file descriptor
815 * @fb: pointer to an #igt_fb structure
816 *
817 * This initializes a cairo surface for @fb and then allocates a drawing context
818 * for it. The return cairo drawing context should be released by calling
819 * cairo_destroy(). This also sets a default font for drawing text on
820 * framebuffers.
821 *
822 * Returns:
823 * The created cairo drawing context.
824 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100825cairo_t *igt_get_cairo_ctx(int fd, struct igt_fb *fb)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100826{
827 cairo_surface_t *surface;
828 cairo_t *cr;
829
Daniel Vetterae461e62014-03-26 16:09:27 +0100830 surface = get_cairo_surface(fd, fb);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100831 cr = cairo_create(surface);
832 cairo_surface_destroy(surface);
Daniel Vetter7568edf2014-03-26 16:36:46 +0100833 igt_assert(cairo_status(cr) == CAIRO_STATUS_SUCCESS);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100834
Daniel Vetter7568edf2014-03-26 16:36:46 +0100835 cairo_select_font_face(cr, "Helvetica", CAIRO_FONT_SLANT_NORMAL,
836 CAIRO_FONT_WEIGHT_NORMAL);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100837 igt_assert(cairo_status(cr) == CAIRO_STATUS_SUCCESS);
838
839 return cr;
840}
841
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100842/**
Daniel Vetter1503d172014-05-13 11:29:34 +0200843 * igt_write_fb_to_png:
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100844 * @fd: open i915 drm file descriptor
845 * @fb: pointer to an #igt_fb structure
846 * @filename: target name for the png image
847 *
848 * This function stores the contents of the supplied framebuffer into a png
849 * image stored at @filename.
850 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100851void igt_write_fb_to_png(int fd, struct igt_fb *fb, const char *filename)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100852{
853 cairo_surface_t *surface;
854 cairo_status_t status;
855
Daniel Vetterae461e62014-03-26 16:09:27 +0100856 surface = get_cairo_surface(fd, fb);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100857 status = cairo_surface_write_to_png(surface, filename);
858 cairo_surface_destroy(surface);
859
860 igt_assert(status == CAIRO_STATUS_SUCCESS);
861}
862
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100863/**
864 * igt_remove_fb:
865 * @fd: open i915 drm file descriptor
866 * @fb: pointer to an #igt_fb structure
867 *
868 * This function releases all resources allocated in igt_create_fb() for @fb.
869 * Note that if this framebuffer is still in use on a primary plane the kernel
870 * will disable the corresponding crtc.
871 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100872void igt_remove_fb(int fd, struct igt_fb *fb)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100873{
874 cairo_surface_destroy(fb->cairo_surface);
875 do_or_die(drmModeRmFB(fd, fb->fb_id));
876 gem_close(fd, fb->gem_handle);
877}
878
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100879/**
880 * igt_bpp_depth_to_drm_format:
881 * @bpp: desired bits per pixel
882 * @depth: desired depth
883 *
884 * Returns:
885 * The rgb drm fourcc pixel format code corresponding to the given @bpp and
886 * @depth values. Fails hard if no match was found.
887 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100888uint32_t igt_bpp_depth_to_drm_format(int bpp, int depth)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100889{
890 struct format_desc_struct *f;
891
892 for_each_format(f)
893 if (f->bpp == bpp && f->depth == depth)
894 return f->drm_id;
895
Damien Lespiau54397ca2014-08-19 11:40:07 +0100896
897 igt_assert_f(0, "can't find drm format with bpp=%d, depth=%d\n", bpp,
898 depth);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100899}
900
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100901/**
902 * igt_drm_format_to_bpp:
903 * @drm_format: drm fourcc pixel format code
904 *
905 * Returns:
906 * The bits per pixel for the given drm fourcc pixel format code. Fails hard if
907 * no match was found.
908 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100909uint32_t igt_drm_format_to_bpp(uint32_t drm_format)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100910{
911 struct format_desc_struct *f;
912
913 for_each_format(f)
914 if (f->drm_id == drm_format)
915 return f->bpp;
916
Damien Lespiau54397ca2014-08-19 11:40:07 +0100917 igt_assert_f(0, "can't find a bpp format for %08x (%s)\n",
918 drm_format, igt_format_str(drm_format));
Daniel Vetter57d7db82014-03-26 09:06:11 +0100919}
920
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100921/**
922 * igt_format_str:
923 * @drm_format: drm fourcc pixel format code
924 *
925 * Returns:
926 * Human-readable fourcc pixel format code for @drm_format or "invalid" no match
927 * was found.
928 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100929const char *igt_format_str(uint32_t drm_format)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100930{
931 struct format_desc_struct *f;
932
933 for_each_format(f)
934 if (f->drm_id == drm_format)
935 return f->name;
936
937 return "invalid";
938}
939
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100940/**
941 * igt_get_all_formats:
942 * @formats: pointer to pointer to store the allocated formats array
943 * @format_count: pointer to integer to store the size of the allocated array
944 *
945 * This functions returns an array of all the drm fourcc codes supported by this
946 * library. The caller must free the allocated array again with free().
947 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100948void igt_get_all_formats(const uint32_t **formats, int *format_count)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100949{
950 static uint32_t *drm_formats;
951
952 if (!drm_formats) {
953 struct format_desc_struct *f;
954 uint32_t *format;
955
956 drm_formats = calloc(ARRAY_SIZE(format_desc),
957 sizeof(*drm_formats));
958 format = &drm_formats[0];
959 for_each_format(f)
960 *format++ = f->drm_id;
961 }
962
963 *formats = drm_formats;
964 *format_count = ARRAY_SIZE(format_desc);
965}