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