igt_draw.c 19.4 KB
Newer Older
Paulo Zanoni's avatar
Paulo Zanoni committed
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 © 2015 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.
 *
 */

#include <sys/mman.h>

#include "igt_draw.h"

#include "drmtest.h"
30
#include "intel_batchbuffer.h"
Paulo Zanoni's avatar
Paulo Zanoni committed
31 32 33 34
#include "intel_chipset.h"
#include "igt_core.h"
#include "igt_fb.h"
#include "ioctl_wrappers.h"
35
#include "i830_reg.h"
36
#include "i915/gem_mman.h"
Paulo Zanoni's avatar
Paulo Zanoni committed
37

38 39 40 41 42 43 44
#ifndef PAGE_ALIGN
#ifndef PAGE_SIZE
#define PAGE_SIZE 4096
#endif
#define PAGE_ALIGN(x) ALIGN(x, PAGE_SIZE)
#endif

Paulo Zanoni's avatar
Paulo Zanoni committed
45 46 47
/**
 * SECTION:igt_draw
 * @short_description: drawing helpers for tests
48
 * @title: Draw
49
 * @include: igt.h
Paulo Zanoni's avatar
Paulo Zanoni committed
50 51 52 53 54
 *
 * This library contains some functions for drawing rectangles on buffers using
 * the many different drawing methods we have. It also contains some wrappers
 * that make the process easier if you have the abstract objects in hand.
 *
55 56 57 58
 * This library only claims support for some pixel formats, but adding support
 * for more formats should be faily easy now that we support both 16bpp and
 * 32bpp. If you need a new pixel format, make sure you update both this file
 * and tests/kms_draw_crc.c.
Paulo Zanoni's avatar
Paulo Zanoni committed
59 60 61 62 63 64 65 66 67 68 69 70 71
 */

/* Some internal data structures to avoid having to pass tons of parameters
 * around everything. */
struct cmd_data {
	drm_intel_bufmgr *bufmgr;
	drm_intel_context *context;
};

struct buf_data {
	uint32_t handle;
	uint32_t size;
	uint32_t stride;
72
	int bpp;
Paulo Zanoni's avatar
Paulo Zanoni committed
73 74 75 76 77 78 79 80 81 82 83
};

struct rect {
	int x;
	int y;
	int w;
	int h;
};

/**
 * igt_draw_get_method_name:
84
 * @method: draw method
Paulo Zanoni's avatar
Paulo Zanoni committed
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
 *
 * Simple function to transform the enum into a string. Useful when naming
 * subtests and printing debug messages.
 */
const char *igt_draw_get_method_name(enum igt_draw_method method)
{
	switch (method) {
	case IGT_DRAW_MMAP_CPU:
		return "mmap-cpu";
	case IGT_DRAW_MMAP_GTT:
		return "mmap-gtt";
	case IGT_DRAW_MMAP_WC:
		return "mmap-wc";
	case IGT_DRAW_PWRITE:
		return "pwrite";
	case IGT_DRAW_BLT:
		return "blt";
	case IGT_DRAW_RENDER:
		return "render";
	default:
		igt_assert(false);
	}
}

109
static unsigned long swizzle_bit(unsigned int bit, unsigned long offset)
Paulo Zanoni's avatar
Paulo Zanoni committed
110
{
111 112
	return (offset & (1ul << bit)) >> (bit - 6);
}
Paulo Zanoni's avatar
Paulo Zanoni committed
113

