igt_fb.c 78.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
/*
 * Copyright © 2013,2014 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 *
 * Authors:
 * 	Daniel Vetter <daniel.vetter@ffwll.ch>
 * 	Damien Lespiau <damien.lespiau@intel.com>
 */

#include <stdio.h>
#include <math.h>
30
#include <wchar.h>
31
#include <inttypes.h>
32
#include <pixman.h>
33 34

#include "drmtest.h"
35
#include "igt_aux.h"
36
#include "igt_color_encoding.h"
37
#include "igt_fb.h"
38
#include "igt_kms.h"
39
#include "igt_matrix.h"
40
#include "igt_vc4.h"
41
#include "igt_x86.h"
42
#include "ioctl_wrappers.h"
43
#include "intel_batchbuffer.h"
44
#include "intel_chipset.h"
45
#include "i915/gem_mman.h"
46

47 48 49
/**
 * SECTION:igt_fb
 * @short_description: Framebuffer handling and drawing library
50
 * @title: Framebuffer
51
 * @include: igt.h
52 53 54
 *
 * This library contains helper functions for handling kms framebuffer objects
 * using #igt_fb structures to track all the metadata.  igt_create_fb() creates
55
 * a basic framebuffer and igt_remove_fb() cleans everything up again.
56 57 58 59 60 61 62
 *
 * It also supports drawing using the cairo library and provides some simplified
 * helper functions to easily draw test patterns. The main function to create a
 * cairo drawing context for a framebuffer object is igt_get_cairo_ctx().
 *
 * Finally it also pulls in the drm fourcc headers and provides some helper
 * functions to work with these pixel format codes.
63 64
 */

65 66
#define PIXMAN_invalid	0

67 68 69 70 71 72 73 74 75 76 77 78 79 80
#if CAIRO_VERSION < CAIRO_VERSION_ENCODE(1, 17, 2)
/*
 * We need cairo 1.17.2 to use HDR formats, but the only thing added is a value
 * to cairo_format_t.
 *
 * To prevent going outside the enum, make cairo_format_t an int and define
 * ourselves.
 */

#define CAIRO_FORMAT_RGB96F (6)
#define CAIRO_FORMAT_RGBA128F (7)
#define cairo_format_t int
#endif

