blob: 76ffb6c2d279c1c754aa7d2763293a96b3a26eb8 [file] [log] [blame]
Paulo Zanonicf9f48e2015-02-19 15:41:15 -02001/*
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_chipset.h"
31#include "igt_core.h"
32#include "igt_fb.h"
33#include "ioctl_wrappers.h"
Akash Goela844ccb2017-04-28 20:07:31 +053034#include "i830_reg.h"
Paulo Zanonicf9f48e2015-02-19 15:41:15 -020035
36/**
37 * SECTION:igt_draw
38 * @short_description: drawing helpers for tests
Damien Lespiau6ebd8c22015-06-26 14:28:41 +010039 * @title: Draw
Thomas Woodf0381d12015-09-07 09:26:01 +010040 * @include: igt.h
Paulo Zanonicf9f48e2015-02-19 15:41:15 -020041 *
42 * This library contains some functions for drawing rectangles on buffers using
43 * the many different drawing methods we have. It also contains some wrappers
44 * that make the process easier if you have the abstract objects in hand.
45 *
Paulo Zanonicaaf3b82015-08-03 14:41:35 -030046 * This library only claims support for some pixel formats, but adding support
47 * for more formats should be faily easy now that we support both 16bpp and
48 * 32bpp. If you need a new pixel format, make sure you update both this file
49 * and tests/kms_draw_crc.c.
Paulo Zanonicf9f48e2015-02-19 15:41:15 -020050 */
51
52/* Some internal data structures to avoid having to pass tons of parameters
53 * around everything. */
54struct cmd_data {
55 drm_intel_bufmgr *bufmgr;
56 drm_intel_context *context;
57};
58
59struct buf_data {
60 uint32_t handle;
61 uint32_t size;
62 uint32_t stride;
Paulo Zanonicaaf3b82015-08-03 14:41:35 -030063 int bpp;
Paulo Zanonicf9f48e2015-02-19 15:41:15 -020064};
65
66struct rect {
67 int x;
68 int y;
69 int w;
70 int h;
71};
72
73/**
74 * igt_draw_get_method_name:
Thomas Wood6141aa22015-05-14 16:00:25 +010075 * @method: draw method
Paulo Zanonicf9f48e2015-02-19 15:41:15 -020076 *
77 * Simple function to transform the enum into a string. Useful when naming
78 * subtests and printing debug messages.
79 */
80const char *igt_draw_get_method_name(enum igt_draw_method method)
81{
82 switch (method) {
83 case IGT_DRAW_MMAP_CPU:
84 return "mmap-cpu";
85 case IGT_DRAW_MMAP_GTT:
86 return "mmap-gtt";
87 case IGT_DRAW_MMAP_WC:
88 return "mmap-wc";
89 case IGT_DRAW_PWRITE:
90 return "pwrite";
91 case IGT_DRAW_BLT:
92 return "blt";
93 case IGT_DRAW_RENDER:
94 return "render";
95 default:
96 igt_assert(false);
97 }
98}
99
100#define BIT(num, bit) ((num >> bit) & 1)
101
102static int swizzle_addr(int addr, int swizzle)
103{
104 int bit6;
105
106 switch (swizzle) {
107 case I915_BIT_6_SWIZZLE_NONE:
108 bit6 = BIT(addr, 6);
109 break;
110 case I915_BIT_6_SWIZZLE_9:
111 bit6 = BIT(addr, 6) ^ BIT(addr, 9);
112 break;
113 case I915_BIT_6_SWIZZLE_9_10:
114 bit6 = BIT(addr, 6) ^ BIT(addr, 9) ^ BIT(addr, 10);
115 break;
116 case I915_BIT_6_SWIZZLE_9_11:
117 bit6 = BIT(addr, 6) ^ BIT(addr, 9) ^ BIT(addr, 11);
118 break;
119 case I915_BIT_6_SWIZZLE_9_10_11:
120 bit6 = BIT(addr, 6) ^ BIT(addr, 9) ^ BIT(addr, 10) ^
121 BIT(addr, 11);
122 break;
123 case I915_BIT_6_SWIZZLE_UNKNOWN:
124 case I915_BIT_6_SWIZZLE_9_17:
125 case I915_BIT_6_SWIZZLE_9_10_17:
126 default:
127 /* If we hit this case, we need to implement support for the
128 * appropriate swizzling method. */
129 igt_require(false);
130 break;
131 }
132
133 addr &= ~(1 << 6);
134 addr |= (bit6 << 6);
135 return addr;
136}
137
Paulo Zanoni10e010f2017-07-18 22:52:58 +0530138static int tile(int x, int y, uint32_t x_tile_size, uint32_t y_tile_size,
139 uint32_t line_size, bool xmajor)
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200140{
Paulo Zanoni10e010f2017-07-18 22:52:58 +0530141 int tile_size, tiles_per_line, x_tile_n, y_tile_n, tile_off, pos;
142 int tile_n, x_tile_off, y_tile_off;
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200143
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200144 tiles_per_line = line_size / x_tile_size;
Paulo Zanoni10e010f2017-07-18 22:52:58 +0530145 tile_size = x_tile_size * y_tile_size;
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200146
Paulo Zanoni10e010f2017-07-18 22:52:58 +0530147 x_tile_n = x / x_tile_size;
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200148 y_tile_n = y / y_tile_size;
Paulo Zanoni10e010f2017-07-18 22:52:58 +0530149 tile_n = y_tile_n * tiles_per_line + x_tile_n;
150
151 x_tile_off = x % x_tile_size;
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200152 y_tile_off = y % y_tile_size;
153
Paulo Zanoni10e010f2017-07-18 22:52:58 +0530154 if (xmajor)
155 tile_off = y_tile_off * x_tile_size + x_tile_off;
156 else
157 tile_off = x_tile_off * y_tile_size + y_tile_off;
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200158
Paulo Zanoni10e010f2017-07-18 22:52:58 +0530159 pos = tile_n * tile_size + tile_off;
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200160
Paulo Zanoni10e010f2017-07-18 22:52:58 +0530161 return pos;
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200162}
163
Paulo Zanoni10e010f2017-07-18 22:52:58 +0530164static void untile(int tiled_pos, int x_tile_size, int y_tile_size,
165 uint32_t line_size, bool xmajor, int *x, int *y)
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200166{
Paulo Zanoni10e010f2017-07-18 22:52:58 +0530167 int tile_n, tile_off, tiles_per_line;
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200168 int x_tile_off, y_tile_off;
169 int x_tile_n, y_tile_n;
Paulo Zanoni10e010f2017-07-18 22:52:58 +0530170 int tile_size;
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200171
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200172 tile_size = x_tile_size * y_tile_size;
173 tiles_per_line = line_size / x_tile_size;
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200174
175 tile_n = tiled_pos / tile_size;
176 tile_off = tiled_pos % tile_size;
177
Paulo Zanoni10e010f2017-07-18 22:52:58 +0530178 if (xmajor) {
179 y_tile_off = tile_off / x_tile_size;
180 x_tile_off = tile_off % x_tile_size;
181 } else {
182 y_tile_off = tile_off % y_tile_size;
183 x_tile_off = tile_off / y_tile_size;
184 }
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200185
186 x_tile_n = tile_n % tiles_per_line;
187 y_tile_n = tile_n / tiles_per_line;
188
Paulo Zanoni10e010f2017-07-18 22:52:58 +0530189 *x = (x_tile_n * x_tile_size + x_tile_off);
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200190 *y = y_tile_n * y_tile_size + y_tile_off;
191}
192
Paulo Zanoni10e010f2017-07-18 22:52:58 +0530193static int linear_x_y_to_xtiled_pos(int x, int y, uint32_t stride, int swizzle,
194 int bpp)
195{
196 int pos;
197 int pixel_size = bpp / 8;
198
199 x *= pixel_size;
200 pos = tile(x, y, 512, 8, stride, true);
201 pos = swizzle_addr(pos, swizzle);
202 return pos / pixel_size;
203}
204
205static int linear_x_y_to_ytiled_pos(int x, int y, uint32_t stride, int swizzle,
206 int bpp)
207{
208 int ow_tile_n, pos;
209 int ow_size = 16;
210 int pixel_size = bpp / 8;
211
212 /* We have an Y tiling of OWords, so use the tile() function to get the
213 * OW number, then adjust to the fact that the OW may have more than one
214 * pixel. */
215 x *= pixel_size;
216 ow_tile_n = tile(x / ow_size, y, 128 / ow_size, 32,
217 stride / ow_size, false);
218 pos = ow_tile_n * ow_size + (x % ow_size);
219 pos = swizzle_addr(pos, swizzle);
220 return pos / pixel_size;
221}
222
223static void xtiled_pos_to_x_y_linear(int tiled_pos, uint32_t stride,
224 int swizzle, int bpp, int *x, int *y)
225{
226 int pixel_size = bpp / 8;
227
228 tiled_pos = swizzle_addr(tiled_pos, swizzle);
229
230 untile(tiled_pos, 512, 8, stride, true, x, y);
231 *x /= pixel_size;
232}
233
234static void ytiled_pos_to_x_y_linear(int tiled_pos, uint32_t stride,
235 int swizzle, int bpp, int *x, int *y)
236{
237 int ow_tile_n;
238 int ow_size = 16;
239 int pixel_size = bpp / 8;
240
241 tiled_pos = swizzle_addr(tiled_pos, swizzle);
242
243 ow_tile_n = tiled_pos / ow_size;
244 untile(ow_tile_n, 128 / ow_size, 32, stride / ow_size, false, x, y);
245 *x *= ow_size;
246 *x += tiled_pos % ow_size;
247 *x /= pixel_size;
248}
249
Paulo Zanonicaaf3b82015-08-03 14:41:35 -0300250static void set_pixel(void *_ptr, int index, uint32_t color, int bpp)
251{
252 if (bpp == 16) {
253 uint16_t *ptr = _ptr;
254 ptr[index] = color;
255 } else if (bpp == 32) {
256 uint32_t *ptr = _ptr;
257 ptr[index] = color;
258 } else {
259 igt_assert_f(false, "bpp: %d\n", bpp);
260 }
261}
262
Akash Goela844ccb2017-04-28 20:07:31 +0530263static void switch_blt_tiling(struct intel_batchbuffer *batch, uint32_t tiling,
264 bool on)
265{
266 uint32_t bcs_swctrl;
267
268 /* Default is X-tile */
269 if (tiling != I915_TILING_Y)
270 return;
271
272 bcs_swctrl = (0x3 << 16) | (on ? 0x3 : 0x0);
273
274 /* To change the tile register, insert an MI_FLUSH_DW followed by an
275 * MI_LOAD_REGISTER_IMM
276 */
277 BEGIN_BATCH(4, 0);
278 OUT_BATCH(MI_FLUSH_DW | 2);
279 OUT_BATCH(0x0);
280 OUT_BATCH(0x0);
281 OUT_BATCH(0x0);
282 ADVANCE_BATCH();
283
284 BEGIN_BATCH(4, 0);
285 OUT_BATCH(MI_LOAD_REGISTER_IMM);
286 OUT_BATCH(0x22200); /* BCS_SWCTRL */
287 OUT_BATCH(bcs_swctrl);
288 OUT_BATCH(MI_NOOP);
289 ADVANCE_BATCH();
290}
291
Paulo Zanonicaaf3b82015-08-03 14:41:35 -0300292static void draw_rect_ptr_linear(void *ptr, uint32_t stride,
293 struct rect *rect, uint32_t color, int bpp)
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200294{
295 int x, y, line_begin;
296
297 for (y = rect->y; y < rect->y + rect->h; y++) {
Paulo Zanonicaaf3b82015-08-03 14:41:35 -0300298 line_begin = y * stride / (bpp / 8);
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200299 for (x = rect->x; x < rect->x + rect->w; x++)
Paulo Zanonicaaf3b82015-08-03 14:41:35 -0300300 set_pixel(ptr, line_begin + x, color, bpp);
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200301 }
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200302}
303
Paulo Zanoni10e010f2017-07-18 22:52:58 +0530304static void draw_rect_ptr_tiled(void *ptr, uint32_t stride, uint32_t tiling,
305 int swizzle, struct rect *rect, uint32_t color,
306 int bpp)
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200307{
308 int x, y, pos;
309
310 for (y = rect->y; y < rect->y + rect->h; y++) {
311 for (x = rect->x; x < rect->x + rect->w; x++) {
Paulo Zanoni10e010f2017-07-18 22:52:58 +0530312 switch (tiling) {
313 case I915_TILING_X:
314 pos = linear_x_y_to_xtiled_pos(x, y, stride,
315 swizzle, bpp);
316 break;
317 case I915_TILING_Y:
318 pos = linear_x_y_to_ytiled_pos(x, y, stride,
319 swizzle, bpp);
320 break;
321 default:
322 igt_assert(false);
323 }
Paulo Zanonicaaf3b82015-08-03 14:41:35 -0300324 set_pixel(ptr, pos, color, bpp);
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200325 }
326 }
327}
328
329static void draw_rect_mmap_cpu(int fd, struct buf_data *buf, struct rect *rect,
330 uint32_t color)
331{
332 uint32_t *ptr;
333 uint32_t tiling, swizzle;
334
335 gem_set_domain(fd, buf->handle, I915_GEM_DOMAIN_CPU,
336 I915_GEM_DOMAIN_CPU);
Chris Wilsone2762682016-10-19 14:07:25 +0100337 igt_require(gem_get_tiling(fd, buf->handle, &tiling, &swizzle));
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200338
339 /* We didn't implement suport for the older tiling methods yet. */
340 if (tiling != I915_TILING_NONE)
341 igt_require(intel_gen(intel_get_drm_devid(fd)) >= 5);
342
Ville Syrjäläf52e7ec2015-10-09 19:11:39 +0300343 ptr = gem_mmap__cpu(fd, buf->handle, 0, buf->size, 0);
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200344
345 switch (tiling) {
346 case I915_TILING_NONE:
Paulo Zanonicaaf3b82015-08-03 14:41:35 -0300347 draw_rect_ptr_linear(ptr, buf->stride, rect, color, buf->bpp);
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200348 break;
349 case I915_TILING_X:
Paulo Zanoni10e010f2017-07-18 22:52:58 +0530350 case I915_TILING_Y:
351 draw_rect_ptr_tiled(ptr, buf->stride, tiling, swizzle, rect,
352 color, buf->bpp);
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200353 break;
354 default:
355 igt_assert(false);
356 break;
357 }
358
359 gem_sw_finish(fd, buf->handle);
360
Maarten Lankhorstd930b642017-02-09 10:42:01 +0100361 igt_assert(gem_munmap(ptr, buf->size) == 0);
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200362}
363
364static void draw_rect_mmap_gtt(int fd, struct buf_data *buf, struct rect *rect,
365 uint32_t color)
366{
367 uint32_t *ptr;
368
Paulo Zanonie86557c2015-06-25 14:19:24 -0300369 gem_set_domain(fd, buf->handle, I915_GEM_DOMAIN_GTT,
370 I915_GEM_DOMAIN_GTT);
371
Ville Syrjäläf52e7ec2015-10-09 19:11:39 +0300372 ptr = gem_mmap__gtt(fd, buf->handle, buf->size, PROT_READ | PROT_WRITE);
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200373
Paulo Zanonicaaf3b82015-08-03 14:41:35 -0300374 draw_rect_ptr_linear(ptr, buf->stride, rect, color, buf->bpp);
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200375
Maarten Lankhorstd930b642017-02-09 10:42:01 +0100376 igt_assert(gem_munmap(ptr, buf->size) == 0);
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200377}
378
379static void draw_rect_mmap_wc(int fd, struct buf_data *buf, struct rect *rect,
380 uint32_t color)
381{
382 uint32_t *ptr;
383 uint32_t tiling, swizzle;
384
Paulo Zanonie86557c2015-06-25 14:19:24 -0300385 gem_set_domain(fd, buf->handle, I915_GEM_DOMAIN_GTT,
386 I915_GEM_DOMAIN_GTT);
Chris Wilsone2762682016-10-19 14:07:25 +0100387 igt_require(gem_get_tiling(fd, buf->handle, &tiling, &swizzle));
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200388
389 /* We didn't implement suport for the older tiling methods yet. */
390 if (tiling != I915_TILING_NONE)
391 igt_require(intel_gen(intel_get_drm_devid(fd)) >= 5);
392
Ville Syrjäläf52e7ec2015-10-09 19:11:39 +0300393 ptr = gem_mmap__wc(fd, buf->handle, 0, buf->size,
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200394 PROT_READ | PROT_WRITE);
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200395
396 switch (tiling) {
397 case I915_TILING_NONE:
Paulo Zanonicaaf3b82015-08-03 14:41:35 -0300398 draw_rect_ptr_linear(ptr, buf->stride, rect, color, buf->bpp);
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200399 break;
400 case I915_TILING_X:
Paulo Zanoni10e010f2017-07-18 22:52:58 +0530401 case I915_TILING_Y:
402 draw_rect_ptr_tiled(ptr, buf->stride, tiling, swizzle, rect,
403 color, buf->bpp);
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200404 break;
405 default:
406 igt_assert(false);
407 break;
408 }
409
Maarten Lankhorstd930b642017-02-09 10:42:01 +0100410 igt_assert(gem_munmap(ptr, buf->size) == 0);
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200411}
412
413static void draw_rect_pwrite_untiled(int fd, struct buf_data *buf,
414 struct rect *rect, uint32_t color)
415{
Paulo Zanonicaaf3b82015-08-03 14:41:35 -0300416 int i, y, offset;
417 int pixel_size = buf->bpp / 8;
418 uint8_t tmp[rect->w * pixel_size];
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200419
420 for (i = 0; i < rect->w; i++)
Paulo Zanonicaaf3b82015-08-03 14:41:35 -0300421 set_pixel(tmp, i, color, buf->bpp);
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200422
423 for (y = rect->y; y < rect->y + rect->h; y++) {
Paulo Zanonicaaf3b82015-08-03 14:41:35 -0300424 offset = (y * buf->stride) + (rect->x * pixel_size);
425 gem_write(fd, buf->handle, offset, tmp, rect->w * pixel_size);
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200426 }
427}
428
429static void draw_rect_pwrite_tiled(int fd, struct buf_data *buf,
Paulo Zanoni10e010f2017-07-18 22:52:58 +0530430 uint32_t tiling, struct rect *rect,
431 uint32_t color, uint32_t swizzle)
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200432{
433 int i;
Paulo Zanonicaaf3b82015-08-03 14:41:35 -0300434 int tiled_pos, x, y, pixel_size;
435 uint8_t tmp[4096];
436 int tmp_used = 0, tmp_size;
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200437 bool flush_tmp = false;
438 int tmp_start_pos = 0;
Paulo Zanoni9113c9a2015-08-13 17:37:06 -0300439 int pixels_written = 0;
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200440
441 /* We didn't implement suport for the older tiling methods yet. */
442 igt_require(intel_gen(intel_get_drm_devid(fd)) >= 5);
443
Paulo Zanonicaaf3b82015-08-03 14:41:35 -0300444 pixel_size = buf->bpp / 8;
445 tmp_size = sizeof(tmp) / pixel_size;
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200446
447 /* Instead of doing one pwrite per pixel, we try to group the maximum
448 * amount of consecutive pixels we can in a single pwrite: that's why we
449 * use the "tmp" variables. */
450 for (i = 0; i < tmp_size; i++)
Paulo Zanonicaaf3b82015-08-03 14:41:35 -0300451 set_pixel(tmp, i, color, buf->bpp);
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200452
Paulo Zanonicaaf3b82015-08-03 14:41:35 -0300453 for (tiled_pos = 0; tiled_pos < buf->size; tiled_pos += pixel_size) {
Paulo Zanoni10e010f2017-07-18 22:52:58 +0530454 switch (tiling) {
455 case I915_TILING_X:
456 xtiled_pos_to_x_y_linear(tiled_pos, buf->stride,
457 swizzle, buf->bpp, &x, &y);
458 break;
459 case I915_TILING_Y:
460 ytiled_pos_to_x_y_linear(tiled_pos, buf->stride,
461 swizzle, buf->bpp, &x, &y);
462 break;
463 default:
464 igt_assert(false);
465 }
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200466
467 if (x >= rect->x && x < rect->x + rect->w &&
468 y >= rect->y && y < rect->y + rect->h) {
469 if (tmp_used == 0)
470 tmp_start_pos = tiled_pos;
471 tmp_used++;
472 } else {
473 flush_tmp = true;
474 }
475
Paulo Zanoni9194f4e2015-08-13 17:25:31 -0300476 if (tmp_used == tmp_size || (flush_tmp && tmp_used > 0) ||
477 tiled_pos + pixel_size >= buf->size) {
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200478 gem_write(fd, buf->handle, tmp_start_pos, tmp,
Paulo Zanonicaaf3b82015-08-03 14:41:35 -0300479 tmp_used * pixel_size);
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200480 flush_tmp = false;
Paulo Zanoni9113c9a2015-08-13 17:37:06 -0300481 pixels_written += tmp_used;
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200482 tmp_used = 0;
Paulo Zanoni9113c9a2015-08-13 17:37:06 -0300483
484 if (pixels_written == rect->w * rect->h)
485 break;
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200486 }
487 }
488}
489
490static void draw_rect_pwrite(int fd, struct buf_data *buf,
491 struct rect *rect, uint32_t color)
492{
493 uint32_t tiling, swizzle;
494
Chris Wilsone2762682016-10-19 14:07:25 +0100495 igt_require(gem_get_tiling(fd, buf->handle, &tiling, &swizzle));
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200496
497 switch (tiling) {
498 case I915_TILING_NONE:
499 draw_rect_pwrite_untiled(fd, buf, rect, color);
500 break;
501 case I915_TILING_X:
Paulo Zanoni10e010f2017-07-18 22:52:58 +0530502 case I915_TILING_Y:
503 draw_rect_pwrite_tiled(fd, buf, tiling, rect, color, swizzle);
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200504 break;
505 default:
506 igt_assert(false);
507 break;
508 }
509}
510
511static void draw_rect_blt(int fd, struct cmd_data *cmd_data,
512 struct buf_data *buf, struct rect *rect,
513 uint32_t color)
514{
515 drm_intel_bo *dst;
516 struct intel_batchbuffer *batch;
Paulo Zanonicaaf3b82015-08-03 14:41:35 -0300517 int blt_cmd_len, blt_cmd_tiling, blt_cmd_depth;
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200518 uint32_t devid = intel_get_drm_devid(fd);
519 int gen = intel_gen(devid);
520 uint32_t tiling, swizzle;
521 int pitch;
522
Chris Wilsone2762682016-10-19 14:07:25 +0100523 igt_require(gem_get_tiling(fd, buf->handle, &tiling, &swizzle));
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200524
525 dst = gem_handle_to_libdrm_bo(cmd_data->bufmgr, fd, "", buf->handle);
526 igt_assert(dst);
527
528 batch = intel_batchbuffer_alloc(cmd_data->bufmgr, devid);
529 igt_assert(batch);
530
Paulo Zanonicaaf3b82015-08-03 14:41:35 -0300531 switch (buf->bpp) {
532 case 8:
533 blt_cmd_depth = 0;
534 break;
535 case 16: /* we're assuming 565 */
536 blt_cmd_depth = 1 << 24;
537 break;
538 case 32:
539 blt_cmd_depth = 3 << 24;
540 break;
541 default:
542 igt_assert(false);
543 }
544
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200545 blt_cmd_len = (gen >= 8) ? 0x5 : 0x4;
546 blt_cmd_tiling = (tiling) ? XY_COLOR_BLT_TILED : 0;
547 pitch = (tiling) ? buf->stride / 4 : buf->stride;
548
Akash Goela844ccb2017-04-28 20:07:31 +0530549 switch_blt_tiling(batch, tiling, true);
550
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200551 BEGIN_BATCH(6, 1);
552 OUT_BATCH(XY_COLOR_BLT_CMD_NOLEN | XY_COLOR_BLT_WRITE_ALPHA |
553 XY_COLOR_BLT_WRITE_RGB | blt_cmd_tiling | blt_cmd_len);
Paulo Zanonicaaf3b82015-08-03 14:41:35 -0300554 OUT_BATCH(blt_cmd_depth | (0xF0 << 16) | pitch);
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200555 OUT_BATCH((rect->y << 16) | rect->x);
556 OUT_BATCH(((rect->y + rect->h) << 16) | (rect->x + rect->w));
557 OUT_RELOC_FENCED(dst, 0, I915_GEM_DOMAIN_RENDER, 0);
558 OUT_BATCH(color);
559 ADVANCE_BATCH();
560
Akash Goela844ccb2017-04-28 20:07:31 +0530561 switch_blt_tiling(batch, tiling, false);
562
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200563 intel_batchbuffer_flush(batch);
564 intel_batchbuffer_free(batch);
565}
566
567static void draw_rect_render(int fd, struct cmd_data *cmd_data,
568 struct buf_data *buf, struct rect *rect,
569 uint32_t color)
570{
571 drm_intel_bo *src, *dst;
572 uint32_t devid = intel_get_drm_devid(fd);
573 igt_render_copyfunc_t rendercopy = igt_get_render_copyfunc(devid);
574 struct igt_buf src_buf, dst_buf;
575 struct intel_batchbuffer *batch;
576 uint32_t tiling, swizzle;
577 struct buf_data tmp;
Paulo Zanonicaaf3b82015-08-03 14:41:35 -0300578 int pixel_size = buf->bpp / 8;
579 unsigned adjusted_w, adjusted_dst_x;
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200580
581 igt_skip_on(!rendercopy);
582
Paulo Zanonicaaf3b82015-08-03 14:41:35 -0300583 /* Rendercopy works at 32bpp, so if you try to do copies on buffers with
584 * smaller bpps you won't succeeed if you need to copy "half" of a 32bpp
585 * pixel or something similar. */
586 igt_skip_on(rect->x % (32 / buf->bpp) != 0 ||
587 rect->y % (32 / buf->bpp) != 0 ||
588 rect->w % (32 / buf->bpp) != 0 ||
589 rect->h % (32 / buf->bpp) != 0);
590
Chris Wilsone2762682016-10-19 14:07:25 +0100591 igt_require(gem_get_tiling(fd, buf->handle, &tiling, &swizzle));
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200592
593 /* We create a temporary buffer and copy from it using rendercopy. */
Paulo Zanonicaaf3b82015-08-03 14:41:35 -0300594 tmp.size = rect->w * rect->h * pixel_size;
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200595 tmp.handle = gem_create(fd, tmp.size);
Paulo Zanonicaaf3b82015-08-03 14:41:35 -0300596 tmp.stride = rect->w * pixel_size;
597 tmp.bpp = buf->bpp;
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200598 draw_rect_mmap_cpu(fd, &tmp, &(struct rect){0, 0, rect->w, rect->h},
599 color);
600
601 src = gem_handle_to_libdrm_bo(cmd_data->bufmgr, fd, "", tmp.handle);
602 igt_assert(src);
603 dst = gem_handle_to_libdrm_bo(cmd_data->bufmgr, fd, "", buf->handle);
604 igt_assert(dst);
605
606 src_buf.bo = src;
607 src_buf.stride = tmp.stride;
608 src_buf.tiling = I915_TILING_NONE;
609 src_buf.size = tmp.size;
610 dst_buf.bo = dst;
611 dst_buf.stride = buf->stride;
612 dst_buf.tiling = tiling;
613 dst_buf.size = buf->size;
614
615 batch = intel_batchbuffer_alloc(cmd_data->bufmgr, devid);
616 igt_assert(batch);
617
Paulo Zanonicaaf3b82015-08-03 14:41:35 -0300618 switch (buf->bpp) {
619 case 16:
620 case 32:
621 adjusted_w = rect->w / (32 / buf->bpp);
622 adjusted_dst_x = rect->x / (32 / buf->bpp);
623 break;
624 default:
625 igt_assert(false);
626 }
627
628 rendercopy(batch, cmd_data->context, &src_buf, 0, 0, adjusted_w,
629 rect->h, &dst_buf, adjusted_dst_x, rect->y);
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200630
631 intel_batchbuffer_free(batch);
632 gem_close(fd, tmp.handle);
633}
634
635/**
636 * igt_draw_rect:
637 * @fd: the DRM file descriptor
638 * @bufmgr: the libdrm bufmgr, only required for IGT_DRAW_BLT and
639 * IGT_DRAW_RENDER
640 * @context: the context, can be NULL if you don't want to think about it
641 * @buf_handle: the handle of the buffer where you're going to draw to
642 * @buf_size: the size of the buffer
643 * @buf_stride: the stride of the buffer
644 * @method: method you're going to use to write to the buffer
645 * @rect_x: horizontal position on the buffer where your rectangle starts
646 * @rect_y: vertical position on the buffer where your rectangle starts
647 * @rect_w: width of the rectangle
648 * @rect_h: height of the rectangle
649 * @color: color of the rectangle
Paulo Zanonicaaf3b82015-08-03 14:41:35 -0300650 * @bpp: bits per pixel
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200651 *
652 * This function draws a colored rectangle on the destination buffer, allowing
Paulo Zanonicaaf3b82015-08-03 14:41:35 -0300653 * you to specify the method used to draw the rectangle.
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200654 */
655void igt_draw_rect(int fd, drm_intel_bufmgr *bufmgr, drm_intel_context *context,
656 uint32_t buf_handle, uint32_t buf_size, uint32_t buf_stride,
657 enum igt_draw_method method, int rect_x, int rect_y,
Paulo Zanonicaaf3b82015-08-03 14:41:35 -0300658 int rect_w, int rect_h, uint32_t color, int bpp)
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200659{
660 struct cmd_data cmd_data = {
661 .bufmgr = bufmgr,
662 .context = context,
663 };
664 struct buf_data buf = {
665 .handle = buf_handle,
666 .size = buf_size,
667 .stride = buf_stride,
Paulo Zanonicaaf3b82015-08-03 14:41:35 -0300668 .bpp = bpp,
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200669 };
670 struct rect rect = {
671 .x = rect_x,
672 .y = rect_y,
673 .w = rect_w,
674 .h = rect_h,
675 };
676
677 switch (method) {
678 case IGT_DRAW_MMAP_CPU:
679 draw_rect_mmap_cpu(fd, &buf, &rect, color);
680 break;
681 case IGT_DRAW_MMAP_GTT:
682 draw_rect_mmap_gtt(fd, &buf, &rect, color);
683 break;
684 case IGT_DRAW_MMAP_WC:
685 draw_rect_mmap_wc(fd, &buf, &rect, color);
686 break;
687 case IGT_DRAW_PWRITE:
688 draw_rect_pwrite(fd, &buf, &rect, color);
689 break;
690 case IGT_DRAW_BLT:
691 draw_rect_blt(fd, &cmd_data, &buf, &rect, color);
692 break;
693 case IGT_DRAW_RENDER:
694 draw_rect_render(fd, &cmd_data, &buf, &rect, color);
695 break;
696 default:
697 igt_assert(false);
698 break;
699 }
700}
701
702/**
703 * igt_draw_rect_fb:
Thomas Wood6141aa22015-05-14 16:00:25 +0100704 * @fd: the DRM file descriptor
705 * @bufmgr: the libdrm bufmgr, only required for IGT_DRAW_BLT and
706 * IGT_DRAW_RENDER
707 * @context: the context, can be NULL if you don't want to think about it
708 * @fb: framebuffer
709 * @method: method you're going to use to write to the buffer
710 * @rect_x: horizontal position on the buffer where your rectangle starts
711 * @rect_y: vertical position on the buffer where your rectangle starts
712 * @rect_w: width of the rectangle
713 * @rect_h: height of the rectangle
714 * @color: color of the rectangle
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200715 *
716 * This is exactly the same as igt_draw_rect, but you can pass an igt_fb instead
717 * of manually providing its details. See igt_draw_rect.
718 */
719void igt_draw_rect_fb(int fd, drm_intel_bufmgr *bufmgr,
720 drm_intel_context *context, struct igt_fb *fb,
721 enum igt_draw_method method, int rect_x, int rect_y,
722 int rect_w, int rect_h, uint32_t color)
723{
724 igt_draw_rect(fd, bufmgr, context, fb->gem_handle, fb->size, fb->stride,
Paulo Zanonicaaf3b82015-08-03 14:41:35 -0300725 method, rect_x, rect_y, rect_w, rect_h, color,
Paulo Zanoni12c1eb62016-01-25 21:17:50 -0200726 igt_drm_format_to_bpp(fb->drm_format));
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200727}
728
729/**
730 * igt_draw_fill_fb:
731 * @fd: the DRM file descriptor
732 * @fb: the FB that is going to be filled
733 * @color: the color you're going to paint it
734 *
Paulo Zanonicaaf3b82015-08-03 14:41:35 -0300735 * This function just paints an igt_fb using the provided color.
Paulo Zanonicf9f48e2015-02-19 15:41:15 -0200736 */
737void igt_draw_fill_fb(int fd, struct igt_fb *fb, uint32_t color)
738{
739 igt_draw_rect_fb(fd, NULL, NULL, fb, IGT_DRAW_MMAP_GTT,
740 0, 0, fb->width, fb->height, color);
741}