blob: 1234ed9232629acb9e009d8639e580c4e8456851 [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,
Chris Wilsondb4cc742014-09-06 12:07:49 +010079 uint32_t *gem_handle_ret,
80 unsigned *size_ret,
81 unsigned *stride_ret)
Daniel Vetter57d7db82014-03-26 09:06:11 +010082{
83 uint32_t gem_handle;
Daniel Vettercc730c42014-03-11 16:14:33 +010084 int size, ret = 0;
Daniel Vetter57d7db82014-03-26 09:06:11 +010085 unsigned stride;
86
Tvrtko Ursuline36091d2015-03-03 14:11:01 +000087 if (tiling != LOCAL_DRM_FORMAT_MOD_NONE) {
Daniel Vetter57d7db82014-03-26 09:06:11 +010088 int v;
89
90 /* Round the tiling up to the next power-of-two and the
91 * region up to the next pot fence size so that this works
92 * on all generations.
93 *
94 * This can still fail if the framebuffer is too large to
95 * be tiled. But then that failure is expected.
96 */
97
98 v = width * bpp / 8;
99 for (stride = 512; stride < v; stride *= 2)
100 ;
101
102 v = stride * height;
103 for (size = 1024*1024; size < v; size *= 2)
104 ;
105 } else {
106 /* Scan-out has a 64 byte alignment restriction */
107 stride = (width * (bpp / 8) + 63) & ~63;
108 size = stride * height;
109 }
110
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100111 if (bo_size == 0)
112 bo_size = size;
113 gem_handle = gem_create(fd, bo_size);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100114
Damien Lespiauff451a62015-03-03 14:11:04 +0000115 if (tiling == LOCAL_I915_FORMAT_MOD_X_TILED)
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000116 ret = __gem_set_tiling(fd, gem_handle, I915_TILING_X, stride);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100117
118 *stride_ret = stride;
119 *size_ret = size;
120 *gem_handle_ret = gem_handle;
121
Daniel Vettercc730c42014-03-11 16:14:33 +0100122 return ret;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100123}
124
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100125/**
126 * igt_paint_color:
127 * @cr: cairo drawing context
128 * @x: pixel x-coordination of the fill rectangle
129 * @y: pixel y-coordination of the fill rectangle
130 * @w: width of the fill rectangle
131 * @h: height of the fill rectangle
132 * @r: red value to use as fill color
Thomas Woodd01ebbd2015-06-29 16:47:14 +0100133 * @g: green value to use as fill color
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100134 * @b: blue value to use as fill color
135 *
136 * This functions draws a solid rectangle with the given color using the drawing
137 * context @cr.
138 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100139void igt_paint_color(cairo_t *cr, int x, int y, int w, int h,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100140 double r, double g, double b)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100141{
142 cairo_rectangle(cr, x, y, w, h);
143 cairo_set_source_rgb(cr, r, g, b);
144 cairo_fill(cr);
145}
146
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100147/**
148 * igt_paint_color_alpha:
149 * @cr: cairo drawing context
150 * @x: pixel x-coordination of the fill rectangle
151 * @y: pixel y-coordination of the fill rectangle
152 * @w: width of the fill rectangle
153 * @h: height of the fill rectangle
154 * @r: red value to use as fill color
Thomas Woodd01ebbd2015-06-29 16:47:14 +0100155 * @g: green value to use as fill color
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100156 * @b: blue value to use as fill color
157 * @a: alpha value to use as fill color
158 *
159 * This functions draws a rectangle with the given color and alpha values using
160 * the drawing context @cr.
161 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100162void igt_paint_color_alpha(cairo_t *cr, int x, int y, int w, int h,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100163 double r, double g, double b, double a)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100164{
165 cairo_rectangle(cr, x, y, w, h);
166 cairo_set_source_rgba(cr, r, g, b, a);
167 cairo_fill(cr);
168}
169
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100170/**
171 * igt_paint_color_gradient:
172 * @cr: cairo drawing context
173 * @x: pixel x-coordination of the fill rectangle
174 * @y: pixel y-coordination of the fill rectangle
175 * @w: width of the fill rectangle
176 * @h: height of the fill rectangle
177 * @r: red value to use as fill color
Thomas Woodd01ebbd2015-06-29 16:47:14 +0100178 * @g: green value to use as fill color
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100179 * @b: blue value to use as fill color
180 *
181 * This functions draws a gradient into the rectangle which fades in from black
182 * to the given values using the drawing context @cr.
183 */
Daniel Vetter57d7db82014-03-26 09:06:11 +0100184void
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100185igt_paint_color_gradient(cairo_t *cr, int x, int y, int w, int h,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100186 int r, int g, int b)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100187{
188 cairo_pattern_t *pat;
189
190 pat = cairo_pattern_create_linear(x, y, x + w, y + h);
191 cairo_pattern_add_color_stop_rgba(pat, 1, 0, 0, 0, 1);
192 cairo_pattern_add_color_stop_rgba(pat, 0, r, g, b, 1);
193
194 cairo_rectangle(cr, x, y, w, h);
195 cairo_set_source(cr, pat);
196 cairo_fill(cr);
197 cairo_pattern_destroy(pat);
198}
199
200static void
201paint_test_patterns(cairo_t *cr, int width, int height)
202{
203 double gr_height, gr_width;
204 int x, y;
205
206 y = height * 0.10;
207 gr_width = width * 0.75;
208 gr_height = height * 0.08;
209 x = (width / 2) - (gr_width / 2);
210
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100211 igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 1, 0, 0);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100212
213 y += gr_height;
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100214 igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 0, 1, 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, 0, 1);
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, 1, 1, 1);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100221}
222
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100223/**
224 * igt_cairo_printf_line:
225 * @cr: cairo drawing context
226 * @align: text alignment
227 * @yspacing: additional y-direction feed after this line
228 * @fmt: format string
229 * @...: optional arguments used in the format string
230 *
231 * This is a little helper to draw text onto framebuffers. All the initial setup
232 * (like setting the font size and the moving to the starting position) still
233 * needs to be done manually with explicit cairo calls on @cr.
234 *
235 * Returns:
236 * The width of the drawn text.
237 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100238int igt_cairo_printf_line(cairo_t *cr, enum igt_text_align align,
Daniel Vetter57d7db82014-03-26 09:06:11 +0100239 double yspacing, const char *fmt, ...)
240{
241 double x, y, xofs, yofs;
242 cairo_text_extents_t extents;
243 char *text;
244 va_list ap;
245 int ret;
246
247 va_start(ap, fmt);
248 ret = vasprintf(&text, fmt, ap);
249 igt_assert(ret >= 0);
250 va_end(ap);
251
252 cairo_text_extents(cr, text, &extents);
253
254 xofs = yofs = 0;
255 if (align & align_right)
256 xofs = -extents.width;
257 else if (align & align_hcenter)
258 xofs = -extents.width / 2;
259
260 if (align & align_top)
261 yofs = extents.height;
262 else if (align & align_vcenter)
263 yofs = extents.height / 2;
264
265 cairo_get_current_point(cr, &x, &y);
266 if (xofs || yofs)
267 cairo_rel_move_to(cr, xofs, yofs);
268
269 cairo_text_path(cr, text);
270 cairo_set_source_rgb(cr, 0, 0, 0);
271 cairo_stroke_preserve(cr);
272 cairo_set_source_rgb(cr, 1, 1, 1);
273 cairo_fill(cr);
274
275 cairo_move_to(cr, x, y + extents.height + yspacing);
276
277 free(text);
278
279 return extents.width;
280}
281
282static void
283paint_marker(cairo_t *cr, int x, int y)
284{
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100285 enum igt_text_align align;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100286 int xoff, yoff;
287
288 cairo_move_to(cr, x, y - 20);
289 cairo_line_to(cr, x, y + 20);
290 cairo_move_to(cr, x - 20, y);
291 cairo_line_to(cr, x + 20, y);
292 cairo_new_sub_path(cr);
293 cairo_arc(cr, x, y, 10, 0, M_PI * 2);
294 cairo_set_line_width(cr, 4);
295 cairo_set_source_rgb(cr, 0, 0, 0);
296 cairo_stroke_preserve(cr);
297 cairo_set_source_rgb(cr, 1, 1, 1);
298 cairo_set_line_width(cr, 2);
299 cairo_stroke(cr);
300
301 xoff = x ? -20 : 20;
302 align = x ? align_right : align_left;
303
304 yoff = y ? -20 : 20;
305 align |= y ? align_bottom : align_top;
306
307 cairo_move_to(cr, x + xoff, y + yoff);
308 cairo_set_font_size(cr, 18);
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100309 igt_cairo_printf_line(cr, align, 0, "(%d, %d)", x, y);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100310}
311
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100312/**
313 * igt_paint_test_pattern:
314 * @cr: cairo drawing context
315 * @width: width of the visible area
316 * @height: height of the visible area
317 *
318 * This functions draws an entire set of test patterns for the given visible
319 * area using the drawing context @cr. This is useful for manual visual
320 * inspection of displayed framebuffers.
321 *
322 * The test patterns include
323 * - corner markers to check for over/underscan and
324 * - a set of color and b/w gradients.
325 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100326void igt_paint_test_pattern(cairo_t *cr, int width, int height)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100327{
328 paint_test_patterns(cr, width, height);
329
330 cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
331
332 /* Paint corner markers */
333 paint_marker(cr, 0, 0);
334 paint_marker(cr, width, 0);
335 paint_marker(cr, 0, height);
336 paint_marker(cr, width, height);
337
338 igt_assert(!cairo_status(cr));
339}
340
Thomas Woodecb03262015-04-13 17:37:22 +0100341static cairo_status_t
342stdio_read_func(void *closure, unsigned char* data, unsigned int size)
343{
344 if (fread(data, 1, size, (FILE*)closure) != size)
345 return CAIRO_STATUS_READ_ERROR;
346
347 return CAIRO_STATUS_SUCCESS;
348}
349
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100350/**
351 * igt_paint_image:
352 * @cr: cairo drawing context
353 * @filename: filename of the png image to draw
354 * @dst_x: pixel x-coordination of the destination rectangle
355 * @dst_y: pixel y-coordination of the destination rectangle
356 * @dst_width: width of the destination rectangle
357 * @dst_height: height of the destination rectangle
358 *
Thomas Woodecb03262015-04-13 17:37:22 +0100359 * This function can be used to draw a scaled version of the supplied png image,
360 * which is loaded from the package data directory.
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100361 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100362void igt_paint_image(cairo_t *cr, const char *filename,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100363 int dst_x, int dst_y, int dst_width, int dst_height)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100364{
365 cairo_surface_t *image;
366 int img_width, img_height;
367 double scale_x, scale_y;
Thomas Woodecb03262015-04-13 17:37:22 +0100368 FILE* f;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100369
Thomas Woodecb03262015-04-13 17:37:22 +0100370 f = igt_fopen_data(filename);
371
372 image = cairo_image_surface_create_from_png_stream(&stdio_read_func, f);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100373 igt_assert(cairo_surface_status(image) == CAIRO_STATUS_SUCCESS);
374
375 img_width = cairo_image_surface_get_width(image);
376 img_height = cairo_image_surface_get_height(image);
377
378 scale_x = (double)dst_width / img_width;
379 scale_y = (double)dst_height / img_height;
380
381 cairo_save(cr);
382
383 cairo_translate(cr, dst_x, dst_y);
384 cairo_scale(cr, scale_x, scale_y);
385 cairo_set_source_surface(cr, image, 0, 0);
386 cairo_paint(cr);
387
388 cairo_surface_destroy(image);
389
390 cairo_restore(cr);
Tvrtko Ursulinc317b782015-04-30 12:27:54 +0100391
392 fclose(f);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100393}
394
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100395/**
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100396 * igt_create_fb_with_bo_size:
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100397 * @fd: open i915 drm file descriptor
398 * @width: width of the framebuffer in pixel
399 * @height: height of the framebuffer in pixel
400 * @format: drm fourcc pixel format code
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000401 * @tiling: tiling layout of the framebuffer (as framebuffer modifier)
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100402 * @fb: pointer to an #igt_fb structure
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100403 * @bo_size: size of the backing bo (0 for minimum needed size)
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100404 *
405 * This function allocates a gem buffer object suitable to back a framebuffer
406 * with the requested properties and then wraps it up in a drm framebuffer
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100407 * object of the requested size. All metadata is stored in @fb.
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100408 *
409 * The backing storage of the framebuffer is filled with all zeros, i.e. black
410 * for rgb pixel formats.
411 *
412 * Returns:
Damien Lespiau50166d22014-08-19 11:55:22 +0100413 * The kms id of the created framebuffer.
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100414 */
Damien Lespiau378e61e2014-06-23 14:53:24 +0100415unsigned int
416igt_create_fb_with_bo_size(int fd, int width, int height,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000417 uint32_t format, uint64_t tiling,
Damien Lespiau378e61e2014-06-23 14:53:24 +0100418 struct igt_fb *fb, unsigned bo_size)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100419{
Daniel Vetter57d7db82014-03-26 09:06:11 +0100420 uint32_t fb_id;
421 int bpp;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100422
423 memset(fb, 0, sizeof(*fb));
424
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100425 bpp = igt_drm_format_to_bpp(format);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100426
Damien Lespiaudde047f2015-03-12 14:31:15 +0000427 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 +0100428 __func__, width, height, format, bpp, tiling, bo_size);
429 do_or_die(create_bo_for_fb(fd, width, height, bpp, tiling, bo_size,
430 &fb->gem_handle, &fb->size, &fb->stride));
431
Chris Wilsondb4cc742014-09-06 12:07:49 +0100432 igt_debug("%s(handle=%d, pitch=%d)\n",
Tvrtko Ursulineb93c1b2015-03-03 14:11:03 +0000433 __func__, fb->gem_handle, fb->stride);
434
435 if (tiling != LOCAL_DRM_FORMAT_MOD_NONE &&
436 tiling != LOCAL_I915_FORMAT_MOD_X_TILED) {
437 do_or_die(__kms_addfb(fd, fb->gem_handle, width, height,
438 fb->stride, format, tiling,
439 LOCAL_DRM_MODE_FB_MODIFIERS, &fb_id));
440 } else {
441 uint32_t handles[4];
442 uint32_t pitches[4];
443 uint32_t offsets[4];
444
445 memset(handles, 0, sizeof(handles));
446 memset(pitches, 0, sizeof(pitches));
447 memset(offsets, 0, sizeof(offsets));
448
449 handles[0] = fb->gem_handle;
450 pitches[0] = fb->stride;
451
452 do_or_die(drmModeAddFB2(fd, width, height, format,
453 handles, pitches, offsets,
454 &fb_id, 0));
455 }
Daniel Vetter57d7db82014-03-26 09:06:11 +0100456
457 fb->width = width;
458 fb->height = height;
Damien Lespiau378e61e2014-06-23 14:53:24 +0100459 fb->tiling = tiling;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100460 fb->drm_format = format;
461 fb->fb_id = fb_id;
462
463 return fb_id;
464}
465
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100466/**
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100467 * igt_create_fb:
468 * @fd: open i915 drm file descriptor
469 * @width: width of the framebuffer in pixel
470 * @height: height of the framebuffer in pixel
471 * @format: drm fourcc pixel format code
Damien Lespiau378e61e2014-06-23 14:53:24 +0100472 * @tiling: tiling layout of the framebuffer
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100473 * @fb: pointer to an #igt_fb structure
474 *
475 * This function allocates a gem buffer object suitable to back a framebuffer
476 * with the requested properties and then wraps it up in a drm framebuffer
477 * object. All metadata is stored in @fb.
478 *
479 * The backing storage of the framebuffer is filled with all zeros, i.e. black
480 * for rgb pixel formats.
481 *
482 * Returns:
Damien Lespiau50166d22014-08-19 11:55:22 +0100483 * The kms id of the created framebuffer.
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100484 */
485unsigned int igt_create_fb(int fd, int width, int height, uint32_t format,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000486 uint64_t tiling, struct igt_fb *fb)
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100487{
Damien Lespiau378e61e2014-06-23 14:53:24 +0100488 return igt_create_fb_with_bo_size(fd, width, height, format, tiling, fb, 0);
Oscar Mateo5bdd4d92014-05-16 14:07:11 +0100489}
490
491/**
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100492 * igt_create_color_fb:
493 * @fd: open i915 drm file descriptor
494 * @width: width of the framebuffer in pixel
495 * @height: height of the framebuffer in pixel
496 * @format: drm fourcc pixel format code
Damien Lespiau378e61e2014-06-23 14:53:24 +0100497 * @tiling: tiling layout of the framebuffer
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100498 * @r: red value to use as fill color
499 * @g: gree value to use as fill color
500 * @b: blue value to use as fill color
501 * @fb: pointer to an #igt_fb structure
502 *
503 * This function allocates a gem buffer object suitable to back a framebuffer
504 * with the requested properties and then wraps it up in a drm framebuffer
505 * object. All metadata is stored in @fb.
506 *
507 * Compared to igt_create_fb() this function also fills the entire framebuffer
508 * with the given color, which is useful for some simple pipe crc based tests.
509 *
510 * Returns:
511 * The kms id of the created framebuffer on success or a negative error code on
512 * failure.
513 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100514unsigned int igt_create_color_fb(int fd, int width, int height,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000515 uint32_t format, uint64_t tiling,
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100516 double r, double g, double b,
517 struct igt_fb *fb /* out */)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100518{
519 unsigned int fb_id;
520 cairo_t *cr;
521
Damien Lespiau378e61e2014-06-23 14:53:24 +0100522 fb_id = igt_create_fb(fd, width, height, format, tiling, fb);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100523 igt_assert(fb_id);
524
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100525 cr = igt_get_cairo_ctx(fd, fb);
526 igt_paint_color(cr, 0, 0, width, height, r, g, b);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100527 igt_assert(cairo_status(cr) == 0);
528 cairo_destroy(cr);
529
530 return fb_id;
531}
532
Thomas Wood4cb19462014-08-04 16:14:51 +0100533struct box {
534 int x, y, width, height;
535};
536
537struct stereo_fb_layout {
538 int fb_width, fb_height;
539 struct box left, right;
540};
541
542static void box_init(struct box *box, int x, int y, int bwidth, int bheight)
543{
544 box->x = x;
545 box->y = y;
546 box->width = bwidth;
547 box->height = bheight;
548}
549
550
551static void stereo_fb_layout_from_mode(struct stereo_fb_layout *layout,
552 drmModeModeInfo *mode)
553{
554 unsigned int format = mode->flags & DRM_MODE_FLAG_3D_MASK;
555 const int hdisplay = mode->hdisplay, vdisplay = mode->vdisplay;
556 int middle;
557
558 switch (format) {
559 case DRM_MODE_FLAG_3D_TOP_AND_BOTTOM:
560 layout->fb_width = hdisplay;
561 layout->fb_height = vdisplay;
562
563 middle = vdisplay / 2;
564 box_init(&layout->left, 0, 0, hdisplay, middle);
565 box_init(&layout->right,
566 0, middle, hdisplay, vdisplay - middle);
567 break;
568 case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF:
569 layout->fb_width = hdisplay;
570 layout->fb_height = vdisplay;
571
572 middle = hdisplay / 2;
573 box_init(&layout->left, 0, 0, middle, vdisplay);
574 box_init(&layout->right,
575 middle, 0, hdisplay - middle, vdisplay);
576 break;
577 case DRM_MODE_FLAG_3D_FRAME_PACKING:
578 {
579 int vactive_space = mode->vtotal - vdisplay;
580
581 layout->fb_width = hdisplay;
582 layout->fb_height = 2 * vdisplay + vactive_space;
583
584 box_init(&layout->left,
585 0, 0, hdisplay, vdisplay);
586 box_init(&layout->right,
587 0, vdisplay + vactive_space, hdisplay, vdisplay);
588 break;
589 }
590 default:
591 igt_assert(0);
592 }
593}
594
595/**
596 * igt_create_stereo_fb:
597 * @drm_fd: open i915 drm file descriptor
598 * @mode: A stereo 3D mode.
599 * @format: drm fourcc pixel format code
600 * @tiling: tiling layout of the framebuffer
601 *
602 * Create a framebuffer for use with the stereo 3D mode specified by @mode.
603 *
604 * Returns:
605 * The kms id of the created framebuffer on success or a negative error code on
606 * failure.
607 */
608unsigned int igt_create_stereo_fb(int drm_fd, drmModeModeInfo *mode,
Tvrtko Ursuline36091d2015-03-03 14:11:01 +0000609 uint32_t format, uint64_t tiling)
Thomas Wood4cb19462014-08-04 16:14:51 +0100610{
611 struct stereo_fb_layout layout;
612 cairo_t *cr;
613 uint32_t fb_id;
614 struct igt_fb fb;
615
616 stereo_fb_layout_from_mode(&layout, mode);
617 fb_id = igt_create_fb(drm_fd, layout.fb_width, layout.fb_height, format,
618 tiling, &fb);
619 cr = igt_get_cairo_ctx(drm_fd, &fb);
620
Thomas Woodecb03262015-04-13 17:37:22 +0100621 igt_paint_image(cr, "1080p-left.png",
Thomas Wood4cb19462014-08-04 16:14:51 +0100622 layout.left.x, layout.left.y,
623 layout.left.width, layout.left.height);
Thomas Woodecb03262015-04-13 17:37:22 +0100624 igt_paint_image(cr, "1080p-right.png",
Thomas Wood4cb19462014-08-04 16:14:51 +0100625 layout.right.x, layout.right.y,
626 layout.right.width, layout.right.height);
627
628 cairo_destroy(cr);
629
630 return fb_id;
631}
632
Daniel Vetter57d7db82014-03-26 09:06:11 +0100633static cairo_format_t drm_format_to_cairo(uint32_t drm_format)
634{
635 struct format_desc_struct *f;
636
637 for_each_format(f)
638 if (f->drm_id == drm_format)
639 return f->cairo_id;
640
Damien Lespiau54397ca2014-08-19 11:40:07 +0100641 igt_assert_f(0, "can't find a cairo format for %08x (%s)\n",
642 drm_format, igt_format_str(drm_format));
Daniel Vetter57d7db82014-03-26 09:06:11 +0100643}
644
Damien Lespiauff451a62015-03-03 14:11:04 +0000645struct fb_blit_upload {
646 int fd;
647 struct igt_fb *fb;
648 struct {
649 uint32_t handle;
650 unsigned size, stride;
651 uint8_t *map;
652 } linear;
653};
654
Tvrtko Ursulin30a13602015-04-29 13:24:34 +0100655static unsigned int fb_mod_to_obj_tiling(uint64_t fb_mod)
656{
657 switch (fb_mod) {
658 case LOCAL_DRM_FORMAT_MOD_NONE:
659 return I915_TILING_NONE;
660 case LOCAL_I915_FORMAT_MOD_X_TILED:
661 return I915_TILING_X;
662 case LOCAL_I915_FORMAT_MOD_Y_TILED:
663 return I915_TILING_Y;
664 case LOCAL_I915_FORMAT_MOD_Yf_TILED:
665 return I915_TILING_Yf;
666 default:
667 igt_assert(0);
668 }
669}
670
Damien Lespiauff451a62015-03-03 14:11:04 +0000671static void destroy_cairo_surface__blit(void *arg)
672{
673 struct fb_blit_upload *blit = arg;
674 struct igt_fb *fb = blit->fb;
Tvrtko Ursulin30a13602015-04-29 13:24:34 +0100675 unsigned int obj_tiling = fb_mod_to_obj_tiling(fb->tiling);
Damien Lespiauff451a62015-03-03 14:11:04 +0000676
677 munmap(blit->linear.map, blit->linear.size);
678 fb->cairo_surface = NULL;
679
680 gem_set_domain(blit->fd, blit->linear.handle,
681 I915_GEM_DOMAIN_GTT, 0);
682
Damien Lespiauff451a62015-03-03 14:11:04 +0000683 igt_blitter_fast_copy__raw(blit->fd,
684 blit->linear.handle,
685 blit->linear.stride,
686 I915_TILING_NONE,
687 0, 0, /* src_x, src_y */
688 fb->width, fb->height,
689 fb->gem_handle,
690 fb->stride,
691 obj_tiling,
692 0, 0 /* dst_x, dst_y */);
693
694 gem_sync(blit->fd, blit->linear.handle);
695 gem_close(blit->fd, blit->linear.handle);
696
697 free(blit);
698}
699
700static void create_cairo_surface__blit(int fd, struct igt_fb *fb)
701{
702 struct fb_blit_upload *blit;
703 cairo_format_t cairo_format;
Tvrtko Ursulin30a13602015-04-29 13:24:34 +0100704 unsigned int obj_tiling = fb_mod_to_obj_tiling(fb->tiling);
Damien Lespiauff451a62015-03-03 14:11:04 +0000705 int bpp, ret;
706
707 blit = malloc(sizeof(*blit));
708 igt_assert(blit);
709
710 /*
711 * We create a linear BO that we'll map for the CPU to write to (using
712 * cairo). This linear bo will be then blitted to its final
713 * destination, tiling it at the same time.
714 */
715 bpp = igt_drm_format_to_bpp(fb->drm_format);
716 ret = create_bo_for_fb(fd, fb->width, fb->height, bpp,
717 LOCAL_DRM_FORMAT_MOD_NONE, 0,
718 &blit->linear.handle,
719 &blit->linear.size,
720 &blit->linear.stride);
721
722 igt_assert(ret == 0);
723
724 blit->fd = fd;
725 blit->fb = fb;
Tvrtko Ursulin30a13602015-04-29 13:24:34 +0100726
727 /* Copy fb content to linear BO */
728 gem_set_domain(fd, blit->linear.handle,
729 I915_GEM_DOMAIN_GTT, 0);
730
731 igt_blitter_fast_copy__raw(fd,
732 fb->gem_handle,
733 fb->stride,
734 obj_tiling,
735 0, 0, /* src_x, src_y */
736 fb->width, fb->height,
737 blit->linear.handle,
738 blit->linear.stride,
739 I915_TILING_NONE,
740 0, 0 /* dst_x, dst_y */);
741
742 gem_sync(fd, blit->linear.handle);
743
744 gem_set_domain(fd, blit->linear.handle,
745 I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
746
747 /* Setup cairo context */
Damien Lespiauff451a62015-03-03 14:11:04 +0000748 blit->linear.map = gem_mmap__cpu(fd,
749 blit->linear.handle,
750 0,
751 blit->linear.size,
752 PROT_READ | PROT_WRITE);
753 igt_assert(blit->linear.map);
754
Damien Lespiauff451a62015-03-03 14:11:04 +0000755 cairo_format = drm_format_to_cairo(fb->drm_format);
756 fb->cairo_surface =
757 cairo_image_surface_create_for_data(blit->linear.map,
758 cairo_format,
759 fb->width, fb->height,
760 blit->linear.stride);
761
762 cairo_surface_set_user_data(fb->cairo_surface,
763 (cairo_user_data_key_t *)create_cairo_surface__blit,
764 blit, destroy_cairo_surface__blit);
765}
766
Damien Lespiau4aadbc82014-06-23 16:41:43 +0100767static void destroy_cairo_surface__gtt(void *arg)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100768{
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100769 struct igt_fb *fb = arg;
Damien Lespiau72357f32014-07-11 14:45:37 +0100770
Daniel Vetter57d7db82014-03-26 09:06:11 +0100771 munmap(cairo_image_surface_get_data(fb->cairo_surface), fb->size);
Damien Lespiau72357f32014-07-11 14:45:37 +0100772 fb->cairo_surface = NULL;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100773}
774
Damien Lespiau4aadbc82014-06-23 16:41:43 +0100775static void create_cairo_surface__gtt(int fd, struct igt_fb *fb)
776{
777 fb->cairo_surface =
778 cairo_image_surface_create_for_data(gem_mmap(fd, fb->gem_handle, fb->size, PROT_READ | PROT_WRITE),
779 drm_format_to_cairo(fb->drm_format),
780 fb->width, fb->height, fb->stride);
781
782 cairo_surface_set_user_data(fb->cairo_surface,
783 (cairo_user_data_key_t *)create_cairo_surface__gtt,
784 fb, destroy_cairo_surface__gtt);
785}
786
Daniel Vetterae461e62014-03-26 16:09:27 +0100787static cairo_surface_t *get_cairo_surface(int fd, struct igt_fb *fb)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100788{
Damien Lespiauff451a62015-03-03 14:11:04 +0000789 if (fb->cairo_surface == NULL) {
790 if (fb->tiling == LOCAL_I915_FORMAT_MOD_Y_TILED ||
791 fb->tiling == LOCAL_I915_FORMAT_MOD_Yf_TILED)
792 create_cairo_surface__blit(fd, fb);
793 else
794 create_cairo_surface__gtt(fd, fb);
795 }
Daniel Vetter57d7db82014-03-26 09:06:11 +0100796
797 gem_set_domain(fd, fb->gem_handle,
798 I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
799
800 igt_assert(cairo_surface_status(fb->cairo_surface) == CAIRO_STATUS_SUCCESS);
Damien Lespiau0db75bb2014-06-30 16:34:20 +0100801 return fb->cairo_surface;
Daniel Vetter57d7db82014-03-26 09:06:11 +0100802}
803
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100804/**
805 * igt_get_cairo_ctx:
806 * @fd: open i915 drm file descriptor
807 * @fb: pointer to an #igt_fb structure
808 *
809 * This initializes a cairo surface for @fb and then allocates a drawing context
810 * for it. The return cairo drawing context should be released by calling
811 * cairo_destroy(). This also sets a default font for drawing text on
812 * framebuffers.
813 *
814 * Returns:
815 * The created cairo drawing context.
816 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100817cairo_t *igt_get_cairo_ctx(int fd, struct igt_fb *fb)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100818{
819 cairo_surface_t *surface;
820 cairo_t *cr;
821
Daniel Vetterae461e62014-03-26 16:09:27 +0100822 surface = get_cairo_surface(fd, fb);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100823 cr = cairo_create(surface);
824 cairo_surface_destroy(surface);
Daniel Vetter7568edf2014-03-26 16:36:46 +0100825 igt_assert(cairo_status(cr) == CAIRO_STATUS_SUCCESS);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100826
Daniel Vetter7568edf2014-03-26 16:36:46 +0100827 cairo_select_font_face(cr, "Helvetica", CAIRO_FONT_SLANT_NORMAL,
828 CAIRO_FONT_WEIGHT_NORMAL);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100829 igt_assert(cairo_status(cr) == CAIRO_STATUS_SUCCESS);
830
831 return cr;
832}
833
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100834/**
Daniel Vetter1503d172014-05-13 11:29:34 +0200835 * igt_write_fb_to_png:
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100836 * @fd: open i915 drm file descriptor
837 * @fb: pointer to an #igt_fb structure
838 * @filename: target name for the png image
839 *
840 * This function stores the contents of the supplied framebuffer into a png
841 * image stored at @filename.
842 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100843void igt_write_fb_to_png(int fd, struct igt_fb *fb, const char *filename)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100844{
845 cairo_surface_t *surface;
846 cairo_status_t status;
847
Daniel Vetterae461e62014-03-26 16:09:27 +0100848 surface = get_cairo_surface(fd, fb);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100849 status = cairo_surface_write_to_png(surface, filename);
850 cairo_surface_destroy(surface);
851
852 igt_assert(status == CAIRO_STATUS_SUCCESS);
853}
854
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100855/**
856 * igt_remove_fb:
857 * @fd: open i915 drm file descriptor
858 * @fb: pointer to an #igt_fb structure
859 *
860 * This function releases all resources allocated in igt_create_fb() for @fb.
861 * Note that if this framebuffer is still in use on a primary plane the kernel
862 * will disable the corresponding crtc.
863 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100864void igt_remove_fb(int fd, struct igt_fb *fb)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100865{
866 cairo_surface_destroy(fb->cairo_surface);
867 do_or_die(drmModeRmFB(fd, fb->fb_id));
868 gem_close(fd, fb->gem_handle);
869}
870
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100871/**
872 * igt_bpp_depth_to_drm_format:
873 * @bpp: desired bits per pixel
874 * @depth: desired depth
875 *
876 * Returns:
877 * The rgb drm fourcc pixel format code corresponding to the given @bpp and
878 * @depth values. Fails hard if no match was found.
879 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100880uint32_t igt_bpp_depth_to_drm_format(int bpp, int depth)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100881{
882 struct format_desc_struct *f;
883
884 for_each_format(f)
885 if (f->bpp == bpp && f->depth == depth)
886 return f->drm_id;
887
Damien Lespiau54397ca2014-08-19 11:40:07 +0100888
889 igt_assert_f(0, "can't find drm format with bpp=%d, depth=%d\n", bpp,
890 depth);
Daniel Vetter57d7db82014-03-26 09:06:11 +0100891}
892
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100893/**
894 * igt_drm_format_to_bpp:
895 * @drm_format: drm fourcc pixel format code
896 *
897 * Returns:
898 * The bits per pixel for the given drm fourcc pixel format code. Fails hard if
899 * no match was found.
900 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100901uint32_t igt_drm_format_to_bpp(uint32_t drm_format)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100902{
903 struct format_desc_struct *f;
904
905 for_each_format(f)
906 if (f->drm_id == drm_format)
907 return f->bpp;
908
Damien Lespiau54397ca2014-08-19 11:40:07 +0100909 igt_assert_f(0, "can't find a bpp format for %08x (%s)\n",
910 drm_format, igt_format_str(drm_format));
Daniel Vetter57d7db82014-03-26 09:06:11 +0100911}
912
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100913/**
914 * igt_format_str:
915 * @drm_format: drm fourcc pixel format code
916 *
917 * Returns:
918 * Human-readable fourcc pixel format code for @drm_format or "invalid" no match
919 * was found.
920 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100921const char *igt_format_str(uint32_t drm_format)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100922{
923 struct format_desc_struct *f;
924
925 for_each_format(f)
926 if (f->drm_id == drm_format)
927 return f->name;
928
929 return "invalid";
930}
931
Daniel Vetter3d9e63f2014-03-26 16:37:15 +0100932/**
933 * igt_get_all_formats:
934 * @formats: pointer to pointer to store the allocated formats array
935 * @format_count: pointer to integer to store the size of the allocated array
936 *
937 * This functions returns an array of all the drm fourcc codes supported by this
938 * library. The caller must free the allocated array again with free().
939 */
Daniel Vetter9aea7ae2014-03-26 09:18:11 +0100940void igt_get_all_formats(const uint32_t **formats, int *format_count)
Daniel Vetter57d7db82014-03-26 09:06:11 +0100941{
942 static uint32_t *drm_formats;
943
944 if (!drm_formats) {
945 struct format_desc_struct *f;
946 uint32_t *format;
947
948 drm_formats = calloc(ARRAY_SIZE(format_desc),
949 sizeof(*drm_formats));
950 format = &drm_formats[0];
951 for_each_format(f)
952 *format++ = f->drm_id;
953 }
954
955 *formats = drm_formats;
956 *format_count = ARRAY_SIZE(format_desc);
957}