81
/* drm fourcc/cairo format maps */
82
static const struct format_desc_struct {
83
	const char *name;
84 85
	uint32_t drm_id;
	cairo_format_t cairo_id;
86
	pixman_format_code_t pixman_id;
87
	int depth;
88
	int num_planes;
89
	int plane_bpp[4];
90 91
	uint8_t hsub;
	uint8_t vsub;
92
} format_desc[] = {
Maxime Ripard's avatar
Maxime Ripard committed
93 94 95 96
	{ .name = "ARGB1555", .depth = -1, .drm_id = DRM_FORMAT_ARGB1555,
	  .cairo_id = CAIRO_FORMAT_INVALID,
	  .pixman_id = PIXMAN_a1r5g5b5,
	  .num_planes = 1, .plane_bpp = { 16, },
97
	  .hsub = 1, .vsub = 1,
Maxime Ripard's avatar
Maxime Ripard committed
98 99 100 101 102
	},
	{ .name = "XRGB1555", .depth = -1, .drm_id = DRM_FORMAT_XRGB1555,
	  .cairo_id = CAIRO_FORMAT_INVALID,
	  .pixman_id = PIXMAN_x1r5g5b5,
	  .num_planes = 1, .plane_bpp = { 16, },
103
	  .hsub = 1, .vsub = 1,
Maxime Ripard's avatar
Maxime Ripard committed
104
	},
105 106
	{ .name = "RGB565", .depth = 16, .drm_id = DRM_FORMAT_RGB565,
	  .cairo_id = CAIRO_FORMAT_RGB16_565,
107
	  .pixman_id = PIXMAN_r5g6b5,
108
	  .num_planes = 1, .plane_bpp = { 16, },
109
	  .hsub = 1, .vsub = 1,
110
	},
Maxime Ripard's avatar
Maxime Ripard committed
111 112 113 114
	{ .name = "BGR565", .depth = -1, .drm_id = DRM_FORMAT_BGR565,
	  .cairo_id = CAIRO_FORMAT_INVALID,
	  .pixman_id = PIXMAN_b5g6r5,
	  .num_planes = 1, .plane_bpp = { 16, },
115
	  .hsub = 1, .vsub = 1,
Maxime Ripard's avatar
Maxime Ripard committed
116 117 118 119 120
	},
	{ .name = "BGR888", .depth = -1, .drm_id = DRM_FORMAT_BGR888,
	  .cairo_id = CAIRO_FORMAT_INVALID,
	  .pixman_id = PIXMAN_b8g8r8,
	  .num_planes = 1, .plane_bpp = { 24, },
121
	  .hsub = 1, .vsub = 1,
Maxime Ripard's avatar
Maxime Ripard committed
122
	},
Maxime Ripard's avatar
Maxime Ripard committed
123 124
	{ .name = "RGB888", .depth = -1, .drm_id = DRM_FORMAT_RGB888,
	  .cairo_id = CAIRO_FORMAT_INVALID,
125
	  .pixman_id = PIXMAN_r8g8b8,
Maxime Ripard's avatar
Maxime Ripard committed
126
	  .num_planes = 1, .plane_bpp = { 24, },
127
	  .hsub = 1, .vsub = 1,
Maxime Ripard's avatar
Maxime Ripard committed
128
	},
129 130 131
	{ .name = "XYUV8888", .depth = -1, .drm_id = DRM_FORMAT_XYUV8888,
	  .cairo_id = CAIRO_FORMAT_RGB24,
	  .num_planes = 1, .plane_bpp = { 32, },
132
	  .hsub = 1, .vsub = 1,
133
	},
134 135
	{ .name = "XRGB8888", .depth = 24, .drm_id = DRM_FORMAT_XRGB8888,
	  .cairo_id = CAIRO_FORMAT_RGB24,
136
	  .pixman_id = PIXMAN_x8r8g8b8,
137
	  .num_planes = 1, .plane_bpp = { 32, },
138
	  .hsub = 1, .vsub = 1,
139
	},
Maxime Ripard's avatar
Maxime Ripard committed
140 141 142 143
	{ .name = "XBGR8888", .depth = -1, .drm_id = DRM_FORMAT_XBGR8888,
	  .cairo_id = CAIRO_FORMAT_INVALID,
	  .pixman_id = PIXMAN_x8b8g8r8,
	  .num_planes = 1, .plane_bpp = { 32, },
144
	  .hsub = 1, .vsub = 1,
Maxime Ripard's avatar
Maxime Ripard committed
145
	},
146 147
	{ .name = "XRGB2101010", .depth = 30, .drm_id = DRM_FORMAT_XRGB2101010,
	  .cairo_id = CAIRO_FORMAT_RGB30,
148
	  .pixman_id = PIXMAN_x2r10g10b10,
149
	  .num_planes = 1, .plane_bpp = { 32, },
150
	  .hsub = 1, .vsub = 1,
151 152 153
	},
	{ .name = "ARGB8888", .depth = 32, .drm_id = DRM_FORMAT_ARGB8888,
	  .cairo_id = CAIRO_FORMAT_ARGB32,
154
	  .pixman_id = PIXMAN_a8r8g8b8,
155
	  .num_planes = 1, .plane_bpp = { 32, },
156
	  .hsub = 1, .vsub = 1,
157
	},
Maxime Ripard's avatar
Maxime Ripard committed
158 159 160 161
	{ .name = "ABGR8888", .depth = -1, .drm_id = DRM_FORMAT_ABGR8888,
	  .cairo_id = CAIRO_FORMAT_INVALID,
	  .pixman_id = PIXMAN_a8b8g8r8,
	  .num_planes = 1, .plane_bpp = { 32, },
162
	  .hsub = 1, .vsub = 1,
Maxime Ripard's avatar
Maxime Ripard committed
163
	},
164 165 166
	{ .name = "NV12", .depth = -1, .drm_id = DRM_FORMAT_NV12,
	  .cairo_id = CAIRO_FORMAT_RGB24,
	  .num_planes = 2, .plane_bpp = { 8, 16, },
167
	  .hsub = 2, .vsub = 2,
168
	},
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
	{ .name = "NV16", .depth = -1, .drm_id = DRM_FORMAT_NV16,
	  .cairo_id = CAIRO_FORMAT_RGB24,
	  .num_planes = 2, .plane_bpp = { 8, 16, },
	  .hsub = 2, .vsub = 1,
	},
	{ .name = "NV21", .depth = -1, .drm_id = DRM_FORMAT_NV21,
	  .cairo_id = CAIRO_FORMAT_RGB24,
	  .num_planes = 2, .plane_bpp = { 8, 16, },
	  .hsub = 2, .vsub = 2,
	},
	{ .name = "NV61", .depth = -1, .drm_id = DRM_FORMAT_NV61,
	  .cairo_id = CAIRO_FORMAT_RGB24,
	  .num_planes = 2, .plane_bpp = { 8, 16, },
	  .hsub = 2, .vsub = 1,
	},
184 185 186
	{ .name = "YUYV", .depth = -1, .drm_id = DRM_FORMAT_YUYV,
	  .cairo_id = CAIRO_FORMAT_RGB24,
	  .num_planes = 1, .plane_bpp = { 16, },
187
	  .hsub = 2, .vsub = 1,
188 189 190 191
	},
	{ .name = "YVYU", .depth = -1, .drm_id = DRM_FORMAT_YVYU,
	  .cairo_id = CAIRO_FORMAT_RGB24,
	  .num_planes = 1, .plane_bpp = { 16, },
192
	  .hsub = 2, .vsub = 1,
193 194 195 196
	},
	{ .name = "UYVY", .depth = -1, .drm_id = DRM_FORMAT_UYVY,
	  .cairo_id = CAIRO_FORMAT_RGB24,
	  .num_planes = 1, .plane_bpp = { 16, },
197
	  .hsub = 2, .vsub = 1,
198 199 200 201
	},
	{ .name = "VYUY", .depth = -1, .drm_id = DRM_FORMAT_VYUY,
	  .cairo_id = CAIRO_FORMAT_RGB24,
	  .num_planes = 1, .plane_bpp = { 16, },
202
	  .hsub = 2, .vsub = 1,
203
	},
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
	{ .name = "YU12", .depth = -1, .drm_id = DRM_FORMAT_YUV420,
	  .cairo_id = CAIRO_FORMAT_RGB24,
	  .num_planes = 3, .plane_bpp = { 8, 8, 8, },
	  .hsub = 2, .vsub = 2,
	},
	{ .name = "YU16", .depth = -1, .drm_id = DRM_FORMAT_YUV422,
	  .cairo_id = CAIRO_FORMAT_RGB24,
	  .num_planes = 3, .plane_bpp = { 8, 8, 8, },
	  .hsub = 2, .vsub = 1,
	},
	{ .name = "YV12", .depth = -1, .drm_id = DRM_FORMAT_YVU420,
	  .cairo_id = CAIRO_FORMAT_RGB24,
	  .num_planes = 3, .plane_bpp = { 8, 8, 8, },
	  .hsub = 2, .vsub = 2,
	},
	{ .name = "YV16", .depth = -1, .drm_id = DRM_FORMAT_YVU422,
	  .cairo_id = CAIRO_FORMAT_RGB24,
	  .num_planes = 3, .plane_bpp = { 8, 8, 8, },
	  .hsub = 2, .vsub = 1,
	},
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
	{ .name = "P010", .depth = -1, .drm_id = DRM_FORMAT_P010,
	  .cairo_id = CAIRO_FORMAT_RGB96F,
	  .num_planes = 2, .plane_bpp = { 16, 32 },
	  .vsub = 2, .hsub = 2,
	},
	{ .name = "P012", .depth = -1, .drm_id = DRM_FORMAT_P012,
	  .cairo_id = CAIRO_FORMAT_RGB96F,
	  .num_planes = 2, .plane_bpp = { 16, 32 },
	  .vsub = 2, .hsub = 2,
	},
	{ .name = "P016", .depth = -1, .drm_id = DRM_FORMAT_P016,
	  .cairo_id = CAIRO_FORMAT_RGB96F,
	  .num_planes = 2, .plane_bpp = { 16, 32 },
	  .vsub = 2, .hsub = 2,
	},
	{ .name = "IGT-FLOAT", .depth = -1, .drm_id = IGT_FORMAT_FLOAT,
	  .cairo_id = CAIRO_FORMAT_INVALID,
	  .num_planes = 1, .plane_bpp = { 128 },
	},
243 244 245 246
};
#define for_each_format(f)	\
	for (f = format_desc; f - format_desc < ARRAY_SIZE(format_desc); f++)

247
static const struct format_desc_struct *lookup_drm_format(uint32_t drm_format)
248
{
249
	const struct format_desc_struct *format;
250 251 252 253 254 255 256 257 258 259 260

	for_each_format(format) {
		if (format->drm_id != drm_format)
			continue;

		return format;
	}

	return NULL;
}

261 262 263
/**
 * igt_get_fb_tile_size:
 * @fd: the DRM file descriptor
264
 * @modifier: tiling layout of the framebuffer (as framebuffer modifier)
265 266 267 268 269 270 271
 * @fb_bpp: bits per pixel of the framebuffer
 * @width_ret: width of the tile in bytes
 * @height_ret: height of the tile in lines
 *
 * This function returns width and height of a tile based on the given tiling
 * format.
 */
272
void igt_get_fb_tile_size(int fd, uint64_t modifier, int fb_bpp,
273
			  unsigned *width_ret, unsigned *height_ret)
