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