114 115
static int swizzle_addr(unsigned long addr, int swizzle)
{
Paulo Zanoni's avatar
Paulo Zanoni committed
116 117
	switch (swizzle) {
	case I915_BIT_6_SWIZZLE_NONE:
118
		return addr;
Paulo Zanoni's avatar
Paulo Zanoni committed
119
	case I915_BIT_6_SWIZZLE_9:
120
		return addr ^ swizzle_bit(9, addr);
Paulo Zanoni's avatar
Paulo Zanoni committed
121
	case I915_BIT_6_SWIZZLE_9_10:
122
		return addr ^ swizzle_bit(9, addr) ^ swizzle_bit(10, addr);
Paulo Zanoni's avatar
Paulo Zanoni committed
123
	case I915_BIT_6_SWIZZLE_9_11:
124
		return addr ^ swizzle_bit(9, addr) ^ swizzle_bit(11, addr);
Paulo Zanoni's avatar
Paulo Zanoni committed
125
	case I915_BIT_6_SWIZZLE_9_10_11:
126 127 128 129 130
		return (addr ^
			swizzle_bit(9, addr) ^
			swizzle_bit(10, addr) ^
			swizzle_bit(11, addr));

Paulo Zanoni's avatar
Paulo Zanoni committed
131 132 133 134 135 136 137
	case I915_BIT_6_SWIZZLE_UNKNOWN:
	case I915_BIT_6_SWIZZLE_9_17:
	case I915_BIT_6_SWIZZLE_9_10_17:
	default:
		/* If we hit this case, we need to implement support for the
		 * appropriate swizzling method. */
		igt_require(false);
138
		return addr;
Paulo Zanoni's avatar
Paulo Zanoni committed
139 140 141
	}
}

142 143
static int tile(int x, int y, uint32_t x_tile_size, uint32_t y_tile_size,
		uint32_t line_size, bool xmajor)
Paulo Zanoni's avatar
Paulo Zanoni committed
144
{
145 146
	int tile_size, tiles_per_line, x_tile_n, y_tile_n, tile_off, pos;
	int tile_n, x_tile_off, y_tile_off;
Paulo Zanoni's avatar
Paulo Zanoni committed
147 148

	tiles_per_line = line_size / x_tile_size;
149
	tile_size = x_tile_size * y_tile_size;
Paulo Zanoni's avatar
Paulo Zanoni committed
150

151
	x_tile_n = x / x_tile_size;
Paulo Zanoni's avatar
Paulo Zanoni committed
152
	y_tile_n = y / y_tile_size;
153
	tile_n = y_tile_n * tiles_per_line + x_tile_n;
Paulo Zanoni's avatar
Paulo Zanoni committed
154

155 156
	x_tile_off = x % x_tile_size;
	y_tile_off = y % y_tile_size;
Paulo Zanoni's avatar
Paulo Zanoni committed
157

158 159 160 161
	if (xmajor)
		tile_off = y_tile_off * x_tile_size + x_tile_off;
	else
		tile_off = x_tile_off * y_tile_size + y_tile_off;
Paulo Zanoni's avatar
Paulo Zanoni committed
162

163
	pos = tile_n * tile_size + tile_off;
Paulo Zanoni's avatar
Paulo Zanoni committed
164

165
	return pos;
Paulo Zanoni's avatar
Paulo Zanoni committed
166 167
}

168 169
static void untile(int tiled_pos, int x_tile_size, int y_tile_size,
		   uint32_t line_size, bool xmajor, int *x, int *y)
Paulo Zanoni's avatar
Paulo Zanoni committed
170
{
171
	int tile_n, tile_off, tiles_per_line;
Paulo Zanoni's avatar
Paulo Zanoni committed
172 173
	int x_tile_off, y_tile_off;
	int x_tile_n, y_tile_n;
174
	int tile_size;
Paulo Zanoni's avatar
Paulo Zanoni committed
175 176 177 178 179 180 181

	tile_size = x_tile_size * y_tile_size;
	tiles_per_line = line_size / x_tile_size;

	tile_n = tiled_pos / tile_size;
	tile_off = tiled_pos % tile_size;

182 183 184 185 186 187 188
	if (xmajor) {
		y_tile_off = tile_off / x_tile_size;
		x_tile_off = tile_off % x_tile_size;
	} else {
		y_tile_off = tile_off % y_tile_size;
		x_tile_off = tile_off / y_tile_size;
	}
Paulo Zanoni's avatar
Paulo Zanoni committed
189 190 191 192

	x_tile_n = tile_n % tiles_per_line;
	y_tile_n = tile_n / tiles_per_line;

193
	*x = (x_tile_n * x_tile_size + x_tile_off);
Paulo Zanoni's avatar
Paulo Zanoni committed
194 195 196
	*y = y_tile_n * y_tile_size + y_tile_off;
}

197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
static int linear_x_y_to_xtiled_pos(int x, int y, uint32_t stride, int swizzle,
				    int bpp)
{
	int pos;
	int pixel_size = bpp / 8;

	x *= pixel_size;
	pos = tile(x, y, 512, 8, stride, true);
	pos = swizzle_addr(pos, swizzle);
	return pos / pixel_size;
}