274
{
275
	uint32_t vc4_modifier_param = 0;
276 277

	if (is_vc4_device(fd)) {
278 279
		vc4_modifier_param = fourcc_mod_broadcom_param(modifier);
		modifier = fourcc_mod_broadcom_mod(modifier);
280
	}
281

282
	switch (modifier) {
283
	case LOCAL_DRM_FORMAT_MOD_NONE:
284 285 286 287 288
		if (is_i915_device(fd))
			*width_ret = 64;
		else
			*width_ret = 1;

289 290 291
		*height_ret = 1;
		break;
	case LOCAL_I915_FORMAT_MOD_X_TILED:
292 293
		igt_require_intel(fd);
		if (intel_gen(intel_get_drm_devid(fd)) == 2) {
294 295 296 297 298 299 300 301
			*width_ret = 128;
			*height_ret = 16;
		} else {
			*width_ret = 512;
			*height_ret = 8;
		}
		break;
	case LOCAL_I915_FORMAT_MOD_Y_TILED:
302
	case LOCAL_I915_FORMAT_MOD_Y_TILED_CCS:
303 304
		igt_require_intel(fd);
		if (intel_gen(intel_get_drm_devid(fd)) == 2) {
305 306
			*width_ret = 128;
			*height_ret = 16;
307
		} else if (IS_915(intel_get_drm_devid(fd))) {
308
			*width_ret = 512;
309 310
			*height_ret = 8;
		} else {
311
			*width_ret = 128;
312 313
			*height_ret = 32;
		}
314 315
		break;
	case LOCAL_I915_FORMAT_MOD_Yf_TILED:
316
	case LOCAL_I915_FORMAT_MOD_Yf_TILED_CCS:
317
		igt_require_intel(fd);
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
		switch (fb_bpp) {
		case 8:
			*width_ret = 64;
			*height_ret = 64;
			break;
		case 16:
		case 32:
			*width_ret = 128;
			*height_ret = 32;
			break;
		case 64:
		case 128:
			*width_ret = 256;
			*height_ret = 16;
			break;
		default:
			igt_assert(false);
		}
		break;
337 338 339 340 341
	case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
		igt_require_vc4(fd);
		*width_ret = 128;
		*height_ret = 32;
		break;
342 343 344
	case DRM_FORMAT_MOD_BROADCOM_SAND32:
		igt_require_vc4(fd);
		*width_ret = 32;
345
		*height_ret = vc4_modifier_param;
346 347 348 349
		break;
	case DRM_FORMAT_MOD_BROADCOM_SAND64:
		igt_require_vc4(fd);
		*width_ret = 64;
350
		*height_ret = vc4_modifier_param;
351 352 353 354
		break;
	case DRM_FORMAT_MOD_BROADCOM_SAND128:
		igt_require_vc4(fd);
		*width_ret = 128;
355
		*height_ret = vc4_modifier_param;
356 357 358 359
		break;
	case DRM_FORMAT_MOD_BROADCOM_SAND256:
		igt_require_vc4(fd);
		*width_ret = 256;
360
		*height_ret = vc4_modifier_param;
361
		break;
362 363 364 365
	default:
		igt_assert(false);
	}
}
366

367 368 369 370 371 372
static bool is_ccs_modifier(uint64_t modifier)
{
	return modifier == LOCAL_I915_FORMAT_MOD_Y_TILED_CCS ||
		modifier == LOCAL_I915_FORMAT_MOD_Yf_TILED_CCS;
}

373
static unsigned fb_plane_width(const struct igt_fb *fb, int plane)
374
{
375 376
	const struct format_desc_struct *format = lookup_drm_format(fb->drm_format);

377
	if (is_ccs_modifier(fb->modifier) && plane == 1)
378 379
		return DIV_ROUND_UP(fb->width, 1024) * 128;

380 381
	if (plane == 0)
		return fb->width;
382

383
	return DIV_ROUND_UP(fb->width, format->hsub);
384 385
}

386
static unsigned fb_plane_bpp(const struct igt_fb *fb, int plane)
387
{
388 389
	const struct format_desc_struct *format = lookup_drm_format(fb->drm_format);

390
	if (is_ccs_modifier(fb->modifier) && plane == 1)
391 392 393
		return 8;
	else
		return format->plane_bpp[plane];
394 395
}

396
static unsigned fb_plane_height(const struct igt_fb *fb, int plane)
397
{
398 399
	const struct format_desc_struct *format = lookup_drm_format(fb->drm_format);

400
	if (is_ccs_modifier(fb->modifier) && plane == 1)
401 402
		return DIV_ROUND_UP(fb->height, 512) * 32;

403 404
	if (plane == 0)
		return fb->height;
405

406
	return DIV_ROUND_UP(fb->height, format->vsub);
407 408
}

409
static int fb_num_planes(const struct igt_fb *fb)
410
{
411
	const struct format_desc_struct *format = lookup_drm_format(fb->drm_format);
412

413
	if (is_ccs_modifier(fb->modifier))
414 415 416
		return 2;
	else
		return format->num_planes;
417 418
}

419 420 421 422 423 424
static void fb_init(struct igt_fb *fb,
		    int fd, int width, int height,
		    uint32_t drm_format,
		    uint64_t modifier,
		    enum igt_color_encoding color_encoding,
		    enum igt_color_range color_range)
425
{
426 427 428 429 430 431 432 433
	const struct format_desc_struct *f = lookup_drm_format(drm_format);

	igt_assert_f(f, "DRM format %08x not found\n", drm_format);

	memset(fb, 0, sizeof(*fb));

	fb->width = width;
	fb->height = height;
434
	fb->modifier = modifier;
435 436 437 438 439 440 441 442 443 444 445
	fb->drm_format = drm_format;
	fb->fd = fd;
	fb->num_planes = fb_num_planes(fb);
	fb->color_encoding = color_encoding;
	fb->color_range = color_range;

	for (int i = 0; i < fb->num_planes; i++) {
		fb->plane_bpp[i] = fb_plane_bpp(fb, i);
		fb->plane_height[i] = fb_plane_height(fb, i);
		fb->plane_width[i] = fb_plane_width(fb, i);
	}
446 447
}

448
static uint32_t calc_plane_stride(struct igt_fb *fb, int plane)
449
{
450 451
	uint32_t min_stride = fb->plane_width[plane] *
		(fb->plane_bpp[plane] / 8);
452

453
	if (fb->modifier != LOCAL_DRM_FORMAT_MOD_NONE &&
454
	    is_i915_device(fb->fd) &&
455
	    intel_gen(intel_get_drm_devid(fb->fd)) <= 3) {
456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472
		uint32_t stride;

		/* Round the tiling up to the next power-of-two and the region
		 * up to the next pot fence size so that this works on all
		 * generations.
		 *
		 * This can still fail if the framebuffer is too large to be
		 * tiled. But then that failure is expected.
		 */

		stride = max(min_stride, 512);
		stride = roundup_power_of_two(stride);

		return stride;
	} else {
		unsigned int tile_width, tile_height;

473
		igt_get_fb_tile_size(fb->fd, fb->modifier, fb->plane_bpp[plane],
474 475 476 477 478 479
				     &tile_width, &tile_height);

		return ALIGN(min_stride, tile_width);
	}
}

480
static uint64_t calc_plane_size(struct igt_fb *fb, int plane)
481
{
482
	if (fb->modifier != LOCAL_DRM_FORMAT_MOD_NONE &&
483
	    is_i915_device(fb->fd) &&
484 485 486
	    intel_gen(intel_get_drm_devid(fb->fd)) <= 3) {
		uint64_t min_size = (uint64_t) fb->strides[plane] *
			fb->plane_height[plane];
487 488
		uint64_t size;

489 490 491
		/* Round the tiling up to the next power-of-two and the region
		 * up to the next pot fence size so that this works on all
		 * generations.
492
		 *
493 494
		 * This can still fail if the framebuffer is too large to be
		 * tiled. But then that failure is expected.
495 496
		 */

497
		size = max(min_size, 1024*1024);
498
		size = roundup_power_of_two(size);
499 500

		return size;
501
	} else {
502 503
		unsigned int tile_width, tile_height;

504
		igt_get_fb_tile_size(fb->fd, fb->modifier, fb->plane_bpp[plane],
505
				     &tile_width, &tile_height);
506

507 508 509 510 511 512 513
		/* Special case where the "tile height" represents a
		 * height-based stride, such as with VC4 SAND tiling modes.
		 */

		if (tile_height > fb->plane_height[plane])
			return fb->strides[plane] * tile_height;

514 515
		return (uint64_t) fb->strides[plane] *
			ALIGN(fb->plane_height[plane], tile_height);
516 517 518
	}
}

