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 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice (including the next
17 * paragraph) shall be included in all copies or substantial portions of the
18 * Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 * DEALINGS IN THE SOFTWARE.
27 */
28
29 #include "pan_props.h"
30
31 #include "panvk_device.h"
32 #include "panvk_device_memory.h"
33 #include "panvk_entrypoints.h"
34 #include "panvk_image.h"
35 #include "panvk_instance.h"
36 #include "panvk_physical_device.h"
37
38 #include "drm-uapi/drm_fourcc.h"
39 #include "util/u_atomic.h"
40 #include "util/u_debug.h"
41 #include "util/u_drm.h"
42
43 #include "vk_format.h"
44 #include "vk_log.h"
45 #include "vk_object.h"
46 #include "vk_util.h"
47
48 #define PANVK_MAX_PLANES 1
49
50 static bool
panvk_image_can_use_mod(struct panvk_image * image,uint64_t mod)51 panvk_image_can_use_mod(struct panvk_image *image, uint64_t mod)
52 {
53 struct panvk_physical_device *phys_dev =
54 to_panvk_physical_device(image->vk.base.device->physical);
55 unsigned arch = pan_arch(phys_dev->kmod.props.gpu_prod_id);
56 struct panvk_instance *instance =
57 to_panvk_instance(image->vk.base.device->physical->instance);
58 enum pipe_format pfmt = vk_format_to_pipe_format(image->vk.format);
59 bool forced_linear = (instance->debug_flags & PANVK_DEBUG_LINEAR) ||
60 image->vk.tiling == VK_IMAGE_TILING_LINEAR ||
61 image->vk.image_type == VK_IMAGE_TYPE_1D;
62
63 /* If the image is meant to be linear, don't bother testing the
64 * other cases. */
65 if (forced_linear)
66 return mod == DRM_FORMAT_MOD_LINEAR;
67
68 if (drm_is_afbc(mod)) {
69 /* Disallow AFBC if either of these is true
70 * - PANVK_DEBUG does not have the 'afbc' flag set
71 * - storage image views are requested
72 * - this is a multisample image
73 * - the GPU doesn't support AFBC
74 * - the format is not AFBC-able
75 * - tiling is set to linear
76 * - this is a 1D image
77 * - this is a 3D image on a pre-v7 GPU
78 */
79 if (!(instance->debug_flags & PANVK_DEBUG_AFBC) ||
80 ((image->vk.usage | image->vk.stencil_usage) &
81 VK_IMAGE_USAGE_STORAGE_BIT) ||
82 image->vk.samples > 1 ||
83 !panfrost_query_afbc(&phys_dev->kmod.props) ||
84 !panfrost_format_supports_afbc(arch, pfmt) ||
85 image->vk.tiling == VK_IMAGE_TILING_LINEAR ||
86 image->vk.image_type == VK_IMAGE_TYPE_1D ||
87 (image->vk.image_type == VK_IMAGE_TYPE_3D && arch < 7))
88 return false;
89
90 const struct util_format_description *fdesc =
91 util_format_description(pfmt);
92 bool is_rgb = fdesc->colorspace == UTIL_FORMAT_COLORSPACE_RGB ||
93 fdesc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB;
94
95 if ((mod & AFBC_FORMAT_MOD_YTR) && (!is_rgb || fdesc->nr_channels >= 3))
96 return false;
97
98 /* We assume all other unsupported AFBC modes have been filtered out
99 * through pan_best_modifiers[]. */
100 return true;
101 }
102
103 if (mod == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED) {
104 /* If we're dealing with a compressed format that requires non-compressed
105 * views we can't use U_INTERLEAVED tiling because the tiling is different
106 * between compressed and non-compressed formats. If we wanted to support
107 * format re-interpretation we would have to specialize the shaders
108 * accessing non-compressed image views (coordinate patching for
109 * sampled/storage image, frag_coord patching for color attachments). Let's
110 * keep things simple for now and make all compressed images that
111 * have VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT set linear. */
112 return !(image->vk.create_flags &
113 VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT);
114 }
115
116 /* If we get there, it must be linear to be supported. */
117 return mod == DRM_FORMAT_MOD_LINEAR;
118 }
119
120 static void
panvk_image_apply_explicit_mod(struct panvk_image * image,const VkImageDrmFormatModifierExplicitCreateInfoEXT * explicit)121 panvk_image_apply_explicit_mod(
122 struct panvk_image *image,
123 const VkImageDrmFormatModifierExplicitCreateInfoEXT *explicit)
124 {
125 struct panvk_physical_device *phys_dev =
126 to_panvk_physical_device(image->vk.base.device->physical);
127 unsigned arch = pan_arch(phys_dev->kmod.props.gpu_prod_id);
128 uint64_t mod = explicit->drmFormatModifier;
129
130 /* TODO: support arrays, 3D, multisample and depth-stencil. */
131 struct pan_image_explicit_layout plane0_layout = {
132 .offset = explicit->pPlaneLayouts[0].offset,
133 .row_stride = explicit->pPlaneLayouts[0].rowPitch,
134 };
135
136 assert(!vk_format_is_depth_or_stencil(image->vk.format));
137 assert(image->vk.samples == 1);
138 assert(image->vk.array_layers == 1);
139 assert(image->vk.image_type != VK_IMAGE_TYPE_3D);
140 assert(explicit->drmFormatModifierPlaneCount == 1);
141 assert(panvk_image_can_use_mod(image, mod));
142
143 image->pimage.layout.modifier = mod;
144 pan_image_layout_init(arch, &image->pimage.layout, &plane0_layout);
145 }
146
147 static void
panvk_image_select_mod_from_list(struct panvk_image * image,const uint64_t * mods,uint32_t mod_count)148 panvk_image_select_mod_from_list(struct panvk_image *image,
149 const uint64_t *mods, uint32_t mod_count)
150 {
151 struct panvk_physical_device *phys_dev =
152 to_panvk_physical_device(image->vk.base.device->physical);
153 unsigned arch = pan_arch(phys_dev->kmod.props.gpu_prod_id);
154
155 for (unsigned i = 0; i < PAN_MODIFIER_COUNT; ++i) {
156 if (!panvk_image_can_use_mod(image, pan_best_modifiers[i]))
157 continue;
158
159 if (!mod_count ||
160 drm_find_modifier(pan_best_modifiers[i], mods, mod_count)) {
161 image->pimage.layout.modifier = pan_best_modifiers[i];
162 pan_image_layout_init(arch, &image->pimage.layout, NULL);
163 return;
164 }
165 }
166
167 /* If we reached that point without finding a proper modifier, there's
168 * a serious issue. */
169 image->pimage.layout.modifier = DRM_FORMAT_MOD_INVALID;
170 assert(!"Invalid modifier");
171 }
172
173 static void
panvk_image_select_mod(struct panvk_image * image,const VkImageCreateInfo * pCreateInfo)174 panvk_image_select_mod(struct panvk_image *image,
175 const VkImageCreateInfo *pCreateInfo)
176 {
177 if (pCreateInfo->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) {
178 const VkImageDrmFormatModifierListCreateInfoEXT *mod_list =
179 vk_find_struct_const(pCreateInfo->pNext,
180 IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT);
181 const VkImageDrmFormatModifierExplicitCreateInfoEXT *explicit_mod =
182 vk_find_struct_const(
183 pCreateInfo->pNext,
184 IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT);
185
186 if (explicit_mod)
187 panvk_image_apply_explicit_mod(image, explicit_mod);
188 else if (mod_list)
189 panvk_image_select_mod_from_list(image, mod_list->pDrmFormatModifiers,
190 mod_list->drmFormatModifierCount);
191 else
192 assert(!"Missing modifier info");
193
194 return;
195 }
196
197 panvk_image_select_mod_from_list(image, NULL, 0);
198 }
199
200 static void
panvk_image_pre_mod_select_meta_adjustments(struct panvk_image * image)201 panvk_image_pre_mod_select_meta_adjustments(struct panvk_image *image)
202 {
203 const VkImageAspectFlags aspects = vk_format_aspects(image->vk.format);
204
205 /* We do image blit/resolve with vk_meta, so when an image is flagged as
206 * being a potential transfer source, we also need to add the sampled usage.
207 */
208 if (image->vk.usage & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) {
209 image->vk.usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
210 if (aspects & VK_IMAGE_ASPECT_STENCIL_BIT)
211 image->vk.stencil_usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
212 }
213
214 if (image->vk.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT) {
215 /* Similarly, image that can be a transfer destination can be attached
216 * as a color or depth-stencil attachment by vk_meta. */
217 if (aspects & VK_IMAGE_ASPECT_DEPTH_BIT)
218 image->vk.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
219
220 if (aspects & VK_IMAGE_ASPECT_STENCIL_BIT)
221 image->vk.stencil_usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
222
223 if (aspects & VK_IMAGE_ASPECT_COLOR_BIT) {
224 image->vk.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
225 image->vk.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
226 }
227
228 /* vk_meta creates 2D array views of 3D images. */
229 if (image->vk.image_type == VK_IMAGE_TYPE_3D)
230 image->vk.create_flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
231 }
232
233 /* Needed for resolve operations. */
234 if (image->vk.usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)
235 image->vk.usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
236
237 if (image->vk.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
238 if (aspects & VK_IMAGE_ASPECT_DEPTH_BIT)
239 image->vk.usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
240
241 if (aspects & VK_IMAGE_ASPECT_STENCIL_BIT)
242 image->vk.stencil_usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
243 }
244
245 if ((image->vk.usage &
246 (VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT)) &&
247 util_format_is_compressed(image->pimage.layout.format)) {
248 /* We need to be able to create RGBA views of compressed formats for
249 * vk_meta copies. */
250 image->vk.create_flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT |
251 VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT;
252 }
253 }
254
255 static uint64_t
panvk_image_get_total_size(const struct panvk_image * image)256 panvk_image_get_total_size(const struct panvk_image *image)
257 {
258 assert(util_format_get_num_planes(image->pimage.layout.format) == 1);
259 return image->pimage.layout.data_size;
260 }
261
262 static enum mali_texture_dimension
panvk_image_type_to_mali_tex_dim(VkImageType type)263 panvk_image_type_to_mali_tex_dim(VkImageType type)
264 {
265 switch (type) {
266 case VK_IMAGE_TYPE_1D:
267 return MALI_TEXTURE_DIMENSION_1D;
268 case VK_IMAGE_TYPE_2D:
269 return MALI_TEXTURE_DIMENSION_2D;
270 case VK_IMAGE_TYPE_3D:
271 return MALI_TEXTURE_DIMENSION_3D;
272 default:
273 unreachable("Invalid image type");
274 }
275 }
276
277 VKAPI_ATTR VkResult VKAPI_CALL
panvk_CreateImage(VkDevice device,const VkImageCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkImage * pImage)278 panvk_CreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo,
279 const VkAllocationCallbacks *pAllocator, VkImage *pImage)
280 {
281 VK_FROM_HANDLE(panvk_device, dev, device);
282
283 struct panvk_image *image =
284 vk_image_create(&dev->vk, pCreateInfo, pAllocator, sizeof(*image));
285 if (!image)
286 return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
287
288 image->pimage.layout = (struct pan_image_layout){
289 .format = vk_format_to_pipe_format(image->vk.format),
290 .dim = panvk_image_type_to_mali_tex_dim(image->vk.image_type),
291 .width = image->vk.extent.width,
292 .height = image->vk.extent.height,
293 .depth = image->vk.extent.depth,
294 .array_size = image->vk.array_layers,
295 .nr_samples = image->vk.samples,
296 .nr_slices = image->vk.mip_levels,
297 };
298
299 /* Add any create/usage flags that might be needed for meta operations.
300 * This is run before the modifier selection because some
301 * usage/create_flags influence the modifier selection logic. */
302 panvk_image_pre_mod_select_meta_adjustments(image);
303
304 /* Now that we've patched the create/usage flags, we can proceed with the
305 * modifier selection. */
306 panvk_image_select_mod(image, pCreateInfo);
307
308 *pImage = panvk_image_to_handle(image);
309 return VK_SUCCESS;
310 }
311
312 VKAPI_ATTR void VKAPI_CALL
panvk_DestroyImage(VkDevice _device,VkImage _image,const VkAllocationCallbacks * pAllocator)313 panvk_DestroyImage(VkDevice _device, VkImage _image,
314 const VkAllocationCallbacks *pAllocator)
315 {
316 VK_FROM_HANDLE(panvk_device, device, _device);
317 VK_FROM_HANDLE(panvk_image, image, _image);
318
319 if (!image)
320 return;
321
322 if (image->bo)
323 pan_kmod_bo_put(image->bo);
324
325 vk_image_destroy(&device->vk, pAllocator, &image->vk);
326 }
327
328 static unsigned
panvk_plane_index(VkFormat format,VkImageAspectFlags aspect_mask)329 panvk_plane_index(VkFormat format, VkImageAspectFlags aspect_mask)
330 {
331 switch (aspect_mask) {
332 default:
333 return 0;
334 case VK_IMAGE_ASPECT_PLANE_1_BIT:
335 return 1;
336 case VK_IMAGE_ASPECT_PLANE_2_BIT:
337 return 2;
338 case VK_IMAGE_ASPECT_STENCIL_BIT:
339 return format == VK_FORMAT_D32_SFLOAT_S8_UINT;
340 }
341 }
342
343 VKAPI_ATTR void VKAPI_CALL
panvk_GetImageSubresourceLayout(VkDevice _device,VkImage _image,const VkImageSubresource * pSubresource,VkSubresourceLayout * pLayout)344 panvk_GetImageSubresourceLayout(VkDevice _device, VkImage _image,
345 const VkImageSubresource *pSubresource,
346 VkSubresourceLayout *pLayout)
347 {
348 VK_FROM_HANDLE(panvk_image, image, _image);
349
350 unsigned plane =
351 panvk_plane_index(image->vk.format, pSubresource->aspectMask);
352 assert(plane < PANVK_MAX_PLANES);
353
354 const struct pan_image_slice_layout *slice_layout =
355 &image->pimage.layout.slices[pSubresource->mipLevel];
356
357 pLayout->offset = slice_layout->offset + (pSubresource->arrayLayer *
358 image->pimage.layout.array_stride);
359 pLayout->size = slice_layout->size;
360 pLayout->rowPitch = slice_layout->row_stride;
361 pLayout->arrayPitch = image->pimage.layout.array_stride;
362 pLayout->depthPitch = slice_layout->surface_stride;
363 }
364
365 VKAPI_ATTR void VKAPI_CALL
panvk_GetImageMemoryRequirements2(VkDevice device,const VkImageMemoryRequirementsInfo2 * pInfo,VkMemoryRequirements2 * pMemoryRequirements)366 panvk_GetImageMemoryRequirements2(VkDevice device,
367 const VkImageMemoryRequirementsInfo2 *pInfo,
368 VkMemoryRequirements2 *pMemoryRequirements)
369 {
370 VK_FROM_HANDLE(panvk_image, image, pInfo->image);
371
372 const uint64_t alignment = 4096;
373 const uint64_t size = panvk_image_get_total_size(image);
374
375 pMemoryRequirements->memoryRequirements.memoryTypeBits = 1;
376 pMemoryRequirements->memoryRequirements.alignment = alignment;
377 pMemoryRequirements->memoryRequirements.size = size;
378 }
379
380 VKAPI_ATTR void VKAPI_CALL
panvk_GetImageSparseMemoryRequirements2(VkDevice device,const VkImageSparseMemoryRequirementsInfo2 * pInfo,uint32_t * pSparseMemoryRequirementCount,VkSparseImageMemoryRequirements2 * pSparseMemoryRequirements)381 panvk_GetImageSparseMemoryRequirements2(
382 VkDevice device, const VkImageSparseMemoryRequirementsInfo2 *pInfo,
383 uint32_t *pSparseMemoryRequirementCount,
384 VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements)
385 {
386 panvk_stub();
387 }
388
389 VKAPI_ATTR VkResult VKAPI_CALL
panvk_BindImageMemory2(VkDevice device,uint32_t bindInfoCount,const VkBindImageMemoryInfo * pBindInfos)390 panvk_BindImageMemory2(VkDevice device, uint32_t bindInfoCount,
391 const VkBindImageMemoryInfo *pBindInfos)
392 {
393 for (uint32_t i = 0; i < bindInfoCount; ++i) {
394 VK_FROM_HANDLE(panvk_image, image, pBindInfos[i].image);
395 VK_FROM_HANDLE(panvk_device_memory, mem, pBindInfos[i].memory);
396 struct pan_kmod_bo *old_bo = image->bo;
397
398 assert(mem);
399 image->bo = pan_kmod_bo_get(mem->bo);
400 image->pimage.data.base = mem->addr.dev;
401 image->pimage.data.offset = pBindInfos[i].memoryOffset;
402 /* Reset the AFBC headers */
403 if (drm_is_afbc(image->pimage.layout.modifier)) {
404 /* Transient CPU mapping */
405 void *base = pan_kmod_bo_mmap(mem->bo, 0, pan_kmod_bo_size(mem->bo),
406 PROT_WRITE, MAP_SHARED, NULL);
407
408 assert(base != MAP_FAILED);
409
410 for (unsigned layer = 0; layer < image->pimage.layout.array_size;
411 layer++) {
412 for (unsigned level = 0; level < image->pimage.layout.nr_slices;
413 level++) {
414 void *header = base + image->pimage.data.offset +
415 (layer * image->pimage.layout.array_stride) +
416 image->pimage.layout.slices[level].offset;
417 memset(header, 0,
418 image->pimage.layout.slices[level].afbc.header_size);
419 }
420 }
421
422 ASSERTED int ret = os_munmap(base, pan_kmod_bo_size(mem->bo));
423 assert(!ret);
424 }
425
426 pan_kmod_bo_put(old_bo);
427 }
428
429 return VK_SUCCESS;
430 }
431
432 VKAPI_ATTR VkResult VKAPI_CALL
panvk_GetImageDrmFormatModifierPropertiesEXT(VkDevice device,VkImage _image,VkImageDrmFormatModifierPropertiesEXT * pProperties)433 panvk_GetImageDrmFormatModifierPropertiesEXT(
434 VkDevice device, VkImage _image,
435 VkImageDrmFormatModifierPropertiesEXT *pProperties)
436 {
437 VK_FROM_HANDLE(panvk_image, image, _image);
438
439 assert(pProperties->sType ==
440 VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT);
441
442 pProperties->drmFormatModifier = image->pimage.layout.modifier;
443 return VK_SUCCESS;
444 }
445