1 /*
2  * Copyright © 2015 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  */
24 
25 #include <sys/mman.h>
26 
27 #include "igt_draw.h"
28 
29 #include "drmtest.h"
30 #include "intel_batchbuffer.h"
31 #include "intel_chipset.h"
32 #include "igt_core.h"
33 #include "igt_fb.h"
34 #include "ioctl_wrappers.h"
35 #include "i830_reg.h"
36 #include "i915/gem_mman.h"
37 
38 #ifndef PAGE_ALIGN
39 #ifndef PAGE_SIZE
40 #define PAGE_SIZE 4096
41 #endif
42 #define PAGE_ALIGN(x) ALIGN(x, PAGE_SIZE)
43 #endif
44 
45 /**
46  * SECTION:igt_draw
47  * @short_description: drawing helpers for tests
48  * @title: Draw
49  * @include: igt.h
50  *
51  * This library contains some functions for drawing rectangles on buffers using
52  * the many different drawing methods we have. It also contains some wrappers
53  * that make the process easier if you have the abstract objects in hand.
54  *
55  * This library only claims support for some pixel formats, but adding support
56  * for more formats should be faily easy now that we support both 16bpp and
57  * 32bpp. If you need a new pixel format, make sure you update both this file
58  * and tests/kms_draw_crc.c.
59  */
60 
61 /* Some internal data structures to avoid having to pass tons of parameters
62  * around everything. */
63 struct cmd_data {
64 	drm_intel_bufmgr *bufmgr;
65 	drm_intel_context *context;
66 };
67 
68 struct buf_data {
69 	uint32_t handle;
70 	uint32_t size;
71 	uint32_t stride;
72 	int bpp;
73 };
74 
75 struct rect {
76 	int x;
77 	int y;
78 	int w;
79 	int h;
80 };
81 
82 /**
83  * igt_draw_get_method_name:
84  * @method: draw method
85  *
86  * Simple function to transform the enum into a string. Useful when naming
87  * subtests and printing debug messages.
88  */
igt_draw_get_method_name(enum igt_draw_method method)89 const char *igt_draw_get_method_name(enum igt_draw_method method)
90 {
91 	switch (method) {
92 	case IGT_DRAW_MMAP_CPU:
93 		return "mmap-cpu";
94 	case IGT_DRAW_MMAP_GTT:
95 		return "mmap-gtt";
96 	case IGT_DRAW_MMAP_WC:
97 		return "mmap-wc";
98 	case IGT_DRAW_PWRITE:
99 		return "pwrite";
100 	case IGT_DRAW_BLT:
101 		return "blt";
102 	case IGT_DRAW_RENDER:
103 		return "render";
104 	default:
105 		igt_assert(false);
106 	}
107 }
108 
swizzle_bit(unsigned int bit,unsigned long offset)109 static unsigned long swizzle_bit(unsigned int bit, unsigned long offset)
110 {
111 	return (offset & (1ul << bit)) >> (bit - 6);
112 }
113 
swizzle_addr(unsigned long addr,int swizzle)114 static int swizzle_addr(unsigned long addr, int swizzle)
115 {
116 	switch (swizzle) {
117 	case I915_BIT_6_SWIZZLE_NONE:
118 		return addr;
119 	case I915_BIT_6_SWIZZLE_9:
120 		return addr ^ swizzle_bit(9, addr);
121 	case I915_BIT_6_SWIZZLE_9_10:
122 		return addr ^ swizzle_bit(9, addr) ^ swizzle_bit(10, addr);
123 	case I915_BIT_6_SWIZZLE_9_11:
124 		return addr ^ swizzle_bit(9, addr) ^ swizzle_bit(11, addr);
125 	case I915_BIT_6_SWIZZLE_9_10_11:
126 		return (addr ^
127 			swizzle_bit(9, addr) ^
128 			swizzle_bit(10, addr) ^
129 			swizzle_bit(11, addr));
130 
131 	case I915_BIT_6_SWIZZLE_UNKNOWN:
132 	case I915_BIT_6_SWIZZLE_9_17:
133 	case I915_BIT_6_SWIZZLE_9_10_17:
134 	default:
135 		/* If we hit this case, we need to implement support for the
136 		 * appropriate swizzling method. */
137 		igt_require(false);
138 		return addr;
139 	}
140 }
141 
tile(int x,int y,uint32_t x_tile_size,uint32_t y_tile_size,uint32_t line_size,bool xmajor)142 static int tile(int x, int y, uint32_t x_tile_size, uint32_t y_tile_size,
143 		uint32_t line_size, bool xmajor)
144 {
145 	int tile_size, tiles_per_line, x_tile_n, y_tile_n, tile_off, pos;
146 	int tile_n, x_tile_off, y_tile_off;
147 
148 	tiles_per_line = line_size / x_tile_size;
149 	tile_size = x_tile_size * y_tile_size;
150 
151 	x_tile_n = x / x_tile_size;
152 	y_tile_n = y / y_tile_size;
153 	tile_n = y_tile_n * tiles_per_line + x_tile_n;
154 
155 	x_tile_off = x % x_tile_size;
156 	y_tile_off = y % y_tile_size;
157 
158 	if (xmajor)
159 		tile_off = y_tile_off * x_tile_size + x_tile_off;
160 	else
161 		tile_off = x_tile_off * y_tile_size + y_tile_off;
162 
163 	pos = tile_n * tile_size + tile_off;
164 
165 	return pos;
166 }
167 
untile(int tiled_pos,int x_tile_size,int y_tile_size,uint32_t line_size,bool xmajor,int * x,int * y)168 static void untile(int tiled_pos, int x_tile_size, int y_tile_size,
169 		   uint32_t line_size, bool xmajor, int *x, int *y)
170 {
171 	int tile_n, tile_off, tiles_per_line;
172 	int x_tile_off, y_tile_off;
173 	int x_tile_n, y_tile_n;
174 	int tile_size;
175 
176 	tile_size = x_tile_size * y_tile_size;
177 	tiles_per_line = line_size / x_tile_size;
178 
179 	tile_n = tiled_pos / tile_size;
180 	tile_off = tiled_pos % tile_size;
181 
182 	if (xmajor) {
183 		y_tile_off = tile_off / x_tile_size;
184 		x_tile_off = tile_off % x_tile_size;
185 	} else {
186 		y_tile_off = tile_off % y_tile_size;
187 		x_tile_off = tile_off / y_tile_size;
188 	}
189 
190 	x_tile_n = tile_n % tiles_per_line;
191 	y_tile_n = tile_n / tiles_per_line;
192 
193 	*x = (x_tile_n * x_tile_size + x_tile_off);
194 	*y = y_tile_n * y_tile_size + y_tile_off;
195 }
196 
linear_x_y_to_xtiled_pos(int x,int y,uint32_t stride,int swizzle,int bpp)197 static int linear_x_y_to_xtiled_pos(int x, int y, uint32_t stride, int swizzle,
198 				    int bpp)
199 {
200 	int pos;
201 	int pixel_size = bpp / 8;
202 
203 	x *= pixel_size;
204 	pos = tile(x, y, 512, 8, stride, true);
205 	pos = swizzle_addr(pos, swizzle);
206 	return pos / pixel_size;
207 }
208 
linear_x_y_to_ytiled_pos(int x,int y,uint32_t stride,int swizzle,int bpp)209 static int linear_x_y_to_ytiled_pos(int x, int y, uint32_t stride, int swizzle,
210 				    int bpp)
211 {
212 	int ow_tile_n, pos;
213 	int ow_size = 16;
214 	int pixel_size = bpp / 8;
215 
216 	/* We have an Y tiling of OWords, so use the tile() function to get the
217 	 * OW number, then adjust to the fact that the OW may have more than one
218 	 * pixel. */
219 	x *= pixel_size;
220 	ow_tile_n = tile(x / ow_size, y, 128 / ow_size, 32,
221 			 stride / ow_size, false);
222 	pos = ow_tile_n * ow_size + (x % ow_size);
223 	pos = swizzle_addr(pos, swizzle);
224 	return pos / pixel_size;
225 }
226 
xtiled_pos_to_x_y_linear(int tiled_pos,uint32_t stride,int swizzle,int bpp,int * x,int * y)227 static void xtiled_pos_to_x_y_linear(int tiled_pos, uint32_t stride,
228 				     int swizzle, int bpp, int *x, int *y)
229 {
230 	int pixel_size = bpp / 8;
231 
232 	tiled_pos = swizzle_addr(tiled_pos, swizzle);
233 
234 	untile(tiled_pos, 512, 8, stride, true, x, y);
235 	*x /= pixel_size;
236 }
237 
ytiled_pos_to_x_y_linear(int tiled_pos,uint32_t stride,int swizzle,int bpp,int * x,int * y)238 static void ytiled_pos_to_x_y_linear(int tiled_pos, uint32_t stride,
239 				     int swizzle, int bpp, int *x, int *y)
240 {
241 	int ow_tile_n;
242 	int ow_size = 16;
243 	int pixel_size = bpp / 8;
244 
245 	tiled_pos = swizzle_addr(tiled_pos, swizzle);
246 
247 	ow_tile_n = tiled_pos / ow_size;
248 	untile(ow_tile_n, 128 / ow_size, 32, stride / ow_size, false, x, y);
249 	*x *= ow_size;
250 	*x += tiled_pos % ow_size;
251 	*x /= pixel_size;
252 }
253 
set_pixel(void * _ptr,int index,uint32_t color,int bpp)254 static void set_pixel(void *_ptr, int index, uint32_t color, int bpp)
255 {
256 	if (bpp == 16) {
257 		uint16_t *ptr = _ptr;
258 		ptr[index] = color;
259 	} else if (bpp == 32) {
260 		uint32_t *ptr = _ptr;
261 		ptr[index] = color;
262 	} else {
263 		igt_assert_f(false, "bpp: %d\n", bpp);
264 	}
265 }
266 
switch_blt_tiling(struct intel_batchbuffer * batch,uint32_t tiling,bool on)267 static void switch_blt_tiling(struct intel_batchbuffer *batch, uint32_t tiling,
268 			      bool on)
269 {
270 	uint32_t bcs_swctrl;
271 
272 	/* Default is X-tile */
273 	if (tiling != I915_TILING_Y)
274 		return;
275 
276 	bcs_swctrl = (0x3 << 16) | (on ? 0x3 : 0x0);
277 
278 	/* To change the tile register, insert an MI_FLUSH_DW followed by an
279 	 * MI_LOAD_REGISTER_IMM
280 	 */
281 	BEGIN_BATCH(4, 0);
282 	OUT_BATCH(MI_FLUSH_DW | 2);
283 	OUT_BATCH(0x0);
284 	OUT_BATCH(0x0);
285 	OUT_BATCH(0x0);
286 	ADVANCE_BATCH();
287 
288 	BEGIN_BATCH(4, 0);
289 	OUT_BATCH(MI_LOAD_REGISTER_IMM);
290 	OUT_BATCH(0x22200); /* BCS_SWCTRL */
291 	OUT_BATCH(bcs_swctrl);
292 	OUT_BATCH(MI_NOOP);
293 	ADVANCE_BATCH();
294 }
295 
draw_rect_ptr_linear(void * ptr,uint32_t stride,struct rect * rect,uint32_t color,int bpp)296 static void draw_rect_ptr_linear(void *ptr, uint32_t stride,
297 				 struct rect *rect, uint32_t color, int bpp)
298 {
299 	int x, y, line_begin;
300 
301 	for (y = rect->y; y < rect->y + rect->h; y++) {
302 		line_begin = y * stride / (bpp / 8);
303 		for (x = rect->x; x < rect->x + rect->w; x++)
304 			set_pixel(ptr, line_begin + x, color, bpp);
305 	}
306 }
307 
draw_rect_ptr_tiled(void * ptr,uint32_t stride,uint32_t tiling,int swizzle,struct rect * rect,uint32_t color,int bpp)308 static void draw_rect_ptr_tiled(void *ptr, uint32_t stride, uint32_t tiling,
309 				int swizzle, struct rect *rect, uint32_t color,
310 				int bpp)
311 {
312 	int x, y, pos;
313 
314 	for (y = rect->y; y < rect->y + rect->h; y++) {
315 		for (x = rect->x; x < rect->x + rect->w; x++) {
316 			switch (tiling) {
317 			case I915_TILING_X:
318 				pos = linear_x_y_to_xtiled_pos(x, y, stride,
319 							       swizzle, bpp);
320 				break;
321 			case I915_TILING_Y:
322 				pos = linear_x_y_to_ytiled_pos(x, y, stride,
323 							       swizzle, bpp);
324 				break;
325 			default:
326 				igt_assert(false);
327 			}
328 			set_pixel(ptr, pos, color, bpp);
329 		}
330 	}
331 }
332 
draw_rect_mmap_cpu(int fd,struct buf_data * buf,struct rect * rect,uint32_t color)333 static void draw_rect_mmap_cpu(int fd, struct buf_data *buf, struct rect *rect,
334 			       uint32_t color)
335 {
336 	uint32_t *ptr;
337 	uint32_t tiling, swizzle;
338 
339 	gem_set_domain(fd, buf->handle, I915_GEM_DOMAIN_CPU,
340 		       I915_GEM_DOMAIN_CPU);
341 	igt_require(gem_get_tiling(fd, buf->handle, &tiling, &swizzle));
342 
343 	/* We didn't implement suport for the older tiling methods yet. */
344 	if (tiling != I915_TILING_NONE)
345 		igt_require(intel_gen(intel_get_drm_devid(fd)) >= 5);
346 
347 	ptr = gem_mmap__cpu(fd, buf->handle, 0, PAGE_ALIGN(buf->size), 0);
348 
349 	switch (tiling) {
350 	case I915_TILING_NONE:
351 		draw_rect_ptr_linear(ptr, buf->stride, rect, color, buf->bpp);
352 		break;
353 	case I915_TILING_X:
354 	case I915_TILING_Y:
355 		draw_rect_ptr_tiled(ptr, buf->stride, tiling, swizzle, rect,
356 				    color, buf->bpp);
357 		break;
358 	default:
359 		igt_assert(false);
360 		break;
361 	}
362 
363 	gem_sw_finish(fd, buf->handle);
364 
365 	igt_assert(gem_munmap(ptr, buf->size) == 0);
366 }
367 
draw_rect_mmap_gtt(int fd,struct buf_data * buf,struct rect * rect,uint32_t color)368 static void draw_rect_mmap_gtt(int fd, struct buf_data *buf, struct rect *rect,
369 			       uint32_t color)
370 {
371 	uint32_t *ptr;
372 
373 	gem_set_domain(fd, buf->handle, I915_GEM_DOMAIN_GTT,
374 		       I915_GEM_DOMAIN_GTT);
375 
376 	ptr = gem_mmap__gtt(fd, buf->handle, PAGE_ALIGN(buf->size),
377 			    PROT_READ | PROT_WRITE);
378 
379 	draw_rect_ptr_linear(ptr, buf->stride, rect, color, buf->bpp);
380 
381 	igt_assert(gem_munmap(ptr, buf->size) == 0);
382 }
383 
draw_rect_mmap_wc(int fd,struct buf_data * buf,struct rect * rect,uint32_t color)384 static void draw_rect_mmap_wc(int fd, struct buf_data *buf, struct rect *rect,
385 			      uint32_t color)
386 {
387 	uint32_t *ptr;
388 	uint32_t tiling, swizzle;
389 
390 	gem_set_domain(fd, buf->handle, I915_GEM_DOMAIN_GTT,
391 		       I915_GEM_DOMAIN_GTT);
392 	igt_require(gem_get_tiling(fd, buf->handle, &tiling, &swizzle));
393 
394 	/* We didn't implement suport for the older tiling methods yet. */
395 	if (tiling != I915_TILING_NONE)
396 		igt_require(intel_gen(intel_get_drm_devid(fd)) >= 5);
397 
398 	ptr = gem_mmap__wc(fd, buf->handle, 0, PAGE_ALIGN(buf->size),
399 			   PROT_READ | PROT_WRITE);
400 
401 	switch (tiling) {
402 	case I915_TILING_NONE:
403 		draw_rect_ptr_linear(ptr, buf->stride, rect, color, buf->bpp);
404 		break;
405 	case I915_TILING_X:
406 	case I915_TILING_Y:
407 		draw_rect_ptr_tiled(ptr, buf->stride, tiling, swizzle, rect,
408 				    color, buf->bpp);
409 		break;
410 	default:
411 		igt_assert(false);
412 		break;
413 	}
414 
415 	igt_assert(gem_munmap(ptr, buf->size) == 0);
416 }
417 
draw_rect_pwrite_untiled(int fd,struct buf_data * buf,struct rect * rect,uint32_t color)418 static void draw_rect_pwrite_untiled(int fd, struct buf_data *buf,
419 				     struct rect *rect, uint32_t color)
420 {
421 	int i, y, offset;
422 	int pixel_size = buf->bpp / 8;
423 	uint8_t tmp[rect->w * pixel_size];
424 
425 	for (i = 0; i < rect->w; i++)
426 		set_pixel(tmp, i, color, buf->bpp);
427 
428 	for (y = rect->y; y < rect->y + rect->h; y++) {
429 		offset = (y * buf->stride) + (rect->x * pixel_size);
430 		gem_write(fd, buf->handle, offset, tmp, rect->w * pixel_size);
431 	}
432 }
433 
draw_rect_pwrite_tiled(int fd,struct buf_data * buf,uint32_t tiling,struct rect * rect,uint32_t color,uint32_t swizzle)434 static void draw_rect_pwrite_tiled(int fd, struct buf_data *buf,
435 				   uint32_t tiling, struct rect *rect,
436 				   uint32_t color, uint32_t swizzle)
437 {
438 	int i;
439 	int tiled_pos, x, y, pixel_size;
440 	uint8_t tmp[4096];
441 	int tmp_used = 0, tmp_size;
442 	bool flush_tmp = false;
443 	int tmp_start_pos = 0;
444 	int pixels_written = 0;
445 
446 	/* We didn't implement suport for the older tiling methods yet. */
447 	igt_require(intel_gen(intel_get_drm_devid(fd)) >= 5);
448 
449 	pixel_size = buf->bpp / 8;
450 	tmp_size = sizeof(tmp) / pixel_size;
451 
452 	/* Instead of doing one pwrite per pixel, we try to group the maximum
453 	 * amount of consecutive pixels we can in a single pwrite: that's why we
454 	 * use the "tmp" variables. */
455 	for (i = 0; i < tmp_size; i++)
456 		set_pixel(tmp, i, color, buf->bpp);
457 
458 	for (tiled_pos = 0; tiled_pos < buf->size; tiled_pos += pixel_size) {
459 		switch (tiling) {
460 		case I915_TILING_X:
461 			xtiled_pos_to_x_y_linear(tiled_pos, buf->stride,
462 						 swizzle, buf->bpp, &x, &y);
463 			break;
464 		case I915_TILING_Y:
465 			ytiled_pos_to_x_y_linear(tiled_pos, buf->stride,
466 						 swizzle, buf->bpp, &x, &y);
467 			break;
468 		default:
469 			igt_assert(false);
470 		}
471 
472 		if (x >= rect->x && x < rect->x + rect->w &&
473 		    y >= rect->y && y < rect->y + rect->h) {
474 			if (tmp_used == 0)
475 				tmp_start_pos = tiled_pos;
476 			tmp_used++;
477 		} else {
478 			flush_tmp = true;
479 		}
480 
481 		if (tmp_used == tmp_size || (flush_tmp && tmp_used > 0) ||
482 		    tiled_pos + pixel_size >= buf->size) {
483 			gem_write(fd, buf->handle, tmp_start_pos, tmp,
484 				  tmp_used * pixel_size);
485 			flush_tmp = false;
486 			pixels_written += tmp_used;
487 			tmp_used = 0;
488 
489 			if (pixels_written == rect->w * rect->h)
490 				break;
491 		}
492 	}
493 }
494 
draw_rect_pwrite(int fd,struct buf_data * buf,struct rect * rect,uint32_t color)495 static void draw_rect_pwrite(int fd, struct buf_data *buf,
496 			     struct rect *rect, uint32_t color)
497 {
498 	uint32_t tiling, swizzle;
499 
500 	igt_require(gem_get_tiling(fd, buf->handle, &tiling, &swizzle));
501 
502 	switch (tiling) {
503 	case I915_TILING_NONE:
504 		draw_rect_pwrite_untiled(fd, buf, rect, color);
505 		break;
506 	case I915_TILING_X:
507 	case I915_TILING_Y:
508 		draw_rect_pwrite_tiled(fd, buf, tiling, rect, color, swizzle);
509 		break;
510 	default:
511 		igt_assert(false);
512 		break;
513 	}
514 }
515 
draw_rect_blt(int fd,struct cmd_data * cmd_data,struct buf_data * buf,struct rect * rect,uint32_t color)516 static void draw_rect_blt(int fd, struct cmd_data *cmd_data,
517 			  struct buf_data *buf, struct rect *rect,
518 			  uint32_t color)
519 {
520 	drm_intel_bo *dst;
521 	struct intel_batchbuffer *batch;
522 	int blt_cmd_len, blt_cmd_tiling, blt_cmd_depth;
523 	uint32_t devid = intel_get_drm_devid(fd);
524 	int gen = intel_gen(devid);
525 	uint32_t tiling, swizzle;
526 	int pitch;
527 
528 	igt_require(gem_get_tiling(fd, buf->handle, &tiling, &swizzle));
529 
530 	dst = gem_handle_to_libdrm_bo(cmd_data->bufmgr, fd, "", buf->handle);
531 	igt_assert(dst);
532 
533 	batch = intel_batchbuffer_alloc(cmd_data->bufmgr, devid);
534 	igt_assert(batch);
535 
536 	switch (buf->bpp) {
537 	case 8:
538 		blt_cmd_depth = 0;
539 		break;
540 	case 16: /* we're assuming 565 */
541 		blt_cmd_depth = 1 << 24;
542 		break;
543 	case 32:
544 		blt_cmd_depth = 3 << 24;
545 		break;
546 	default:
547 		igt_assert(false);
548 	}
549 
550 	blt_cmd_len = (gen >= 8) ?  0x5 : 0x4;
551 	blt_cmd_tiling = (tiling) ? XY_COLOR_BLT_TILED : 0;
552 	pitch = (tiling) ? buf->stride / 4 : buf->stride;
553 
554 	switch_blt_tiling(batch, tiling, true);
555 
556 	BEGIN_BATCH(6, 1);
557 	OUT_BATCH(XY_COLOR_BLT_CMD_NOLEN | XY_COLOR_BLT_WRITE_ALPHA |
558 		  XY_COLOR_BLT_WRITE_RGB | blt_cmd_tiling | blt_cmd_len);
559 	OUT_BATCH(blt_cmd_depth | (0xF0 << 16) | pitch);
560 	OUT_BATCH((rect->y << 16) | rect->x);
561 	OUT_BATCH(((rect->y + rect->h) << 16) | (rect->x + rect->w));
562 	OUT_RELOC_FENCED(dst, 0, I915_GEM_DOMAIN_RENDER, 0);
563 	OUT_BATCH(color);
564 	ADVANCE_BATCH();
565 
566 	switch_blt_tiling(batch, tiling, false);
567 
568 	intel_batchbuffer_flush(batch);
569 	intel_batchbuffer_free(batch);
570 	drm_intel_bo_unreference(dst);
571 }
572 
draw_rect_render(int fd,struct cmd_data * cmd_data,struct buf_data * buf,struct rect * rect,uint32_t color)573 static void draw_rect_render(int fd, struct cmd_data *cmd_data,
574 			     struct buf_data *buf, struct rect *rect,
575 			     uint32_t color)
576 {
577 	drm_intel_bo *src, *dst;
578 	uint32_t devid = intel_get_drm_devid(fd);
579 	igt_render_copyfunc_t rendercopy = igt_get_render_copyfunc(devid);
580 	struct igt_buf src_buf = {}, dst_buf = {};
581 	struct intel_batchbuffer *batch;
582 	uint32_t tiling, swizzle;
583 	struct buf_data tmp;
584 	int pixel_size = buf->bpp / 8;
585 
586 	igt_skip_on(!rendercopy);
587 
588 	igt_require(gem_get_tiling(fd, buf->handle, &tiling, &swizzle));
589 
590 	/* We create a temporary buffer and copy from it using rendercopy. */
591 	tmp.size = rect->w * rect->h * pixel_size;
592 	tmp.handle = gem_create(fd, tmp.size);
593 	tmp.stride = rect->w * pixel_size;
594 	tmp.bpp = buf->bpp;
595 	draw_rect_mmap_cpu(fd, &tmp, &(struct rect){0, 0, rect->w, rect->h},
596 			   color);
597 
598 	src = gem_handle_to_libdrm_bo(cmd_data->bufmgr, fd, "", tmp.handle);
599 	igt_assert(src);
600 	dst = gem_handle_to_libdrm_bo(cmd_data->bufmgr, fd, "", buf->handle);
601 	igt_assert(dst);
602 
603 	src_buf.bo = src;
604 	src_buf.stride = tmp.stride;
605 	src_buf.tiling = I915_TILING_NONE;
606 	src_buf.size = tmp.size;
607 	src_buf.bpp = tmp.bpp;
608 	dst_buf.bo = dst;
609 	dst_buf.stride = buf->stride;
610 	dst_buf.tiling = tiling;
611 	dst_buf.size = buf->size;
612 	dst_buf.bpp = buf->bpp;
613 
614 	batch = intel_batchbuffer_alloc(cmd_data->bufmgr, devid);
615 	igt_assert(batch);
616 
617 	rendercopy(batch, cmd_data->context, &src_buf, 0, 0, rect->w,
618 		   rect->h, &dst_buf, rect->x, rect->y);
619 
620 	intel_batchbuffer_free(batch);
621 	drm_intel_bo_unreference(src);
622 	drm_intel_bo_unreference(dst);
623 	gem_close(fd, tmp.handle);
624 }
625 
626 /**
627  * igt_draw_rect:
628  * @fd: the DRM file descriptor
629  * @bufmgr: the libdrm bufmgr, only required for IGT_DRAW_BLT and
630  *          IGT_DRAW_RENDER
631  * @context: the context, can be NULL if you don't want to think about it
632  * @buf_handle: the handle of the buffer where you're going to draw to
633  * @buf_size: the size of the buffer
634  * @buf_stride: the stride of the buffer
635  * @method: method you're going to use to write to the buffer
636  * @rect_x: horizontal position on the buffer where your rectangle starts
637  * @rect_y: vertical position on the buffer where your rectangle starts
638  * @rect_w: width of the rectangle
639  * @rect_h: height of the rectangle
640  * @color: color of the rectangle
641  * @bpp: bits per pixel
642  *
643  * This function draws a colored rectangle on the destination buffer, allowing
644  * you to specify the method used to draw the rectangle.
645  */
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,int rect_w,int rect_h,uint32_t color,int bpp)646 void igt_draw_rect(int fd, drm_intel_bufmgr *bufmgr, drm_intel_context *context,
647 		   uint32_t buf_handle, uint32_t buf_size, uint32_t buf_stride,
648 		   enum igt_draw_method method, int rect_x, int rect_y,
649 		   int rect_w, int rect_h, uint32_t color, int bpp)
650 {
651 	struct cmd_data cmd_data = {
652 		.bufmgr = bufmgr,
653 		.context = context,
654 	};
655 	struct buf_data buf = {
656 		.handle = buf_handle,
657 		.size = buf_size,
658 		.stride = buf_stride,
659 		.bpp = bpp,
660 	};
661 	struct rect rect = {
662 		.x = rect_x,
663 		.y = rect_y,
664 		.w = rect_w,
665 		.h = rect_h,
666 	};
667 
668 	switch (method) {
669 	case IGT_DRAW_MMAP_CPU:
670 		draw_rect_mmap_cpu(fd, &buf, &rect, color);
671 		break;
672 	case IGT_DRAW_MMAP_GTT:
673 		draw_rect_mmap_gtt(fd, &buf, &rect, color);
674 		break;
675 	case IGT_DRAW_MMAP_WC:
676 		draw_rect_mmap_wc(fd, &buf, &rect, color);
677 		break;
678 	case IGT_DRAW_PWRITE:
679 		draw_rect_pwrite(fd, &buf, &rect, color);
680 		break;
681 	case IGT_DRAW_BLT:
682 		draw_rect_blt(fd, &cmd_data, &buf, &rect, color);
683 		break;
684 	case IGT_DRAW_RENDER:
685 		draw_rect_render(fd, &cmd_data, &buf, &rect, color);
686 		break;
687 	default:
688 		igt_assert(false);
689 		break;
690 	}
691 }
692 
693 /**
694  * igt_draw_rect_fb:
695  * @fd: the DRM file descriptor
696  * @bufmgr: the libdrm bufmgr, only required for IGT_DRAW_BLT and
697  *          IGT_DRAW_RENDER
698  * @context: the context, can be NULL if you don't want to think about it
699  * @fb: framebuffer
700  * @method: method you're going to use to write to the buffer
701  * @rect_x: horizontal position on the buffer where your rectangle starts
702  * @rect_y: vertical position on the buffer where your rectangle starts
703  * @rect_w: width of the rectangle
704  * @rect_h: height of the rectangle
705  * @color: color of the rectangle
706  *
707  * This is exactly the same as igt_draw_rect, but you can pass an igt_fb instead
708  * of manually providing its details. See igt_draw_rect.
709  */
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)710 void igt_draw_rect_fb(int fd, drm_intel_bufmgr *bufmgr,
711 		      drm_intel_context *context, struct igt_fb *fb,
712 		      enum igt_draw_method method, int rect_x, int rect_y,
713 		      int rect_w, int rect_h, uint32_t color)
714 {
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));
718 }
719 
720 /**
721  * igt_draw_fill_fb:
722  * @fd: the DRM file descriptor
723  * @fb: the FB that is going to be filled
724  * @color: the color you're going to paint it
725  *
726  * This function just paints an igt_fb using the provided color.
727  */
igt_draw_fill_fb(int fd,struct igt_fb * fb,uint32_t color)728 void igt_draw_fill_fb(int fd, struct igt_fb *fb, uint32_t color)
729 {
730 	igt_draw_rect_fb(fd, NULL, NULL, fb, IGT_DRAW_MMAP_GTT,
731 			 0, 0, fb->width, fb->height, color);
732 }
733