519
static uint64_t calc_fb_size(struct igt_fb *fb)
520 521 522 523
{
	uint64_t size = 0;
	int plane;

524 525 526 527
	for (plane = 0; plane < fb->num_planes; plane++) {
		/* respect the stride requested by the caller */
		if (!fb->strides[plane])
			fb->strides[plane] = calc_plane_stride(fb, plane);
528

529
		fb->offsets[plane] = size;
530

531
		size += calc_plane_size(fb, plane);
532 533 534
	}

	return size;
535 536
}

537 538 539 540 541 542
/**
 * igt_calc_fb_size:
 * @fd: the DRM file descriptor
 * @width: width of the framebuffer in pixels
 * @height: height of the framebuffer in pixels
 * @format: drm fourcc pixel format code
543
 * @modifier: tiling layout of the framebuffer (as framebuffer modifier)
544 545 546 547 548 549
 * @size_ret: returned size for the framebuffer
 * @stride_ret: returned stride for the framebuffer
 *
 * This function returns valid stride and size values for a framebuffer with the
 * specified parameters.
 */
550
void igt_calc_fb_size(int fd, int width, int height, uint32_t drm_format, uint64_t modifier,
551
		      uint64_t *size_ret, unsigned *stride_ret)
552
{
553
	struct igt_fb fb;
554

555
	fb_init(&fb, fd, width, height, drm_format, modifier,
556
		IGT_COLOR_YCBCR_BT709, IGT_COLOR_YCBCR_LIMITED_RANGE);
557

558 559 560 561 562 563
	fb.size = calc_fb_size(&fb);

	if (size_ret)
		*size_ret = fb.size;
	if (stride_ret)
		*stride_ret = fb.strides[0];
564 565
}

566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583
/**
 * igt_fb_mod_to_tiling:
 * @modifier: DRM framebuffer modifier
 *
 * This function converts a DRM framebuffer modifier to its corresponding
 * tiling constant.
 *
 * Returns:
 * A tiling constant
 */
uint64_t igt_fb_mod_to_tiling(uint64_t modifier)
{
	switch (modifier) {
	case LOCAL_DRM_FORMAT_MOD_NONE:
		return I915_TILING_NONE;
	case LOCAL_I915_FORMAT_MOD_X_TILED:
		return I915_TILING_X;
	case LOCAL_I915_FORMAT_MOD_Y_TILED:
584
	case LOCAL_I915_FORMAT_MOD_Y_TILED_CCS:
585 586
		return I915_TILING_Y;
	case LOCAL_I915_FORMAT_MOD_Yf_TILED:
587
	case LOCAL_I915_FORMAT_MOD_Yf_TILED_CCS:
588 589 590 591 592 593
		return I915_TILING_Yf;
	default:
		igt_assert(0);
	}
}

594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619
/**
 * igt_fb_tiling_to_mod:
 * @tiling: DRM framebuffer tiling
 *
 * This function converts a DRM framebuffer tiling to its corresponding
 * modifier constant.
 *
 * Returns:
 * A modifier constant
 */
uint64_t igt_fb_tiling_to_mod(uint64_t tiling)
{
	switch (tiling) {
	case I915_TILING_NONE:
		return LOCAL_DRM_FORMAT_MOD_NONE;
	case I915_TILING_X:
		return LOCAL_I915_FORMAT_MOD_X_TILED;
	case I915_TILING_Y:
		return LOCAL_I915_FORMAT_MOD_Y_TILED;
	case I915_TILING_Yf:
		return LOCAL_I915_FORMAT_MOD_Yf_TILED;
	default:
		igt_assert(0);
	}
}

620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655
static void clear_yuv_buffer(struct igt_fb *fb)
{
	bool full_range = fb->color_range == IGT_COLOR_YCBCR_FULL_RANGE;
	void *ptr;

	igt_assert(igt_format_is_yuv(fb->drm_format));

	/* Ensure the framebuffer is preallocated */
	ptr = igt_fb_map_buffer(fb->fd, fb);
	igt_assert(*(uint32_t *)ptr == 0);

	switch (fb->drm_format) {
	case DRM_FORMAT_NV12:
		memset(ptr + fb->offsets[0],
		       full_range ? 0x00 : 0x10,
		       fb->strides[0] * fb->plane_height[0]);
		memset(ptr + fb->offsets[1],
		       0x80,
		       fb->strides[1] * fb->plane_height[1]);
		break;
	case DRM_FORMAT_XYUV8888:
		wmemset(ptr + fb->offsets[0], full_range ? 0x00008080 : 0x00108080,
			fb->strides[0] * fb->plane_height[0] / sizeof(wchar_t));
		break;
	case DRM_FORMAT_YUYV:
	case DRM_FORMAT_YVYU:
		wmemset(ptr + fb->offsets[0],
			full_range ? 0x80008000 : 0x80108010,
			fb->strides[0] * fb->plane_height[0] / sizeof(wchar_t));
		break;
	case DRM_FORMAT_UYVY:
	case DRM_FORMAT_VYUY:
		wmemset(ptr + fb->offsets[0],
			full_range ? 0x00800080 : 0x10801080,
			fb->strides[0] * fb->plane_height[0] / sizeof(wchar_t));
		break;
656 657 658 659 660 661 662 663
	case DRM_FORMAT_P010:
	case DRM_FORMAT_P012:
	case DRM_FORMAT_P016:
		wmemset(ptr, full_range ? 0 : 0x10001000,
			fb->offsets[1] / sizeof(wchar_t));
		wmemset(ptr + fb->offsets[1], 0x80008000,
			fb->strides[1] * fb->plane_height[1] / sizeof(wchar_t));
		break;
664 665 666 667 668
	}

	igt_fb_unmap_buffer(fb, ptr);
}

669
/* helpers to create nice-looking framebuffers */
670
static int create_bo_for_fb(struct igt_fb *fb)
671
{
672 673 674
	const struct format_desc_struct *fmt = lookup_drm_format(fb->drm_format);
	unsigned int bpp = 0;
	unsigned int plane;
675
	unsigned *strides = &fb->strides[0];
676
	bool device_bo = false;
677
	int fd = fb->fd;
678
	uint64_t size;
679

680 681 682 683 684
	/*
	 * The current dumb buffer allocation API doesn't really allow to
	 * specify a custom size or stride. Yet the caller is free to specify
	 * them, so we need to make sure to use a device BO then.
	 */
685
	if (fb->modifier || fb->size || fb->strides[0] ||
686 687
	    (is_i915_device(fd) && igt_format_is_yuv(fb->drm_format)))
		device_bo = true;
688

689 690
	/* Sets offets and stride if necessary. */
	size = calc_fb_size(fb);
691

692 693 694
	/* Respect the size requested by the caller. */
	if (fb->size == 0)
		fb->size = size;
695

696
	if (device_bo) {
697
		fb->is_dumb = false;
698 699 700 701

		if (is_i915_device(fd)) {
			fb->gem_handle = gem_create(fd, fb->size);
			gem_set_tiling(fd, fb->gem_handle,
702
				       igt_fb_mod_to_tiling(fb->modifier),
703
				       fb->strides[0]);
704 705 706
		} else if (is_vc4_device(fd)) {
			fb->gem_handle = igt_vc4_create_bo(fd, fb->size);

707
			if (fb->modifier == DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED)
708
				igt_vc4_set_tiling(fd, fb->gem_handle,
709
						   fb->modifier);
710 711 712
		} else {
			igt_assert(false);
		}
713

714
		goto out;
715
	}
716

717 718 719
	for (plane = 0; plane < fb->num_planes; plane++)
		bpp += DIV_ROUND_UP(fb->plane_bpp[plane],
				    plane ? fmt->hsub * fmt->vsub : 1);
720

721
	fb->is_dumb = true;
722 723 724 725 726 727 728 729 730 731 732 733 734 735

	/*
	 * We can't really pass the stride array here since the dumb
	 * buffer allocation is assuming that it operates on one
	 * plane, and therefore will calculate the stride as if each
	 * pixel was stored on a single plane.
	 *
	 * This might cause issues at some point on drivers that would
	 * change the stride of YUV buffers, but we haven't
	 * encountered any yet.
	 */
	if (fb->num_planes > 1)
		strides = NULL;

736
	fb->gem_handle = kmstest_dumb_create(fd, fb->width, fb->height,
737
					     bpp, strides, &fb->size);
738

739
out:
740 741 742
	if (igt_format_is_yuv(fb->drm_format))
		clear_yuv_buffer(fb);

743
	return fb->gem_handle;
744 745
}