static int linear_x_y_to_ytiled_pos(int x, int y, uint32_t stride, int swizzle,
				    int bpp)
{
	int ow_tile_n, pos;
	int ow_size = 16;
	int pixel_size = bpp / 8;

	/* We have an Y tiling of OWords, so use the tile() function to get the
	 * OW number, then adjust to the fact that the OW may have more than one
	 * pixel. */
	x *= pixel_size;
	ow_tile_n = tile(x / ow_size, y, 128 / ow_size, 32,
			 stride / ow_size, false);
	pos = ow_tile_n * ow_size + (x % ow_size);
	pos = swizzle_addr(pos, swizzle);
	return pos / pixel_size;
}

static void xtiled_pos_to_x_y_linear(int tiled_pos, uint32_t stride,
				     int swizzle, int bpp, int *x, int *y)
{
	int pixel_size = bpp / 8;

	tiled_pos = swizzle_addr(tiled_pos, swizzle);

	untile(tiled_pos, 512, 8, stride, true, x, y);
	*x /= pixel_size;
}

static void ytiled_pos_to_x_y_linear(int tiled_pos, uint32_t stride,
				     int swizzle, int bpp, int *x, int *y)
{
	int ow_tile_n;
	int ow_size = 16;
	int pixel_size = bpp / 8;

	tiled_pos = swizzle_addr(tiled_pos, swizzle);

	ow_tile_n = tiled_pos / ow_size;
	untile(ow_tile_n, 128 / ow_size, 32, stride / ow_size, false, x, y);
	*x *= ow_size;
	*x += tiled_pos % ow_size;
	*x /= pixel_size;
}

254 255 256 257 258 259 260 261 262 263 264 265 266
static void set_pixel(void *_ptr, int index, uint32_t color, int bpp)
{
	if (bpp == 16) {
		uint16_t *ptr = _ptr;
		ptr[index] = color;
	} else if (bpp == 32) {
		uint32_t *ptr = _ptr;
		ptr[index] = color;
	} else {
		igt_assert_f(false, "bpp: %d\n", bpp);
	}
}

267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
static void switch_blt_tiling(struct intel_batchbuffer *batch, uint32_t tiling,
			      bool on)
{
	uint32_t bcs_swctrl;

	/* Default is X-tile */
	if (tiling != I915_TILING_Y)
		return;

	bcs_swctrl = (0x3 << 16) | (on ? 0x3 : 0x0);

	/* To change the tile register, insert an MI_FLUSH_DW followed by an
	 * MI_LOAD_REGISTER_IMM
	 */
	BEGIN_BATCH(4, 0);
	OUT_BATCH(MI_FLUSH_DW | 2);
	OUT_BATCH(0x0);
	OUT_BATCH(0x0);
	OUT_BATCH(0x0);
	ADVANCE_BATCH();

	BEGIN_BATCH(4, 0);
	OUT_BATCH(MI_LOAD_REGISTER_IMM);
	OUT_BATCH(0x22200); /* BCS_SWCTRL */
	OUT_BATCH(bcs_swctrl);
	OUT_BATCH(MI_NOOP);
	ADVANCE_BATCH();
}

296 297
static void draw_rect_ptr_linear(void *ptr, uint32_t stride,
				 struct rect *rect, uint32_t color, int bpp)
Paulo Zanoni's avatar
Paulo Zanoni committed
298 299 300 301
{
	int x, y, line_begin;

	for (y = rect->y; y < rect->y + rect->h; y++) {
302
		line_begin = y * stride / (bpp / 8);
Paulo Zanoni's avatar
Paulo Zanoni committed
303
		for (x = rect->x; x < rect->x + rect->w; x++)
304
			set_pixel(ptr, line_begin + x, color, bpp);
Paulo Zanoni's avatar
Paulo Zanoni committed
305 306 307
	}
}

308 309 310
static void draw_rect_ptr_tiled(void *ptr, uint32_t stride, uint32_t tiling,
				int swizzle, struct rect *rect, uint32_t color,
				int bpp)
