xref: /aosp_15_r20/external/mesa3d/src/asahi/vulkan/hk_image.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright 2024 Valve Corporation
3  * Copyright 2024 Alyssa Rosenzweig
4  * Copyright 2022-2023 Collabora Ltd. and Red Hat Inc.
5  * SPDX-License-Identifier: MIT
6  */
7 #include "hk_image.h"
8 #include "asahi/layout/layout.h"
9 #include "drm-uapi/drm_fourcc.h"
10 #include "util/bitscan.h"
11 #include "util/format/u_format.h"
12 #include "util/format/u_formats.h"
13 #include "util/macros.h"
14 #include "util/u_math.h"
15 #include "vulkan/vulkan_core.h"
16 
17 #include "hk_device.h"
18 #include "hk_device_memory.h"
19 #include "hk_entrypoints.h"
20 #include "hk_physical_device.h"
21 
22 #include "vk_format.h"
23 
24 /* Minimum alignment encodable for our descriptors. The hardware texture/PBE
25  * descriptors require 16-byte alignment. Our software PBE atomic descriptor
26  * requires 128-byte alignment, but we could relax that one if we wanted.
27  */
28 #define HK_PLANE_ALIGN_B 128
29 
30 static VkFormatFeatureFlags2
hk_get_image_plane_format_features(struct hk_physical_device * pdev,VkFormat vk_format,VkImageTiling tiling)31 hk_get_image_plane_format_features(struct hk_physical_device *pdev,
32                                    VkFormat vk_format, VkImageTiling tiling)
33 {
34    VkFormatFeatureFlags2 features = 0;
35 
36    /* Conformance fails with these optional formats. Just drop them for now.
37     * TODO: Investigate later if we have a use case.
38     */
39    switch (vk_format) {
40    case VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR:
41    case VK_FORMAT_A8_UNORM_KHR:
42       return 0;
43    default:
44       break;
45    }
46 
47    enum pipe_format p_format = vk_format_to_pipe_format(vk_format);
48    if (p_format == PIPE_FORMAT_NONE)
49       return 0;
50 
51    /* NPOT formats only supported for texel buffers */
52    if (!util_is_power_of_two_nonzero(util_format_get_blocksize(p_format)))
53       return 0;
54 
55    if (util_format_is_compressed(p_format)) {
56       /* Linear block-compressed images are all sorts of problematic, not sure
57        * if AGX even supports them. Don't try.
58        */
59       if (tiling != VK_IMAGE_TILING_OPTIMAL)
60          return 0;
61 
62       /* XXX: Conformance fails, e.g.:
63        * dEQP-VK.pipeline.monolithic.sampler.view_type.2d.format.etc2_r8g8b8a1_unorm_block.mipmap.linear.lod.select_bias_3_7
64        *
65        * I suspect ail bug with mipmapping of compressed :-/
66        */
67       switch (util_format_description(p_format)->layout) {
68       case UTIL_FORMAT_LAYOUT_ETC:
69       case UTIL_FORMAT_LAYOUT_ASTC:
70          return 0;
71       default:
72          break;
73       }
74    }
75 
76    if (ail_pixel_format[p_format].texturable) {
77       features |= VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT;
78       features |= VK_FORMAT_FEATURE_2_BLIT_SRC_BIT;
79 
80       /* We can sample integer formats but it doesn't make sense to linearly
81        * filter them.
82        */
83       if (!util_format_is_pure_integer(p_format)) {
84          features |= VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
85       }
86 
87       if (vk_format_has_depth(vk_format)) {
88          features |= VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_DEPTH_COMPARISON_BIT;
89       }
90    }
91 
92    if (ail_pixel_format[p_format].renderable) {
93       /* For now, disable snorm rendering due to nir_lower_blend bugs.
94        *
95        * TODO: revisit.
96        */
97       if (!util_format_is_snorm(p_format)) {
98          features |= VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT;
99          features |= VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BLEND_BIT;
100       }
101 
102       features |= VK_FORMAT_FEATURE_2_BLIT_DST_BIT;
103       features |= VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT |
104                   VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT |
105                   VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT;
106    }
107 
108    if (vk_format_is_depth_or_stencil(vk_format)) {
109       if (!(p_format == PIPE_FORMAT_Z32_FLOAT ||
110             p_format == PIPE_FORMAT_S8_UINT ||
111             p_format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT ||
112             p_format == PIPE_FORMAT_Z16_UNORM) ||
113           tiling == VK_IMAGE_TILING_LINEAR)
114          return 0;
115 
116       features |= VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT;
117    }
118 
119    /* Our image atomic lowering doesn't bother to handle linear */
120    if ((p_format == PIPE_FORMAT_R32_UINT || p_format == PIPE_FORMAT_R32_SINT) &&
121        tiling == VK_IMAGE_TILING_OPTIMAL) {
122 
123       features |= VK_FORMAT_FEATURE_2_STORAGE_IMAGE_ATOMIC_BIT;
124    }
125 
126    if (features != 0) {
127       features |= VK_FORMAT_FEATURE_2_TRANSFER_SRC_BIT;
128       features |= VK_FORMAT_FEATURE_2_TRANSFER_DST_BIT;
129       features |= VK_FORMAT_FEATURE_2_HOST_IMAGE_TRANSFER_BIT_EXT;
130    }
131 
132    return features;
133 }
134 
135 VkFormatFeatureFlags2
hk_get_image_format_features(struct hk_physical_device * pdev,VkFormat vk_format,VkImageTiling tiling)136 hk_get_image_format_features(struct hk_physical_device *pdev,
137                              VkFormat vk_format, VkImageTiling tiling)
138 {
139    const struct vk_format_ycbcr_info *ycbcr_info =
140       vk_format_get_ycbcr_info(vk_format);
141    if (ycbcr_info == NULL)
142       return hk_get_image_plane_format_features(pdev, vk_format, tiling);
143 
144    /* For multi-plane, we get the feature flags of each plane separately,
145     * then take their intersection as the overall format feature flags
146     */
147    VkFormatFeatureFlags2 features = ~0ull;
148    bool cosited_chroma = false;
149    for (uint8_t plane = 0; plane < ycbcr_info->n_planes; plane++) {
150       const struct vk_format_ycbcr_plane *plane_info =
151          &ycbcr_info->planes[plane];
152       features &=
153          hk_get_image_plane_format_features(pdev, plane_info->format, tiling);
154       if (plane_info->denominator_scales[0] > 1 ||
155           plane_info->denominator_scales[1] > 1)
156          cosited_chroma = true;
157    }
158    if (features == 0)
159       return 0;
160 
161    /* Uh... We really should be able to sample from YCbCr */
162    assert(features & VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT);
163    assert(features & VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_LINEAR_BIT);
164 
165    /* These aren't allowed for YCbCr formats */
166    features &=
167       ~(VK_FORMAT_FEATURE_2_BLIT_SRC_BIT | VK_FORMAT_FEATURE_2_BLIT_DST_BIT |
168         VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT |
169         VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BLEND_BIT |
170         VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT);
171 
172    /* This is supported on all YCbCr formats */
173    features |=
174       VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT;
175 
176    if (ycbcr_info->n_planes > 1) {
177       /* DISJOINT_BIT implies that each plane has its own separate binding,
178        * while SEPARATE_RECONSTRUCTION_FILTER_BIT implies that luma and chroma
179        * each have their own, separate filters, so these two bits make sense
180        * for multi-planar formats only.
181        *
182        * For MIDPOINT_CHROMA_SAMPLES_BIT, NVIDIA HW on single-plane interleaved
183        * YCbCr defaults to COSITED_EVEN, which is inaccurate and fails tests.
184        * This can be fixed with a NIR tweak but for now, we only enable this bit
185        * for multi-plane formats. See Issue #9525 on the mesa/main tracker.
186        */
187       features |=
188          VK_FORMAT_FEATURE_DISJOINT_BIT |
189          VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT |
190          VK_FORMAT_FEATURE_2_MIDPOINT_CHROMA_SAMPLES_BIT;
191    }
192 
193    if (cosited_chroma)
194       features |= VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT;
195 
196    return features;
197 }
198 
199 static VkFormatFeatureFlags2
vk_image_usage_to_format_features(VkImageUsageFlagBits usage_flag)200 vk_image_usage_to_format_features(VkImageUsageFlagBits usage_flag)
201 {
202    assert(util_bitcount(usage_flag) == 1);
203    switch (usage_flag) {
204    case VK_IMAGE_USAGE_TRANSFER_SRC_BIT:
205       return VK_FORMAT_FEATURE_2_TRANSFER_SRC_BIT |
206              VK_FORMAT_FEATURE_BLIT_SRC_BIT;
207    case VK_IMAGE_USAGE_TRANSFER_DST_BIT:
208       return VK_FORMAT_FEATURE_2_TRANSFER_DST_BIT |
209              VK_FORMAT_FEATURE_BLIT_DST_BIT;
210    case VK_IMAGE_USAGE_SAMPLED_BIT:
211       return VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT;
212    case VK_IMAGE_USAGE_STORAGE_BIT:
213       return VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT;
214    case VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT:
215       return VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT;
216    case VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT:
217       return VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT;
218    default:
219       return 0;
220    }
221 }
222 
223 static bool
hk_can_compress(struct agx_device * dev,VkFormat format,unsigned plane,unsigned width,unsigned height,unsigned samples,VkImageCreateFlagBits flags,VkImageUsageFlagBits usage,const void * pNext)224 hk_can_compress(struct agx_device *dev, VkFormat format, unsigned plane,
225                 unsigned width, unsigned height, unsigned samples,
226                 VkImageCreateFlagBits flags, VkImageUsageFlagBits usage,
227                 const void *pNext)
228 {
229    const struct vk_format_ycbcr_info *ycbcr_info =
230       vk_format_get_ycbcr_info(format);
231 
232    if (ycbcr_info) {
233       format = ycbcr_info->planes[plane].format;
234       width /= ycbcr_info->planes[plane].denominator_scales[0];
235       height /= ycbcr_info->planes[plane].denominator_scales[0];
236    } else if (format == VK_FORMAT_D32_SFLOAT_S8_UINT) {
237       format = (plane == 0) ? VK_FORMAT_D32_SFLOAT : VK_FORMAT_S8_UINT;
238    }
239 
240    /* Allow disabling compression for debugging */
241    if (dev->debug & AGX_DBG_NOCOMPRESS)
242       return false;
243 
244    /* Image compression is not (yet?) supported with host image copies,
245     * although the vendor driver does support something similar if I recall.
246     * Compression is not supported in hardware for storage images or mutable
247     * formats in general.
248     */
249    if (usage &
250        (VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT | VK_IMAGE_USAGE_STORAGE_BIT))
251       return false;
252 
253    enum pipe_format p_format = vk_format_to_pipe_format(format);
254 
255    /* Check for format compatibility if mutability is enabled. */
256    if (flags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT) {
257       const struct VkImageFormatListCreateInfo *format_list =
258          (void *)vk_find_struct_const(pNext, IMAGE_FORMAT_LIST_CREATE_INFO);
259 
260       if (!format_list || format_list->viewFormatCount == 0)
261          return false;
262 
263       for (unsigned i = 0; i < format_list->viewFormatCount; ++i) {
264          if (format_list->pViewFormats[i] == VK_FORMAT_UNDEFINED)
265             continue;
266 
267          enum pipe_format view_format =
268             vk_format_to_pipe_format(format_list->pViewFormats[i]);
269 
270          if (!ail_formats_compatible(p_format, view_format))
271             return false;
272       }
273    }
274 
275    /* TODO: Need to smarten up the blitter */
276    if (samples > 1)
277       return false;
278 
279    return ail_can_compress(p_format, width, height, samples);
280 }
281 
282 static bool
hk_can_compress_format(struct agx_device * dev,VkFormat format)283 hk_can_compress_format(struct agx_device *dev, VkFormat format)
284 {
285    /* Check compressability of a sufficiently large image of the same
286     * format, since we don't have dimensions here. This is lossy for
287     * small images, but that's ok.
288     *
289     * Likewise, we do not set flags as flags only disable compression.
290     */
291    return hk_can_compress(dev, format, 0, 64, 64, 1, 0, 0, NULL);
292 }
293 
294 VKAPI_ATTR VkResult VKAPI_CALL
hk_GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice,const VkPhysicalDeviceImageFormatInfo2 * pImageFormatInfo,VkImageFormatProperties2 * pImageFormatProperties)295 hk_GetPhysicalDeviceImageFormatProperties2(
296    VkPhysicalDevice physicalDevice,
297    const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo,
298    VkImageFormatProperties2 *pImageFormatProperties)
299 {
300    VK_FROM_HANDLE(hk_physical_device, pdev, physicalDevice);
301 
302    const VkPhysicalDeviceExternalImageFormatInfo *external_info =
303       vk_find_struct_const(pImageFormatInfo->pNext,
304                            PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO);
305 
306    /* Initialize to zero in case we return VK_ERROR_FORMAT_NOT_SUPPORTED */
307    memset(&pImageFormatProperties->imageFormatProperties, 0,
308           sizeof(pImageFormatProperties->imageFormatProperties));
309 
310    const struct vk_format_ycbcr_info *ycbcr_info =
311       vk_format_get_ycbcr_info(pImageFormatInfo->format);
312 
313    /* For the purposes of these checks, we don't care about all the extra
314     * YCbCr features and we just want the accumulation of features available
315     * to all planes of the given format.
316     */
317    VkFormatFeatureFlags2 features;
318    if (ycbcr_info == NULL) {
319       features = hk_get_image_plane_format_features(
320          pdev, pImageFormatInfo->format, pImageFormatInfo->tiling);
321    } else {
322       features = ~0ull;
323       assert(ycbcr_info->n_planes > 0);
324       for (uint8_t plane = 0; plane < ycbcr_info->n_planes; plane++) {
325          const VkFormat plane_format = ycbcr_info->planes[plane].format;
326          features &= hk_get_image_plane_format_features(
327             pdev, plane_format, pImageFormatInfo->tiling);
328       }
329    }
330    if (features == 0)
331       return VK_ERROR_FORMAT_NOT_SUPPORTED;
332 
333    if (pImageFormatInfo->tiling == VK_IMAGE_TILING_LINEAR &&
334        pImageFormatInfo->type != VK_IMAGE_TYPE_2D)
335       return VK_ERROR_FORMAT_NOT_SUPPORTED;
336 
337    if (ycbcr_info && pImageFormatInfo->type != VK_IMAGE_TYPE_2D)
338       return VK_ERROR_FORMAT_NOT_SUPPORTED;
339 
340    /* From the Vulkan 1.3.279 spec:
341     *
342     *    VUID-VkImageCreateInfo-tiling-04121
343     *
344     *    "If tiling is VK_IMAGE_TILING_LINEAR, flags must not contain
345     *    VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT"
346     *
347     *    VUID-VkImageCreateInfo-imageType-00970
348     *
349     *    "If imageType is VK_IMAGE_TYPE_1D, flags must not contain
350     *    VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT"
351     */
352    if (pImageFormatInfo->flags & VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT &&
353        (pImageFormatInfo->type == VK_IMAGE_TYPE_1D ||
354         pImageFormatInfo->tiling == VK_IMAGE_TILING_LINEAR))
355       return VK_ERROR_FORMAT_NOT_SUPPORTED;
356 
357    /* From the Vulkan 1.3.279 spec:
358     *
359     *    VUID-VkImageCreateInfo-flags-09403
360     *
361     *    "If flags contains VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT, flags
362     *    must not include VK_IMAGE_CREATE_SPARSE_ALIASED_BIT,
363     *    VK_IMAGE_CREATE_SPARSE_BINDING_BIT, or
364     *    VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT"
365     */
366    if ((pImageFormatInfo->flags & VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT) &&
367        (pImageFormatInfo->flags & (VK_IMAGE_CREATE_SPARSE_ALIASED_BIT |
368                                    VK_IMAGE_CREATE_SPARSE_BINDING_BIT |
369                                    VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT)))
370       return VK_ERROR_FORMAT_NOT_SUPPORTED;
371 
372    /* We don't yet support sparse, but it shouldn't be too hard */
373    if (pImageFormatInfo->flags & (VK_IMAGE_CREATE_SPARSE_ALIASED_BIT |
374                                   VK_IMAGE_CREATE_SPARSE_BINDING_BIT |
375                                   VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT))
376       return VK_ERROR_FORMAT_NOT_SUPPORTED;
377 
378    const uint32_t max_dim = 16384;
379    VkExtent3D maxExtent;
380    uint32_t maxArraySize;
381    switch (pImageFormatInfo->type) {
382    case VK_IMAGE_TYPE_1D:
383       maxExtent = (VkExtent3D){max_dim, 1, 1};
384       maxArraySize = 2048;
385       break;
386    case VK_IMAGE_TYPE_2D:
387       maxExtent = (VkExtent3D){max_dim, max_dim, 1};
388       maxArraySize = 2048;
389       break;
390    case VK_IMAGE_TYPE_3D:
391       maxExtent = (VkExtent3D){max_dim, max_dim, max_dim};
392       maxArraySize = 1;
393       break;
394    default:
395       unreachable("Invalid image type");
396    }
397    if (pImageFormatInfo->tiling == VK_IMAGE_TILING_LINEAR)
398       maxArraySize = 1;
399 
400    assert(util_is_power_of_two_nonzero(max_dim));
401    uint32_t maxMipLevels = util_logbase2(max_dim) + 1;
402    if (ycbcr_info != NULL || pImageFormatInfo->tiling == VK_IMAGE_TILING_LINEAR)
403       maxMipLevels = 1;
404 
405    VkSampleCountFlags sampleCounts = VK_SAMPLE_COUNT_1_BIT;
406    if (pImageFormatInfo->tiling == VK_IMAGE_TILING_OPTIMAL &&
407        pImageFormatInfo->type == VK_IMAGE_TYPE_2D && ycbcr_info == NULL &&
408        (features & (VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT |
409                     VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT)) &&
410        !(pImageFormatInfo->flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT)) {
411 
412       sampleCounts =
413          VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_2_BIT | VK_SAMPLE_COUNT_4_BIT;
414    }
415 
416    /* From the Vulkan 1.2.199 spec:
417     *
418     *    "VK_IMAGE_CREATE_EXTENDED_USAGE_BIT specifies that the image can be
419     *    created with usage flags that are not supported for the format the
420     *    image is created with but are supported for at least one format a
421     *    VkImageView created from the image can have."
422     *
423     * If VK_IMAGE_CREATE_EXTENDED_USAGE_BIT is set, views can be created with
424     * different usage than the image so we can't always filter on usage.
425     * There is one exception to this below for storage.
426     */
427    const VkImageUsageFlags image_usage = pImageFormatInfo->usage;
428    VkImageUsageFlags view_usage = image_usage;
429    if (pImageFormatInfo->flags & VK_IMAGE_CREATE_EXTENDED_USAGE_BIT)
430       view_usage = 0;
431 
432    if (view_usage & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) {
433       if (!(features & (VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT |
434                         VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT))) {
435          return VK_ERROR_FORMAT_NOT_SUPPORTED;
436       }
437    }
438 
439    u_foreach_bit(b, view_usage) {
440       VkFormatFeatureFlags2 usage_features =
441          vk_image_usage_to_format_features(1 << b);
442       if (usage_features && !(features & usage_features))
443          return VK_ERROR_FORMAT_NOT_SUPPORTED;
444    }
445 
446    const VkExternalMemoryProperties *ext_mem_props = NULL;
447    if (external_info != NULL && external_info->handleType != 0) {
448       bool tiling_has_explicit_layout;
449       switch (pImageFormatInfo->tiling) {
450       case VK_IMAGE_TILING_LINEAR:
451       case VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT:
452          tiling_has_explicit_layout = true;
453          break;
454       case VK_IMAGE_TILING_OPTIMAL:
455          tiling_has_explicit_layout = false;
456          break;
457       default:
458          unreachable("Unsupported VkImageTiling");
459       }
460 
461       switch (external_info->handleType) {
462       case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT:
463          /* No special restrictions */
464          if (tiling_has_explicit_layout) {
465             /* With an explicit memory layout, we don't care which type of
466              * fd the image belongs too. Both OPAQUE_FD and DMA_BUF are
467              * interchangeable here.
468              */
469             ext_mem_props = &hk_dma_buf_mem_props;
470          } else {
471             ext_mem_props = &hk_opaque_fd_mem_props;
472          }
473          break;
474 
475       case VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT:
476          if (!tiling_has_explicit_layout) {
477             return vk_errorf(pdev, VK_ERROR_FORMAT_NOT_SUPPORTED,
478                              "VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT "
479                              "requires VK_IMAGE_TILING_LINEAR or "
480                              "VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT");
481          }
482          ext_mem_props = &hk_dma_buf_mem_props;
483          break;
484 
485       default:
486          /* From the Vulkan 1.3.256 spec:
487           *
488           *    "If handleType is not compatible with the [parameters] in
489           *    VkPhysicalDeviceImageFormatInfo2, then
490           *    vkGetPhysicalDeviceImageFormatProperties2 returns
491           *    VK_ERROR_FORMAT_NOT_SUPPORTED."
492           */
493          return vk_errorf(pdev, VK_ERROR_FORMAT_NOT_SUPPORTED,
494                           "unsupported VkExternalMemoryTypeFlagBits 0x%x",
495                           external_info->handleType);
496       }
497    }
498 
499    const unsigned plane_count =
500       vk_format_get_plane_count(pImageFormatInfo->format);
501 
502    /* From the Vulkan 1.3.259 spec, VkImageCreateInfo:
503     *
504     *    VUID-VkImageCreateInfo-imageCreateFormatFeatures-02260
505     *
506     *    "If format is a multi-planar format, and if imageCreateFormatFeatures
507     *    (as defined in Image Creation Limits) does not contain
508     *    VK_FORMAT_FEATURE_DISJOINT_BIT, then flags must not contain
509     *    VK_IMAGE_CREATE_DISJOINT_BIT"
510     *
511     * This is satisfied trivially because we support DISJOINT on all
512     * multi-plane formats.  Also,
513     *
514     *    VUID-VkImageCreateInfo-format-01577
515     *
516     *    "If format is not a multi-planar format, and flags does not include
517     *    VK_IMAGE_CREATE_ALIAS_BIT, flags must not contain
518     *    VK_IMAGE_CREATE_DISJOINT_BIT"
519     */
520    if (plane_count == 1 &&
521        !(pImageFormatInfo->flags & VK_IMAGE_CREATE_ALIAS_BIT) &&
522        (pImageFormatInfo->flags & VK_IMAGE_CREATE_DISJOINT_BIT))
523       return VK_ERROR_FORMAT_NOT_SUPPORTED;
524 
525    if (ycbcr_info &&
526        ((pImageFormatInfo->flags & VK_IMAGE_CREATE_SPARSE_BINDING_BIT) ||
527         (pImageFormatInfo->flags & VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT)))
528       return VK_ERROR_FORMAT_NOT_SUPPORTED;
529 
530    pImageFormatProperties->imageFormatProperties = (VkImageFormatProperties){
531       .maxExtent = maxExtent,
532       .maxMipLevels = maxMipLevels,
533       .maxArrayLayers = maxArraySize,
534       .sampleCounts = sampleCounts,
535       .maxResourceSize = UINT32_MAX, /* TODO */
536    };
537 
538    vk_foreach_struct(s, pImageFormatProperties->pNext) {
539       switch (s->sType) {
540       case VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES: {
541          VkExternalImageFormatProperties *p = (void *)s;
542          /* From the Vulkan 1.3.256 spec:
543           *
544           *    "If handleType is 0, vkGetPhysicalDeviceImageFormatProperties2
545           *    will behave as if VkPhysicalDeviceExternalImageFormatInfo was
546           *    not present, and VkExternalImageFormatProperties will be
547           *    ignored."
548           *
549           * This is true if and only if ext_mem_props == NULL
550           */
551          if (ext_mem_props != NULL)
552             p->externalMemoryProperties = *ext_mem_props;
553          break;
554       }
555       case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES: {
556          VkSamplerYcbcrConversionImageFormatProperties *ycbcr_props = (void *)s;
557          ycbcr_props->combinedImageSamplerDescriptorCount = plane_count;
558          break;
559       }
560       case VK_STRUCTURE_TYPE_HOST_IMAGE_COPY_DEVICE_PERFORMANCE_QUERY_EXT: {
561          VkHostImageCopyDevicePerformanceQueryEXT *hic_props = (void *)s;
562 
563          hic_props->optimalDeviceAccess = hic_props->identicalMemoryLayout =
564             !(pImageFormatInfo->tiling == VK_IMAGE_TILING_OPTIMAL &&
565               hk_can_compress_format(&pdev->dev, pImageFormatInfo->format));
566          break;
567       }
568       default:
569          vk_debug_ignored_stype(s->sType);
570          break;
571       }
572    }
573 
574    return VK_SUCCESS;
575 }
576 
577 static VkSparseImageFormatProperties
hk_fill_sparse_image_fmt_props(VkImageAspectFlags aspects)578 hk_fill_sparse_image_fmt_props(VkImageAspectFlags aspects)
579 {
580    /* TODO */
581    return (VkSparseImageFormatProperties){
582       .aspectMask = aspects,
583       .flags = VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT,
584       .imageGranularity =
585          {
586             .width = 1,
587             .height = 1,
588             .depth = 1,
589          },
590    };
591 }
592 
593 VKAPI_ATTR void VKAPI_CALL
hk_GetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice,const VkPhysicalDeviceSparseImageFormatInfo2 * pFormatInfo,uint32_t * pPropertyCount,VkSparseImageFormatProperties2 * pProperties)594 hk_GetPhysicalDeviceSparseImageFormatProperties2(
595    VkPhysicalDevice physicalDevice,
596    const VkPhysicalDeviceSparseImageFormatInfo2 *pFormatInfo,
597    uint32_t *pPropertyCount, VkSparseImageFormatProperties2 *pProperties)
598 {
599    VkResult result;
600 
601    /* Check if the given format info is valid first before returning sparse
602     * props.  The easiest way to do this is to just call
603     * hk_GetPhysicalDeviceImageFormatProperties2()
604     */
605    const VkPhysicalDeviceImageFormatInfo2 img_fmt_info = {
606       .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
607       .format = pFormatInfo->format,
608       .type = pFormatInfo->type,
609       .tiling = pFormatInfo->tiling,
610       .usage = pFormatInfo->usage,
611       .flags = VK_IMAGE_CREATE_SPARSE_BINDING_BIT |
612                VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT,
613    };
614 
615    VkImageFormatProperties2 img_fmt_props2 = {
616       .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
617       .pNext = NULL,
618    };
619 
620    result = hk_GetPhysicalDeviceImageFormatProperties2(
621       physicalDevice, &img_fmt_info, &img_fmt_props2);
622    if (result != VK_SUCCESS) {
623       *pPropertyCount = 0;
624       return;
625    }
626 
627    const VkImageFormatProperties *props = &img_fmt_props2.imageFormatProperties;
628    if (!(pFormatInfo->samples & props->sampleCounts)) {
629       *pPropertyCount = 0;
630       return;
631    }
632 
633    VK_OUTARRAY_MAKE_TYPED(VkSparseImageFormatProperties2, out, pProperties,
634                           pPropertyCount);
635 
636    VkImageAspectFlags aspects = vk_format_aspects(pFormatInfo->format);
637 
638    vk_outarray_append_typed(VkSparseImageFormatProperties2, &out, props)
639    {
640       props->properties = hk_fill_sparse_image_fmt_props(aspects);
641    }
642 }
643 
644 static enum ail_tiling
hk_map_tiling(struct hk_device * dev,const VkImageCreateInfo * info,unsigned plane)645 hk_map_tiling(struct hk_device *dev, const VkImageCreateInfo *info,
646               unsigned plane)
647 {
648    switch (info->tiling) {
649    case VK_IMAGE_TILING_LINEAR:
650       return AIL_TILING_LINEAR;
651 
652    case VK_IMAGE_TILING_OPTIMAL:
653       if (hk_can_compress(&dev->dev, info->format, plane, info->extent.width,
654                           info->extent.height, info->samples, info->flags,
655                           info->usage, info->pNext)) {
656          return AIL_TILING_TWIDDLED_COMPRESSED;
657       } else {
658          return AIL_TILING_TWIDDLED;
659       }
660 
661    case VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT:
662       /* TODO */
663       return AIL_TILING_TWIDDLED;
664    default:
665       unreachable("invalid tiling");
666    }
667 }
668 
669 static uint32_t
modifier_get_score(uint64_t mod)670 modifier_get_score(uint64_t mod)
671 {
672    switch (mod) {
673    case DRM_FORMAT_MOD_APPLE_TWIDDLED_COMPRESSED:
674       return 10;
675 
676    case DRM_FORMAT_MOD_APPLE_TWIDDLED:
677       return 5;
678 
679    case DRM_FORMAT_MOD_LINEAR:
680       return 1;
681 
682    default:
683       return 0;
684    }
685 }
686 
687 static uint64_t
choose_drm_format_mod(uint32_t modifier_count,const uint64_t * modifiers)688 choose_drm_format_mod(uint32_t modifier_count, const uint64_t *modifiers)
689 {
690    uint64_t best_mod = UINT64_MAX;
691    uint32_t best_score = 0;
692 
693    for (uint32_t i = 0; i < modifier_count; ++i) {
694       uint32_t score = modifier_get_score(modifiers[i]);
695       if (score > best_score) {
696          best_mod = modifiers[i];
697          best_score = score;
698       }
699    }
700 
701    if (best_score > 0)
702       return best_mod;
703    else
704       return DRM_FORMAT_MOD_INVALID;
705 }
706 
707 static VkResult
hk_image_init(struct hk_device * dev,struct hk_image * image,const VkImageCreateInfo * pCreateInfo)708 hk_image_init(struct hk_device *dev, struct hk_image *image,
709               const VkImageCreateInfo *pCreateInfo)
710 {
711    vk_image_init(&dev->vk, &image->vk, pCreateInfo);
712 
713    if ((image->vk.usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
714                            VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) &&
715        image->vk.samples > 1) {
716       image->vk.usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
717       image->vk.stencil_usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
718    }
719 
720    if (image->vk.usage & VK_IMAGE_USAGE_TRANSFER_SRC_BIT)
721       image->vk.usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
722    if (image->vk.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT)
723       image->vk.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
724 
725    image->plane_count = vk_format_get_plane_count(pCreateInfo->format);
726    image->disjoint = image->plane_count > 1 &&
727                      (pCreateInfo->flags & VK_IMAGE_CREATE_DISJOINT_BIT);
728 
729    /* We do not support interleaved depth/stencil. Instead, we decompose to
730     * a depth plane and a stencil plane.
731     */
732    if (image->vk.format == VK_FORMAT_D32_SFLOAT_S8_UINT) {
733       image->plane_count = 2;
734    }
735 
736    if (image->vk.create_flags & VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT) {
737       /* Sparse multiplane is not supported. Sparse depth/stencil not supported
738        * on G13 so we're fine there too.
739        */
740       assert(image->plane_count == 1);
741    }
742 
743    const struct VkImageDrmFormatModifierExplicitCreateInfoEXT
744       *mod_explicit_info = NULL;
745 
746    if (pCreateInfo->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) {
747       assert(!image->vk.wsi_legacy_scanout);
748       mod_explicit_info = vk_find_struct_const(
749          pCreateInfo->pNext,
750          IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT);
751 
752       uint64_t modifier = DRM_FORMAT_MOD_INVALID;
753 
754       if (mod_explicit_info) {
755          modifier = mod_explicit_info->drmFormatModifier;
756       } else {
757          const struct VkImageDrmFormatModifierListCreateInfoEXT *mod_list_info =
758             vk_find_struct_const(
759                pCreateInfo->pNext,
760                IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT);
761 
762          modifier = choose_drm_format_mod(mod_list_info->drmFormatModifierCount,
763                                           mod_list_info->pDrmFormatModifiers);
764       }
765 
766       assert(modifier != DRM_FORMAT_MOD_INVALID);
767       assert(image->vk.drm_format_mod == DRM_FORMAT_MOD_INVALID);
768       image->vk.drm_format_mod = modifier;
769    }
770 
771    const struct vk_format_ycbcr_info *ycbcr_info =
772       vk_format_get_ycbcr_info(pCreateInfo->format);
773    for (uint8_t plane = 0; plane < image->plane_count; plane++) {
774       VkFormat format =
775          ycbcr_info ? ycbcr_info->planes[plane].format : pCreateInfo->format;
776 
777       if (format == VK_FORMAT_D32_SFLOAT_S8_UINT) {
778          format = (plane == 0) ? VK_FORMAT_D32_SFLOAT : VK_FORMAT_S8_UINT;
779       }
780 
781       const uint8_t width_scale =
782          ycbcr_info ? ycbcr_info->planes[plane].denominator_scales[0] : 1;
783       const uint8_t height_scale =
784          ycbcr_info ? ycbcr_info->planes[plane].denominator_scales[1] : 1;
785 
786       enum ail_tiling tiling = hk_map_tiling(dev, pCreateInfo, plane);
787 
788       image->planes[plane].layout = (struct ail_layout){
789          .tiling = tiling,
790          .mipmapped_z = pCreateInfo->imageType == VK_IMAGE_TYPE_3D,
791          .format = vk_format_to_pipe_format(format),
792 
793          .width_px = pCreateInfo->extent.width / width_scale,
794          .height_px = pCreateInfo->extent.height / height_scale,
795          .depth_px = MAX2(pCreateInfo->extent.depth, pCreateInfo->arrayLayers),
796 
797          .levels = pCreateInfo->mipLevels,
798          .sample_count_sa = pCreateInfo->samples,
799          .writeable_image = tiling != AIL_TILING_TWIDDLED_COMPRESSED,
800 
801          /* TODO: Maybe optimize this, our GL driver doesn't bother though */
802          .renderable = true,
803       };
804 
805       ail_make_miptree(&image->planes[plane].layout);
806    }
807 
808    return VK_SUCCESS;
809 }
810 
811 static VkResult
hk_image_plane_alloc_vma(struct hk_device * dev,struct hk_image_plane * plane,VkImageCreateFlags create_flags)812 hk_image_plane_alloc_vma(struct hk_device *dev, struct hk_image_plane *plane,
813                          VkImageCreateFlags create_flags)
814 {
815    const bool sparse_bound = create_flags & VK_IMAGE_CREATE_SPARSE_BINDING_BIT;
816    const bool sparse_resident =
817       create_flags & VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT;
818    assert(sparse_bound || !sparse_resident);
819 
820    if (sparse_bound) {
821       plane->vma_size_B = plane->layout.size_B;
822 #if 0
823       plane->addr = nouveau_ws_alloc_vma(dev->ws_dev, 0, plane->vma_size_B,
824                                          plane->layout.align_B,
825                                          false, sparse_resident);
826 #endif
827       if (plane->addr == 0) {
828          return vk_errorf(dev, VK_ERROR_OUT_OF_DEVICE_MEMORY,
829                           "Sparse VMA allocation failed");
830       }
831    }
832 
833    return VK_SUCCESS;
834 }
835 
836 static void
hk_image_plane_finish(struct hk_device * dev,struct hk_image_plane * plane,VkImageCreateFlags create_flags,const VkAllocationCallbacks * pAllocator)837 hk_image_plane_finish(struct hk_device *dev, struct hk_image_plane *plane,
838                       VkImageCreateFlags create_flags,
839                       const VkAllocationCallbacks *pAllocator)
840 {
841    if (plane->vma_size_B) {
842 #if 0
843       const bool sparse_resident =
844          create_flags & VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT;
845 
846       agx_bo_unbind_vma(dev->ws_dev, plane->addr, plane->vma_size_B);
847       nouveau_ws_free_vma(dev->ws_dev, plane->addr, plane->vma_size_B,
848                           false, sparse_resident);
849 #endif
850    }
851 }
852 
853 static void
hk_image_finish(struct hk_device * dev,struct hk_image * image,const VkAllocationCallbacks * pAllocator)854 hk_image_finish(struct hk_device *dev, struct hk_image *image,
855                 const VkAllocationCallbacks *pAllocator)
856 {
857    for (uint8_t plane = 0; plane < image->plane_count; plane++) {
858       hk_image_plane_finish(dev, &image->planes[plane], image->vk.create_flags,
859                             pAllocator);
860    }
861 
862    vk_image_finish(&image->vk);
863 }
864 
865 VKAPI_ATTR VkResult VKAPI_CALL
hk_CreateImage(VkDevice _device,const VkImageCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkImage * pImage)866 hk_CreateImage(VkDevice _device, const VkImageCreateInfo *pCreateInfo,
867                const VkAllocationCallbacks *pAllocator, VkImage *pImage)
868 {
869    VK_FROM_HANDLE(hk_device, dev, _device);
870    struct hk_physical_device *pdev = hk_device_physical(dev);
871    struct hk_image *image;
872    VkResult result;
873 
874 #ifdef HK_USE_WSI_PLATFORM
875    /* Ignore swapchain creation info on Android. Since we don't have an
876     * implementation in Mesa, we're guaranteed to access an Android object
877     * incorrectly.
878     */
879    const VkImageSwapchainCreateInfoKHR *swapchain_info =
880       vk_find_struct_const(pCreateInfo->pNext, IMAGE_SWAPCHAIN_CREATE_INFO_KHR);
881    if (swapchain_info && swapchain_info->swapchain != VK_NULL_HANDLE) {
882       return wsi_common_create_swapchain_image(
883          &pdev->wsi_device, pCreateInfo, swapchain_info->swapchain, pImage);
884    }
885 #endif
886 
887    image = vk_zalloc2(&dev->vk.alloc, pAllocator, sizeof(*image), 8,
888                       VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
889    if (!image)
890       return vk_error(dev, VK_ERROR_OUT_OF_HOST_MEMORY);
891 
892    result = hk_image_init(dev, image, pCreateInfo);
893    if (result != VK_SUCCESS) {
894       vk_free2(&dev->vk.alloc, pAllocator, image);
895       return result;
896    }
897 
898    for (uint8_t plane = 0; plane < image->plane_count; plane++) {
899       result = hk_image_plane_alloc_vma(dev, &image->planes[plane],
900                                         image->vk.create_flags);
901       if (result != VK_SUCCESS) {
902          hk_image_finish(dev, image, pAllocator);
903          vk_free2(&dev->vk.alloc, pAllocator, image);
904          return result;
905       }
906    }
907 
908    *pImage = hk_image_to_handle(image);
909 
910    return VK_SUCCESS;
911 }
912 
913 VKAPI_ATTR void VKAPI_CALL
hk_DestroyImage(VkDevice device,VkImage _image,const VkAllocationCallbacks * pAllocator)914 hk_DestroyImage(VkDevice device, VkImage _image,
915                 const VkAllocationCallbacks *pAllocator)
916 {
917    VK_FROM_HANDLE(hk_device, dev, device);
918    VK_FROM_HANDLE(hk_image, image, _image);
919 
920    if (!image)
921       return;
922 
923    hk_image_finish(dev, image, pAllocator);
924    vk_free2(&dev->vk.alloc, pAllocator, image);
925 }
926 
927 static void
hk_image_plane_add_req(struct hk_image_plane * plane,uint64_t * size_B,uint32_t * align_B)928 hk_image_plane_add_req(struct hk_image_plane *plane, uint64_t *size_B,
929                        uint32_t *align_B)
930 {
931    assert(util_is_power_of_two_or_zero64(*align_B));
932    assert(util_is_power_of_two_or_zero64(HK_PLANE_ALIGN_B));
933 
934    *align_B = MAX2(*align_B, HK_PLANE_ALIGN_B);
935    *size_B = align64(*size_B, HK_PLANE_ALIGN_B);
936    *size_B += plane->layout.size_B;
937 }
938 
939 static void
hk_get_image_memory_requirements(struct hk_device * dev,struct hk_image * image,VkImageAspectFlags aspects,VkMemoryRequirements2 * pMemoryRequirements)940 hk_get_image_memory_requirements(struct hk_device *dev, struct hk_image *image,
941                                  VkImageAspectFlags aspects,
942                                  VkMemoryRequirements2 *pMemoryRequirements)
943 {
944    struct hk_physical_device *pdev = hk_device_physical(dev);
945    uint32_t memory_types = (1 << pdev->mem_type_count) - 1;
946 
947    // TODO hope for the best?
948 
949    uint64_t size_B = 0;
950    uint32_t align_B = 0;
951    if (image->disjoint) {
952       uint8_t plane = hk_image_aspects_to_plane(image, aspects);
953       hk_image_plane_add_req(&image->planes[plane], &size_B, &align_B);
954    } else {
955       for (unsigned plane = 0; plane < image->plane_count; plane++)
956          hk_image_plane_add_req(&image->planes[plane], &size_B, &align_B);
957    }
958 
959    pMemoryRequirements->memoryRequirements.memoryTypeBits = memory_types;
960    pMemoryRequirements->memoryRequirements.alignment = align_B;
961    pMemoryRequirements->memoryRequirements.size = size_B;
962 
963    vk_foreach_struct_const(ext, pMemoryRequirements->pNext) {
964       switch (ext->sType) {
965       case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS: {
966          VkMemoryDedicatedRequirements *dedicated = (void *)ext;
967          dedicated->prefersDedicatedAllocation = false;
968          dedicated->requiresDedicatedAllocation = false;
969          break;
970       }
971       default:
972          vk_debug_ignored_stype(ext->sType);
973          break;
974       }
975    }
976 }
977 
978 VKAPI_ATTR void VKAPI_CALL
hk_GetImageMemoryRequirements2(VkDevice device,const VkImageMemoryRequirementsInfo2 * pInfo,VkMemoryRequirements2 * pMemoryRequirements)979 hk_GetImageMemoryRequirements2(VkDevice device,
980                                const VkImageMemoryRequirementsInfo2 *pInfo,
981                                VkMemoryRequirements2 *pMemoryRequirements)
982 {
983    VK_FROM_HANDLE(hk_device, dev, device);
984    VK_FROM_HANDLE(hk_image, image, pInfo->image);
985 
986    const VkImagePlaneMemoryRequirementsInfo *plane_info =
987       vk_find_struct_const(pInfo->pNext, IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO);
988    const VkImageAspectFlags aspects =
989       image->disjoint ? plane_info->planeAspect : image->vk.aspects;
990 
991    hk_get_image_memory_requirements(dev, image, aspects, pMemoryRequirements);
992 }
993 
994 VKAPI_ATTR void VKAPI_CALL
hk_GetDeviceImageMemoryRequirements(VkDevice device,const VkDeviceImageMemoryRequirements * pInfo,VkMemoryRequirements2 * pMemoryRequirements)995 hk_GetDeviceImageMemoryRequirements(VkDevice device,
996                                     const VkDeviceImageMemoryRequirements *pInfo,
997                                     VkMemoryRequirements2 *pMemoryRequirements)
998 {
999    VK_FROM_HANDLE(hk_device, dev, device);
1000    ASSERTED VkResult result;
1001    struct hk_image image = {0};
1002 
1003    result = hk_image_init(dev, &image, pInfo->pCreateInfo);
1004    assert(result == VK_SUCCESS);
1005 
1006    const VkImageAspectFlags aspects =
1007       image.disjoint ? pInfo->planeAspect : image.vk.aspects;
1008 
1009    hk_get_image_memory_requirements(dev, &image, aspects, pMemoryRequirements);
1010 
1011    hk_image_finish(dev, &image, NULL);
1012 }
1013 
1014 static VkSparseImageMemoryRequirements
hk_fill_sparse_image_memory_reqs(const struct ail_layout * layout,VkImageAspectFlags aspects)1015 hk_fill_sparse_image_memory_reqs(const struct ail_layout *layout,
1016                                  VkImageAspectFlags aspects)
1017 {
1018    VkSparseImageFormatProperties sparse_format_props =
1019       hk_fill_sparse_image_fmt_props(aspects);
1020 
1021    // assert(layout->mip_tail_first_lod <= layout->num_levels);
1022    VkSparseImageMemoryRequirements sparse_memory_reqs = {
1023       .formatProperties = sparse_format_props,
1024       .imageMipTailFirstLod = 0, // layout->mip_tail_first_lod,
1025       .imageMipTailStride = 0,
1026    };
1027 
1028    sparse_memory_reqs.imageMipTailSize = layout->size_B;
1029    sparse_memory_reqs.imageMipTailOffset = 0;
1030    return sparse_memory_reqs;
1031 }
1032 
1033 static void
hk_get_image_sparse_memory_requirements(struct hk_device * dev,struct hk_image * image,VkImageAspectFlags aspects,uint32_t * pSparseMemoryRequirementCount,VkSparseImageMemoryRequirements2 * pSparseMemoryRequirements)1034 hk_get_image_sparse_memory_requirements(
1035    struct hk_device *dev, struct hk_image *image, VkImageAspectFlags aspects,
1036    uint32_t *pSparseMemoryRequirementCount,
1037    VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements)
1038 {
1039    VK_OUTARRAY_MAKE_TYPED(VkSparseImageMemoryRequirements2, out,
1040                           pSparseMemoryRequirements,
1041                           pSparseMemoryRequirementCount);
1042 
1043    /* From the Vulkan 1.3.279 spec:
1044     *
1045     *    "The sparse image must have been created using the
1046     *    VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT flag to retrieve valid sparse
1047     *    image memory requirements."
1048     */
1049    if (!(image->vk.create_flags & VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT))
1050       return;
1051 
1052    /* We don't support multiplane sparse for now */
1053    if (image->plane_count > 1)
1054       return;
1055 
1056    vk_outarray_append_typed(VkSparseImageMemoryRequirements2, &out, reqs)
1057    {
1058       reqs->memoryRequirements =
1059          hk_fill_sparse_image_memory_reqs(&image->planes[0].layout, aspects);
1060    };
1061 }
1062 
1063 VKAPI_ATTR void VKAPI_CALL
hk_GetImageSparseMemoryRequirements2(VkDevice device,const VkImageSparseMemoryRequirementsInfo2 * pInfo,uint32_t * pSparseMemoryRequirementCount,VkSparseImageMemoryRequirements2 * pSparseMemoryRequirements)1064 hk_GetImageSparseMemoryRequirements2(
1065    VkDevice device, const VkImageSparseMemoryRequirementsInfo2 *pInfo,
1066    uint32_t *pSparseMemoryRequirementCount,
1067    VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements)
1068 {
1069    VK_FROM_HANDLE(hk_device, dev, device);
1070    VK_FROM_HANDLE(hk_image, image, pInfo->image);
1071 
1072    const VkImageAspectFlags aspects = image->vk.aspects;
1073 
1074    hk_get_image_sparse_memory_requirements(dev, image, aspects,
1075                                            pSparseMemoryRequirementCount,
1076                                            pSparseMemoryRequirements);
1077 }
1078 
1079 VKAPI_ATTR void VKAPI_CALL
hk_GetDeviceImageSparseMemoryRequirements(VkDevice device,const VkDeviceImageMemoryRequirements * pInfo,uint32_t * pSparseMemoryRequirementCount,VkSparseImageMemoryRequirements2 * pSparseMemoryRequirements)1080 hk_GetDeviceImageSparseMemoryRequirements(
1081    VkDevice device, const VkDeviceImageMemoryRequirements *pInfo,
1082    uint32_t *pSparseMemoryRequirementCount,
1083    VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements)
1084 {
1085    VK_FROM_HANDLE(hk_device, dev, device);
1086    ASSERTED VkResult result;
1087    struct hk_image image = {0};
1088 
1089    result = hk_image_init(dev, &image, pInfo->pCreateInfo);
1090    assert(result == VK_SUCCESS);
1091 
1092    const VkImageAspectFlags aspects =
1093       image.disjoint ? pInfo->planeAspect : image.vk.aspects;
1094 
1095    hk_get_image_sparse_memory_requirements(dev, &image, aspects,
1096                                            pSparseMemoryRequirementCount,
1097                                            pSparseMemoryRequirements);
1098 
1099    hk_image_finish(dev, &image, NULL);
1100 }
1101 
1102 static void
hk_get_image_subresource_layout(UNUSED struct hk_device * dev,struct hk_image * image,const VkImageSubresource2KHR * pSubresource,VkSubresourceLayout2KHR * pLayout)1103 hk_get_image_subresource_layout(UNUSED struct hk_device *dev,
1104                                 struct hk_image *image,
1105                                 const VkImageSubresource2KHR *pSubresource,
1106                                 VkSubresourceLayout2KHR *pLayout)
1107 {
1108    const VkImageSubresource *isr = &pSubresource->imageSubresource;
1109 
1110    const uint8_t p = hk_image_aspects_to_plane(image, isr->aspectMask);
1111    const struct hk_image_plane *plane = &image->planes[p];
1112 
1113    uint64_t offset_B = 0;
1114    if (!image->disjoint) {
1115       uint32_t align_B = 0;
1116       for (unsigned plane = 0; plane < p; plane++)
1117          hk_image_plane_add_req(&image->planes[plane], &offset_B, &align_B);
1118    }
1119    offset_B +=
1120       ail_get_layer_level_B(&plane->layout, isr->arrayLayer, isr->mipLevel);
1121 
1122    bool is_3d = image->vk.image_type == VK_IMAGE_TYPE_3D;
1123 
1124    pLayout->subresourceLayout = (VkSubresourceLayout){
1125       .offset = offset_B,
1126       .size = ail_get_level_size_B(&plane->layout, isr->mipLevel),
1127 
1128       /* From the spec:
1129        *
1130        *     It is legal to call vkGetImageSubresourceLayout2KHR with a image
1131        *     created with tiling equal to VK_IMAGE_TILING_OPTIMAL, but the
1132        * members of VkSubresourceLayout2KHR::subresourceLayout will have
1133        * undefined values in this case.
1134        *
1135        * So don't collapse with mips.
1136        */
1137       .rowPitch = isr->mipLevel
1138                      ? 0
1139                      : ail_get_wsi_stride_B(&plane->layout, isr->mipLevel),
1140       .arrayPitch = is_3d ? 0 : plane->layout.layer_stride_B,
1141       .depthPitch = is_3d ? plane->layout.layer_stride_B : 0,
1142    };
1143 
1144    VkSubresourceHostMemcpySizeEXT *memcpy_size =
1145       vk_find_struct(pLayout, SUBRESOURCE_HOST_MEMCPY_SIZE_EXT);
1146    if (memcpy_size) {
1147       memcpy_size->size = pLayout->subresourceLayout.size;
1148    }
1149 }
1150 
1151 VKAPI_ATTR void VKAPI_CALL
hk_GetImageSubresourceLayout2KHR(VkDevice device,VkImage _image,const VkImageSubresource2KHR * pSubresource,VkSubresourceLayout2KHR * pLayout)1152 hk_GetImageSubresourceLayout2KHR(VkDevice device, VkImage _image,
1153                                  const VkImageSubresource2KHR *pSubresource,
1154                                  VkSubresourceLayout2KHR *pLayout)
1155 {
1156    VK_FROM_HANDLE(hk_device, dev, device);
1157    VK_FROM_HANDLE(hk_image, image, _image);
1158 
1159    hk_get_image_subresource_layout(dev, image, pSubresource, pLayout);
1160 }
1161 
1162 VKAPI_ATTR void VKAPI_CALL
hk_GetDeviceImageSubresourceLayoutKHR(VkDevice device,const VkDeviceImageSubresourceInfoKHR * pInfo,VkSubresourceLayout2KHR * pLayout)1163 hk_GetDeviceImageSubresourceLayoutKHR(
1164    VkDevice device, const VkDeviceImageSubresourceInfoKHR *pInfo,
1165    VkSubresourceLayout2KHR *pLayout)
1166 {
1167    VK_FROM_HANDLE(hk_device, dev, device);
1168    ASSERTED VkResult result;
1169    struct hk_image image = {0};
1170 
1171    result = hk_image_init(dev, &image, pInfo->pCreateInfo);
1172    assert(result == VK_SUCCESS);
1173 
1174    hk_get_image_subresource_layout(dev, &image, pInfo->pSubresource, pLayout);
1175 
1176    hk_image_finish(dev, &image, NULL);
1177 }
1178 
1179 static void
hk_image_plane_bind(struct hk_device * dev,struct hk_image_plane * plane,struct hk_device_memory * mem,uint64_t * offset_B)1180 hk_image_plane_bind(struct hk_device *dev, struct hk_image_plane *plane,
1181                     struct hk_device_memory *mem, uint64_t *offset_B)
1182 {
1183    *offset_B = align64(*offset_B, HK_PLANE_ALIGN_B);
1184 
1185    if (plane->vma_size_B) {
1186 #if 0
1187       agx_bo_bind_vma(dev->ws_dev,
1188                              mem->bo,
1189                              plane->addr,
1190                              plane->vma_size_B,
1191                              *offset_B,
1192                              plane->nil.pte_kind);
1193 #endif
1194       unreachable("todo");
1195    } else {
1196       plane->addr = mem->bo->va->addr + *offset_B;
1197       plane->map = mem->bo->map + *offset_B;
1198       plane->rem = mem->bo->size - (*offset_B);
1199    }
1200 
1201    *offset_B += plane->layout.size_B;
1202 }
1203 
1204 VKAPI_ATTR VkResult VKAPI_CALL
hk_BindImageMemory2(VkDevice device,uint32_t bindInfoCount,const VkBindImageMemoryInfo * pBindInfos)1205 hk_BindImageMemory2(VkDevice device, uint32_t bindInfoCount,
1206                     const VkBindImageMemoryInfo *pBindInfos)
1207 {
1208    VK_FROM_HANDLE(hk_device, dev, device);
1209    for (uint32_t i = 0; i < bindInfoCount; ++i) {
1210       VK_FROM_HANDLE(hk_device_memory, mem, pBindInfos[i].memory);
1211       VK_FROM_HANDLE(hk_image, image, pBindInfos[i].image);
1212 
1213       /* Ignore this struct on Android, we cannot access swapchain structures
1214        * there. */
1215 #ifdef HK_USE_WSI_PLATFORM
1216       const VkBindImageMemorySwapchainInfoKHR *swapchain_info =
1217          vk_find_struct_const(pBindInfos[i].pNext,
1218                               BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR);
1219 
1220       if (swapchain_info && swapchain_info->swapchain != VK_NULL_HANDLE) {
1221          VkImage _wsi_image = wsi_common_get_image(swapchain_info->swapchain,
1222                                                    swapchain_info->imageIndex);
1223          VK_FROM_HANDLE(hk_image, wsi_img, _wsi_image);
1224 
1225          assert(image->plane_count == 1);
1226          assert(wsi_img->plane_count == 1);
1227 
1228          struct hk_image_plane *plane = &image->planes[0];
1229          struct hk_image_plane *swapchain_plane = &wsi_img->planes[0];
1230 
1231          /* Copy memory binding information from swapchain image to the current
1232           * image's plane. */
1233          plane->addr = swapchain_plane->addr;
1234          continue;
1235       }
1236 #endif
1237 
1238       uint64_t offset_B = pBindInfos[i].memoryOffset;
1239       if (image->disjoint) {
1240          const VkBindImagePlaneMemoryInfo *plane_info = vk_find_struct_const(
1241             pBindInfos[i].pNext, BIND_IMAGE_PLANE_MEMORY_INFO);
1242          uint8_t plane =
1243             hk_image_aspects_to_plane(image, plane_info->planeAspect);
1244          hk_image_plane_bind(dev, &image->planes[plane], mem, &offset_B);
1245       } else {
1246          for (unsigned plane = 0; plane < image->plane_count; plane++) {
1247             hk_image_plane_bind(dev, &image->planes[plane], mem, &offset_B);
1248          }
1249       }
1250 
1251       const VkBindMemoryStatusKHR *status =
1252          vk_find_struct_const(pBindInfos[i].pNext, BIND_MEMORY_STATUS_KHR);
1253       if (status != NULL && status->pResult != NULL)
1254          *status->pResult = VK_SUCCESS;
1255    }
1256 
1257    return VK_SUCCESS;
1258 }
1259 
1260 static uint32_t
hk_plane_index(VkFormat format,VkImageAspectFlags aspect_mask)1261 hk_plane_index(VkFormat format, VkImageAspectFlags aspect_mask)
1262 {
1263    switch (aspect_mask) {
1264    default:
1265       assert(aspect_mask != VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT);
1266       return 0;
1267    case VK_IMAGE_ASPECT_PLANE_1_BIT:
1268    case VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT:
1269       return 1;
1270    case VK_IMAGE_ASPECT_PLANE_2_BIT:
1271    case VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT:
1272       return 2;
1273    case VK_IMAGE_ASPECT_STENCIL_BIT:
1274       return format == VK_FORMAT_D32_SFLOAT_S8_UINT;
1275    }
1276 }
1277 
1278 static void
hk_copy_memory_to_image(struct hk_device * device,struct hk_image * dst_image,const VkMemoryToImageCopyEXT * info,bool copy_memcpy)1279 hk_copy_memory_to_image(struct hk_device *device, struct hk_image *dst_image,
1280                         const VkMemoryToImageCopyEXT *info, bool copy_memcpy)
1281 {
1282    unsigned plane =
1283       hk_plane_index(dst_image->vk.format, info->imageSubresource.aspectMask);
1284    const struct ail_layout *layout = &dst_image->planes[plane].layout;
1285 
1286    VkOffset3D offset = info->imageOffset;
1287    VkExtent3D extent = info->imageExtent;
1288    uint32_t src_width = info->memoryRowLength ?: extent.width;
1289    uint32_t src_height = info->memoryImageHeight ?: extent.height;
1290 
1291    uint32_t blocksize_B = util_format_get_blocksize(layout->format);
1292    uint32_t src_pitch = src_width * blocksize_B;
1293 
1294    unsigned start_layer = (dst_image->vk.image_type == VK_IMAGE_TYPE_3D)
1295                              ? offset.z
1296                              : info->imageSubresource.baseArrayLayer;
1297    uint32_t layers =
1298       MAX2(extent.depth, vk_image_subresource_layer_count(
1299                             &dst_image->vk, &info->imageSubresource));
1300 
1301    unsigned level = info->imageSubresource.mipLevel;
1302    uint32_t image_offset = ail_get_layer_level_B(layout, start_layer, level);
1303    uint32_t dst_layer_stride = layout->layer_stride_B;
1304    uint32_t src_layer_stride = copy_memcpy
1305                                   ? ail_get_level_size_B(layout, level)
1306                                   : (src_width * src_height * blocksize_B);
1307    bool tiled = ail_is_level_twiddled_uncompressed(
1308       layout, info->imageSubresource.mipLevel);
1309 
1310    const char *src =
1311       (const char *)info->pHostPointer + start_layer * dst_layer_stride;
1312    char *dst = (char *)dst_image->planes[plane].map + image_offset;
1313    for (unsigned layer = 0; layer < layers;
1314         layer++, src += src_layer_stride, dst += dst_layer_stride) {
1315       if (copy_memcpy) {
1316          memcpy(dst, src, ail_get_level_size_B(layout, level));
1317       } else if (!tiled) {
1318          uint32_t dst_pitch = ail_get_linear_stride_B(layout, level);
1319          /*TODO:comp*/
1320          for (unsigned y = 0; y < extent.height; y++) {
1321             memcpy(dst + dst_pitch * (y + offset.y) + offset.x * blocksize_B,
1322                    src + src_pitch * y, extent.width * blocksize_B);
1323          }
1324       } else {
1325          ail_tile(dst, (void *)src, layout, level, src_pitch, offset.x,
1326                   offset.y, extent.width, extent.height);
1327       }
1328    }
1329 }
1330 
1331 VKAPI_ATTR VkResult VKAPI_CALL
hk_CopyMemoryToImageEXT(VkDevice _device,const VkCopyMemoryToImageInfoEXT * info)1332 hk_CopyMemoryToImageEXT(VkDevice _device,
1333                         const VkCopyMemoryToImageInfoEXT *info)
1334 {
1335    VK_FROM_HANDLE(hk_device, device, _device);
1336    VK_FROM_HANDLE(hk_image, dst_image, info->dstImage);
1337 
1338    for (unsigned i = 0; i < info->regionCount; i++) {
1339       hk_copy_memory_to_image(device, dst_image, &info->pRegions[i],
1340                               info->flags & VK_HOST_IMAGE_COPY_MEMCPY_EXT);
1341    }
1342 
1343    return VK_SUCCESS;
1344 }
1345 
1346 static void
hk_copy_image_to_memory(struct hk_device * device,struct hk_image * src_image,const VkImageToMemoryCopyEXT * info,bool copy_memcpy)1347 hk_copy_image_to_memory(struct hk_device *device, struct hk_image *src_image,
1348                         const VkImageToMemoryCopyEXT *info, bool copy_memcpy)
1349 {
1350    unsigned plane =
1351       hk_plane_index(src_image->vk.format, info->imageSubresource.aspectMask);
1352    const struct ail_layout *layout = &src_image->planes[plane].layout;
1353 
1354    VkOffset3D offset = info->imageOffset;
1355    VkExtent3D extent = info->imageExtent;
1356    uint32_t dst_width = info->memoryRowLength ?: extent.width;
1357    uint32_t dst_height = info->memoryImageHeight ?: extent.height;
1358 
1359 #if 0
1360    copy_compressed(src_image->vk.format, &offset, &extent, &dst_width,
1361                    &dst_height);
1362 #endif
1363 
1364    uint32_t blocksize_B = util_format_get_blocksize(layout->format);
1365    uint32_t dst_pitch = dst_width * blocksize_B;
1366 
1367    unsigned start_layer = (src_image->vk.image_type == VK_IMAGE_TYPE_3D)
1368                              ? offset.z
1369                              : info->imageSubresource.baseArrayLayer;
1370    uint32_t layers =
1371       MAX2(extent.depth, vk_image_subresource_layer_count(
1372                             &src_image->vk, &info->imageSubresource));
1373    unsigned level = info->imageSubresource.mipLevel;
1374 
1375    uint32_t image_offset = ail_get_layer_level_B(layout, start_layer, level);
1376    uint32_t src_layer_stride = layout->layer_stride_B;
1377    uint32_t dst_layer_stride = copy_memcpy
1378                                   ? ail_get_level_size_B(layout, level)
1379                                   : (dst_width * dst_height * blocksize_B);
1380 
1381    bool tiled = ail_is_level_twiddled_uncompressed(
1382       layout, info->imageSubresource.mipLevel);
1383 
1384    const char *src = (const char *)src_image->planes[plane].map + image_offset;
1385    char *dst = (char *)info->pHostPointer + start_layer * dst_layer_stride;
1386    for (unsigned layer = 0; layer < layers;
1387         layer++, src += src_layer_stride, dst += dst_layer_stride) {
1388 
1389       if (copy_memcpy) {
1390          memcpy(dst, src, dst_layer_stride);
1391       } else if (!tiled) {
1392          /* TODO: comp */
1393          uint32_t src_pitch = ail_get_linear_stride_B(layout, level);
1394          for (unsigned y = 0; y < extent.height; y++) {
1395             memcpy(dst + dst_pitch * y,
1396                    src + src_pitch * (y + offset.y) + offset.x * blocksize_B,
1397                    extent.width * blocksize_B);
1398          }
1399       } else {
1400          ail_detile((void *)src, dst, layout, info->imageSubresource.mipLevel,
1401                     dst_pitch, offset.x, offset.y, extent.width, extent.height);
1402       }
1403    }
1404 }
1405 
1406 VKAPI_ATTR VkResult VKAPI_CALL
hk_CopyImageToMemoryEXT(VkDevice _device,const VkCopyImageToMemoryInfoEXT * info)1407 hk_CopyImageToMemoryEXT(VkDevice _device,
1408                         const VkCopyImageToMemoryInfoEXT *info)
1409 {
1410    VK_FROM_HANDLE(hk_device, device, _device);
1411    VK_FROM_HANDLE(hk_image, image, info->srcImage);
1412 
1413    for (unsigned i = 0; i < info->regionCount; i++) {
1414       hk_copy_image_to_memory(device, image, &info->pRegions[i],
1415                               info->flags & VK_HOST_IMAGE_COPY_MEMCPY_EXT);
1416    }
1417 
1418    return VK_SUCCESS;
1419 }
1420 
1421 static void
hk_copy_image_to_image_cpu(struct hk_device * device,struct hk_image * src_image,struct hk_image * dst_image,const VkImageCopy2 * info,bool copy_memcpy)1422 hk_copy_image_to_image_cpu(struct hk_device *device, struct hk_image *src_image,
1423                            struct hk_image *dst_image, const VkImageCopy2 *info,
1424                            bool copy_memcpy)
1425 {
1426    unsigned src_plane =
1427       hk_plane_index(src_image->vk.format, info->srcSubresource.aspectMask);
1428    unsigned dst_plane =
1429       hk_plane_index(dst_image->vk.format, info->dstSubresource.aspectMask);
1430 
1431    const struct ail_layout *src_layout = &src_image->planes[src_plane].layout;
1432    const struct ail_layout *dst_layout = &dst_image->planes[dst_plane].layout;
1433 
1434    VkOffset3D src_offset = info->srcOffset;
1435    VkOffset3D dst_offset = info->dstOffset;
1436    VkExtent3D extent = info->extent;
1437    uint32_t layers_to_copy = MAX2(
1438       info->extent.depth,
1439       vk_image_subresource_layer_count(&src_image->vk, &info->srcSubresource));
1440 
1441    /* See comment above. */
1442 #if 0
1443    copy_compressed(src_image->vk.format, &src_offset, &extent, NULL, NULL);
1444    copy_compressed(dst_image->vk.format, &dst_offset, NULL, NULL, NULL);
1445 #endif
1446 
1447    unsigned src_start_layer = (src_image->vk.image_type == VK_IMAGE_TYPE_3D)
1448                                  ? src_offset.z
1449                                  : info->srcSubresource.baseArrayLayer;
1450    unsigned dst_start_layer = (dst_image->vk.image_type == VK_IMAGE_TYPE_3D)
1451                                  ? dst_offset.z
1452                                  : info->dstSubresource.baseArrayLayer;
1453 
1454    uint32_t src_layer_stride = src_layout->layer_stride_B;
1455    uint32_t dst_layer_stride = dst_layout->layer_stride_B;
1456 
1457    uint32_t dst_block_B = util_format_get_blocksize(dst_layout->format);
1458    uint32_t src_block_B = util_format_get_blocksize(src_layout->format);
1459 
1460    uint32_t src_image_offset = ail_get_layer_level_B(
1461       src_layout, src_start_layer, info->srcSubresource.mipLevel);
1462    uint32_t dst_image_offset = ail_get_layer_level_B(
1463       dst_layout, dst_start_layer, info->dstSubresource.mipLevel);
1464 
1465    bool src_tiled = ail_is_level_twiddled_uncompressed(
1466       src_layout, info->srcSubresource.mipLevel);
1467    bool dst_tiled = ail_is_level_twiddled_uncompressed(
1468       dst_layout, info->dstSubresource.mipLevel);
1469 
1470    const char *src =
1471       (const char *)src_image->planes[src_plane].map + src_image_offset;
1472    char *dst = (char *)dst_image->planes[dst_plane].map + dst_image_offset;
1473    for (unsigned layer = 0; layer < layers_to_copy;
1474         layer++, src += src_layer_stride, dst += dst_layer_stride) {
1475 
1476       if (copy_memcpy) {
1477          uint32_t src_size =
1478             ail_get_level_size_B(src_layout, info->srcSubresource.mipLevel);
1479          uint32_t dst_size =
1480             ail_get_level_size_B(dst_layout, info->dstSubresource.mipLevel);
1481 
1482          assert(src_size == dst_size);
1483          memcpy(dst, src, src_size);
1484       } else if (!src_tiled && !dst_tiled) {
1485          /* TODO comp */
1486          uint32_t src_pitch =
1487             ail_get_linear_stride_B(src_layout, info->srcSubresource.mipLevel);
1488 
1489          uint32_t dst_pitch =
1490             ail_get_linear_stride_B(dst_layout, info->dstSubresource.mipLevel);
1491 
1492          for (unsigned y = 0; y < extent.height; y++) {
1493             memcpy(dst + dst_pitch * (y + dst_offset.y) +
1494                       dst_offset.x * dst_block_B,
1495                    src + src_pitch * (y + src_offset.y) +
1496                       src_offset.x * src_block_B,
1497                    extent.width * src_block_B);
1498          }
1499       } else if (!src_tiled) {
1500          unreachable("todo");
1501 #if 0
1502          fdl6_memcpy_linear_to_tiled(
1503             dst_offset.x, dst_offset.y, extent.width, extent.height, dst,
1504             src + src_pitch * src_offset.y + src_offset.x * src_layout->cpp,
1505             dst_layout, info->dstSubresource.mipLevel, src_pitch,
1506             &device->physical_device->ubwc_config);
1507 #endif
1508       } else if (!dst_tiled) {
1509          unreachable("todo");
1510 #if 0
1511          fdl6_memcpy_tiled_to_linear(
1512             src_offset.x, src_offset.y, extent.width, extent.height,
1513             dst + dst_pitch * dst_offset.y + dst_offset.x * dst_layout->cpp,
1514             src, src_layout, info->dstSubresource.mipLevel, dst_pitch,
1515             &device->physical_device->ubwc_config);
1516 #endif
1517       } else {
1518          /* Work tile-by-tile, holding the unswizzled tile in a temporary
1519           * buffer.
1520           */
1521          char temp_tile[16384];
1522 
1523          unsigned src_level = info->srcSubresource.mipLevel;
1524          unsigned dst_level = info->dstSubresource.mipLevel;
1525          uint32_t block_width = src_layout->tilesize_el[src_level].width_el;
1526          uint32_t block_height = src_layout->tilesize_el[src_level].height_el;
1527          uint32_t temp_pitch = block_width * src_block_B;
1528          ;
1529 
1530          for (unsigned by = src_offset.y / block_height;
1531               by * block_height < src_offset.y + extent.height; by++) {
1532             uint32_t src_y_start = MAX2(src_offset.y, by * block_height);
1533             uint32_t dst_y_start = src_y_start - src_offset.y + dst_offset.y;
1534             uint32_t height =
1535                MIN2((by + 1) * block_height, src_offset.y + extent.height) -
1536                src_y_start;
1537             for (unsigned bx = src_offset.x / block_width;
1538                  bx * block_width < src_offset.x + extent.width; bx++) {
1539                uint32_t src_x_start = MAX2(src_offset.x, bx * block_width);
1540                uint32_t dst_x_start = src_x_start - src_offset.x + dst_offset.x;
1541                uint32_t width =
1542                   MIN2((bx + 1) * block_width, src_offset.x + extent.width) -
1543                   src_x_start;
1544 
1545                ail_detile((void *)src, temp_tile, src_layout, src_level,
1546                           temp_pitch, src_x_start, src_y_start, width, height);
1547                ail_tile(dst, temp_tile, dst_layout, dst_level, temp_pitch,
1548                         dst_x_start, dst_y_start, width, height);
1549             }
1550          }
1551       }
1552    }
1553 }
1554 
1555 VKAPI_ATTR VkResult VKAPI_CALL
hk_CopyImageToImageEXT(VkDevice _device,const VkCopyImageToImageInfoEXT * pCopyImageToImageInfo)1556 hk_CopyImageToImageEXT(VkDevice _device,
1557                        const VkCopyImageToImageInfoEXT *pCopyImageToImageInfo)
1558 {
1559    VK_FROM_HANDLE(hk_device, device, _device);
1560    VK_FROM_HANDLE(hk_image, src_image, pCopyImageToImageInfo->srcImage);
1561    VK_FROM_HANDLE(hk_image, dst_image, pCopyImageToImageInfo->dstImage);
1562    bool copy_memcpy =
1563       pCopyImageToImageInfo->flags & VK_HOST_IMAGE_COPY_MEMCPY_EXT;
1564 
1565    for (uint32_t i = 0; i < pCopyImageToImageInfo->regionCount; ++i) {
1566       if (src_image->vk.format == VK_FORMAT_D32_SFLOAT_S8_UINT) {
1567          VkImageCopy2 info = pCopyImageToImageInfo->pRegions[i];
1568          u_foreach_bit(b, info.dstSubresource.aspectMask) {
1569             info.srcSubresource.aspectMask = BITFIELD_BIT(b);
1570             info.dstSubresource.aspectMask = BITFIELD_BIT(b);
1571             hk_copy_image_to_image_cpu(device, src_image, dst_image, &info,
1572                                        copy_memcpy);
1573          }
1574          continue;
1575       }
1576 
1577       hk_copy_image_to_image_cpu(device, src_image, dst_image,
1578                                  pCopyImageToImageInfo->pRegions + i,
1579                                  copy_memcpy);
1580    }
1581 
1582    return VK_SUCCESS;
1583 }
1584 
1585 VKAPI_ATTR VkResult VKAPI_CALL
hk_TransitionImageLayoutEXT(VkDevice device,uint32_t transitionCount,const VkHostImageLayoutTransitionInfoEXT * transitions)1586 hk_TransitionImageLayoutEXT(
1587    VkDevice device, uint32_t transitionCount,
1588    const VkHostImageLayoutTransitionInfoEXT *transitions)
1589 {
1590    /* We don't do anything with layouts so this should be a no-op */
1591    return VK_SUCCESS;
1592 }
1593