746 747 748 749 750 751 752 753 754
void igt_create_bo_for_fb(int fd, int width, int height,
			  uint32_t format, uint64_t modifier,
			  struct igt_fb *fb /* out */)
{
	fb_init(fb, fd, width, height, format, modifier,
		IGT_COLOR_YCBCR_BT709, IGT_COLOR_YCBCR_LIMITED_RANGE);
	create_bo_for_fb(fb);
}

755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774
/**
 * igt_create_bo_with_dimensions:
 * @fd: open drm file descriptor
 * @width: width of the buffer object in pixels
 * @height: height of the buffer object in pixels
 * @format: drm fourcc pixel format code
 * @modifier: modifier corresponding to the tiling layout of the buffer object
 * @stride: stride of the buffer object in bytes (0 for automatic stride)
 * @size_ret: size of the buffer object as created by the kernel
 * @stride_ret: stride of the buffer object as created by the kernel
 * @is_dumb: whether the created buffer object is a dumb buffer or not
 *
 * This function allocates a gem buffer object matching the requested
 * properties.
 *
 * Returns:
 * The kms id of the created buffer object.
 */
int igt_create_bo_with_dimensions(int fd, int width, int height,
				  uint32_t format, uint64_t modifier,
775
				  unsigned stride, uint64_t *size_ret,
776
				  unsigned *stride_ret, bool *is_dumb)
777
{
778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795
	struct igt_fb fb;

	fb_init(&fb, fd, width, height, format, modifier,
		IGT_COLOR_YCBCR_BT709, IGT_COLOR_YCBCR_LIMITED_RANGE);

	for (int i = 0; i < fb.num_planes; i++)
		fb.strides[i] = stride;

	create_bo_for_fb(&fb);

	if (size_ret)
		*size_ret = fb.size;
	if (stride_ret)
		*stride_ret = fb.strides[0];
	if (is_dumb)
		*is_dumb = fb.is_dumb;

	return fb.gem_handle;
796 797
}

798 799 800 801 802 803 804 805
/**
 * igt_paint_color:
 * @cr: cairo drawing context
 * @x: pixel x-coordination of the fill rectangle
 * @y: pixel y-coordination of the fill rectangle
 * @w: width of the fill rectangle
 * @h: height of the fill rectangle
 * @r: red value to use as fill color
806
 * @g: green value to use as fill color
807 808 809 810 811
 * @b: blue value to use as fill color
 *
 * This functions draws a solid rectangle with the given color using the drawing
 * context @cr.
 */
812
void igt_paint_color(cairo_t *cr, int x, int y, int w, int h,
813
		     double r, double g, double b)
814 815 816 817 818 819
{
	cairo_rectangle(cr, x, y, w, h);
	cairo_set_source_rgb(cr, r, g, b);
	cairo_fill(cr);
}

820 821 822 823 824 825 826 827
/**
 * igt_paint_color_alpha:
 * @cr: cairo drawing context
 * @x: pixel x-coordination of the fill rectangle
 * @y: pixel y-coordination of the fill rectangle
 * @w: width of the fill rectangle
 * @h: height of the fill rectangle
 * @r: red value to use as fill color
828
 * @g: green value to use as fill color
829 830 831 832 833 834
 * @b: blue value to use as fill color
 * @a: alpha value to use as fill color
 *
 * This functions draws a rectangle with the given color and alpha values using
 * the drawing context @cr.
 */
835
void igt_paint_color_alpha(cairo_t *cr, int x, int y, int w, int h,
836
			   double r, double g, double b, double a)
837 838 839 840 841 842
{
	cairo_rectangle(cr, x, y, w, h);
	cairo_set_source_rgba(cr, r, g, b, a);
	cairo_fill(cr);
}

843 844 845 846 847 848 849 850
/**
 * igt_paint_color_gradient:
 * @cr: cairo drawing context
 * @x: pixel x-coordination of the fill rectangle
 * @y: pixel y-coordination of the fill rectangle
 * @w: width of the fill rectangle
 * @h: height of the fill rectangle
 * @r: red value to use as fill color
851
 * @g: green value to use as fill color
852 853 854 855 856
 * @b: blue value to use as fill color
 *
 * This functions draws a gradient into the rectangle which fades in from black
 * to the given values using the drawing context @cr.
 */
857
void
858
igt_paint_color_gradient(cairo_t *cr, int x, int y, int w, int h,
859
			 int r, int g, int b)
860 861 862 863 864 865 866 867 868 869 870 871 872
{
	cairo_pattern_t *pat;

	pat = cairo_pattern_create_linear(x, y, x + w, y + h);
	cairo_pattern_add_color_stop_rgba(pat, 1, 0, 0, 0, 1);
	cairo_pattern_add_color_stop_rgba(pat, 0, r, g, b, 1);

	cairo_rectangle(cr, x, y, w, h);
	cairo_set_source(cr, pat);
	cairo_fill(cr);
	cairo_pattern_destroy(pat);
}

873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906
/**
 * igt_paint_color_gradient_range:
 * @cr: cairo drawing context
 * @x: pixel x-coordination of the fill rectangle
 * @y: pixel y-coordination of the fill rectangle
 * @w: width of the fill rectangle
 * @h: height of the fill rectangle
 * @sr: red value to use as start gradient color
 * @sg: green value to use as start gradient color
 * @sb: blue value to use as start gradient color
 * @er: red value to use as end gradient color
 * @eg: green value to use as end gradient color
 * @eb: blue value to use as end gradient color
 *
 * This functions draws a gradient into the rectangle which fades in
 * from one color to the other using the drawing context @cr.
 */
void
igt_paint_color_gradient_range(cairo_t *cr, int x, int y, int w, int h,
			       double sr, double sg, double sb,
			       double er, double eg, double eb)
{
	cairo_pattern_t *pat;

	pat = cairo_pattern_create_linear(x, y, x + w, y + h);
	cairo_pattern_add_color_stop_rgba(pat, 1, sr, sg, sb, 1);
	cairo_pattern_add_color_stop_rgba(pat, 0, er, eg, eb, 1);

	cairo_rectangle(cr, x, y, w, h);
	cairo_set_source(cr, pat);
	cairo_fill(cr);
	cairo_pattern_destroy(pat);
}