Paulo Zanoni's avatar
Paulo Zanoni committed
311 312 313 314 315
{
	int x, y, pos;

	for (y = rect->y; y < rect->y + rect->h; y++) {
		for (x = rect->x; x < rect->x + rect->w; x++) {
316 317 318 319 320 321 322 323 324 325 326 327
			switch (tiling) {
			case I915_TILING_X:
				pos = linear_x_y_to_xtiled_pos(x, y, stride,
							       swizzle, bpp);
				break;
			case I915_TILING_Y:
				pos = linear_x_y_to_ytiled_pos(x, y, stride,
							       swizzle, bpp);
				break;
			default:
				igt_assert(false);
			}
328
			set_pixel(ptr, pos, color, bpp);
Paulo Zanoni's avatar
Paulo Zanoni committed
329 330 331 332 333 334 335 336 337 338 339 340
		}
	}
}

static void draw_rect_mmap_cpu(int fd, struct buf_data *buf, struct rect *rect,
			       uint32_t color)
{
	uint32_t *ptr;
	uint32_t tiling, swizzle;

	gem_set_domain(fd, buf->handle, I915_GEM_DOMAIN_CPU,
		       I915_GEM_DOMAIN_CPU);
341
	igt_require(gem_get_tiling(fd, buf->handle, &tiling, &swizzle));
Paulo Zanoni's avatar
Paulo Zanoni committed
342 343 344 345 346

	/* We didn't implement suport for the older tiling methods yet. */
	if (tiling != I915_TILING_NONE)
		igt_require(intel_gen(intel_get_drm_devid(fd)) >= 5);

347
	ptr = gem_mmap__cpu(fd, buf->handle, 0, PAGE_ALIGN(buf->size), 0);
Paulo Zanoni's avatar
Paulo Zanoni committed
348 349 350

	switch (tiling) {
	case I915_TILING_NONE:
351
		draw_rect_ptr_linear(ptr, buf->stride, rect, color, buf->bpp);
Paulo Zanoni's avatar
Paulo Zanoni committed
352 353
		break;
	case I915_TILING_X:
354 355 356
	case I915_TILING_Y:
		draw_rect_ptr_tiled(ptr, buf->stride, tiling, swizzle, rect,
				    color, buf->bpp);
Paulo Zanoni's avatar
Paulo Zanoni committed
357 358 359 360 361 362 363 364
		break;
	default:
		igt_assert(false);
		break;
	}

	gem_sw_finish(fd, buf->handle);

365
	igt_assert(gem_munmap(ptr, buf->size) == 0);
Paulo Zanoni's avatar
Paulo Zanoni committed
366 367 368 369 370 371 372
}

static void draw_rect_mmap_gtt(int fd, struct buf_data *buf, struct rect *rect,
			       uint32_t color)
{
	uint32_t *ptr;

373 374 375
	gem_set_domain(fd, buf->handle, I915_GEM_DOMAIN_GTT,
		       I915_GEM_DOMAIN_GTT);

376 377
	ptr = gem_mmap__gtt(fd, buf->handle, PAGE_ALIGN(buf->size),
			    PROT_READ | PROT_WRITE);
Paulo Zanoni's avatar
Paulo Zanoni committed
378

379
	draw_rect_ptr_linear(ptr, buf->stride, rect, color, buf->bpp);
Paulo Zanoni's avatar
Paulo Zanoni committed
380

381
	igt_assert(gem_munmap(ptr, buf->size) == 0);
Paulo Zanoni's avatar
Paulo Zanoni committed
382 383 384 385 386 387 388 389
}

