Search code examples
3dvulkan

How can I query all GPU texture formats using the Vulkan API?


I am struggling to understand a simple feature I need to query using the Vulkan API: I need to determine all the texture formats supported by my GPU. After searching around, I found this code:

uint32_t formatCount;
vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr);
if (formatCount != 0) {
    details.formats.resize(formatCount);
    vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, details.formats.data());
    int counter = 0;
    int numFormats = details.formats.size();
    for (const auto& format : details.formats) {
        VkFormat vkFormat = format.format;
        VkColorSpaceKHR colorSpace = format.colorSpace;
        std::cout << "[" << counter << "] Format: " <<
            vkFormatToString(vkFormat) <<
            ", Color Space: " << colorSpace << std::endl;
        counter++;
    }
}

The output I receive is limited to:

[0] Format: VK_FORMAT_R8G8B8A8_UNORM, Color Space: 0
[1] Format: VK_FORMAT_B8G8R8A8_UNORM, Color Space: 0
[2] Format: VK_FORMAT_R8G8B8A8_SRGB, Color Space: 0
[3] Format: VK_FORMAT_B8G8R8A8_SRGB, Color Space: 0

This looks incorrect because I am using a powerful AMD GPU (Radeon), which supports compressed formats like "VK_FORMAT_BC1_RGBA_UNORM_BLOCK." This is evident because I can successfully create an image using this format:

imageInfo.format = VK_FORMAT_BC1_RGBA_UNORM_BLOCK;
imageInfo.tiling = tiling;
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageInfo.usage = usage;
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
if (vkCreateImage(device, &imageInfo, nullptr, &image) != VK_SUCCESS) {
    throw std::runtime_error("failed to create image!");
}

I suspect my previous code only enumerates KHR Surface capabilities and not the GPU texture formats.

In summary, how can I query the available GPU texture formats?

Thank you very much for your assistance.


Solution

  • vkGetPhysicalDeviceSurfaceFormatsKHR is only for querying the GPUs supported formats for a surface as part of VK_KHR_surface.

    Querying support for image formats can be done with vkGetPhysicalDeviceFormatPropertiesarchive.

    void IterateFormats(VkFormat min, VkFormat max)
    {
        for(VkFormat fmt = min; fmt <= max; ++fmt)
        {
            VkFormatProperties properties{};
            vkGetPhysicalDeviceFormatProperties(device, fmt, &properties);
            SaveFormat(fmt, properties);
        }
    }
    
    void IterateFormatGroups()
    {
        // VK_VERSION_1_0
        IterateFormats(VK_FORMAT_R4G4_UNORM_PACK8, VK_FORMAT_ASTC_12x12_SRGB_BLOCK);
        // VK_VERSION_1_1, VK_KHR_sampler_ycbcr_conversion
        IterateFormats(VK_FORMAT_G8B8G8R8_422_UNORM, VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM);
        // VK_VERSION_1_3, VK_EXT_ycbcr_2plane_444_formats
        IterateFormats(VK_FORMAT_G8_B8R8_2PLANE_444_UNORM, VK_FORMAT_G16_B16R16_2PLANE_444_UNORM);
        // VK_VERSION_1_3, VK_EXT_4444_formats
        IterateFormats(VK_FORMAT_A4R4G4B4_UNORM_PACK16, VK_FORMAT_A4B4G4R4_UNORM_PACK16);
        // VK_VERSION_1_3, VK_EXT_texture_compression_astc_hdr
        IterateFormats(VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK, VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK);
        // VK_IMG_format_pvrtc
        IterateFormats(VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG, VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG);
        // VK_NV_optical_flow
        IterateFormats(VK_FORMAT_R16G16_SFIXED5_NV, VK_FORMAT_R16G16_SFIXED5_NV);
        // VK_KHR_maintenance5
        IterateFormats(VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR, VK_FORMAT_A8_UNORM_KHR);
    }