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