static void draw_rect_mmap_wc(int fd, struct buf_data *buf, struct rect *rect,
			      uint32_t color)
{
	uint32_t *ptr;
	uint32_t tiling, swizzle;

390 391
	gem_set_domain(fd, buf->handle, I915_GEM_DOMAIN_GTT,
		       I915_GEM_DOMAIN_GTT);
392
	igt_require(gem_get_tiling(fd, buf->handle, &tiling, &swizzle));
Paulo Zanoni's avatar
Paulo Zanoni committed
393 394 395 396 397

	/* We didn't implement suport for the older tiling methods yet. */
	if (tiling != I915_TILING_NONE)
		igt_require(intel_gen(intel_get_drm_devid(fd)) >= 5);

398
	ptr = gem_mmap__wc(fd, buf->handle, 0, PAGE_ALIGN(buf->size),
Paulo Zanoni's avatar
Paulo Zanoni committed
399 400 401 402
			   PROT_READ | PROT_WRITE);

	switch (tiling) {
	case I915_TILING_NONE:
403
		draw_rect_ptr_linear(ptr, buf->stride, rect, color, buf->bpp);
Paulo Zanoni's avatar
Paulo Zanoni committed
404 405
		break;
	case I915_TILING_X:
406 407 408
	case I915_TILING_Y:
		draw_rect_ptr_tiled(ptr, buf->stride, tiling, swizzle, rect,
				    color, buf->bpp);
Paulo Zanoni's avatar
Paulo Zanoni committed
409 410 411 412 413 414
		break;
	default:
		igt_assert(false);
		break;
	}

415
	igt_assert(gem_munmap(ptr, buf->size) == 0);
Paulo Zanoni's avatar
Paulo Zanoni committed
416 417 418 419 420
}

static void draw_rect_pwrite_untiled(int fd, struct buf_data *buf,
				     struct rect *rect, uint32_t color)
{
421 422 423
	int i, y, offset;
	int pixel_size = buf->bpp / 8;
	uint8_t tmp[rect->w * pixel_size];
Paulo Zanoni's avatar
Paulo Zanoni committed
424 425

	for (i = 0; i < rect->w; i++)
426
		set_pixel(tmp, i, color, buf->bpp);
Paulo Zanoni's avatar
Paulo Zanoni committed
427 428

	for (y = rect->y; y < rect->y + rect->h; y++) {
429 430
		offset = (y * buf->stride) + (rect->x * pixel_size);
		gem_write(fd, buf->handle, offset, tmp, rect->w * pixel_size);
Paulo Zanoni's avatar
Paulo Zanoni committed
431 432 433 434
	}
}

static void draw_rect_pwrite_tiled(int fd, struct buf_data *buf,
435 436
				   uint32_t tiling, struct rect *rect,
				   uint32_t color, uint32_t swizzle)
Paulo Zanoni's avatar
Paulo Zanoni committed
437 438
{
	int i;
439 440 441
	int tiled_pos, x, y, pixel_size;
	uint8_t tmp[4096];
	int tmp_used = 0, tmp_size;
Paulo Zanoni's avatar
Paulo Zanoni committed
442 443
	bool flush_tmp = false;
	int tmp_start_pos = 0;
444
	int pixels_written = 0;
Paulo Zanoni's avatar
Paulo Zanoni committed
445 446 447 448

	/* We didn't implement suport for the older tiling methods yet. */
	igt_require(intel_gen(intel_get_drm_devid(fd)) >= 5);

449 450
	pixel_size = buf->bpp / 8;
	tmp_size = sizeof(tmp) / pixel_size;
Paulo Zanoni's avatar
Paulo Zanoni committed
451 452 453 454 455

	/* Instead of doing one pwrite per pixel, we try to group the maximum
	 * amount of consecutive pixels we can in a single pwrite: that's why we
	 * use the "tmp" variables. */
	for (i = 0; i < tmp_size; i++)
456
		set_pixel(tmp, i, color, buf->bpp);
Paulo Zanoni's avatar
Paulo Zanoni committed
457

458
	for (tiled_pos = 0; tiled_pos < buf->size; tiled_pos += pixel_size) {
459 460 461 462 463 464 465 466 467 468 469 470
		switch (tiling) {
		case I915_TILING_X:
			xtiled_pos_to_x_y_linear(tiled_pos, buf->stride,
						 swizzle, buf->bpp, &x, &y);
			break;
		case I915_TILING_Y:
			ytiled_pos_to_x_y_linear(tiled_pos, buf->stride,
						 swizzle, buf->bpp, &x, &y);
			break;
		default:
			igt_assert(false);
		}
Paulo Zanoni's avatar
Paulo Zanoni committed
471 472 473 474 475 476 477 478 479 480

		if (x >= rect->x && x < rect->x + rect->w &&
		    y >= rect->y && y < rect->y + rect->h) {
			if (tmp_used == 0)
				tmp_start_pos = tiled_pos;
			tmp_used++;
		} else {
			flush_tmp = true;
		}

481 482
		if (tmp_used == tmp_size || (flush_tmp && tmp_used > 0) ||
		    tiled_pos + pixel_size >= buf->size) {
Paulo Zanoni's avatar
Paulo Zanoni committed
483
			gem_write(fd, buf->handle, tmp_start_pos, tmp,
484
				  tmp_used * pixel_size);
Paulo Zanoni's avatar
Paulo Zanoni committed
485
			flush_tmp = false;
486
			pixels_written += tmp_used;
Paulo Zanoni's avatar
Paulo Zanoni committed
487
			tmp_used = 0;
488 489 490

			if (pixels_written == rect->w * rect->h)
				break;
Paulo Zanoni's avatar
Paulo Zanoni committed
491 492 493 494 495 496 497 498 499
		}
	}
}

