Home | History | Annotate | Line # | Download | only in vulkan
      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
     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
     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
     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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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