mirror of
				https://git.suyu.dev/suyu/suyu
				synced 2025-11-03 16:39:01 -06:00 
			
		
		
		
	vk_device: Add miscellaneous features and minor style changes
* Increase minimum Vulkan requirements * Require VK_EXT_vertex_attribute_divisor * Require depthClamp, samplerAnisotropy and largePoints features * Search and expose VK_KHR_uniform_buffer_standard_layout * Search and expose VK_EXT_index_type_uint8 * Search and expose native float16 arithmetics * Track current driver with VK_KHR_driver_properties * Query and expose SSBO alignment * Query more image formats * Improve logging overall * Minor style changes * Minor rephrasing of commentaries
This commit is contained in:
		@@ -2,9 +2,10 @@
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#include <map>
 | 
			
		||||
#include <bitset>
 | 
			
		||||
#include <optional>
 | 
			
		||||
#include <set>
 | 
			
		||||
#include <string_view>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include "common/assert.h"
 | 
			
		||||
#include "video_core/renderer_vulkan/declarations.h"
 | 
			
		||||
@@ -12,13 +13,32 @@
 | 
			
		||||
 | 
			
		||||
namespace Vulkan {
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
void SetNext(void**& next, T& data) {
 | 
			
		||||
    *next = &data;
 | 
			
		||||
    next = &data.pNext;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
T GetFeatures(vk::PhysicalDevice physical, vk::DispatchLoaderDynamic dldi) {
 | 
			
		||||
    vk::PhysicalDeviceFeatures2 features;
 | 
			
		||||
    T extension_features;
 | 
			
		||||
    features.pNext = &extension_features;
 | 
			
		||||
    physical.getFeatures2(&features, dldi);
 | 
			
		||||
    return extension_features;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // Anonymous namespace
 | 
			
		||||
 | 
			
		||||
namespace Alternatives {
 | 
			
		||||
 | 
			
		||||
constexpr std::array<vk::Format, 3> Depth24UnormS8Uint = {
 | 
			
		||||
    vk::Format::eD32SfloatS8Uint, vk::Format::eD16UnormS8Uint, {}};
 | 
			
		||||
constexpr std::array<vk::Format, 3> Depth16UnormS8Uint = {
 | 
			
		||||
    vk::Format::eD24UnormS8Uint, vk::Format::eD32SfloatS8Uint, {}};
 | 
			
		||||
constexpr std::array<vk::Format, 2> Astc = {vk::Format::eA8B8G8R8UnormPack32, {}};
 | 
			
		||||
constexpr std::array Depth24UnormS8Uint = {vk::Format::eD32SfloatS8Uint,
 | 
			
		||||
                                           vk::Format::eD16UnormS8Uint, vk::Format{}};
 | 
			
		||||
constexpr std::array Depth16UnormS8Uint = {vk::Format::eD24UnormS8Uint,
 | 
			
		||||
                                           vk::Format::eD32SfloatS8Uint, vk::Format{}};
 | 
			
		||||
constexpr std::array Astc = {vk::Format::eA8B8G8R8UnormPack32, vk::Format{}};
 | 
			
		||||
 | 
			
		||||
} // namespace Alternatives
 | 
			
		||||
 | 
			
		||||
@@ -58,16 +78,53 @@ VKDevice::VKDevice(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice phy
 | 
			
		||||
VKDevice::~VKDevice() = default;
 | 
			
		||||
 | 
			
		||||
bool VKDevice::Create(const vk::DispatchLoaderDynamic& dldi, vk::Instance instance) {
 | 
			
		||||
    vk::PhysicalDeviceFeatures device_features;
 | 
			
		||||
    device_features.vertexPipelineStoresAndAtomics = true;
 | 
			
		||||
    device_features.independentBlend = true;
 | 
			
		||||
    device_features.textureCompressionASTC_LDR = is_optimal_astc_supported;
 | 
			
		||||
 | 
			
		||||
    const auto queue_cis = GetDeviceQueueCreateInfos();
 | 
			
		||||
    const std::vector<const char*> extensions = LoadExtensions(dldi);
 | 
			
		||||
    const vk::DeviceCreateInfo device_ci({}, static_cast<u32>(queue_cis.size()), queue_cis.data(),
 | 
			
		||||
                                         0, nullptr, static_cast<u32>(extensions.size()),
 | 
			
		||||
                                         extensions.data(), &device_features);
 | 
			
		||||
    const std::vector extensions = LoadExtensions(dldi);
 | 
			
		||||
 | 
			
		||||
    vk::PhysicalDeviceFeatures2 features2;
 | 
			
		||||
    void** next = &features2.pNext;
 | 
			
		||||
    auto& features = features2.features;
 | 
			
		||||
    features.vertexPipelineStoresAndAtomics = true;
 | 
			
		||||
    features.independentBlend = true;
 | 
			
		||||
    features.depthClamp = true;
 | 
			
		||||
    features.samplerAnisotropy = true;
 | 
			
		||||
    features.largePoints = true;
 | 
			
		||||
    features.textureCompressionASTC_LDR = is_optimal_astc_supported;
 | 
			
		||||
 | 
			
		||||
    vk::PhysicalDeviceVertexAttributeDivisorFeaturesEXT vertex_divisor;
 | 
			
		||||
    vertex_divisor.vertexAttributeInstanceRateDivisor = true;
 | 
			
		||||
    vertex_divisor.vertexAttributeInstanceRateZeroDivisor = true;
 | 
			
		||||
    SetNext(next, vertex_divisor);
 | 
			
		||||
 | 
			
		||||
    vk::PhysicalDeviceFloat16Int8FeaturesKHR float16_int8;
 | 
			
		||||
    if (is_float16_supported) {
 | 
			
		||||
        float16_int8.shaderFloat16 = true;
 | 
			
		||||
        SetNext(next, float16_int8);
 | 
			
		||||
    } else {
 | 
			
		||||
        LOG_INFO(Render_Vulkan, "Device doesn't support float16 natively");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vk::PhysicalDeviceUniformBufferStandardLayoutFeaturesKHR std430_layout;
 | 
			
		||||
    if (khr_uniform_buffer_standard_layout) {
 | 
			
		||||
        std430_layout.uniformBufferStandardLayout = true;
 | 
			
		||||
        SetNext(next, std430_layout);
 | 
			
		||||
    } else {
 | 
			
		||||
        LOG_INFO(Render_Vulkan, "Device doesn't support packed UBOs");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vk::PhysicalDeviceIndexTypeUint8FeaturesEXT index_type_uint8;
 | 
			
		||||
    if (ext_index_type_uint8) {
 | 
			
		||||
        index_type_uint8.indexTypeUint8 = true;
 | 
			
		||||
        SetNext(next, index_type_uint8);
 | 
			
		||||
    } else {
 | 
			
		||||
        LOG_INFO(Render_Vulkan, "Device doesn't support uint8 indexes");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vk::DeviceCreateInfo device_ci({}, static_cast<u32>(queue_cis.size()), queue_cis.data(), 0,
 | 
			
		||||
                                   nullptr, static_cast<u32>(extensions.size()), extensions.data(),
 | 
			
		||||
                                   nullptr);
 | 
			
		||||
    device_ci.pNext = &features2;
 | 
			
		||||
 | 
			
		||||
    vk::Device dummy_logical;
 | 
			
		||||
    if (physical.createDevice(&device_ci, nullptr, &dummy_logical, dldi) != vk::Result::eSuccess) {
 | 
			
		||||
        LOG_CRITICAL(Render_Vulkan, "Logical device failed to be created!");
 | 
			
		||||
@@ -78,6 +135,17 @@ bool VKDevice::Create(const vk::DispatchLoaderDynamic& dldi, vk::Instance instan
 | 
			
		||||
    logical = UniqueDevice(
 | 
			
		||||
        dummy_logical, vk::ObjectDestroy<vk::NoParent, vk::DispatchLoaderDynamic>(nullptr, dld));
 | 
			
		||||
 | 
			
		||||
    if (khr_driver_properties) {
 | 
			
		||||
        vk::PhysicalDeviceDriverPropertiesKHR driver;
 | 
			
		||||
        vk::PhysicalDeviceProperties2 properties;
 | 
			
		||||
        properties.pNext = &driver;
 | 
			
		||||
        physical.getProperties2(&properties, dld);
 | 
			
		||||
        driver_id = driver.driverID;
 | 
			
		||||
        LOG_INFO(Render_Vulkan, "Driver: {} {}", driver.driverName, driver.driverInfo);
 | 
			
		||||
    } else {
 | 
			
		||||
        LOG_INFO(Render_Vulkan, "Driver: Unknown");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    graphics_queue = logical->getQueue(graphics_family, 0, dld);
 | 
			
		||||
    present_queue = logical->getQueue(present_family, 0, dld);
 | 
			
		||||
    return true;
 | 
			
		||||
@@ -92,20 +160,19 @@ vk::Format VKDevice::GetSupportedFormat(vk::Format wanted_format,
 | 
			
		||||
    // The wanted format is not supported by hardware, search for alternatives
 | 
			
		||||
    const vk::Format* alternatives = GetFormatAlternatives(wanted_format);
 | 
			
		||||
    if (alternatives == nullptr) {
 | 
			
		||||
        LOG_CRITICAL(Render_Vulkan,
 | 
			
		||||
                     "Format={} with usage={} and type={} has no defined alternatives and host "
 | 
			
		||||
                     "hardware does not support it",
 | 
			
		||||
                     vk::to_string(wanted_format), vk::to_string(wanted_usage),
 | 
			
		||||
                     static_cast<u32>(format_type));
 | 
			
		||||
        UNREACHABLE();
 | 
			
		||||
        UNREACHABLE_MSG("Format={} with usage={} and type={} has no defined alternatives and host "
 | 
			
		||||
                        "hardware does not support it",
 | 
			
		||||
                        vk::to_string(wanted_format), vk::to_string(wanted_usage),
 | 
			
		||||
                        static_cast<u32>(format_type));
 | 
			
		||||
        return wanted_format;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::size_t i = 0;
 | 
			
		||||
    for (vk::Format alternative = alternatives[0]; alternative != vk::Format{};
 | 
			
		||||
         alternative = alternatives[++i]) {
 | 
			
		||||
        if (!IsFormatSupported(alternative, wanted_usage, format_type))
 | 
			
		||||
        if (!IsFormatSupported(alternative, wanted_usage, format_type)) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        LOG_WARNING(Render_Vulkan,
 | 
			
		||||
                    "Emulating format={} with alternative format={} with usage={} and type={}",
 | 
			
		||||
                    static_cast<u32>(wanted_format), static_cast<u32>(alternative),
 | 
			
		||||
@@ -114,12 +181,10 @@ vk::Format VKDevice::GetSupportedFormat(vk::Format wanted_format,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // No alternatives found, panic
 | 
			
		||||
    LOG_CRITICAL(Render_Vulkan,
 | 
			
		||||
                 "Format={} with usage={} and type={} is not supported by the host hardware and "
 | 
			
		||||
                 "doesn't support any of the alternatives",
 | 
			
		||||
                 static_cast<u32>(wanted_format), static_cast<u32>(wanted_usage),
 | 
			
		||||
                 static_cast<u32>(format_type));
 | 
			
		||||
    UNREACHABLE();
 | 
			
		||||
    UNREACHABLE_MSG("Format={} with usage={} and type={} is not supported by the host hardware and "
 | 
			
		||||
                    "doesn't support any of the alternatives",
 | 
			
		||||
                    static_cast<u32>(wanted_format), static_cast<u32>(wanted_usage),
 | 
			
		||||
                    static_cast<u32>(format_type));
 | 
			
		||||
    return wanted_format;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -132,7 +197,7 @@ bool VKDevice::IsOptimalAstcSupported(const vk::PhysicalDeviceFeatures& features
 | 
			
		||||
        vk::FormatFeatureFlagBits::eSampledImage | vk::FormatFeatureFlagBits::eBlitSrc |
 | 
			
		||||
        vk::FormatFeatureFlagBits::eBlitDst | vk::FormatFeatureFlagBits::eTransferSrc |
 | 
			
		||||
        vk::FormatFeatureFlagBits::eTransferDst};
 | 
			
		||||
    constexpr std::array<vk::Format, 9> astc_formats = {
 | 
			
		||||
    constexpr std::array astc_formats = {
 | 
			
		||||
        vk::Format::eAstc4x4UnormBlock, vk::Format::eAstc4x4SrgbBlock,
 | 
			
		||||
        vk::Format::eAstc8x8SrgbBlock,  vk::Format::eAstc8x6SrgbBlock,
 | 
			
		||||
        vk::Format::eAstc5x4SrgbBlock,  vk::Format::eAstc5x5UnormBlock,
 | 
			
		||||
@@ -151,76 +216,120 @@ bool VKDevice::IsFormatSupported(vk::Format wanted_format, vk::FormatFeatureFlag
 | 
			
		||||
                                 FormatType format_type) const {
 | 
			
		||||
    const auto it = format_properties.find(wanted_format);
 | 
			
		||||
    if (it == format_properties.end()) {
 | 
			
		||||
        LOG_CRITICAL(Render_Vulkan, "Unimplemented format query={}", vk::to_string(wanted_format));
 | 
			
		||||
        UNREACHABLE();
 | 
			
		||||
        UNIMPLEMENTED_MSG("Unimplemented format query={}", vk::to_string(wanted_format));
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    const vk::FormatFeatureFlags supported_usage = GetFormatFeatures(it->second, format_type);
 | 
			
		||||
    const auto supported_usage = GetFormatFeatures(it->second, format_type);
 | 
			
		||||
    return (supported_usage & wanted_usage) == wanted_usage;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool VKDevice::IsSuitable(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical,
 | 
			
		||||
                          vk::SurfaceKHR surface) {
 | 
			
		||||
    bool has_swapchain{};
 | 
			
		||||
    LOG_INFO(Render_Vulkan, "{}", physical.getProperties(dldi).deviceName);
 | 
			
		||||
    bool is_suitable = true;
 | 
			
		||||
 | 
			
		||||
    constexpr std::array required_extensions = {VK_KHR_SWAPCHAIN_EXTENSION_NAME,
 | 
			
		||||
                                                VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME};
 | 
			
		||||
    std::bitset<required_extensions.size()> available_extensions{};
 | 
			
		||||
 | 
			
		||||
    for (const auto& prop : physical.enumerateDeviceExtensionProperties(nullptr, dldi)) {
 | 
			
		||||
        has_swapchain |= prop.extensionName == std::string(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
 | 
			
		||||
        for (std::size_t i = 0; i < required_extensions.size(); ++i) {
 | 
			
		||||
            if (available_extensions[i]) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            available_extensions[i] =
 | 
			
		||||
                required_extensions[i] == std::string_view{prop.extensionName};
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (!has_swapchain) {
 | 
			
		||||
        // The device doesn't support creating swapchains.
 | 
			
		||||
        return false;
 | 
			
		||||
    if (!available_extensions.all()) {
 | 
			
		||||
        for (std::size_t i = 0; i < required_extensions.size(); ++i) {
 | 
			
		||||
            if (available_extensions[i]) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            LOG_INFO(Render_Vulkan, "Missing required extension: {}", required_extensions[i]);
 | 
			
		||||
            is_suitable = false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool has_graphics{}, has_present{};
 | 
			
		||||
    const auto queue_family_properties = physical.getQueueFamilyProperties(dldi);
 | 
			
		||||
    for (u32 i = 0; i < static_cast<u32>(queue_family_properties.size()); ++i) {
 | 
			
		||||
        const auto& family = queue_family_properties[i];
 | 
			
		||||
        if (family.queueCount == 0)
 | 
			
		||||
        if (family.queueCount == 0) {
 | 
			
		||||
            continue;
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        has_graphics |=
 | 
			
		||||
            (family.queueFlags & vk::QueueFlagBits::eGraphics) != static_cast<vk::QueueFlagBits>(0);
 | 
			
		||||
        has_present |= physical.getSurfaceSupportKHR(i, surface, dldi) != 0;
 | 
			
		||||
    }
 | 
			
		||||
    if (!has_graphics || !has_present) {
 | 
			
		||||
        // The device doesn't have a graphics and present queue.
 | 
			
		||||
        return false;
 | 
			
		||||
        LOG_INFO(Render_Vulkan, "Device lacks a graphics and present queue");
 | 
			
		||||
        is_suitable = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // TODO(Rodrigo): Check if the device matches all requeriments.
 | 
			
		||||
    const auto properties{physical.getProperties(dldi)};
 | 
			
		||||
    const auto limits{properties.limits};
 | 
			
		||||
    if (limits.maxUniformBufferRange < 65536) {
 | 
			
		||||
        return false;
 | 
			
		||||
    const auto& limits{properties.limits};
 | 
			
		||||
 | 
			
		||||
    constexpr u32 required_ubo_size = 65536;
 | 
			
		||||
    if (limits.maxUniformBufferRange < required_ubo_size) {
 | 
			
		||||
        LOG_INFO(Render_Vulkan, "Device UBO size {} is too small, {} is required)",
 | 
			
		||||
                 limits.maxUniformBufferRange, required_ubo_size);
 | 
			
		||||
        is_suitable = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const vk::PhysicalDeviceFeatures features{physical.getFeatures(dldi)};
 | 
			
		||||
    if (!features.vertexPipelineStoresAndAtomics || !features.independentBlend) {
 | 
			
		||||
        return false;
 | 
			
		||||
    const auto features{physical.getFeatures(dldi)};
 | 
			
		||||
    const std::array feature_report = {
 | 
			
		||||
        std::make_pair(features.vertexPipelineStoresAndAtomics, "vertexPipelineStoresAndAtomics"),
 | 
			
		||||
        std::make_pair(features.independentBlend, "independentBlend"),
 | 
			
		||||
        std::make_pair(features.depthClamp, "depthClamp"),
 | 
			
		||||
        std::make_pair(features.samplerAnisotropy, "samplerAnisotropy"),
 | 
			
		||||
        std::make_pair(features.largePoints, "largePoints"),
 | 
			
		||||
    };
 | 
			
		||||
    for (const auto& [supported, name] : feature_report) {
 | 
			
		||||
        if (supported) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        LOG_INFO(Render_Vulkan, "Missing required feature: {}", name);
 | 
			
		||||
        is_suitable = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Device is suitable.
 | 
			
		||||
    return true;
 | 
			
		||||
    return is_suitable;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::vector<const char*> VKDevice::LoadExtensions(const vk::DispatchLoaderDynamic& dldi) {
 | 
			
		||||
    std::vector<const char*> extensions;
 | 
			
		||||
    extensions.reserve(2);
 | 
			
		||||
    extensions.reserve(7);
 | 
			
		||||
    extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
 | 
			
		||||
    extensions.push_back(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME);
 | 
			
		||||
 | 
			
		||||
    const auto Test = [&](const vk::ExtensionProperties& extension,
 | 
			
		||||
                          std::optional<std::reference_wrapper<bool>> status, const char* name,
 | 
			
		||||
                          u32 revision) {
 | 
			
		||||
        if (extension.extensionName != std::string(name)) {
 | 
			
		||||
                          bool push) {
 | 
			
		||||
        if (extension.extensionName != std::string_view(name)) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        extensions.push_back(name);
 | 
			
		||||
        if (push) {
 | 
			
		||||
            extensions.push_back(name);
 | 
			
		||||
        }
 | 
			
		||||
        if (status) {
 | 
			
		||||
            status->get() = true;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    bool khr_shader_float16_int8{};
 | 
			
		||||
    for (const auto& extension : physical.enumerateDeviceExtensionProperties(nullptr, dldi)) {
 | 
			
		||||
        Test(extension, ext_scalar_block_layout, VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME, 1);
 | 
			
		||||
        Test(extension, khr_uniform_buffer_standard_layout,
 | 
			
		||||
             VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_EXTENSION_NAME, true);
 | 
			
		||||
        Test(extension, ext_index_type_uint8, VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME, true);
 | 
			
		||||
        Test(extension, khr_driver_properties, VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, true);
 | 
			
		||||
        Test(extension, khr_shader_float16_int8, VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (khr_shader_float16_int8) {
 | 
			
		||||
        is_float16_supported =
 | 
			
		||||
            GetFeatures<vk::PhysicalDeviceFloat16Int8FeaturesKHR>(physical, dldi).shaderFloat16;
 | 
			
		||||
        extensions.push_back(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return extensions;
 | 
			
		||||
@@ -250,9 +359,10 @@ void VKDevice::SetupFamilies(const vk::DispatchLoaderDynamic& dldi, vk::SurfaceK
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VKDevice::SetupProperties(const vk::DispatchLoaderDynamic& dldi) {
 | 
			
		||||
    const vk::PhysicalDeviceProperties props = physical.getProperties(dldi);
 | 
			
		||||
    const auto props = physical.getProperties(dldi);
 | 
			
		||||
    device_type = props.deviceType;
 | 
			
		||||
    uniform_buffer_alignment = static_cast<u64>(props.limits.minUniformBufferOffsetAlignment);
 | 
			
		||||
    storage_buffer_alignment = static_cast<u64>(props.limits.minStorageBufferOffsetAlignment);
 | 
			
		||||
    max_storage_buffer_range = static_cast<u64>(props.limits.maxStorageBufferRange);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -273,42 +383,53 @@ std::vector<vk::DeviceQueueCreateInfo> VKDevice::GetDeviceQueueCreateInfos() con
 | 
			
		||||
    return queue_cis;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::map<vk::Format, vk::FormatProperties> VKDevice::GetFormatProperties(
 | 
			
		||||
std::unordered_map<vk::Format, vk::FormatProperties> VKDevice::GetFormatProperties(
 | 
			
		||||
    const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical) {
 | 
			
		||||
    static constexpr std::array formats{vk::Format::eA8B8G8R8UnormPack32,
 | 
			
		||||
                                        vk::Format::eB5G6R5UnormPack16,
 | 
			
		||||
                                        vk::Format::eA2B10G10R10UnormPack32,
 | 
			
		||||
                                        vk::Format::eR32G32B32A32Sfloat,
 | 
			
		||||
                                        vk::Format::eR16G16Unorm,
 | 
			
		||||
                                        vk::Format::eR16G16Snorm,
 | 
			
		||||
                                        vk::Format::eR8G8B8A8Srgb,
 | 
			
		||||
                                        vk::Format::eR8Unorm,
 | 
			
		||||
                                        vk::Format::eB10G11R11UfloatPack32,
 | 
			
		||||
                                        vk::Format::eR32Sfloat,
 | 
			
		||||
                                        vk::Format::eR16Sfloat,
 | 
			
		||||
                                        vk::Format::eR16G16B16A16Sfloat,
 | 
			
		||||
                                        vk::Format::eD32Sfloat,
 | 
			
		||||
                                        vk::Format::eD16Unorm,
 | 
			
		||||
                                        vk::Format::eD16UnormS8Uint,
 | 
			
		||||
                                        vk::Format::eD24UnormS8Uint,
 | 
			
		||||
                                        vk::Format::eD32SfloatS8Uint,
 | 
			
		||||
                                        vk::Format::eBc1RgbaUnormBlock,
 | 
			
		||||
                                        vk::Format::eBc2UnormBlock,
 | 
			
		||||
                                        vk::Format::eBc3UnormBlock,
 | 
			
		||||
                                        vk::Format::eBc4UnormBlock,
 | 
			
		||||
                                        vk::Format::eBc5UnormBlock,
 | 
			
		||||
                                        vk::Format::eBc5SnormBlock,
 | 
			
		||||
                                        vk::Format::eBc7UnormBlock,
 | 
			
		||||
                                        vk::Format::eAstc4x4UnormBlock,
 | 
			
		||||
                                        vk::Format::eAstc4x4SrgbBlock,
 | 
			
		||||
                                        vk::Format::eAstc8x8SrgbBlock,
 | 
			
		||||
                                        vk::Format::eAstc8x6SrgbBlock,
 | 
			
		||||
                                        vk::Format::eAstc5x4SrgbBlock,
 | 
			
		||||
                                        vk::Format::eAstc5x5UnormBlock,
 | 
			
		||||
                                        vk::Format::eAstc5x5SrgbBlock,
 | 
			
		||||
                                        vk::Format::eAstc10x8UnormBlock,
 | 
			
		||||
                                        vk::Format::eAstc10x8SrgbBlock};
 | 
			
		||||
    std::map<vk::Format, vk::FormatProperties> format_properties;
 | 
			
		||||
    constexpr std::array formats{vk::Format::eA8B8G8R8UnormPack32,
 | 
			
		||||
                                 vk::Format::eA8B8G8R8SnormPack32,
 | 
			
		||||
                                 vk::Format::eA8B8G8R8SrgbPack32,
 | 
			
		||||
                                 vk::Format::eB5G6R5UnormPack16,
 | 
			
		||||
                                 vk::Format::eA2B10G10R10UnormPack32,
 | 
			
		||||
                                 vk::Format::eR32G32B32A32Sfloat,
 | 
			
		||||
                                 vk::Format::eR16G16B16A16Uint,
 | 
			
		||||
                                 vk::Format::eR16G16Unorm,
 | 
			
		||||
                                 vk::Format::eR16G16Snorm,
 | 
			
		||||
                                 vk::Format::eR16G16Sfloat,
 | 
			
		||||
                                 vk::Format::eR16Unorm,
 | 
			
		||||
                                 vk::Format::eR8G8B8A8Srgb,
 | 
			
		||||
                                 vk::Format::eR8G8Unorm,
 | 
			
		||||
                                 vk::Format::eR8G8Snorm,
 | 
			
		||||
                                 vk::Format::eR8Unorm,
 | 
			
		||||
                                 vk::Format::eB10G11R11UfloatPack32,
 | 
			
		||||
                                 vk::Format::eR32Sfloat,
 | 
			
		||||
                                 vk::Format::eR16Sfloat,
 | 
			
		||||
                                 vk::Format::eR16G16B16A16Sfloat,
 | 
			
		||||
                                 vk::Format::eB8G8R8A8Unorm,
 | 
			
		||||
                                 vk::Format::eD32Sfloat,
 | 
			
		||||
                                 vk::Format::eD16Unorm,
 | 
			
		||||
                                 vk::Format::eD16UnormS8Uint,
 | 
			
		||||
                                 vk::Format::eD24UnormS8Uint,
 | 
			
		||||
                                 vk::Format::eD32SfloatS8Uint,
 | 
			
		||||
                                 vk::Format::eBc1RgbaUnormBlock,
 | 
			
		||||
                                 vk::Format::eBc2UnormBlock,
 | 
			
		||||
                                 vk::Format::eBc3UnormBlock,
 | 
			
		||||
                                 vk::Format::eBc4UnormBlock,
 | 
			
		||||
                                 vk::Format::eBc5UnormBlock,
 | 
			
		||||
                                 vk::Format::eBc5SnormBlock,
 | 
			
		||||
                                 vk::Format::eBc7UnormBlock,
 | 
			
		||||
                                 vk::Format::eBc1RgbaSrgbBlock,
 | 
			
		||||
                                 vk::Format::eBc3SrgbBlock,
 | 
			
		||||
                                 vk::Format::eBc7SrgbBlock,
 | 
			
		||||
                                 vk::Format::eAstc4x4UnormBlock,
 | 
			
		||||
                                 vk::Format::eAstc4x4SrgbBlock,
 | 
			
		||||
                                 vk::Format::eAstc8x8SrgbBlock,
 | 
			
		||||
                                 vk::Format::eAstc8x6SrgbBlock,
 | 
			
		||||
                                 vk::Format::eAstc5x4SrgbBlock,
 | 
			
		||||
                                 vk::Format::eAstc5x5UnormBlock,
 | 
			
		||||
                                 vk::Format::eAstc5x5SrgbBlock,
 | 
			
		||||
                                 vk::Format::eAstc10x8UnormBlock,
 | 
			
		||||
                                 vk::Format::eAstc10x8SrgbBlock};
 | 
			
		||||
    std::unordered_map<vk::Format, vk::FormatProperties> format_properties;
 | 
			
		||||
    for (const auto format : formats) {
 | 
			
		||||
        format_properties.emplace(format, physical.getFormatProperties(format, dldi));
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <map>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "video_core/renderer_vulkan/declarations.h"
 | 
			
		||||
@@ -69,16 +69,26 @@ public:
 | 
			
		||||
        return present_family;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Returns if the device is integrated with the host CPU.
 | 
			
		||||
    /// Returns true if the device is integrated with the host CPU.
 | 
			
		||||
    bool IsIntegrated() const {
 | 
			
		||||
        return device_type == vk::PhysicalDeviceType::eIntegratedGpu;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Returns the driver ID.
 | 
			
		||||
    vk::DriverIdKHR GetDriverID() const {
 | 
			
		||||
        return driver_id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Returns uniform buffer alignment requeriment.
 | 
			
		||||
    u64 GetUniformBufferAlignment() const {
 | 
			
		||||
        return uniform_buffer_alignment;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Returns storage alignment requeriment.
 | 
			
		||||
    u64 GetStorageBufferAlignment() const {
 | 
			
		||||
        return storage_buffer_alignment;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Returns the maximum range for storage buffers.
 | 
			
		||||
    u64 GetMaxStorageBufferRange() const {
 | 
			
		||||
        return max_storage_buffer_range;
 | 
			
		||||
@@ -89,9 +99,19 @@ public:
 | 
			
		||||
        return is_optimal_astc_supported;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Returns true if the device supports float16 natively
 | 
			
		||||
    bool IsFloat16Supported() const {
 | 
			
		||||
        return is_float16_supported;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Returns true if the device supports VK_EXT_scalar_block_layout.
 | 
			
		||||
    bool IsExtScalarBlockLayoutSupported() const {
 | 
			
		||||
        return ext_scalar_block_layout;
 | 
			
		||||
    bool IsKhrUniformBufferStandardLayoutSupported() const {
 | 
			
		||||
        return khr_uniform_buffer_standard_layout;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Returns true if the device supports VK_EXT_index_type_uint8.
 | 
			
		||||
    bool IsExtIndexTypeUint8Supported() const {
 | 
			
		||||
        return ext_index_type_uint8;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Checks if the physical device is suitable.
 | 
			
		||||
@@ -123,22 +143,28 @@ private:
 | 
			
		||||
                           FormatType format_type) const;
 | 
			
		||||
 | 
			
		||||
    /// Returns the device properties for Vulkan formats.
 | 
			
		||||
    static std::map<vk::Format, vk::FormatProperties> GetFormatProperties(
 | 
			
		||||
    static std::unordered_map<vk::Format, vk::FormatProperties> GetFormatProperties(
 | 
			
		||||
        const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical);
 | 
			
		||||
 | 
			
		||||
    const vk::PhysicalDevice physical;  ///< Physical device.
 | 
			
		||||
    vk::DispatchLoaderDynamic dld;      ///< Device function pointers.
 | 
			
		||||
    UniqueDevice logical;               ///< Logical device.
 | 
			
		||||
    vk::Queue graphics_queue;           ///< Main graphics queue.
 | 
			
		||||
    vk::Queue present_queue;            ///< Main present queue.
 | 
			
		||||
    u32 graphics_family{};              ///< Main graphics queue family index.
 | 
			
		||||
    u32 present_family{};               ///< Main present queue family index.
 | 
			
		||||
    vk::PhysicalDeviceType device_type; ///< Physical device type.
 | 
			
		||||
    u64 uniform_buffer_alignment{};     ///< Uniform buffer alignment requeriment.
 | 
			
		||||
    u64 max_storage_buffer_range{};     ///< Max storage buffer size.
 | 
			
		||||
    bool is_optimal_astc_supported{};   ///< Support for native ASTC.
 | 
			
		||||
    bool ext_scalar_block_layout{};     ///< Support for VK_EXT_scalar_block_layout.
 | 
			
		||||
    std::map<vk::Format, vk::FormatProperties> format_properties; ///< Format properties dictionary.
 | 
			
		||||
    const vk::PhysicalDevice physical;         ///< Physical device.
 | 
			
		||||
    vk::DispatchLoaderDynamic dld;             ///< Device function pointers.
 | 
			
		||||
    UniqueDevice logical;                      ///< Logical device.
 | 
			
		||||
    vk::Queue graphics_queue;                  ///< Main graphics queue.
 | 
			
		||||
    vk::Queue present_queue;                   ///< Main present queue.
 | 
			
		||||
    u32 graphics_family{};                     ///< Main graphics queue family index.
 | 
			
		||||
    u32 present_family{};                      ///< Main present queue family index.
 | 
			
		||||
    vk::PhysicalDeviceType device_type;        ///< Physical device type.
 | 
			
		||||
    vk::DriverIdKHR driver_id{};               ///< Driver ID.
 | 
			
		||||
    u64 uniform_buffer_alignment{};            ///< Uniform buffer alignment requeriment.
 | 
			
		||||
    u64 storage_buffer_alignment{};            ///< Storage buffer alignment requeriment.
 | 
			
		||||
    u64 max_storage_buffer_range{};            ///< Max storage buffer size.
 | 
			
		||||
    bool is_optimal_astc_supported{};          ///< Support for native ASTC.
 | 
			
		||||
    bool is_float16_supported{};               ///< Support for float16 arithmetics.
 | 
			
		||||
    bool khr_uniform_buffer_standard_layout{}; ///< Support for std430 on UBOs.
 | 
			
		||||
    bool ext_index_type_uint8{};               ///< Support for VK_EXT_index_type_uint8.
 | 
			
		||||
    bool khr_driver_properties{};              ///< Support for VK_KHR_driver_properties.
 | 
			
		||||
    std::unordered_map<vk::Format, vk::FormatProperties>
 | 
			
		||||
        format_properties; ///< Format properties dictionary.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Vulkan
 | 
			
		||||
 
 | 
			
		||||
@@ -370,8 +370,8 @@ private:
 | 
			
		||||
        u32 binding = const_buffers_base_binding;
 | 
			
		||||
        for (const auto& entry : ir.GetConstantBuffers()) {
 | 
			
		||||
            const auto [index, size] = entry;
 | 
			
		||||
            const Id type =
 | 
			
		||||
                device.IsExtScalarBlockLayoutSupported() ? t_cbuf_scalar_ubo : t_cbuf_std140_ubo;
 | 
			
		||||
            const Id type = device.IsKhrUniformBufferStandardLayoutSupported() ? t_cbuf_scalar_ubo
 | 
			
		||||
                                                                               : t_cbuf_std140_ubo;
 | 
			
		||||
            const Id id = OpVariable(type, spv::StorageClass::Uniform);
 | 
			
		||||
            AddGlobalVariable(Name(id, fmt::format("cbuf_{}", index)));
 | 
			
		||||
 | 
			
		||||
@@ -565,7 +565,7 @@ private:
 | 
			
		||||
            const Id buffer_id = constant_buffers.at(cbuf->GetIndex());
 | 
			
		||||
 | 
			
		||||
            Id pointer{};
 | 
			
		||||
            if (device.IsExtScalarBlockLayoutSupported()) {
 | 
			
		||||
            if (device.IsKhrUniformBufferStandardLayoutSupported()) {
 | 
			
		||||
                const Id buffer_offset = Emit(OpShiftRightLogical(
 | 
			
		||||
                    t_uint, BitcastTo<Type::Uint>(Visit(offset)), Constant(t_uint, 2u)));
 | 
			
		||||
                pointer = Emit(
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user