static void draw_rect_pwrite(int fd, struct buf_data *buf,
			     struct rect *rect, uint32_t color)
{
	uint32_t tiling, swizzle;

500
	igt_require(gem_get_tiling(fd, buf->handle, &tiling, &swizzle));
Paulo Zanoni's avatar
Paulo Zanoni committed
501 502 503 504 505 506

	switch (tiling) {
	case I915_TILING_NONE:
		draw_rect_pwrite_untiled(fd, buf, rect, color);
		break;
	case I915_TILING_X:
507 508
	case I915_TILING_Y:
		draw_rect_pwrite_tiled(fd, buf, tiling, rect, color, swizzle);
Paulo Zanoni's avatar
Paulo Zanoni committed
509 510 511 512 513 514 515 516 517 518 519 520 521
		break;
	default:
		igt_assert(false);
		break;
	}
}

static void draw_rect_blt(int fd, struct cmd_data *cmd_data,
			  struct buf_data *buf, struct rect *rect,
			  uint32_t color)
{
	drm_intel_bo *dst;
	struct intel_batchbuffer *batch;
522
	int blt_cmd_len, blt_cmd_tiling, blt_cmd_depth;
Paulo Zanoni's avatar
Paulo Zanoni committed
523 524 525 526 527
	uint32_t devid = intel_get_drm_devid(fd);
	int gen = intel_gen(devid);
	uint32_t tiling, swizzle;
	int pitch;

528
	igt_require(gem_get_tiling(fd, buf->handle, &tiling, &swizzle));
Paulo Zanoni's avatar
Paulo Zanoni committed
529 530 531 532 533 534 535

	dst = gem_handle_to_libdrm_bo(cmd_data->bufmgr, fd, "", buf->handle);
	igt_assert(dst);

	batch = intel_batchbuffer_alloc(cmd_data->bufmgr, devid);
	igt_assert(batch);

536 537 538 539 540 541 542 543 544 545 546 547 548 549
	switch (buf->bpp) {
	case 8:
		blt_cmd_depth = 0;
		break;
	case 16: /* we're assuming 565 */
		blt_cmd_depth = 1 << 24;
		break;
	case 32:
		blt_cmd_depth = 3 << 24;
		break;
	default:
		igt_assert(false);
	}

Paulo Zanoni's avatar
Paulo Zanoni committed
550 551 552 553
	blt_cmd_len = (gen >= 8) ?  0x5 : 0x4;
	blt_cmd_tiling = (tiling) ? XY_COLOR_BLT_TILED : 0;
	pitch = (tiling) ? buf->stride / 4 : buf->stride;

554 555
	switch_blt_tiling(batch, tiling, true);

Paulo Zanoni's avatar
Paulo Zanoni committed
556 557 558
	BEGIN_BATCH(6, 1);
	OUT_BATCH(XY_COLOR_BLT_CMD_NOLEN | XY_COLOR_BLT_WRITE_ALPHA |
		  XY_COLOR_BLT_WRITE_RGB | blt_cmd_tiling | blt_cmd_len);
559
	OUT_BATCH(blt_cmd_depth | (0xF0 << 16) | pitch);
Paulo Zanoni's avatar
Paulo Zanoni committed
560 561 562 563 564 565
	OUT_BATCH((rect->y << 16) | rect->x);
	OUT_BATCH(((rect->y + rect->h) << 16) | (rect->x + rect->w));
	OUT_RELOC_FENCED(dst, 0, I915_GEM_DOMAIN_RENDER, 0);
	OUT_BATCH(color);
	ADVANCE_BATCH();

566 567
	switch_blt_tiling(batch, tiling, false);

Paulo Zanoni's avatar
Paulo Zanoni committed
568 569
	intel_batchbuffer_flush(batch);
	intel_batchbuffer_free(batch);
570
	drm_intel_bo_unreference(dst);
Paulo Zanoni's avatar
Paulo Zanoni committed
571 572 573 574 575 576 577 578 579
}

