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