/* * Copyright © 2016 Broadcom * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include "drmtest.h" #include "igt_aux.h" #include "igt_core.h" #include "igt_fb.h" #include "igt_vc4.h" #include "ioctl_wrappers.h" #include "intel_reg.h" #include "intel_chipset.h" #include "vc4_drm.h" #include "vc4_packet.h" #if NEW_CONTEXT_PARAM_NO_ERROR_CAPTURE_API #define LOCAL_CONTEXT_PARAM_NO_ERROR_CAPTURE 0x4 #endif /** * SECTION:igt_vc4 * @short_description: VC4 support library * @title: VC4 * @include: igt.h * * This library provides various auxiliary helper functions for writing VC4 * tests. */ bool igt_vc4_is_tiled(uint64_t modifier) { if (modifier >> 56ULL != DRM_FORMAT_MOD_VENDOR_BROADCOM) return false; switch (fourcc_mod_broadcom_mod(modifier)) { case DRM_FORMAT_MOD_BROADCOM_SAND32: case DRM_FORMAT_MOD_BROADCOM_SAND64: case DRM_FORMAT_MOD_BROADCOM_SAND128: case DRM_FORMAT_MOD_BROADCOM_SAND256: case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: return true; default: return false; } } /** * igt_vc4_get_cleared_bo: * @fd: device file descriptor * @size: size of the BO in bytes * @clearval: u32 value that the buffer should be completely cleared with * * This helper returns a new BO with the given size, which has just been * cleared using the render engine. */ uint32_t igt_vc4_get_cleared_bo(int fd, size_t size, uint32_t clearval) { /* A single row will be a page. */ uint32_t width = 1024; uint32_t height = size / (width * 4); uint32_t handle = igt_vc4_create_bo(fd, size); struct drm_vc4_submit_cl submit = { .color_write = { .hindex = 0, .bits = VC4_SET_FIELD(VC4_RENDER_CONFIG_FORMAT_RGBA8888, VC4_RENDER_CONFIG_FORMAT), }, .color_read = { .hindex = ~0 }, .zs_read = { .hindex = ~0 }, .zs_write = { .hindex = ~0 }, .msaa_color_write = { .hindex = ~0 }, .msaa_zs_write = { .hindex = ~0 }, .bo_handles = to_user_pointer(&handle), .bo_handle_count = 1, .width = width, .height = height, .max_x_tile = ALIGN(width, 64) / 64 - 1, .max_y_tile = ALIGN(height, 64) / 64 - 1, .clear_color = { clearval, clearval }, .flags = VC4_SUBMIT_CL_USE_CLEAR_COLOR, }; igt_assert_eq_u32(width * height * 4, size); do_ioctl(fd, DRM_IOCTL_VC4_SUBMIT_CL, &submit); return handle; } int igt_vc4_create_bo(int fd, size_t size) { struct drm_vc4_create_bo create = { .size = size, }; do_ioctl(fd, DRM_IOCTL_VC4_CREATE_BO, &create); return create.handle; } void * igt_vc4_mmap_bo(int fd, uint32_t handle, uint32_t size, unsigned prot) { struct drm_vc4_mmap_bo mmap_bo = { .handle = handle, }; void *ptr; do_ioctl(fd, DRM_IOCTL_VC4_MMAP_BO, &mmap_bo); ptr = mmap(0, size, prot, MAP_SHARED, fd, mmap_bo.offset); if (ptr == MAP_FAILED) return NULL; else return ptr; } void igt_vc4_set_tiling(int fd, uint32_t handle, uint64_t modifier) { struct drm_vc4_set_tiling set = { .handle = handle, .modifier = modifier, }; do_ioctl(fd, DRM_IOCTL_VC4_SET_TILING, &set); } uint64_t igt_vc4_get_tiling(int fd, uint32_t handle) { struct drm_vc4_get_tiling get = { .handle = handle, }; do_ioctl(fd, DRM_IOCTL_VC4_GET_TILING, &get); return get.modifier; } int igt_vc4_get_param(int fd, uint32_t param, uint64_t *val) { struct drm_vc4_get_param arg = { .param = param, }; int ret; ret = igt_ioctl(fd, DRM_IOCTL_VC4_GET_PARAM, &arg); if (ret) return ret; *val = arg.value; return 0; } bool igt_vc4_purgeable_bo(int fd, int handle, bool purgeable) { struct drm_vc4_gem_madvise arg = { .handle = handle, .madv = purgeable ? VC4_MADV_DONTNEED : VC4_MADV_WILLNEED, }; do_ioctl(fd, DRM_IOCTL_VC4_GEM_MADVISE, &arg); return arg.retained; } /* Calculate the t-tile width so that size = width * height * bpp / 8. */ #define VC4_T_TILE_W(size, height, bpp) ((size) / (height) / ((bpp) / 8)) static size_t igt_vc4_t_tiled_offset(size_t stride, size_t height, size_t bpp, size_t x, size_t y) { const size_t t1k_map_even[] = { 0, 3, 1, 2 }; const size_t t1k_map_odd[] = { 2, 1, 3, 0 }; const size_t t4k_t_h = 32; const size_t t1k_t_h = 16; const size_t t64_t_h = 4; size_t offset = 0; size_t t4k_t_w, t4k_w, t4k_x, t4k_y; size_t t1k_t_w, t1k_x, t1k_y; size_t t64_t_w, t64_x, t64_y; size_t pix_x, pix_y; unsigned int index; /* T-tiling is only supported for 16 and 32 bpp. */ igt_assert(bpp == 16 || bpp == 32); /* T-tiling stride must be aligned to the 4K tiles strides. */ igt_assert((stride % (4096 / t4k_t_h)) == 0); /* Calculate the tile width for the bpp. */ t4k_t_w = VC4_T_TILE_W(4096, t4k_t_h, bpp); t1k_t_w = VC4_T_TILE_W(1024, t1k_t_h, bpp); t64_t_w = VC4_T_TILE_W(64, t64_t_h, bpp); /* Aligned total width in number of 4K tiles. */ t4k_w = (stride / (bpp / 8)) / t4k_t_w; /* X and y coordinates in number of 4K tiles. */ t4k_x = x / t4k_t_w; t4k_y = y / t4k_t_h; /* Increase offset to the beginning of the 4K tile row. */ offset += t4k_y * t4k_w * 4096; /* X and Y coordinates in number of 1K tiles within the 4K tile. */ t1k_x = (x % t4k_t_w) / t1k_t_w; t1k_y = (y % t4k_t_h) / t1k_t_h; /* Index for 1K tile map lookup. */ index = 2 * t1k_y + t1k_x; /* Odd rows start from the right, even rows from the left. */ if (t4k_y % 2) { /* Increase offset to the 4K tile (starting from the right). */ offset += (t4k_w - t4k_x - 1) * 4096; /* Incrase offset to the beginning of the (odd) 1K tile. */ offset += t1k_map_odd[index] * 1024; } else { /* Increase offset to the 4K tile (starting from the left). */ offset += t4k_x * 4096; /* Incrase offset to the beginning of the (even) 1K tile. */ offset += t1k_map_even[index] * 1024; } /* X and Y coordinates in number of 64 byte tiles within the 1K tile. */ t64_x = (x % t1k_t_w) / t64_t_w; t64_y = (y % t1k_t_h) / t64_t_h; /* Increase offset to the beginning of the 64-byte tile. */ offset += (t64_y * (t1k_t_w / t64_t_w) + t64_x) * 64; /* X and Y coordinates in number of pixels within the 64-byte tile. */ pix_x = x % t64_t_w; pix_y = y % t64_t_h; /* Increase offset to the correct pixel. */ offset += (pix_y * t64_t_w + pix_x) * bpp / 8; return offset; } static void vc4_fb_convert_plane_to_t_tiled(struct igt_fb *dst, void *dst_buf, struct igt_fb *src, void *src_buf, unsigned int plane) { size_t bpp = src->plane_bpp[plane]; unsigned int i, j; for (i = 0; i < src->height; i++) { for (j = 0; j < src->width; j++) { size_t src_offset = src->offsets[plane]; size_t dst_offset = dst->offsets[plane]; src_offset += src->strides[plane] * i + j * bpp / 8; dst_offset += igt_vc4_t_tiled_offset(dst->strides[plane], dst->height, bpp, j, i); switch (bpp) { case 16: *(uint16_t *)(dst_buf + dst_offset) = *(uint16_t *)(src_buf + src_offset); break; case 32: *(uint32_t *)(dst_buf + dst_offset) = *(uint32_t *)(src_buf + src_offset); break; } } } } static void vc4_fb_convert_plane_from_t_tiled(struct igt_fb *dst, void *dst_buf, struct igt_fb *src, void *src_buf, unsigned int plane) { size_t bpp = src->plane_bpp[plane]; unsigned int i, j; for (i = 0; i < src->height; i++) { for (j = 0; j < src->width; j++) { size_t src_offset = src->offsets[plane]; size_t dst_offset = dst->offsets[plane]; src_offset += igt_vc4_t_tiled_offset(src->strides[plane], src->height, bpp, j, i); src_offset += dst->strides[plane] * i + j * bpp / 8; switch (bpp) { case 16: *(uint16_t *)(dst_buf + dst_offset) = *(uint16_t *)(src_buf + src_offset); break; case 32: *(uint32_t *)(dst_buf + dst_offset) = *(uint32_t *)(src_buf + src_offset); break; } } } } static size_t vc4_sand_tiled_offset(size_t column_width, size_t column_size, size_t x, size_t y, size_t bpp) { size_t offset = 0; size_t cols_x; size_t pix_x; /* Offset to the beginning of the relevant column. */ cols_x = x / column_width; offset += cols_x * column_size; /* Offset to the relevant pixel. */ pix_x = x % column_width; offset += (column_width * y + pix_x) * bpp / 8; return offset; } static void vc4_fb_convert_plane_to_sand_tiled(struct igt_fb *dst, void *dst_buf, struct igt_fb *src, void *src_buf, unsigned int plane) { uint64_t modifier_base = fourcc_mod_broadcom_mod(dst->modifier); uint32_t column_height = fourcc_mod_broadcom_param(dst->modifier); uint32_t column_width_bytes, column_width, column_size; size_t bpp = dst->plane_bpp[plane]; unsigned int i, j; switch (modifier_base) { case DRM_FORMAT_MOD_BROADCOM_SAND32: column_width_bytes = 32; break; case DRM_FORMAT_MOD_BROADCOM_SAND64: column_width_bytes = 64; break; case DRM_FORMAT_MOD_BROADCOM_SAND128: column_width_bytes = 128; break; case DRM_FORMAT_MOD_BROADCOM_SAND256: column_width_bytes = 256; break; default: igt_assert(false); } column_width = column_width_bytes * dst->plane_width[plane] / dst->width; column_size = column_width_bytes * column_height; for (i = 0; i < dst->plane_height[plane]; i++) { for (j = 0; j < src->plane_width[plane]; j++) { size_t src_offset = src->offsets[plane]; size_t dst_offset = dst->offsets[plane]; src_offset += src->strides[plane] * i + j * bpp / 8; dst_offset += vc4_sand_tiled_offset(column_width, column_size, j, i, bpp); switch (bpp) { case 8: *(uint8_t *)(dst_buf + dst_offset) = *(uint8_t *)(src_buf + src_offset); break; case 16: *(uint16_t *)(dst_buf + dst_offset) = *(uint16_t *)(src_buf + src_offset); break; default: igt_assert(false); } } } } static void vc4_fb_convert_plane_from_sand_tiled(struct igt_fb *dst, void *dst_buf, struct igt_fb *src, void *src_buf, unsigned int plane) { uint64_t modifier_base = fourcc_mod_broadcom_mod(src->modifier); uint32_t column_height = fourcc_mod_broadcom_param(src->modifier); uint32_t column_width_bytes, column_width, column_size; size_t bpp = src->plane_bpp[plane]; unsigned int i, j; switch (modifier_base) { case DRM_FORMAT_MOD_BROADCOM_SAND32: column_width_bytes = 32; break; case DRM_FORMAT_MOD_BROADCOM_SAND64: column_width_bytes = 64; break; case DRM_FORMAT_MOD_BROADCOM_SAND128: column_width_bytes = 128; break; case DRM_FORMAT_MOD_BROADCOM_SAND256: column_width_bytes = 256; break; default: igt_assert(false); } column_width = column_width_bytes * src->plane_width[plane] / src->width; column_size = column_width_bytes * column_height; for (i = 0; i < dst->plane_height[plane]; i++) { for (j = 0; j < src->plane_width[plane]; j++) { size_t src_offset = src->offsets[plane]; size_t dst_offset = dst->offsets[plane]; src_offset += vc4_sand_tiled_offset(column_width, column_size, j, i, bpp); dst_offset += dst->strides[plane] * i + j * bpp / 8; switch (bpp) { case 8: *(uint8_t *)(dst_buf + dst_offset) = *(uint8_t *)(src_buf + src_offset); break; case 16: *(uint16_t *)(dst_buf + dst_offset) = *(uint16_t *)(src_buf + src_offset); break; default: igt_assert(false); } } } } void vc4_fb_convert_plane_to_tiled(struct igt_fb *dst, void *dst_buf, struct igt_fb *src, void *src_buf) { unsigned int plane; igt_assert(src->modifier == DRM_FORMAT_MOD_LINEAR); igt_assert(igt_vc4_is_tiled(dst->modifier)); for (plane = 0; plane < src->num_planes; plane++) { if (dst->modifier == DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED) vc4_fb_convert_plane_to_t_tiled(dst, dst_buf, src, src_buf, plane); else vc4_fb_convert_plane_to_sand_tiled(dst, dst_buf, src, src_buf, plane); } } void vc4_fb_convert_plane_from_tiled(struct igt_fb *dst, void *dst_buf, struct igt_fb *src, void *src_buf) { unsigned int plane; igt_assert(igt_vc4_is_tiled(src->modifier)); igt_assert(dst->modifier == DRM_FORMAT_MOD_LINEAR); for (plane = 0; plane < src->num_planes; plane++) { if (src->modifier == DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED) vc4_fb_convert_plane_from_t_tiled(dst, dst_buf, src, src_buf, plane); else vc4_fb_convert_plane_from_sand_tiled(dst, dst_buf, src, src_buf, plane); } }