907 908 909 910 911 912 913 914 915 916 917
static void
paint_test_patterns(cairo_t *cr, int width, int height)
{
	double gr_height, gr_width;
	int x, y;

	y = height * 0.10;
	gr_width = width * 0.75;
	gr_height = height * 0.08;
	x = (width / 2) - (gr_width / 2);

918
	igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 1, 0, 0);
919 920

	y += gr_height;
921
	igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 0, 1, 0);
922 923

	y += gr_height;
924
	igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 0, 0, 1);
925 926

	y += gr_height;
927
	igt_paint_color_gradient(cr, x, y, gr_width, gr_height, 1, 1, 1);
928 929
}

930 931 932 933 934 935 936 937 938 939 940 941 942 943 944
/**
 * igt_cairo_printf_line:
 * @cr: cairo drawing context
 * @align: text alignment
 * @yspacing: additional y-direction feed after this line
 * @fmt: format string
 * @...: optional arguments used in the format string
 *
 * This is a little helper to draw text onto framebuffers. All the initial setup
 * (like setting the font size and the moving to the starting position) still
 * needs to be done manually with explicit cairo calls on @cr.
 *
 * Returns:
 * The width of the drawn text.
 */
945
int igt_cairo_printf_line(cairo_t *cr, enum igt_text_align align,
946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991
				double yspacing, const char *fmt, ...)
{
	double x, y, xofs, yofs;
	cairo_text_extents_t extents;
	char *text;
	va_list ap;
	int ret;

	va_start(ap, fmt);
	ret = vasprintf(&text, fmt, ap);
	igt_assert(ret >= 0);
	va_end(ap);

	cairo_text_extents(cr, text, &extents);

	xofs = yofs = 0;
	if (align & align_right)
		xofs = -extents.width;
	else if (align & align_hcenter)
		xofs = -extents.width / 2;

	if (align & align_top)
		yofs = extents.height;
	else if (align & align_vcenter)
		yofs = extents.height / 2;

	cairo_get_current_point(cr, &x, &y);
	if (xofs || yofs)
		cairo_rel_move_to(cr, xofs, yofs);

	cairo_text_path(cr, text);
	cairo_set_source_rgb(cr, 0, 0, 0);
	cairo_stroke_preserve(cr);
	cairo_set_source_rgb(cr, 1, 1, 1);
	cairo_fill(cr);

	cairo_move_to(cr, x, y + extents.height + yspacing);

	free(text);

	return extents.width;
}

static void
paint_marker(cairo_t *cr, int x, int y)
{
992
	enum igt_text_align align;
993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015
	int xoff, yoff;

	cairo_move_to(cr, x, y - 20);
	cairo_line_to(cr, x, y + 20);
	cairo_move_to(cr, x - 20, y);
	cairo_line_to(cr, x + 20, y);
	cairo_new_sub_path(cr);
	cairo_arc(cr, x, y, 10, 0, M_PI * 2);
	cairo_set_line_width(cr, 4);
	cairo_set_source_rgb(cr, 0, 0, 0);
	cairo_stroke_preserve(cr);
	cairo_set_source_rgb(cr, 1, 1, 1);
	cairo_set_line_width(cr, 2);
	cairo_stroke(cr);

	xoff = x ? -20 : 20;
	align = x ? align_right : align_left;

	yoff = y ? -20 : 20;
	align |= y ? align_bottom : align_top;

	cairo_move_to(cr, x + xoff, y + yoff);
	cairo_set_font_size(cr, 18);
1016
	igt_cairo_printf_line(cr, align, 0, "(%d, %d)", x, y);
1017 1018
}

1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032
/**
 * igt_paint_test_pattern:
 * @cr: cairo drawing context
 * @width: width of the visible area
 * @height: height of the visible area
 *
 * This functions draws an entire set of test patterns for the given visible
 * area using the drawing context @cr. This is useful for manual visual
 * inspection of displayed framebuffers.
 *
 * The test patterns include
 *  - corner markers to check for over/underscan and
 *  - a set of color and b/w gradients.
 */
1033
void igt_paint_test_pattern(cairo_t *cr, int width, int height)
1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047
{
	paint_test_patterns(cr, width, height);

	cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);

	/* Paint corner markers */
	paint_marker(cr, 0, 0);
	paint_marker(cr, width, 0);
	paint_marker(cr, 0, height);
	paint_marker(cr, width, height);

	igt_assert(!cairo_status(cr));
}

1048 1049 1050 1051 1052 1053 1054 1055 1056
static cairo_status_t
stdio_read_func(void *closure, unsigned char* data, unsigned int size)
{
	if (fread(data, 1, size, (FILE*)closure) != size)
		return CAIRO_STATUS_READ_ERROR;

	return CAIRO_STATUS_SUCCESS;
}

1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068
cairo_surface_t *igt_cairo_image_surface_create_from_png(const char *filename)
{
	cairo_surface_t *image;
	FILE *f;

	f = igt_fopen_data(filename);
	image = cairo_image_surface_create_from_png_stream(&stdio_read_func, f);
	fclose(f);

	return image;
}

1069 1070 1071 1072 1073 1074 1075 1076 1077
/**
 * igt_paint_image:
 * @cr: cairo drawing context
 * @filename: filename of the png image to draw
 * @dst_x: pixel x-coordination of the destination rectangle
 * @dst_y: pixel y-coordination of the destination rectangle
 * @dst_width: width of the destination rectangle
 * @dst_height: height of the destination rectangle
 *
1078 1079
 * This function can be used to draw a scaled version of the supplied png image,
 * which is loaded from the package data directory.
1080
 */
1081
void igt_paint_image(cairo_t *cr, const char *filename,
1082
		     int dst_x, int dst_y, int dst_width, int dst_height)
1083 1084 1085 1086 1087
{
	cairo_surface_t *image;
	int img_width, img_height;
	double scale_x, scale_y;

1088
	image = igt_cairo_image_surface_create_from_png(filename);
1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108
	igt_assert(cairo_surface_status(image) == CAIRO_STATUS_SUCCESS);

	img_width = cairo_image_surface_get_width(image);
	img_height = cairo_image_surface_get_height(image);

	scale_x = (double)dst_width / img_width;
	scale_y = (double)dst_height / img_height;

	cairo_save(cr);

	cairo_translate(cr, dst_x, dst_y);
	cairo_scale(cr, scale_x, scale_y);
	cairo_set_source_surface(cr, image, 0, 0);
	cairo_paint(cr);

	cairo_surface_destroy(image);

	cairo_restore(cr);
}

1109
/**
1110
 * igt_create_fb_with_bo_size:
1111 1112 1113 1114
 * @fd: open i915 drm file descriptor
 * @width: width of the framebuffer in pixel
 * @height: height of the framebuffer in pixel
 * @format: drm fourcc pixel format code
1115
 * @modifier: tiling layout of the framebuffer (as framebuffer modifier)
1116
 * @fb: pointer to an #igt_fb structure
1117
 * @bo_size: size of the backing bo (0 for automatic size)
1118
 * @bo_stride: stride of the backing bo (0 for automatic stride)
1119 1120 1121
 *
 * This function allocates a gem buffer object suitable to back a framebuffer
 * with the requested properties and then wraps it up in a drm framebuffer
1122
 * object of the requested size. All metadata is stored in @fb.
1123 1124 1125 1126 1127
 *
 * The backing storage of the framebuffer is filled with all zeros, i.e. black
 * for rgb pixel formats.
 *
 * Returns:
1128
 * The kms id of the created framebuffer.
1129
 */
