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