static void draw_rect_render(int fd, struct cmd_data *cmd_data,
			     struct buf_data *buf, struct rect *rect,
			     uint32_t color)
{
	drm_intel_bo *src, *dst;
	uint32_t devid = intel_get_drm_devid(fd);
	igt_render_copyfunc_t rendercopy = igt_get_render_copyfunc(devid);
580
	struct igt_buf src_buf = {}, dst_buf = {};
Paulo Zanoni's avatar
Paulo Zanoni committed
581 582 583
	struct intel_batchbuffer *batch;
	uint32_t tiling, swizzle;
	struct buf_data tmp;
584
	int pixel_size = buf->bpp / 8;
Paulo Zanoni's avatar
Paulo Zanoni committed
585 586 587

	igt_skip_on(!rendercopy);

588
	igt_require(gem_get_tiling(fd, buf->handle, &tiling, &swizzle));
Paulo Zanoni's avatar
Paulo Zanoni committed
589 590

	/* We create a temporary buffer and copy from it using rendercopy. */
591
	tmp.size = rect->w * rect->h * pixel_size;
Paulo Zanoni's avatar
Paulo Zanoni committed
592
	tmp.handle = gem_create(fd, tmp.size);
593 594
	tmp.stride = rect->w * pixel_size;
	tmp.bpp = buf->bpp;
Paulo Zanoni's avatar
Paulo Zanoni committed
595 596 597 598 599 600 601 602 603 604 605 606
	draw_rect_mmap_cpu(fd, &tmp, &(struct rect){0, 0, rect->w, rect->h},
			   color);

	src = gem_handle_to_libdrm_bo(cmd_data->bufmgr, fd, "", tmp.handle);
	igt_assert(src);
	dst = gem_handle_to_libdrm_bo(cmd_data->bufmgr, fd, "", buf->handle);
	igt_assert(dst);

	src_buf.bo = src;
	src_buf.stride = tmp.stride;
	src_buf.tiling = I915_TILING_NONE;
	src_buf.size = tmp.size;
607
	src_buf.bpp = tmp.bpp;
Paulo Zanoni's avatar
Paulo Zanoni committed
608 609 610 611
	dst_buf.bo = dst;
	dst_buf.stride = buf->stride;
	dst_buf.tiling = tiling;
	dst_buf.size = buf->size;
612
	dst_buf.bpp = buf->bpp;
Paulo Zanoni's avatar
Paulo Zanoni committed
613 614 615 616

	batch = intel_batchbuffer_alloc(cmd_data->bufmgr, devid);
	igt_assert(batch);

617 618
	rendercopy(batch, cmd_data->context, &src_buf, 0, 0, rect->w,
		   rect->h, &dst_buf, rect->x, rect->y);
Paulo Zanoni's avatar
Paulo Zanoni committed
619 620

	intel_batchbuffer_free(batch);
621 622
	drm_intel_bo_unreference(src);
	drm_intel_bo_unreference(dst);
Paulo Zanoni's avatar
Paulo Zanoni committed
623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640
	gem_close(fd, tmp.handle);
}

/**
 * igt_draw_rect:
 * @fd: the DRM file descriptor
 * @bufmgr: the libdrm bufmgr, only required for IGT_DRAW_BLT and
 *          IGT_DRAW_RENDER
 * @context: the context, can be NULL if you don't want to think about it
 * @buf_handle: the handle of the buffer where you're going to draw to
 * @buf_size: the size of the buffer
 * @buf_stride: the stride of the buffer
 * @method: method you're going to use to write to the buffer
 * @rect_x: horizontal position on the buffer where your rectangle starts
 * @rect_y: vertical position on the buffer where your rectangle starts
 * @rect_w: width of the rectangle
 * @rect_h: height of the rectangle
 * @color: color of the rectangle
641
 * @bpp: bits per pixel
Paulo Zanoni's avatar
Paulo Zanoni committed
642 643
 *
 * This function draws a colored rectangle on the destination buffer, allowing
644
 * you to specify the method used to draw the rectangle.
Paulo Zanoni's avatar
Paulo Zanoni committed
645 646 647 648
 */