1130 1131
unsigned int
igt_create_fb_with_bo_size(int fd, int width, int height,
1132
			   uint32_t format, uint64_t modifier,
1133
			   struct igt_fb *fb, uint64_t bo_size,
1134
			   unsigned bo_stride)
1135
{
1136 1137 1138
	/* FIXME allow the caller to pass these in */
	enum igt_color_encoding color_encoding = IGT_COLOR_YCBCR_BT709;
	enum igt_color_range color_range = IGT_COLOR_YCBCR_LIMITED_RANGE;
1139
	uint32_t flags = 0;
1140

1141
	fb_init(fb, fd, width, height, format, modifier,
1142
		color_encoding, color_range);
1143

1144 1145 1146 1147
	for (int i = 0; i < fb->num_planes; i++)
		fb->strides[i] = bo_stride;

	fb->size = bo_size;
1148

1149 1150 1151 1152
	igt_debug("%s(width=%d, height=%d, format=" IGT_FORMAT_FMT
		  ", modifier=0x%"PRIx64", size=%"PRIu64")\n",
		  __func__, width, height, IGT_FORMAT_ARGS(format), modifier,
		  bo_size);
1153 1154

	create_bo_for_fb(fb);
1155
	igt_assert(fb->gem_handle > 0);
1156 1157

	igt_debug("%s(handle=%d, pitch=%d)\n",
1158
		  __func__, fb->gem_handle, fb->strides[0]);
1159

1160
	if (fb->modifier || igt_has_fb_modifiers(fd))
1161 1162
		flags = LOCAL_DRM_MODE_FB_MODIFIERS;

1163 1164
	do_or_die(__kms_addfb(fb->fd, fb->gem_handle,
			      fb->width, fb->height,
1165
			      fb->drm_format, fb->modifier,
1166
			      fb->strides, fb->offsets, fb->num_planes, flags,
1167
			      &fb->fb_id));
1168

1169
	return fb->fb_id;
1170 1171
}

1172 1173 1174 1175 1176 1177
/**
 * igt_create_fb:
 * @fd: open i915 drm file descriptor
 * @width: width of the framebuffer in pixel
 * @height: height of the framebuffer in pixel
 * @format: drm fourcc pixel format code
1178
 * @modifier: tiling layout of the framebuffer
1179 1180 1181 1182 1183 1184 1185 1186 1187 1188
 * @fb: pointer to an #igt_fb structure
 *
 * This function allocates a gem buffer object suitable to back a framebuffer
 * with the requested properties and then wraps it up in a drm framebuffer
 * object. All metadata is stored in @fb.
 *
 * The backing storage of the framebuffer is filled with all zeros, i.e. black
 * for rgb pixel formats.
 *
 * Returns:
1189
 * The kms id of the created framebuffer.
1190 1191
 */
unsigned int igt_create_fb(int fd, int width, int height, uint32_t format,
1192
			   uint64_t modifier, struct igt_fb *fb)
1193
{
1194
	return igt_create_fb_with_bo_size(fd, width, height, format, modifier, fb,
1195
					  0, 0);
1196 1197
}

1198 1199 1200 1201 1202 1203
/**
 * igt_create_color_fb:
 * @fd: open i915 drm file descriptor
 * @width: width of the framebuffer in pixel
 * @height: height of the framebuffer in pixel
 * @format: drm fourcc pixel format code
1204
 * @modifier: tiling layout of the framebuffer
1205
 * @r: red value to use as fill color
1206
 * @g: green value to use as fill color
1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220
 * @b: blue value to use as fill color
 * @fb: pointer to an #igt_fb structure
 *
 * This function allocates a gem buffer object suitable to back a framebuffer
 * with the requested properties and then wraps it up in a drm framebuffer
 * object. All metadata is stored in @fb.
 *
 * Compared to igt_create_fb() this function also fills the entire framebuffer
 * with the given color, which is useful for some simple pipe crc based tests.
 *
 * Returns:
 * The kms id of the created framebuffer on success or a negative error code on
 * failure.
 */
1221
unsigned int igt_create_color_fb(int fd, int width, int height,
1222
				 uint32_t format, uint64_t modifier,
1223 1224
				 double r, double g, double b,
				 struct igt_fb *fb /* out */)
1225 1226 1227 1228
{
	unsigned int fb_id;
	cairo_t *cr;

1229
	fb_id = igt_create_fb(fd, width, height, format, modifier, fb);
1230 1231
	igt_assert(fb_id);

1232 1233
	cr = igt_get_cairo_ctx(fd, fb);
	igt_paint_color(cr, 0, 0, width, height, r, g, b);
1234
	igt_put_cairo_ctx(fd, fb, cr);
1235 1236 1237 1238

	return fb_id;
}

1239 1240 1241 1242 1243 1244
/**
 * igt_create_pattern_fb:
 * @fd: open i915 drm file descriptor
 * @width: width of the framebuffer in pixel
 * @height: height of the framebuffer in pixel
 * @format: drm fourcc pixel format code
1245
 * @modifier: tiling layout of the framebuffer
1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259
 * @fb: pointer to an #igt_fb structure
 *
 * This function allocates a gem buffer object suitable to back a framebuffer
 * with the requested properties and then wraps it up in a drm framebuffer
 * object. All metadata is stored in @fb.
 *
 * Compared to igt_create_fb() this function also draws the standard test pattern
 * into the framebuffer.
 *
 * Returns:
 * The kms id of the created framebuffer on success or a negative error code on
 * failure.
 */
unsigned int igt_create_pattern_fb(int fd, int width, int height,
1260
				   uint32_t format, uint64_t modifier,
1261 1262 1263 1264 1265
				   struct igt_fb *fb /* out */)
{
	unsigned int fb_id;
	cairo_t *cr;

1266
	fb_id = igt_create_fb(fd, width, height, format, modifier, fb);
1267 1268 1269 1270
	igt_assert(fb_id);

	cr = igt_get_cairo_ctx(fd, fb);
	igt_paint_test_pattern(cr, width, height);
1271
	igt_put_cairo_ctx(fd, fb, cr);
1272 1273 1274 1275 1276 1277 1278 1279 1280 1281

	return fb_id;
}

/**
 * igt_create_color_pattern_fb:
 * @fd: open i915 drm file descriptor
 * @width: width of the framebuffer in pixel
 * @height: height of the framebuffer in pixel
 * @format: drm fourcc pixel format code
1282
 * @modifier: tiling layout of the framebuffer
1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300
 * @r: red value to use as fill color
 * @g: green value to use as fill color
 * @b: blue value to use as fill color
 * @fb: pointer to an #igt_fb structure
 *
 * This function allocates a gem buffer object suitable to back a framebuffer
 * with the requested properties and then wraps it up in a drm framebuffer
 * object. All metadata is stored in @fb.
 *
 * Compared to igt_create_fb() this function also fills the entire framebuffer
 * with the given color, and then draws the standard test pattern into the
 * framebuffer.
 *
 * Returns:
 * The kms id of the created framebuffer on success or a negative error code on
 * failure.
 */
unsigned int igt_create_color_pattern_fb(int fd, int width, int height,
1301
					 uint32_t format, uint64_t modifier,
1302 1303 1304 1305 1306 1307
					 double r, double g, double b,
					 struct igt_fb *fb /* out */)
{
	unsigned int fb_id;
	cairo_t *cr;

1308
	fb_id = igt_create_fb(fd, width, height, format, modifier, fb);
1309 1310 1311 1312 1313
	igt_assert(fb_id);

