1 /*
2 * Copyright © 2016 Red Hat.
3 * Copyright © 2016 Bas Nieuwenhuizen
4 * SPDX-License-Identifier: MIT
5 */
6
7 #include "tu_formats.h"
8
9 #include "fdl/fd6_format_table.h"
10 #include "common/freedreno_ubwc.h"
11
12 #include "vk_android.h"
13 #include "vk_enum_defines.h"
14 #include "vk_util.h"
15 #include "drm-uapi/drm_fourcc.h"
16
17 #include "tu_android.h"
18 #include "tu_device.h"
19 #include "tu_image.h"
20
21 #include <vulkan/vulkan_android.h>
22
23 static bool
tu6_format_vtx_supported(enum pipe_format format)24 tu6_format_vtx_supported(enum pipe_format format)
25 {
26 return fd6_vertex_format(format) != FMT6_NONE;
27 }
28
29 struct tu_native_format
tu6_format_vtx(enum pipe_format format)30 tu6_format_vtx(enum pipe_format format)
31 {
32 struct tu_native_format fmt = {
33 .fmt = fd6_vertex_format(format),
34 .swap = fd6_vertex_swap(format),
35 };
36 assert(tu6_format_vtx_supported(format));
37 return fmt;
38 }
39
40 static bool
tu6_format_color_supported(enum pipe_format format)41 tu6_format_color_supported(enum pipe_format format)
42 {
43 return fd6_color_format(format, TILE6_LINEAR) != FMT6_NONE;
44 }
45
46 struct tu_native_format
tu6_format_color(enum pipe_format format,enum a6xx_tile_mode tile_mode)47 tu6_format_color(enum pipe_format format, enum a6xx_tile_mode tile_mode)
48 {
49 struct tu_native_format fmt = {
50 .fmt = fd6_color_format(format, tile_mode),
51 .swap = fd6_color_swap(format, tile_mode),
52 };
53 assert(fmt.fmt != FMT6_NONE);
54 return fmt;
55 }
56
57 static bool
tu6_format_texture_supported(enum pipe_format format)58 tu6_format_texture_supported(enum pipe_format format)
59 {
60 return fd6_texture_format(format, TILE6_LINEAR) != FMT6_NONE;
61 }
62
63 struct tu_native_format
tu6_format_texture(enum pipe_format format,enum a6xx_tile_mode tile_mode)64 tu6_format_texture(enum pipe_format format, enum a6xx_tile_mode tile_mode)
65 {
66 struct tu_native_format fmt = {
67 .fmt = fd6_texture_format(format, tile_mode),
68 .swap = fd6_texture_swap(format, tile_mode),
69 };
70 assert(fmt.fmt != FMT6_NONE);
71 return fmt;
72 }
73
74 static enum fd6_ubwc_compat_type
tu6_ubwc_compat_mode(const struct fd_dev_info * info,VkFormat format)75 tu6_ubwc_compat_mode(const struct fd_dev_info *info, VkFormat format)
76 {
77 return fd6_ubwc_compat_mode(info, vk_format_to_pipe_format(format));
78 }
79
80 bool
tu6_mutable_format_list_ubwc_compatible(const struct fd_dev_info * info,const VkImageFormatListCreateInfo * fmt_list)81 tu6_mutable_format_list_ubwc_compatible(const struct fd_dev_info *info,
82 const VkImageFormatListCreateInfo *fmt_list)
83 {
84 if (!fmt_list || !fmt_list->viewFormatCount)
85 return false;
86
87 /* We're only looking at format list cross compatibility here, check
88 * ubwc_possible() for the base "is the format UBWC-able at all?"
89 */
90 if (fmt_list->viewFormatCount == 1)
91 return true;
92
93 enum fd6_ubwc_compat_type type =
94 tu6_ubwc_compat_mode(info, fmt_list->pViewFormats[0]);
95 if (type == FD6_UBWC_UNKNOWN_COMPAT)
96 return false;
97
98 for (uint32_t i = 1; i < fmt_list->viewFormatCount; i++) {
99 if (tu6_ubwc_compat_mode(info, fmt_list->pViewFormats[i]) != type)
100 return false;
101 }
102
103 return true;
104 }
105
106 static void
tu_physical_device_get_format_properties(struct tu_physical_device * physical_device,VkFormat vk_format,VkFormatProperties3 * out_properties)107 tu_physical_device_get_format_properties(
108 struct tu_physical_device *physical_device,
109 VkFormat vk_format,
110 VkFormatProperties3 *out_properties)
111 {
112 VkFormatFeatureFlags2 linear = 0, optimal = 0, buffer = 0;
113 enum pipe_format format = vk_format_to_pipe_format(vk_format);
114 const struct util_format_description *desc = util_format_description(format);
115
116 bool supported_vtx = tu6_format_vtx_supported(format);
117 bool supported_color = tu6_format_color_supported(format);
118 bool supported_tex = tu6_format_texture_supported(format);
119 bool is_npot = !util_is_power_of_two_or_zero(desc->block.bits);
120
121 if (format == PIPE_FORMAT_NONE ||
122 !(supported_vtx || supported_color || supported_tex)) {
123 goto end;
124 }
125
126 /* We don't support BufferToImage/ImageToBuffer for npot formats */
127 if (!is_npot)
128 buffer |= VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT;
129
130 if (supported_vtx)
131 buffer |= VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT;
132
133 if (supported_tex)
134 buffer |= VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT;
135
136 /* Don't support anything but texel buffers for non-power-of-two formats
137 * with 3 components. We'd need several workarounds for copying and
138 * clearing them because they're not renderable.
139 */
140 if (supported_tex && !is_npot) {
141 optimal |= VK_FORMAT_FEATURE_TRANSFER_SRC_BIT |
142 VK_FORMAT_FEATURE_TRANSFER_DST_BIT |
143 VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT |
144 VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT;
145
146 /* no blit src bit for YUYV/NV12/I420 formats */
147 if (desc->layout != UTIL_FORMAT_LAYOUT_SUBSAMPLED &&
148 desc->layout != UTIL_FORMAT_LAYOUT_PLANAR2 &&
149 desc->layout != UTIL_FORMAT_LAYOUT_PLANAR3) {
150 optimal |= VK_FORMAT_FEATURE_BLIT_SRC_BIT;
151 } else {
152 optimal |= VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT;
153
154 if (desc->layout != UTIL_FORMAT_LAYOUT_SUBSAMPLED) {
155 optimal |= VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT |
156 VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT;
157 if (physical_device->info->a6xx.has_separate_chroma_filter)
158 optimal |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT;
159 }
160 }
161
162 if (!vk_format_is_int(vk_format)) {
163 optimal |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
164
165 if (physical_device->vk.supported_extensions.EXT_filter_cubic)
166 optimal |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT;
167 }
168
169 /* We sample on the CPU so we can technically support anything as long
170 * as it's floating point, but this restricts it to "reasonable" formats
171 * to use, which means two channels and not something weird like
172 * luminance-alpha.
173 */
174 if (util_format_is_float(format) &&
175 desc->nr_channels == 2 && desc->swizzle[0] == PIPE_SWIZZLE_X &&
176 desc->swizzle[1] == PIPE_SWIZZLE_Y) {
177 optimal |= VK_FORMAT_FEATURE_FRAGMENT_DENSITY_MAP_BIT_EXT;
178 }
179 }
180
181 if (supported_color) {
182 assert(supported_tex);
183 optimal |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT |
184 VK_FORMAT_FEATURE_BLIT_DST_BIT |
185 VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT |
186 VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT |
187 VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT;
188
189 buffer |= VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT |
190 VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT |
191 VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT;
192
193 /* TODO: The blob also exposes these for R16G16_UINT/R16G16_SINT, but we
194 * don't have any tests for those.
195 */
196 if (vk_format == VK_FORMAT_R32_UINT || vk_format == VK_FORMAT_R32_SINT) {
197 optimal |= VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT;
198 buffer |= VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT;
199 }
200
201 if (!util_format_is_pure_integer(format))
202 optimal |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT;
203 }
204
205 /* For the most part, we can do anything with a linear image that we could
206 * do with a tiled image. However, we can't support sysmem rendering with a
207 * linear depth texture, because we don't know if there's a bit to control
208 * the tiling of the depth buffer in BYPASS mode, and the blob also
209 * disables linear depth rendering, so there's no way to discover it. We
210 * also can't force GMEM mode, because there are other situations where we
211 * have to use sysmem rendering. So follow the blob here, and only enable
212 * DEPTH_STENCIL_ATTACHMENT_BIT for the optimal features.
213 */
214 linear = optimal;
215 if (tu6_pipe2depth(vk_format) != DEPTH6_NONE)
216 optimal |= VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
217
218 if (!tiling_possible(vk_format) &&
219 /* We don't actually support tiling for this format, but we need to
220 * fake it as it's required by VK_KHR_sampler_ycbcr_conversion.
221 */
222 vk_format != VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM) {
223 optimal = 0;
224 }
225
226 if (vk_format == VK_FORMAT_G8B8G8R8_422_UNORM ||
227 vk_format == VK_FORMAT_B8G8R8G8_422_UNORM ||
228 vk_format == VK_FORMAT_G8_B8R8_2PLANE_420_UNORM ||
229 vk_format == VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM) {
230 /* Disable buffer texturing of subsampled (422) and planar YUV textures.
231 * The subsampling requirement comes from "If format is a block-compressed
232 * format, then bufferFeatures must not support any features for the
233 * format" plus the specification of subsampled as 2x1 compressed block
234 * format. I couldn't find the citation for planar, but 1D access of
235 * planar YUV would be really silly.
236 */
237 buffer = 0;
238 }
239
240 /* We don't support writing into VK_FORMAT_*_PACK16 images/buffers */
241 if (desc->nr_channels > 2 && desc->block.bits == 16) {
242 buffer &= VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT;
243 linear &= ~(VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT |
244 VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT);
245 optimal &= ~(VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT |
246 VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT);
247 }
248
249 /* All our depth formats support shadow comparisons. */
250 if (vk_format_has_depth(vk_format) && (optimal & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
251 optimal |= VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_DEPTH_COMPARISON_BIT;
252 linear |= VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_DEPTH_COMPARISON_BIT;
253 }
254
255 /* From the Vulkan 1.3.205 spec, section 19.3 "43.3. Required Format Support":
256 *
257 * Mandatory format support: depth/stencil with VkImageType
258 * VK_IMAGE_TYPE_2D
259 * [...]
260 * bufferFeatures must not support any features for these formats
261 */
262 if (vk_format_is_depth_or_stencil(vk_format))
263 buffer = 0;
264
265 /* D32_SFLOAT_S8_UINT is tiled as two images, so no linear format
266 * blob enables some linear features, but its not useful, so don't bother.
267 */
268 if (vk_format == VK_FORMAT_D32_SFLOAT_S8_UINT)
269 linear = 0;
270
271 end:
272 out_properties->linearTilingFeatures = linear;
273 out_properties->optimalTilingFeatures = optimal;
274 out_properties->bufferFeatures = buffer;
275 }
276
277 VKAPI_ATTR void VKAPI_CALL
tu_GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice,VkFormat format,VkFormatProperties2 * pFormatProperties)278 tu_GetPhysicalDeviceFormatProperties2(
279 VkPhysicalDevice physicalDevice,
280 VkFormat format,
281 VkFormatProperties2 *pFormatProperties)
282 {
283 VK_FROM_HANDLE(tu_physical_device, physical_device, physicalDevice);
284
285 VkFormatProperties3 local_props3;
286 VkFormatProperties3 *props3 =
287 vk_find_struct(pFormatProperties->pNext, FORMAT_PROPERTIES_3);
288 if (!props3)
289 props3 = &local_props3;
290
291 tu_physical_device_get_format_properties(
292 physical_device, format, props3);
293
294 pFormatProperties->formatProperties = (VkFormatProperties) {
295 .linearTilingFeatures =
296 vk_format_features2_to_features(props3->linearTilingFeatures),
297 .optimalTilingFeatures =
298 vk_format_features2_to_features(props3->optimalTilingFeatures),
299 .bufferFeatures =
300 vk_format_features2_to_features(props3->bufferFeatures),
301 };
302
303 VkDrmFormatModifierPropertiesListEXT *list =
304 vk_find_struct(pFormatProperties->pNext, DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT);
305 if (list) {
306 VK_OUTARRAY_MAKE_TYPED(VkDrmFormatModifierPropertiesEXT, out,
307 list->pDrmFormatModifierProperties,
308 &list->drmFormatModifierCount);
309
310 if (pFormatProperties->formatProperties.linearTilingFeatures) {
311 vk_outarray_append_typed(VkDrmFormatModifierPropertiesEXT, &out, mod_props) {
312 mod_props->drmFormatModifier = DRM_FORMAT_MOD_LINEAR;
313 mod_props->drmFormatModifierPlaneCount = tu6_plane_count(format);
314 mod_props->drmFormatModifierTilingFeatures =
315 pFormatProperties->formatProperties.linearTilingFeatures;
316 }
317 }
318
319 /* note: ubwc_possible() argument values to be ignored except for format */
320 if (pFormatProperties->formatProperties.optimalTilingFeatures &&
321 tiling_possible(format) &&
322 ubwc_possible(NULL, format, VK_IMAGE_TYPE_2D, 0, 0,
323 physical_device->info, VK_SAMPLE_COUNT_1_BIT,
324 false)) {
325 vk_outarray_append_typed(VkDrmFormatModifierPropertiesEXT, &out, mod_props) {
326 mod_props->drmFormatModifier = DRM_FORMAT_MOD_QCOM_COMPRESSED;
327 mod_props->drmFormatModifierPlaneCount = tu6_plane_count(format);
328 mod_props->drmFormatModifierTilingFeatures =
329 pFormatProperties->formatProperties.optimalTilingFeatures;
330 }
331 }
332 }
333 }
334
335 static VkResult
tu_image_unsupported_format(VkImageFormatProperties * pImageFormatProperties)336 tu_image_unsupported_format(VkImageFormatProperties *pImageFormatProperties)
337 {
338 *pImageFormatProperties = (VkImageFormatProperties) {
339 .maxExtent = { 0, 0, 0 },
340 .maxMipLevels = 0,
341 .maxArrayLayers = 0,
342 .sampleCounts = 0,
343 .maxResourceSize = 0,
344 };
345
346 return VK_ERROR_FORMAT_NOT_SUPPORTED;
347 }
348
349 static VkResult
tu_get_image_format_properties(struct tu_physical_device * physical_device,const VkPhysicalDeviceImageFormatInfo2 * info,VkImageFormatProperties * pImageFormatProperties,VkFormatFeatureFlags * p_feature_flags)350 tu_get_image_format_properties(
351 struct tu_physical_device *physical_device,
352 const VkPhysicalDeviceImageFormatInfo2 *info,
353 VkImageFormatProperties *pImageFormatProperties,
354 VkFormatFeatureFlags *p_feature_flags)
355 {
356 VkFormatProperties3 format_props;
357 VkFormatFeatureFlags format_feature_flags;
358 VkExtent3D maxExtent;
359 uint32_t maxMipLevels;
360 uint32_t maxArraySize;
361 BITMASK_ENUM(VkSampleCountFlagBits) sampleCounts = VK_SAMPLE_COUNT_1_BIT;
362
363 tu_physical_device_get_format_properties(physical_device, info->format,
364 &format_props);
365
366 switch (info->tiling) {
367 case VK_IMAGE_TILING_LINEAR:
368 format_feature_flags = format_props.linearTilingFeatures;
369 break;
370
371 case VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT: {
372 const VkPhysicalDeviceImageDrmFormatModifierInfoEXT *drm_info =
373 vk_find_struct_const(info->pNext, PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT);
374
375 /* Subsampled format isn't stable yet, so don't allow
376 * importing/exporting with modifiers yet.
377 */
378 if (info->flags & VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT)
379 return VK_ERROR_FORMAT_NOT_SUPPORTED;
380
381 switch (drm_info->drmFormatModifier) {
382 case DRM_FORMAT_MOD_QCOM_COMPRESSED:
383 /* falling back to linear/non-UBWC isn't possible with explicit modifier */
384
385 /* formats which don't support tiling */
386 if (!format_props.optimalTilingFeatures ||
387 !tiling_possible(info->format))
388 return VK_ERROR_FORMAT_NOT_SUPPORTED;
389
390 if (info->flags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT) {
391 const VkImageFormatListCreateInfo *format_list =
392 vk_find_struct_const(info->pNext,
393 IMAGE_FORMAT_LIST_CREATE_INFO);
394 if (!tu6_mutable_format_list_ubwc_compatible(physical_device->info,
395 format_list))
396 return VK_ERROR_FORMAT_NOT_SUPPORTED;
397 }
398
399 if (!ubwc_possible(NULL, info->format, info->type, info->usage,
400 info->usage, physical_device->info, sampleCounts,
401 false)) {
402 return VK_ERROR_FORMAT_NOT_SUPPORTED;
403 }
404
405 format_feature_flags = format_props.optimalTilingFeatures;
406 break;
407 case DRM_FORMAT_MOD_LINEAR:
408 format_feature_flags = format_props.linearTilingFeatures;
409 break;
410 default:
411 return VK_ERROR_FORMAT_NOT_SUPPORTED;
412 }
413 } break;
414 case VK_IMAGE_TILING_OPTIMAL:
415 format_feature_flags = format_props.optimalTilingFeatures;
416 break;
417 default:
418 unreachable("bad VkPhysicalDeviceImageFormatInfo2");
419 }
420
421 if (format_feature_flags == 0)
422 return tu_image_unsupported_format(pImageFormatProperties);
423
424 if (info->type != VK_IMAGE_TYPE_2D &&
425 vk_format_is_depth_or_stencil(info->format))
426 return tu_image_unsupported_format(pImageFormatProperties);
427
428 switch (info->type) {
429 default:
430 unreachable("bad vkimage type\n");
431 case VK_IMAGE_TYPE_1D:
432 maxExtent.width = 16384;
433 maxExtent.height = 1;
434 maxExtent.depth = 1;
435 maxMipLevels = 15; /* log2(maxWidth) + 1 */
436 maxArraySize = 2048;
437 break;
438 case VK_IMAGE_TYPE_2D:
439 maxExtent.width = 16384;
440 maxExtent.height = 16384;
441 maxExtent.depth = 1;
442 maxMipLevels = 15; /* log2(maxWidth) + 1 */
443 maxArraySize = 2048;
444 break;
445 case VK_IMAGE_TYPE_3D:
446 maxExtent.width = 2048;
447 maxExtent.height = 2048;
448 maxExtent.depth = 2048;
449 maxMipLevels = 12; /* log2(maxWidth) + 1 */
450 maxArraySize = 1;
451 break;
452 }
453
454 if (info->tiling == VK_IMAGE_TILING_OPTIMAL &&
455 info->type == VK_IMAGE_TYPE_2D &&
456 (format_feature_flags &
457 (VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT |
458 VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) &&
459 !(info->flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) &&
460 !(info->usage & VK_IMAGE_USAGE_STORAGE_BIT)) {
461 sampleCounts |= VK_SAMPLE_COUNT_2_BIT | VK_SAMPLE_COUNT_4_BIT;
462 /* note: most operations support 8 samples (GMEM render/resolve do at least)
463 * but some do not (which ones?), just disable 8 samples completely,
464 * (no 8x msaa matches the blob driver behavior)
465 */
466 }
467
468 /* From the Vulkan 1.3.206 spec:
469 *
470 * "VK_IMAGE_CREATE_EXTENDED_USAGE_BIT specifies that the image can be
471 * created with usage flags that are not supported for the format the image
472 * is created with but are supported for at least one format a VkImageView
473 * created from the image can have."
474 *
475 * This means we should relax checks that only depend on the
476 * format_feature_flags, to allow the user to create images that may be
477 * e.g. reinterpreted as storage when the original format doesn't allow it.
478 * The user will have to check against the format features anyway.
479 * Otherwise we'd unnecessarily disallow it.
480 */
481
482 VkImageUsageFlags image_usage = info->usage;
483 if (info->flags & VK_IMAGE_CREATE_EXTENDED_USAGE_BIT)
484 image_usage = 0;
485
486 if (image_usage & VK_IMAGE_USAGE_SAMPLED_BIT) {
487 if (!(format_feature_flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
488 return tu_image_unsupported_format(pImageFormatProperties);
489 }
490 }
491
492 if (image_usage & VK_IMAGE_USAGE_STORAGE_BIT) {
493 if (!(format_feature_flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)) {
494 return tu_image_unsupported_format(pImageFormatProperties);
495 }
496 }
497
498 if (image_usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) {
499 if (!(format_feature_flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) {
500 return tu_image_unsupported_format(pImageFormatProperties);
501 }
502 }
503
504 if (image_usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
505 if (!(format_feature_flags &
506 VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
507 return tu_image_unsupported_format(pImageFormatProperties);
508 }
509 }
510
511 if (image_usage & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) {
512 if (!(format_feature_flags &
513 (VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT |
514 VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT))) {
515 return tu_image_unsupported_format(pImageFormatProperties);
516 }
517 }
518
519 *pImageFormatProperties = (VkImageFormatProperties) {
520 .maxExtent = maxExtent,
521 .maxMipLevels = maxMipLevels,
522 .maxArrayLayers = maxArraySize,
523 .sampleCounts = sampleCounts,
524
525 /* FINISHME: Accurately calculate
526 * VkImageFormatProperties::maxResourceSize.
527 */
528 .maxResourceSize = UINT32_MAX,
529 };
530
531 if (p_feature_flags)
532 *p_feature_flags = format_feature_flags;
533
534 return VK_SUCCESS;
535 }
536
537 static VkResult
tu_get_external_image_format_properties(const struct tu_physical_device * physical_device,const VkPhysicalDeviceImageFormatInfo2 * pImageFormatInfo,VkExternalMemoryHandleTypeFlagBits handleType,VkExternalImageFormatProperties * external_properties)538 tu_get_external_image_format_properties(
539 const struct tu_physical_device *physical_device,
540 const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo,
541 VkExternalMemoryHandleTypeFlagBits handleType,
542 VkExternalImageFormatProperties *external_properties)
543 {
544 BITMASK_ENUM(VkExternalMemoryFeatureFlagBits) flags = 0;
545 VkExternalMemoryHandleTypeFlags export_flags = 0;
546 VkExternalMemoryHandleTypeFlags compat_flags = 0;
547
548 /* From the Vulkan 1.1.98 spec:
549 *
550 * If handleType is not compatible with the format, type, tiling,
551 * usage, and flags specified in VkPhysicalDeviceImageFormatInfo2,
552 * then vkGetPhysicalDeviceImageFormatProperties2 returns
553 * VK_ERROR_FORMAT_NOT_SUPPORTED.
554 */
555
556 switch (handleType) {
557 case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT:
558 case VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT:
559 switch (pImageFormatInfo->type) {
560 case VK_IMAGE_TYPE_2D:
561 flags = VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT |
562 VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT |
563 VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT;
564 compat_flags = export_flags =
565 VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT |
566 VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
567 break;
568 default:
569 return vk_errorf(physical_device, VK_ERROR_FORMAT_NOT_SUPPORTED,
570 "VkExternalMemoryTypeFlagBits(0x%x) unsupported for VkImageType(%d)",
571 handleType, pImageFormatInfo->type);
572 }
573 break;
574 #if DETECT_OS_ANDROID
575 case VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID:
576 flags = VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT |
577 VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT |
578 VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT;
579 compat_flags = export_flags = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
580 break;
581 #endif
582 case VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT:
583 flags = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT;
584 compat_flags = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT;
585 break;
586 default:
587 return vk_errorf(physical_device, VK_ERROR_FORMAT_NOT_SUPPORTED,
588 "VkExternalMemoryTypeFlagBits(0x%x) unsupported",
589 handleType);
590 }
591
592 if (external_properties) {
593 external_properties->externalMemoryProperties =
594 (VkExternalMemoryProperties) {
595 .externalMemoryFeatures = flags,
596 .exportFromImportedHandleTypes = export_flags,
597 .compatibleHandleTypes = compat_flags,
598 };
599 }
600
601 return VK_SUCCESS;
602 }
603
604 VKAPI_ATTR VkResult VKAPI_CALL
tu_GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice,const VkPhysicalDeviceImageFormatInfo2 * base_info,VkImageFormatProperties2 * base_props)605 tu_GetPhysicalDeviceImageFormatProperties2(
606 VkPhysicalDevice physicalDevice,
607 const VkPhysicalDeviceImageFormatInfo2 *base_info,
608 VkImageFormatProperties2 *base_props)
609 {
610 VK_FROM_HANDLE(tu_physical_device, physical_device, physicalDevice);
611 const VkPhysicalDeviceExternalImageFormatInfo *external_info = NULL;
612 const VkPhysicalDeviceImageViewImageFormatInfoEXT *image_view_info = NULL;
613 VkExternalImageFormatProperties *external_props = NULL;
614 VkAndroidHardwareBufferUsageANDROID *android_usage = NULL;
615 VkFilterCubicImageViewImageFormatPropertiesEXT *cubic_props = NULL;
616 VkFormatFeatureFlags format_feature_flags;
617 VkSamplerYcbcrConversionImageFormatProperties *ycbcr_props = NULL;
618 VkResult result;
619
620 result = tu_get_image_format_properties(physical_device,
621 base_info, &base_props->imageFormatProperties, &format_feature_flags);
622 if (result != VK_SUCCESS)
623 return result;
624
625 /* Extract input structs */
626 vk_foreach_struct_const(s, base_info->pNext)
627 {
628 switch (s->sType) {
629 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO:
630 external_info = (const VkPhysicalDeviceExternalImageFormatInfo *) s;
631 break;
632 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_IMAGE_FORMAT_INFO_EXT:
633 image_view_info = (const VkPhysicalDeviceImageViewImageFormatInfoEXT *) s;
634 break;
635 default:
636 break;
637 }
638 }
639
640 /* Extract output structs */
641 vk_foreach_struct(s, base_props->pNext)
642 {
643 switch (s->sType) {
644 case VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES:
645 external_props = (VkExternalImageFormatProperties *) s;
646 break;
647 case VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID:
648 android_usage = (VkAndroidHardwareBufferUsageANDROID *) s;
649 break;
650 case VK_STRUCTURE_TYPE_FILTER_CUBIC_IMAGE_VIEW_IMAGE_FORMAT_PROPERTIES_EXT:
651 cubic_props = (VkFilterCubicImageViewImageFormatPropertiesEXT *) s;
652 break;
653 case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES:
654 ycbcr_props = (VkSamplerYcbcrConversionImageFormatProperties *) s;
655 break;
656 default:
657 break;
658 }
659 }
660
661 /* From the Vulkan 1.0.42 spec:
662 *
663 * If handleType is 0, vkGetPhysicalDeviceImageFormatProperties2 will
664 * behave as if VkPhysicalDeviceExternalImageFormatInfo was not
665 * present and VkExternalImageFormatProperties will be ignored.
666 */
667 if (external_info && external_info->handleType != 0) {
668 result = tu_get_external_image_format_properties(
669 physical_device, base_info, external_info->handleType,
670 external_props);
671 if (result != VK_SUCCESS)
672 goto fail;
673 }
674
675 if (cubic_props) {
676 /* note: blob only allows cubic filtering for 2D and 2D array views
677 * its likely we can enable it for 1D and CUBE, needs testing however
678 */
679 if ((image_view_info->imageViewType == VK_IMAGE_VIEW_TYPE_2D ||
680 image_view_info->imageViewType == VK_IMAGE_VIEW_TYPE_2D_ARRAY) &&
681 (format_feature_flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT)) {
682 cubic_props->filterCubic = true;
683 cubic_props->filterCubicMinmax = true;
684 } else {
685 cubic_props->filterCubic = false;
686 cubic_props->filterCubicMinmax = false;
687 }
688 }
689
690 if (android_usage) {
691 /* Don't expect gralloc to be able to allocate anything other than 3D: */
692 if (base_info->type != VK_IMAGE_TYPE_2D) {
693 result = vk_errorf(physical_device, VK_ERROR_FORMAT_NOT_SUPPORTED,
694 "type (%u) unsupported for AHB", base_info->type);
695 goto fail;
696 }
697 VkImageFormatProperties *props = &base_props->imageFormatProperties;
698 if (!(props->sampleCounts & VK_SAMPLE_COUNT_1_BIT)) {
699 result = vk_errorf(physical_device, VK_ERROR_FORMAT_NOT_SUPPORTED,
700 "sampleCounts (%x) unsupported for AHB", props->sampleCounts);
701 goto fail;
702 }
703 android_usage->androidHardwareBufferUsage =
704 vk_image_usage_to_ahb_usage(base_info->flags, base_info->usage);
705 uint32_t format = vk_image_format_to_ahb_format(base_info->format);
706 if (!format) {
707 result = vk_errorf(physical_device, VK_ERROR_FORMAT_NOT_SUPPORTED,
708 "format (%u) unsupported for AHB", base_info->format);
709 goto fail;
710 }
711 /* We can't advertise support for anything that gralloc cannot allocate
712 * so we are stuck without any better option than attempting a test
713 * allocation:
714 */
715 if (!vk_ahb_probe_format(base_info->format, base_info->flags, base_info->usage)) {
716 result = vk_errorf(physical_device, VK_ERROR_FORMAT_NOT_SUPPORTED,
717 "format (%x) with flags (%x) and usage (%x) unsupported for AHB",
718 base_info->format, base_info->flags, base_info->usage);
719 goto fail;
720 }
721
722 /* AHBs with mipmap usage will ignore this property */
723 props->maxMipLevels = 1;
724 props->sampleCounts = VK_SAMPLE_COUNT_1_BIT;
725 }
726
727 if (ycbcr_props)
728 ycbcr_props->combinedImageSamplerDescriptorCount = 1;
729
730 return VK_SUCCESS;
731
732 fail:
733 if (result == VK_ERROR_FORMAT_NOT_SUPPORTED) {
734 /* From the Vulkan 1.0.42 spec:
735 *
736 * If the combination of parameters to
737 * vkGetPhysicalDeviceImageFormatProperties2 is not supported by
738 * the implementation for use in vkCreateImage, then all members of
739 * imageFormatProperties will be filled with zero.
740 */
741 base_props->imageFormatProperties = (VkImageFormatProperties) {};
742 }
743
744 return result;
745 }
746
747 VKAPI_ATTR void VKAPI_CALL
tu_GetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice,const VkPhysicalDeviceSparseImageFormatInfo2 * pFormatInfo,uint32_t * pPropertyCount,VkSparseImageFormatProperties2 * pProperties)748 tu_GetPhysicalDeviceSparseImageFormatProperties2(
749 VkPhysicalDevice physicalDevice,
750 const VkPhysicalDeviceSparseImageFormatInfo2 *pFormatInfo,
751 uint32_t *pPropertyCount,
752 VkSparseImageFormatProperties2 *pProperties)
753 {
754 /* Sparse images are not yet supported. */
755 *pPropertyCount = 0;
756 }
757