1 /*
2 * Copyright © 2021 Collabora Ltd.
3 *
4 * Derived from tu_image.c which is:
5 * Copyright © 2016 Red Hat.
6 * Copyright © 2016 Bas Nieuwenhuizen
7 * Copyright © 2015 Intel Corporation
8 *
9 * SPDX-License-Identifier: MIT
10 */
11
12 #include "vk_format.h"
13 #include "vk_log.h"
14
15 #include "panvk_device.h"
16 #include "panvk_entrypoints.h"
17 #include "panvk_image.h"
18 #include "panvk_image_view.h"
19 #include "panvk_priv_bo.h"
20
21 #include "genxml/gen_macros.h"
22
23 static enum mali_texture_dimension
panvk_view_type_to_mali_tex_dim(VkImageViewType type)24 panvk_view_type_to_mali_tex_dim(VkImageViewType type)
25 {
26 switch (type) {
27 case VK_IMAGE_VIEW_TYPE_1D:
28 case VK_IMAGE_VIEW_TYPE_1D_ARRAY:
29 return MALI_TEXTURE_DIMENSION_1D;
30 case VK_IMAGE_VIEW_TYPE_2D:
31 case VK_IMAGE_VIEW_TYPE_2D_ARRAY:
32 return MALI_TEXTURE_DIMENSION_2D;
33 case VK_IMAGE_VIEW_TYPE_3D:
34 return MALI_TEXTURE_DIMENSION_3D;
35 case VK_IMAGE_VIEW_TYPE_CUBE:
36 case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:
37 return MALI_TEXTURE_DIMENSION_CUBE;
38 default:
39 unreachable("Invalid view type");
40 }
41 }
42
43 static void
panvk_convert_swizzle(const VkComponentMapping * in,unsigned char * out)44 panvk_convert_swizzle(const VkComponentMapping *in, unsigned char *out)
45 {
46 const VkComponentSwizzle *comp = &in->r;
47 for (unsigned i = 0; i < 4; i++) {
48 switch (comp[i]) {
49 case VK_COMPONENT_SWIZZLE_ZERO:
50 out[i] = PIPE_SWIZZLE_0;
51 break;
52 case VK_COMPONENT_SWIZZLE_ONE:
53 out[i] = PIPE_SWIZZLE_1;
54 break;
55 case VK_COMPONENT_SWIZZLE_R:
56 out[i] = PIPE_SWIZZLE_X;
57 break;
58 case VK_COMPONENT_SWIZZLE_G:
59 out[i] = PIPE_SWIZZLE_Y;
60 break;
61 case VK_COMPONENT_SWIZZLE_B:
62 out[i] = PIPE_SWIZZLE_Z;
63 break;
64 case VK_COMPONENT_SWIZZLE_A:
65 out[i] = PIPE_SWIZZLE_W;
66 break;
67 default:
68 unreachable("Invalid swizzle");
69 }
70 }
71 }
72
73 static VkResult
prepare_tex_descs(struct panvk_image_view * view)74 prepare_tex_descs(struct panvk_image_view *view)
75 {
76 /* Use a temporary pan_image_view so we can tweak it for texture
77 * descriptor emission without changing the original definition.
78 */
79 struct pan_image_view pview = view->pview;
80 struct panvk_image *image =
81 container_of(view->vk.image, struct panvk_image, vk);
82 struct panvk_device *dev = to_panvk_device(view->vk.base.device);
83 bool can_preload_other_aspect =
84 (view->vk.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) &&
85 (image->vk.format == VK_FORMAT_D24_UNORM_S8_UINT ||
86 (image->vk.format == VK_FORMAT_D32_SFLOAT_S8_UINT &&
87 view->vk.aspects ==
88 (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)));
89
90 if (util_format_is_depth_or_stencil(view->pview.format)) {
91 /* Vulkan wants R001, where the depth/stencil is stored in the red
92 * component. Tweak the swizzle so we get what Vulkan wants.
93 */
94 static const unsigned char r001[4] = {
95 PIPE_SWIZZLE_X,
96 PIPE_SWIZZLE_0,
97 PIPE_SWIZZLE_0,
98 PIPE_SWIZZLE_1,
99 };
100
101 util_format_compose_swizzles(r001, view->pview.swizzle, pview.swizzle);
102 }
103 #if PAN_ARCH == 7
104 /* v7 requires AFBC reswizzle. */
105 else if (!panfrost_format_is_yuv(view->pview.format) &&
106 panfrost_format_supports_afbc(PAN_ARCH, view->pview.format))
107 GENX(panfrost_texture_afbc_reswizzle)(&pview);
108 #endif
109
110 /* If the view contains both stencil and depth, we need to keep only the
111 * depth. We'll create another texture with only the stencil.
112 */
113 if (pview.format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT)
114 pview.format = PIPE_FORMAT_Z32_FLOAT;
115
116 struct panvk_pool_alloc_info alloc_info = {
117 #if PAN_ARCH == 6
118 .alignment = pan_alignment(SURFACE_WITH_STRIDE),
119 #elif PAN_ARCH == 7
120 .alignment = pan_alignment(MULTIPLANAR_SURFACE),
121 #else
122 .alignment = pan_alignment(PLANE),
123 #endif
124
125 .size = GENX(panfrost_estimate_texture_payload_size)(&pview) *
126 (can_preload_other_aspect ? 2 : 1),
127 };
128
129 view->mem = panvk_pool_alloc_mem(&dev->mempools.rw, alloc_info);
130 if (!panvk_priv_mem_host_addr(view->mem))
131 return panvk_error(dev, VK_ERROR_OUT_OF_DEVICE_MEMORY);
132
133 struct panfrost_ptr ptr = {
134 .gpu = panvk_priv_mem_dev_addr(view->mem),
135 .cpu = panvk_priv_mem_host_addr(view->mem),
136 };
137
138 GENX(panfrost_new_texture)(&pview, &view->descs.tex, &ptr);
139
140 if (!can_preload_other_aspect)
141 return VK_SUCCESS;
142
143 switch (pview.format) {
144 case PIPE_FORMAT_Z24X8_UNORM:
145 case PIPE_FORMAT_Z24_UNORM_S8_UINT:
146 pview.format = PIPE_FORMAT_X24S8_UINT;
147 break;
148 case PIPE_FORMAT_X24S8_UINT:
149 pview.format = PIPE_FORMAT_Z24X8_UNORM;
150 break;
151 case PIPE_FORMAT_Z32_FLOAT:
152 pview.format = PIPE_FORMAT_S8_UINT;
153 break;
154 case PIPE_FORMAT_S8_UINT:
155 pview.format = PIPE_FORMAT_Z32_FLOAT;
156 break;
157 default:
158 assert(!"Invalid format");
159 }
160
161 ptr.cpu += alloc_info.size / 2;
162 ptr.gpu += alloc_info.size / 2;
163
164 GENX(panfrost_new_texture)(&pview, &view->descs.other_aspect_tex, &ptr);
165 return VK_SUCCESS;
166 }
167
168 #if PAN_ARCH <= 7
169 static void
prepare_attr_buf_descs(struct panvk_image_view * view)170 prepare_attr_buf_descs(struct panvk_image_view *view)
171 {
172 struct panvk_image *image =
173 container_of(view->vk.image, struct panvk_image, vk);
174 unsigned plane_idx = 0;
175
176 /* Stencil is on plane 1 in a D32_S8 image. The special color case is for
177 * vk_meta copies which create color views of depth/stencil images. In
178 * that case, we base the stencil vs depth detection on the format block
179 * size.
180 */
181 if (image->vk.format == VK_FORMAT_D32_SFLOAT_S8_UINT &&
182 (view->vk.aspects == VK_IMAGE_ASPECT_STENCIL_BIT ||
183 (view->vk.aspects == VK_IMAGE_ASPECT_COLOR_BIT &&
184 vk_format_get_blocksize(view->vk.view_format) == 1)))
185 plane_idx = 1;
186
187 bool is_3d =
188 image->planes[plane_idx].layout.dim == MALI_TEXTURE_DIMENSION_3D;
189 unsigned offset = image->planes[plane_idx].data.offset;
190 offset += panfrost_texture_offset(
191 &image->planes[plane_idx].layout, view->pview.first_level,
192 is_3d ? 0 : view->pview.first_layer, is_3d ? view->pview.first_layer : 0);
193
194 pan_pack(&view->descs.img_attrib_buf[0], ATTRIBUTE_BUFFER, cfg) {
195 /* The format is the only thing we lack to emit attribute descriptors
196 * when copying from the set to the attribute tables. Instead of
197 * making the descriptor size to store an extra format, we pack
198 * the 22-bit format with the texel stride, which is expected to be
199 * fit in remaining 10 bits.
200 */
201 uint32_t fmt_blksize = util_format_get_blocksize(view->pview.format);
202 uint32_t hw_fmt =
203 GENX(panfrost_format_from_pipe_format)(view->pview.format)->hw;
204
205 assert(fmt_blksize < BITFIELD_MASK(10));
206 assert(hw_fmt < BITFIELD_MASK(22));
207
208 cfg.type = image->vk.drm_format_mod == DRM_FORMAT_MOD_LINEAR
209 ? MALI_ATTRIBUTE_TYPE_3D_LINEAR
210 : MALI_ATTRIBUTE_TYPE_3D_INTERLEAVED;
211 cfg.pointer = image->planes[plane_idx].data.base + offset;
212 cfg.stride = fmt_blksize | (hw_fmt << 10);
213 cfg.size = pan_kmod_bo_size(image->bo) - offset;
214 }
215
216 struct mali_attribute_buffer_packed *buf = &view->descs.img_attrib_buf[1];
217 pan_cast_and_pack(buf, ATTRIBUTE_BUFFER_CONTINUATION_3D, cfg) {
218 unsigned level = view->pview.first_level;
219 VkExtent3D extent = view->vk.extent;
220
221 cfg.s_dimension = extent.width;
222 cfg.t_dimension = extent.height;
223 cfg.r_dimension =
224 view->pview.dim == MALI_TEXTURE_DIMENSION_3D
225 ? extent.depth
226 : (view->pview.last_layer - view->pview.first_layer + 1);
227 cfg.row_stride = image->planes[plane_idx].layout.slices[level].row_stride;
228 if (cfg.r_dimension > 1) {
229 cfg.slice_stride =
230 panfrost_get_layer_stride(&image->planes[plane_idx].layout, level);
231 }
232 }
233 }
234 #endif
235
236 VKAPI_ATTR VkResult VKAPI_CALL
panvk_per_arch(CreateImageView)237 panvk_per_arch(CreateImageView)(VkDevice _device,
238 const VkImageViewCreateInfo *pCreateInfo,
239 const VkAllocationCallbacks *pAllocator,
240 VkImageView *pView)
241 {
242 VK_FROM_HANDLE(panvk_device, device, _device);
243 VK_FROM_HANDLE(panvk_image, image, pCreateInfo->image);
244 bool driver_internal =
245 (pCreateInfo->flags & VK_IMAGE_VIEW_CREATE_DRIVER_INTERNAL_BIT_MESA) != 0;
246 struct panvk_image_view *view;
247 VkResult result;
248
249 view = vk_image_view_create(&device->vk, driver_internal, pCreateInfo,
250 pAllocator, sizeof(*view));
251 if (view == NULL)
252 return panvk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
253
254 view->pview = (struct pan_image_view){
255 .format = vk_format_to_pipe_format(view->vk.view_format),
256 .dim = panvk_view_type_to_mali_tex_dim(view->vk.view_type),
257 .nr_samples = image->vk.samples,
258 .first_level = view->vk.base_mip_level,
259 .last_level = view->vk.base_mip_level + view->vk.level_count - 1,
260 .first_layer = view->vk.base_array_layer,
261 .last_layer = view->vk.base_array_layer + view->vk.layer_count - 1,
262 };
263 panvk_convert_swizzle(&view->vk.swizzle, view->pview.swizzle);
264
265 u_foreach_bit(aspect_bit, view->vk.aspects) {
266 uint8_t image_plane =
267 panvk_plane_index(image->vk.format, 1u << aspect_bit);
268 view->pview.planes[image_plane] = &image->planes[image_plane];
269 }
270
271 /* Depth/stencil are viewed as color for copies. */
272 if (view->vk.aspects == VK_IMAGE_ASPECT_COLOR_BIT &&
273 image->vk.format == VK_FORMAT_D32_SFLOAT_S8_UINT &&
274 vk_format_get_blocksize(view->vk.view_format) == 1) {
275 view->pview.planes[0] = &image->planes[1];
276 }
277
278 /* We need to patch the view format when the image contains both
279 * depth and stencil but the view only contains one of these components, so
280 * we can ignore the component we don't use.
281 */
282 if (view->vk.view_format == VK_FORMAT_S8_UINT &&
283 image->vk.format == VK_FORMAT_D24_UNORM_S8_UINT)
284 view->pview.format = PIPE_FORMAT_X24S8_UINT;
285
286 /* Attachments need a texture for the FB preload logic. */
287 VkImageUsageFlags tex_usage_mask =
288 VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT |
289 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
290 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
291
292 #if PAN_ARCH >= 9
293 /* Valhall passes a texture descriptor to LEA_TEX. */
294 tex_usage_mask |= VK_IMAGE_USAGE_STORAGE_BIT;
295 #endif
296
297 if (view->vk.usage & tex_usage_mask) {
298 result = prepare_tex_descs(view);
299 if (result != VK_SUCCESS)
300 goto err_destroy_iview;
301 }
302
303 #if PAN_ARCH <= 7
304 if (view->vk.usage & VK_IMAGE_USAGE_STORAGE_BIT)
305 prepare_attr_buf_descs(view);
306 #endif
307
308 *pView = panvk_image_view_to_handle(view);
309 return VK_SUCCESS;
310
311 err_destroy_iview:
312 vk_image_view_destroy(&device->vk, pAllocator, &view->vk);
313 return result;
314 }
315
316 VKAPI_ATTR void VKAPI_CALL
panvk_per_arch(DestroyImageView)317 panvk_per_arch(DestroyImageView)(VkDevice _device, VkImageView _view,
318 const VkAllocationCallbacks *pAllocator)
319 {
320 VK_FROM_HANDLE(panvk_device, device, _device);
321 VK_FROM_HANDLE(panvk_image_view, view, _view);
322
323 if (!view)
324 return;
325
326 panvk_pool_free_mem(&view->mem);
327 vk_image_view_destroy(&device->vk, pAllocator, &view->vk);
328 }
329