	cr = igt_get_cairo_ctx(fd, fb);
	igt_paint_color(cr, 0, 0, width, height, r, g, b);
	igt_paint_test_pattern(cr, width, height);
1314
	igt_put_cairo_ctx(fd, fb, cr);
1315 1316 1317 1318 1319 1320 1321 1322 1323 1324

	return fb_id;
}

/**
 * igt_create_image_fb:
 * @drm_fd: open i915 drm file descriptor
 * @width: width of the framebuffer in pixel or 0
 * @height: height of the framebuffer in pixel or 0
 * @format: drm fourcc pixel format code
1325
 * @modifier: tiling layout of the framebuffer
1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336
 * @filename: filename of the png image to draw
 * @fb: pointer to an #igt_fb structure
 *
 * Create a framebuffer with the specified image. If @width is zero the
 * image width will be used. If @height is zero the image height will be used.
 *
 * Returns:
 * The kms id of the created framebuffer on success or a negative error code on
 * failure.
 */
unsigned int igt_create_image_fb(int fd, int width, int height,
1337
				 uint32_t format, uint64_t modifier,
1338 1339 1340 1341 1342 1343 1344
				 const char *filename,
				 struct igt_fb *fb /* out */)
{
	cairo_surface_t *image;
	uint32_t fb_id;
	cairo_t *cr;

1345
	image = igt_cairo_image_surface_create_from_png(filename);
1346 1347 1348 1349 1350 1351 1352
	igt_assert(cairo_surface_status(image) == CAIRO_STATUS_SUCCESS);
	if (width == 0)
		width = cairo_image_surface_get_width(image);
	if (height == 0)
		height = cairo_image_surface_get_height(image);
	cairo_surface_destroy(image);

1353
	fb_id = igt_create_fb(fd, width, height, format, modifier, fb);
1354 1355 1356

	cr = igt_get_cairo_ctx(fd, fb);
	igt_paint_image(cr, filename, 0, 0, width, height);
1357
	igt_put_cairo_ctx(fd, fb, cr);
1358 1359 1360 1361

	return fb_id;
}

1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428
struct box {
	int x, y, width, height;
};

struct stereo_fb_layout {
	int fb_width, fb_height;
	struct box left, right;
};

static void box_init(struct box *box, int x, int y, int bwidth, int bheight)
{
	box->x = x;
	box->y = y;
	box->width = bwidth;
	box->height = bheight;
}


static void stereo_fb_layout_from_mode(struct stereo_fb_layout *layout,
				       drmModeModeInfo *mode)
{
	unsigned int format = mode->flags & DRM_MODE_FLAG_3D_MASK;
	const int hdisplay = mode->hdisplay, vdisplay = mode->vdisplay;
	int middle;

	switch (format) {
	case DRM_MODE_FLAG_3D_TOP_AND_BOTTOM:
		layout->fb_width = hdisplay;
		layout->fb_height = vdisplay;

		middle = vdisplay / 2;
		box_init(&layout->left, 0, 0, hdisplay, middle);
		box_init(&layout->right,
			 0, middle, hdisplay, vdisplay - middle);
		break;
	case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF:
		layout->fb_width = hdisplay;
		layout->fb_height = vdisplay;

		middle = hdisplay / 2;
		box_init(&layout->left, 0, 0, middle, vdisplay);
		box_init(&layout->right,
			 middle, 0, hdisplay - middle, vdisplay);
		break;
	case DRM_MODE_FLAG_3D_FRAME_PACKING:
	{
		int vactive_space = mode->vtotal - vdisplay;

		layout->fb_width = hdisplay;
		layout->fb_height = 2 * vdisplay + vactive_space;

		box_init(&layout->left,
			 0, 0, hdisplay, vdisplay);
		box_init(&layout->right,
			 0, vdisplay + vactive_space, hdisplay, vdisplay);
		break;
	}
	default:
		igt_assert(0);
	}
}

/**
 * igt_create_stereo_fb:
 * @drm_fd: open i915 drm file descriptor
 * @mode: A stereo 3D mode.
 * @format: drm fourcc pixel format code
1429
 * @modifier: tiling layout of the framebuffer
1430 1431 1432 1433 1434 1435 1436 1437
 *
 * Create a framebuffer for use with the stereo 3D mode specified by @mode.
 *
 * Returns:
 * The kms id of the created framebuffer on success or a negative error code on
 * failure.
 */
unsigned int igt_create_stereo_fb(int drm_fd, drmModeModeInfo *mode,
1438
				  uint32_t format, uint64_t modifier)
1439 1440 1441 1442 1443 1444 1445 1446
{
	struct stereo_fb_layout layout;
	cairo_t *cr;
	uint32_t fb_id;
	struct igt_fb fb;

	stereo_fb_layout_from_mode(&layout, mode);
	fb_id = igt_create_fb(drm_fd, layout.fb_width, layout.fb_height, format,
1447
			      modifier, &fb);
1448 1449
	cr = igt_get_cairo_ctx(drm_fd, &fb);

1450
	igt_paint_image(cr, "1080p-left.png",
1451 1452
			layout.left.x, layout.left.y,
			layout.left.width, layout.left.height);
1453
	igt_paint_image(cr, "1080p-right.png",
1454 1455 1456
			layout.right.x, layout.right.y,
			layout.right.width, layout.right.height);

1457
	igt_put_cairo_ctx(drm_fd, &fb, cr);
1458 1459 1460 1461

	return fb_id;
}

1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473
static pixman_format_code_t drm_format_to_pixman(uint32_t drm_format)
{
	const struct format_desc_struct *f;

	for_each_format(f)
		if (f->drm_id == drm_format)
			return f->pixman_id;

	igt_assert_f(0, "can't find a pixman format for %08x (%s)\n",
		     drm_format, igt_format_str(drm_format));
}

1474 1475
static cairo_format_t drm_format_to_cairo(uint32_t drm_format)
{
1476
	const struct format_desc_struct *f;
1477 1478 1479 1480 1481

	for_each_format(f)
		if (f->drm_id == drm_format)
			return f->cairo_id;

1482 1483
	igt_assert_f(0, "can't find a cairo format for %08x (%s)\n",
		     drm_format, igt_format_str(drm_format));
1484 1485
}

1486
struct fb_blit_linear {
1487
	struct igt_fb fb;
1488 1489 1490
	uint8_t *map;
};

1491 1492 1493
struct fb_blit_upload {
	int fd;
	struct igt_fb *fb;
1494
	struct fb_blit_linear linear;
1495 1496
	drm_intel_bufmgr *bufmgr;
	struct intel_batchbuffer *batch;
1497 1498
};

1499 1500 1501 1502 1503 1504 1505 1506 1507
static void init_buf(struct fb_blit_upload *blit,
		     struct igt_buf *buf,
		     const struct igt_fb *fb,
		     const char *name)
{
	igt_assert_eq(fb->offsets[0], 0);

	buf->bo = gem_handle_to_libdrm_bo(blit->bufmgr, blit->fd,
					  name, fb->gem_handle);
1508
	buf->tiling = igt_fb_mod_to_tiling(fb->modifier);
1509 1510 1511 1512
	buf->stride = fb->strides[0];
	buf->bpp = fb->plane_bpp[0];
	buf->size = fb->size;

Ville Syrjälä's avatar