xref: /aosp_15_r20/external/mesa3d/src/panfrost/vulkan/panvk_image.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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