void igt_draw_rect(int fd, drm_intel_bufmgr *bufmgr, drm_intel_context *context,
		   uint32_t buf_handle, uint32_t buf_size, uint32_t buf_stride,
		   enum igt_draw_method method, int rect_x, int rect_y,
649
		   int rect_w, int rect_h, uint32_t color, int bpp)
Paulo Zanoni's avatar
Paulo Zanoni committed
650 651 652 653 654 655 656 657 658
{
	struct cmd_data cmd_data = {
		.bufmgr = bufmgr,
		.context = context,
	};
	struct buf_data buf = {
		.handle = buf_handle,
		.size = buf_size,
		.stride = buf_stride,
659
		.bpp = bpp,
Paulo Zanoni's avatar
Paulo Zanoni committed
660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694
	};
	struct rect rect = {
		.x = rect_x,
		.y = rect_y,
		.w = rect_w,
		.h = rect_h,
	};

	switch (method) {
	case IGT_DRAW_MMAP_CPU:
		draw_rect_mmap_cpu(fd, &buf, &rect, color);
		break;
	case IGT_DRAW_MMAP_GTT:
		draw_rect_mmap_gtt(fd, &buf, &rect, color);
		break;
	case IGT_DRAW_MMAP_WC:
		draw_rect_mmap_wc(fd, &buf, &rect, color);
		break;
	case IGT_DRAW_PWRITE:
		draw_rect_pwrite(fd, &buf, &rect, color);
		break;
	case IGT_DRAW_BLT:
		draw_rect_blt(fd, &cmd_data, &buf, &rect, color);
		break;
	case IGT_DRAW_RENDER:
		draw_rect_render(fd, &cmd_data, &buf, &rect, color);
		break;
	default:
		igt_assert(false);
		break;
	}
}

/**
 * igt_draw_rect_fb:
695 696 697 698 699 700 701 702 703 704 705
 * @fd: the DRM file descriptor
 * @bufmgr: the libdrm bufmgr, only required for IGT_DRAW_BLT and
 *          IGT_DRAW_RENDER
 * @context: the context, can be NULL if you don't want to think about it
 * @fb: framebuffer
 * @method: method you're going to use to write to the buffer
 * @rect_x: horizontal position on the buffer where your rectangle starts
 * @rect_y: vertical position on the buffer where your rectangle starts
 * @rect_w: width of the rectangle
 * @rect_h: height of the rectangle
 * @color: color of the rectangle
Paulo Zanoni's avatar
Paulo Zanoni committed
706 707 708 709 710 711 712 713 714
 *
 * This is exactly the same as igt_draw_rect, but you can pass an igt_fb instead
 * of manually providing its details. See igt_draw_rect.
 */
void igt_draw_rect_fb(int fd, drm_intel_bufmgr *bufmgr,
		      drm_intel_context *context, struct igt_fb *fb,
		      enum igt_draw_method method, int rect_x, int rect_y,
		      int rect_w, int rect_h, uint32_t color)
{
715
	igt_draw_rect(fd, bufmgr, context, fb->gem_handle, fb->size, fb->strides[0],
716
		      method, rect_x, rect_y, rect_w, rect_h, color,
717
		      igt_drm_format_to_bpp(fb->drm_format));
Paulo Zanoni's avatar
Paulo Zanoni committed
718 719 720 721 722 723 724 725
}

/**
 * igt_draw_fill_fb:
 * @fd: the DRM file descriptor
 * @fb: the FB that is going to be filled
 * @color: the color you're going to paint it
 *
726
 * This function just paints an igt_fb using the provided color.
Paulo Zanoni's avatar
Paulo Zanoni committed
727 728 729 730 731 732
 */
void igt_draw_fill_fb(int fd, struct igt_fb *fb, uint32_t color)
{
	igt_draw_rect_fb(fd, NULL, NULL, fb, IGT_DRAW_MMAP_GTT,
			 0, 0, fb->width, fb->height, color);
}