1 /*
2 * Copyright © 2016 Broadcom
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 #include <assert.h>
25 #include <string.h>
26 #include <signal.h>
27 #include <errno.h>
28 #include <sys/mman.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <sys/ioctl.h>
32 #include <fcntl.h>
33
34 #include "drmtest.h"
35 #include "igt_aux.h"
36 #include "igt_core.h"
37 #include "igt_fb.h"
38 #include "igt_vc4.h"
39 #include "ioctl_wrappers.h"
40 #include "intel_reg.h"
41 #include "intel_chipset.h"
42 #include "vc4_drm.h"
43 #include "vc4_packet.h"
44
45 #if NEW_CONTEXT_PARAM_NO_ERROR_CAPTURE_API
46 #define LOCAL_CONTEXT_PARAM_NO_ERROR_CAPTURE 0x4
47 #endif
48
49 /**
50 * SECTION:igt_vc4
51 * @short_description: VC4 support library
52 * @title: VC4
53 * @include: igt.h
54 *
55 * This library provides various auxiliary helper functions for writing VC4
56 * tests.
57 */
58
igt_vc4_is_tiled(uint64_t modifier)59 bool igt_vc4_is_tiled(uint64_t modifier)
60 {
61 if (modifier >> 56ULL != DRM_FORMAT_MOD_VENDOR_BROADCOM)
62 return false;
63
64 switch (fourcc_mod_broadcom_mod(modifier)) {
65 case DRM_FORMAT_MOD_BROADCOM_SAND32:
66 case DRM_FORMAT_MOD_BROADCOM_SAND64:
67 case DRM_FORMAT_MOD_BROADCOM_SAND128:
68 case DRM_FORMAT_MOD_BROADCOM_SAND256:
69 case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
70 return true;
71 default:
72 return false;
73 }
74 }
75
76 /**
77 * igt_vc4_get_cleared_bo:
78 * @fd: device file descriptor
79 * @size: size of the BO in bytes
80 * @clearval: u32 value that the buffer should be completely cleared with
81 *
82 * This helper returns a new BO with the given size, which has just been
83 * cleared using the render engine.
84 */
igt_vc4_get_cleared_bo(int fd,size_t size,uint32_t clearval)85 uint32_t igt_vc4_get_cleared_bo(int fd, size_t size, uint32_t clearval)
86 {
87 /* A single row will be a page. */
88 uint32_t width = 1024;
89 uint32_t height = size / (width * 4);
90 uint32_t handle = igt_vc4_create_bo(fd, size);
91 struct drm_vc4_submit_cl submit = {
92 .color_write = {
93 .hindex = 0,
94 .bits = VC4_SET_FIELD(VC4_RENDER_CONFIG_FORMAT_RGBA8888,
95 VC4_RENDER_CONFIG_FORMAT),
96 },
97
98 .color_read = { .hindex = ~0 },
99 .zs_read = { .hindex = ~0 },
100 .zs_write = { .hindex = ~0 },
101 .msaa_color_write = { .hindex = ~0 },
102 .msaa_zs_write = { .hindex = ~0 },
103
104 .bo_handles = to_user_pointer(&handle),
105 .bo_handle_count = 1,
106 .width = width,
107 .height = height,
108 .max_x_tile = ALIGN(width, 64) / 64 - 1,
109 .max_y_tile = ALIGN(height, 64) / 64 - 1,
110 .clear_color = { clearval, clearval },
111 .flags = VC4_SUBMIT_CL_USE_CLEAR_COLOR,
112 };
113
114 igt_assert_eq_u32(width * height * 4, size);
115
116 do_ioctl(fd, DRM_IOCTL_VC4_SUBMIT_CL, &submit);
117
118 return handle;
119 }
120
121 int
igt_vc4_create_bo(int fd,size_t size)122 igt_vc4_create_bo(int fd, size_t size)
123 {
124 struct drm_vc4_create_bo create = {
125 .size = size,
126 };
127
128 do_ioctl(fd, DRM_IOCTL_VC4_CREATE_BO, &create);
129
130 return create.handle;
131 }
132
133 void *
igt_vc4_mmap_bo(int fd,uint32_t handle,uint32_t size,unsigned prot)134 igt_vc4_mmap_bo(int fd, uint32_t handle, uint32_t size, unsigned prot)
135 {
136 struct drm_vc4_mmap_bo mmap_bo = {
137 .handle = handle,
138 };
139 void *ptr;
140
141 do_ioctl(fd, DRM_IOCTL_VC4_MMAP_BO, &mmap_bo);
142
143 ptr = mmap(0, size, prot, MAP_SHARED, fd, mmap_bo.offset);
144 if (ptr == MAP_FAILED)
145 return NULL;
146 else
147 return ptr;
148 }
149
igt_vc4_set_tiling(int fd,uint32_t handle,uint64_t modifier)150 void igt_vc4_set_tiling(int fd, uint32_t handle, uint64_t modifier)
151 {
152 struct drm_vc4_set_tiling set = {
153 .handle = handle,
154 .modifier = modifier,
155 };
156
157 do_ioctl(fd, DRM_IOCTL_VC4_SET_TILING, &set);
158 }
159
igt_vc4_get_tiling(int fd,uint32_t handle)160 uint64_t igt_vc4_get_tiling(int fd, uint32_t handle)
161 {
162 struct drm_vc4_get_tiling get = {
163 .handle = handle,
164 };
165
166 do_ioctl(fd, DRM_IOCTL_VC4_GET_TILING, &get);
167
168 return get.modifier;
169 }
170
igt_vc4_get_param(int fd,uint32_t param,uint64_t * val)171 int igt_vc4_get_param(int fd, uint32_t param, uint64_t *val)
172 {
173 struct drm_vc4_get_param arg = {
174 .param = param,
175 };
176 int ret;
177
178 ret = igt_ioctl(fd, DRM_IOCTL_VC4_GET_PARAM, &arg);
179 if (ret)
180 return ret;
181
182 *val = arg.value;
183 return 0;
184 }
185
igt_vc4_purgeable_bo(int fd,int handle,bool purgeable)186 bool igt_vc4_purgeable_bo(int fd, int handle, bool purgeable)
187 {
188 struct drm_vc4_gem_madvise arg = {
189 .handle = handle,
190 .madv = purgeable ? VC4_MADV_DONTNEED : VC4_MADV_WILLNEED,
191 };
192
193 do_ioctl(fd, DRM_IOCTL_VC4_GEM_MADVISE, &arg);
194
195 return arg.retained;
196 }
197
198
199 /* Calculate the t-tile width so that size = width * height * bpp / 8. */
200 #define VC4_T_TILE_W(size, height, bpp) ((size) / (height) / ((bpp) / 8))
201
igt_vc4_t_tiled_offset(size_t stride,size_t height,size_t bpp,size_t x,size_t y)202 static size_t igt_vc4_t_tiled_offset(size_t stride, size_t height, size_t bpp,
203 size_t x, size_t y)
204 {
205 const size_t t1k_map_even[] = { 0, 3, 1, 2 };
206 const size_t t1k_map_odd[] = { 2, 1, 3, 0 };
207 const size_t t4k_t_h = 32;
208 const size_t t1k_t_h = 16;
209 const size_t t64_t_h = 4;
210 size_t offset = 0;
211 size_t t4k_t_w, t4k_w, t4k_x, t4k_y;
212 size_t t1k_t_w, t1k_x, t1k_y;
213 size_t t64_t_w, t64_x, t64_y;
214 size_t pix_x, pix_y;
215 unsigned int index;
216
217 /* T-tiling is only supported for 16 and 32 bpp. */
218 igt_assert(bpp == 16 || bpp == 32);
219
220 /* T-tiling stride must be aligned to the 4K tiles strides. */
221 igt_assert((stride % (4096 / t4k_t_h)) == 0);
222
223 /* Calculate the tile width for the bpp. */
224 t4k_t_w = VC4_T_TILE_W(4096, t4k_t_h, bpp);
225 t1k_t_w = VC4_T_TILE_W(1024, t1k_t_h, bpp);
226 t64_t_w = VC4_T_TILE_W(64, t64_t_h, bpp);
227
228 /* Aligned total width in number of 4K tiles. */
229 t4k_w = (stride / (bpp / 8)) / t4k_t_w;
230
231 /* X and y coordinates in number of 4K tiles. */
232 t4k_x = x / t4k_t_w;
233 t4k_y = y / t4k_t_h;
234
235 /* Increase offset to the beginning of the 4K tile row. */
236 offset += t4k_y * t4k_w * 4096;
237
238 /* X and Y coordinates in number of 1K tiles within the 4K tile. */
239 t1k_x = (x % t4k_t_w) / t1k_t_w;
240 t1k_y = (y % t4k_t_h) / t1k_t_h;
241
242 /* Index for 1K tile map lookup. */
243 index = 2 * t1k_y + t1k_x;
244
245 /* Odd rows start from the right, even rows from the left. */
246 if (t4k_y % 2) {
247 /* Increase offset to the 4K tile (starting from the right). */
248 offset += (t4k_w - t4k_x - 1) * 4096;
249
250 /* Incrase offset to the beginning of the (odd) 1K tile. */
251 offset += t1k_map_odd[index] * 1024;
252 } else {
253 /* Increase offset to the 4K tile (starting from the left). */
254 offset += t4k_x * 4096;
255
256 /* Incrase offset to the beginning of the (even) 1K tile. */
257 offset += t1k_map_even[index] * 1024;
258 }
259
260 /* X and Y coordinates in number of 64 byte tiles within the 1K tile. */
261 t64_x = (x % t1k_t_w) / t64_t_w;
262 t64_y = (y % t1k_t_h) / t64_t_h;
263
264 /* Increase offset to the beginning of the 64-byte tile. */
265 offset += (t64_y * (t1k_t_w / t64_t_w) + t64_x) * 64;
266
267 /* X and Y coordinates in number of pixels within the 64-byte tile. */
268 pix_x = x % t64_t_w;
269 pix_y = y % t64_t_h;
270
271 /* Increase offset to the correct pixel. */
272 offset += (pix_y * t64_t_w + pix_x) * bpp / 8;
273
274 return offset;
275 }
276
vc4_fb_convert_plane_to_t_tiled(struct igt_fb * dst,void * dst_buf,struct igt_fb * src,void * src_buf,unsigned int plane)277 static void vc4_fb_convert_plane_to_t_tiled(struct igt_fb *dst, void *dst_buf,
278 struct igt_fb *src, void *src_buf,
279 unsigned int plane)
280 {
281 size_t bpp = src->plane_bpp[plane];
282 unsigned int i, j;
283
284 for (i = 0; i < src->height; i++) {
285 for (j = 0; j < src->width; j++) {
286 size_t src_offset = src->offsets[plane];
287 size_t dst_offset = dst->offsets[plane];
288
289 src_offset += src->strides[plane] * i + j * bpp / 8;
290 dst_offset += igt_vc4_t_tiled_offset(dst->strides[plane],
291 dst->height,
292 bpp, j, i);
293
294 switch (bpp) {
295 case 16:
296 *(uint16_t *)(dst_buf + dst_offset) =
297 *(uint16_t *)(src_buf + src_offset);
298 break;
299 case 32:
300 *(uint32_t *)(dst_buf + dst_offset) =
301 *(uint32_t *)(src_buf + src_offset);
302 break;
303 }
304 }
305 }
306 }
307
vc4_fb_convert_plane_from_t_tiled(struct igt_fb * dst,void * dst_buf,struct igt_fb * src,void * src_buf,unsigned int plane)308 static void vc4_fb_convert_plane_from_t_tiled(struct igt_fb *dst, void *dst_buf,
309 struct igt_fb *src, void *src_buf,
310 unsigned int plane)
311 {
312 size_t bpp = src->plane_bpp[plane];
313 unsigned int i, j;
314
315 for (i = 0; i < src->height; i++) {
316 for (j = 0; j < src->width; j++) {
317 size_t src_offset = src->offsets[plane];
318 size_t dst_offset = dst->offsets[plane];
319
320 src_offset += igt_vc4_t_tiled_offset(src->strides[plane],
321 src->height,
322 bpp, j, i);
323 src_offset += dst->strides[plane] * i + j * bpp / 8;
324
325 switch (bpp) {
326 case 16:
327 *(uint16_t *)(dst_buf + dst_offset) =
328 *(uint16_t *)(src_buf + src_offset);
329 break;
330 case 32:
331 *(uint32_t *)(dst_buf + dst_offset) =
332 *(uint32_t *)(src_buf + src_offset);
333 break;
334 }
335 }
336 }
337 }
338
vc4_sand_tiled_offset(size_t column_width,size_t column_size,size_t x,size_t y,size_t bpp)339 static size_t vc4_sand_tiled_offset(size_t column_width, size_t column_size, size_t x,
340 size_t y, size_t bpp)
341 {
342 size_t offset = 0;
343 size_t cols_x;
344 size_t pix_x;
345
346 /* Offset to the beginning of the relevant column. */
347 cols_x = x / column_width;
348 offset += cols_x * column_size;
349
350 /* Offset to the relevant pixel. */
351 pix_x = x % column_width;
352 offset += (column_width * y + pix_x) * bpp / 8;
353
354 return offset;
355 }
356
vc4_fb_convert_plane_to_sand_tiled(struct igt_fb * dst,void * dst_buf,struct igt_fb * src,void * src_buf,unsigned int plane)357 static void vc4_fb_convert_plane_to_sand_tiled(struct igt_fb *dst, void *dst_buf,
358 struct igt_fb *src, void *src_buf,
359 unsigned int plane)
360 {
361 uint64_t modifier_base = fourcc_mod_broadcom_mod(dst->modifier);
362 uint32_t column_height = fourcc_mod_broadcom_param(dst->modifier);
363 uint32_t column_width_bytes, column_width, column_size;
364 size_t bpp = dst->plane_bpp[plane];
365 unsigned int i, j;
366
367 switch (modifier_base) {
368 case DRM_FORMAT_MOD_BROADCOM_SAND32:
369 column_width_bytes = 32;
370 break;
371 case DRM_FORMAT_MOD_BROADCOM_SAND64:
372 column_width_bytes = 64;
373 break;
374 case DRM_FORMAT_MOD_BROADCOM_SAND128:
375 column_width_bytes = 128;
376 break;
377 case DRM_FORMAT_MOD_BROADCOM_SAND256:
378 column_width_bytes = 256;
379 break;
380 default:
381 igt_assert(false);
382 }
383
384 column_width = column_width_bytes * dst->plane_width[plane] / dst->width;
385 column_size = column_width_bytes * column_height;
386
387 for (i = 0; i < dst->plane_height[plane]; i++) {
388 for (j = 0; j < src->plane_width[plane]; j++) {
389 size_t src_offset = src->offsets[plane];
390 size_t dst_offset = dst->offsets[plane];
391
392 src_offset += src->strides[plane] * i + j * bpp / 8;
393 dst_offset += vc4_sand_tiled_offset(column_width,
394 column_size, j, i,
395 bpp);
396
397 switch (bpp) {
398 case 8:
399 *(uint8_t *)(dst_buf + dst_offset) =
400 *(uint8_t *)(src_buf + src_offset);
401 break;
402 case 16:
403 *(uint16_t *)(dst_buf + dst_offset) =
404 *(uint16_t *)(src_buf + src_offset);
405 break;
406 default:
407 igt_assert(false);
408 }
409 }
410 }
411 }
412
vc4_fb_convert_plane_from_sand_tiled(struct igt_fb * dst,void * dst_buf,struct igt_fb * src,void * src_buf,unsigned int plane)413 static void vc4_fb_convert_plane_from_sand_tiled(struct igt_fb *dst, void *dst_buf,
414 struct igt_fb *src, void *src_buf,
415 unsigned int plane)
416 {
417 uint64_t modifier_base = fourcc_mod_broadcom_mod(src->modifier);
418 uint32_t column_height = fourcc_mod_broadcom_param(src->modifier);
419 uint32_t column_width_bytes, column_width, column_size;
420 size_t bpp = src->plane_bpp[plane];
421 unsigned int i, j;
422
423 switch (modifier_base) {
424 case DRM_FORMAT_MOD_BROADCOM_SAND32:
425 column_width_bytes = 32;
426 break;
427 case DRM_FORMAT_MOD_BROADCOM_SAND64:
428 column_width_bytes = 64;
429 break;
430 case DRM_FORMAT_MOD_BROADCOM_SAND128:
431 column_width_bytes = 128;
432 break;
433 case DRM_FORMAT_MOD_BROADCOM_SAND256:
434 column_width_bytes = 256;
435 break;
436 default:
437 igt_assert(false);
438 }
439
440 column_width = column_width_bytes * src->plane_width[plane] / src->width;
441 column_size = column_width_bytes * column_height;
442
443 for (i = 0; i < dst->plane_height[plane]; i++) {
444 for (j = 0; j < src->plane_width[plane]; j++) {
445 size_t src_offset = src->offsets[plane];
446 size_t dst_offset = dst->offsets[plane];
447
448 src_offset += vc4_sand_tiled_offset(column_width,
449 column_size, j, i,
450 bpp);
451 dst_offset += dst->strides[plane] * i + j * bpp / 8;
452
453 switch (bpp) {
454 case 8:
455 *(uint8_t *)(dst_buf + dst_offset) =
456 *(uint8_t *)(src_buf + src_offset);
457 break;
458 case 16:
459 *(uint16_t *)(dst_buf + dst_offset) =
460 *(uint16_t *)(src_buf + src_offset);
461 break;
462 default:
463 igt_assert(false);
464 }
465 }
466 }
467 }
468
vc4_fb_convert_plane_to_tiled(struct igt_fb * dst,void * dst_buf,struct igt_fb * src,void * src_buf)469 void vc4_fb_convert_plane_to_tiled(struct igt_fb *dst, void *dst_buf,
470 struct igt_fb *src, void *src_buf)
471 {
472 unsigned int plane;
473
474 igt_assert(src->modifier == DRM_FORMAT_MOD_LINEAR);
475 igt_assert(igt_vc4_is_tiled(dst->modifier));
476
477 for (plane = 0; plane < src->num_planes; plane++) {
478 if (dst->modifier == DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED)
479 vc4_fb_convert_plane_to_t_tiled(dst, dst_buf, src, src_buf, plane);
480 else
481 vc4_fb_convert_plane_to_sand_tiled(dst, dst_buf, src, src_buf, plane);
482 }
483 }
484
vc4_fb_convert_plane_from_tiled(struct igt_fb * dst,void * dst_buf,struct igt_fb * src,void * src_buf)485 void vc4_fb_convert_plane_from_tiled(struct igt_fb *dst, void *dst_buf,
486 struct igt_fb *src, void *src_buf)
487 {
488 unsigned int plane;
489
490 igt_assert(igt_vc4_is_tiled(src->modifier));
491 igt_assert(dst->modifier == DRM_FORMAT_MOD_LINEAR);
492
493 for (plane = 0; plane < src->num_planes; plane++) {
494 if (src->modifier == DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED)
495 vc4_fb_convert_plane_from_t_tiled(dst, dst_buf, src, src_buf, plane);
496 else
497 vc4_fb_convert_plane_from_sand_tiled(dst, dst_buf, src, src_buf, plane);
498 }
499 }
500