Merge pull request #3205 from ReinUsesLisp/vk-device
vk_device: Misc changes
This commit is contained in:
		| @@ -3,6 +3,7 @@ | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| #include <bitset> | ||||
| #include <cstdlib> | ||||
| #include <optional> | ||||
| #include <set> | ||||
| #include <string_view> | ||||
| @@ -15,6 +16,15 @@ namespace Vulkan { | ||||
|  | ||||
| namespace { | ||||
|  | ||||
| namespace Alternatives { | ||||
|  | ||||
| constexpr std::array Depth24UnormS8Uint = {vk::Format::eD32SfloatS8Uint, | ||||
|                                            vk::Format::eD16UnormS8Uint, vk::Format{}}; | ||||
| constexpr std::array Depth16UnormS8Uint = {vk::Format::eD24UnormS8Uint, | ||||
|                                            vk::Format::eD32SfloatS8Uint, vk::Format{}}; | ||||
|  | ||||
| } // namespace Alternatives | ||||
|  | ||||
| template <typename T> | ||||
| void SetNext(void**& next, T& data) { | ||||
|     *next = &data; | ||||
| @@ -22,7 +32,7 @@ void SetNext(void**& next, T& data) { | ||||
| } | ||||
|  | ||||
| template <typename T> | ||||
| T GetFeatures(vk::PhysicalDevice physical, vk::DispatchLoaderDynamic dldi) { | ||||
| T GetFeatures(vk::PhysicalDevice physical, const vk::DispatchLoaderDynamic& dldi) { | ||||
|     vk::PhysicalDeviceFeatures2 features; | ||||
|     T extension_features; | ||||
|     features.pNext = &extension_features; | ||||
| @@ -30,17 +40,14 @@ T GetFeatures(vk::PhysicalDevice physical, vk::DispatchLoaderDynamic dldi) { | ||||
|     return extension_features; | ||||
| } | ||||
|  | ||||
| } // Anonymous namespace | ||||
|  | ||||
| namespace Alternatives { | ||||
|  | ||||
| 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 | ||||
| template <typename T> | ||||
| T GetProperties(vk::PhysicalDevice physical, const vk::DispatchLoaderDynamic& dldi) { | ||||
|     vk::PhysicalDeviceProperties2 properties; | ||||
|     T extension_properties; | ||||
|     properties.pNext = &extension_properties; | ||||
|     physical.getProperties2(&properties, dldi); | ||||
|     return extension_properties; | ||||
| } | ||||
|  | ||||
| constexpr const vk::Format* GetFormatAlternatives(vk::Format format) { | ||||
|     switch (format) { | ||||
| @@ -66,11 +73,13 @@ vk::FormatFeatureFlags GetFormatFeatures(vk::FormatProperties properties, Format | ||||
|     } | ||||
| } | ||||
|  | ||||
| } // Anonymous namespace | ||||
|  | ||||
| VKDevice::VKDevice(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical, | ||||
|                    vk::SurfaceKHR surface) | ||||
|     : physical{physical}, format_properties{GetFormatProperties(dldi, physical)} { | ||||
|     : physical{physical}, properties{physical.getProperties(dldi)}, | ||||
|       format_properties{GetFormatProperties(dldi, physical)} { | ||||
|     SetupFamilies(dldi, surface); | ||||
|     SetupProperties(dldi); | ||||
|     SetupFeatures(dldi); | ||||
| } | ||||
|  | ||||
| @@ -88,12 +97,22 @@ bool VKDevice::Create(const vk::DispatchLoaderDynamic& dldi, vk::Instance instan | ||||
|     features.depthClamp = true; | ||||
|     features.samplerAnisotropy = true; | ||||
|     features.largePoints = true; | ||||
|     features.multiViewport = true; | ||||
|     features.depthBiasClamp = true; | ||||
|     features.geometryShader = true; | ||||
|     features.tessellationShader = true; | ||||
|     features.fragmentStoresAndAtomics = true; | ||||
|     features.shaderImageGatherExtended = true; | ||||
|     features.shaderStorageImageWriteWithoutFormat = 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::PhysicalDevice16BitStorageFeaturesKHR bit16_storage; | ||||
|     bit16_storage.uniformAndStorageBuffer16BitAccess = true; | ||||
|     SetNext(next, bit16_storage); | ||||
|  | ||||
|     vk::PhysicalDevice8BitStorageFeaturesKHR bit8_storage; | ||||
|     bit8_storage.uniformAndStorageBuffer8BitAccess = true; | ||||
|     SetNext(next, bit8_storage); | ||||
|  | ||||
|     vk::PhysicalDeviceFloat16Int8FeaturesKHR float16_int8; | ||||
|     if (is_float16_supported) { | ||||
| @@ -119,6 +138,10 @@ bool VKDevice::Create(const vk::DispatchLoaderDynamic& dldi, vk::Instance instan | ||||
|         LOG_INFO(Render_Vulkan, "Device doesn't support uint8 indexes"); | ||||
|     } | ||||
|  | ||||
|     if (!ext_depth_range_unrestricted) { | ||||
|         LOG_INFO(Render_Vulkan, "Device doesn't support depth range unrestricted"); | ||||
|     } | ||||
|  | ||||
|     vk::DeviceCreateInfo device_ci({}, static_cast<u32>(queue_cis.size()), queue_cis.data(), 0, | ||||
|                                    nullptr, static_cast<u32>(extensions.size()), extensions.data(), | ||||
|                                    nullptr); | ||||
| @@ -134,16 +157,7 @@ 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"); | ||||
|     } | ||||
|     CollectTelemetryParameters(); | ||||
|  | ||||
|     graphics_queue = logical->getQueue(graphics_family, 0, dld); | ||||
|     present_queue = logical->getQueue(present_family, 0, dld); | ||||
| @@ -189,6 +203,18 @@ vk::Format VKDevice::GetSupportedFormat(vk::Format wanted_format, | ||||
|  | ||||
| bool VKDevice::IsOptimalAstcSupported(const vk::PhysicalDeviceFeatures& features, | ||||
|                                       const vk::DispatchLoaderDynamic& dldi) const { | ||||
|     // Disable for now to avoid converting ASTC twice. | ||||
|     return false; | ||||
|     static constexpr std::array astc_formats = { | ||||
|         vk::Format::eAstc4x4SrgbBlock,    vk::Format::eAstc8x8SrgbBlock, | ||||
|         vk::Format::eAstc8x5SrgbBlock,    vk::Format::eAstc5x4SrgbBlock, | ||||
|         vk::Format::eAstc5x5UnormBlock,   vk::Format::eAstc5x5SrgbBlock, | ||||
|         vk::Format::eAstc10x8UnormBlock,  vk::Format::eAstc10x8SrgbBlock, | ||||
|         vk::Format::eAstc6x6UnormBlock,   vk::Format::eAstc6x6SrgbBlock, | ||||
|         vk::Format::eAstc10x10UnormBlock, vk::Format::eAstc10x10SrgbBlock, | ||||
|         vk::Format::eAstc12x12UnormBlock, vk::Format::eAstc12x12SrgbBlock, | ||||
|         vk::Format::eAstc8x6UnormBlock,   vk::Format::eAstc8x6SrgbBlock, | ||||
|         vk::Format::eAstc6x5UnormBlock,   vk::Format::eAstc6x5SrgbBlock}; | ||||
|     if (!features.textureCompressionASTC_LDR) { | ||||
|         return false; | ||||
|     } | ||||
| @@ -196,12 +222,6 @@ 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 astc_formats = { | ||||
|         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}; | ||||
|     for (const auto format : astc_formats) { | ||||
|         const auto format_properties{physical.getFormatProperties(format, dldi)}; | ||||
|         if (!(format_properties.optimalTilingFeatures & format_feature_usage)) { | ||||
| @@ -224,11 +244,17 @@ bool VKDevice::IsFormatSupported(vk::Format wanted_format, vk::FormatFeatureFlag | ||||
|  | ||||
| bool VKDevice::IsSuitable(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical, | ||||
|                           vk::SurfaceKHR surface) { | ||||
|     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}; | ||||
|     constexpr std::array required_extensions = { | ||||
|         VK_KHR_SWAPCHAIN_EXTENSION_NAME, | ||||
|         VK_KHR_16BIT_STORAGE_EXTENSION_NAME, | ||||
|         VK_KHR_8BIT_STORAGE_EXTENSION_NAME, | ||||
|         VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, | ||||
|         VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME, | ||||
|         VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME, | ||||
|         VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME, | ||||
|     }; | ||||
|     std::bitset<required_extensions.size()> available_extensions{}; | ||||
|  | ||||
|     for (const auto& prop : physical.enumerateDeviceExtensionProperties(nullptr, dldi)) { | ||||
| @@ -245,7 +271,7 @@ bool VKDevice::IsSuitable(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDev | ||||
|             if (available_extensions[i]) { | ||||
|                 continue; | ||||
|             } | ||||
|             LOG_INFO(Render_Vulkan, "Missing required extension: {}", required_extensions[i]); | ||||
|             LOG_ERROR(Render_Vulkan, "Missing required extension: {}", required_extensions[i]); | ||||
|             is_suitable = false; | ||||
|         } | ||||
|     } | ||||
| @@ -262,7 +288,7 @@ bool VKDevice::IsSuitable(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDev | ||||
|         has_present |= physical.getSurfaceSupportKHR(i, surface, dldi) != 0; | ||||
|     } | ||||
|     if (!has_graphics || !has_present) { | ||||
|         LOG_INFO(Render_Vulkan, "Device lacks a graphics and present queue"); | ||||
|         LOG_ERROR(Render_Vulkan, "Device lacks a graphics and present queue"); | ||||
|         is_suitable = false; | ||||
|     } | ||||
|  | ||||
| @@ -272,8 +298,15 @@ bool VKDevice::IsSuitable(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDev | ||||
|  | ||||
|     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); | ||||
|         LOG_ERROR(Render_Vulkan, "Device UBO size {} is too small, {} is required", | ||||
|                   limits.maxUniformBufferRange, required_ubo_size); | ||||
|         is_suitable = false; | ||||
|     } | ||||
|  | ||||
|     constexpr u32 required_num_viewports = 16; | ||||
|     if (limits.maxViewports < required_num_viewports) { | ||||
|         LOG_INFO(Render_Vulkan, "Device number of viewports {} is too small, {} is required", | ||||
|                  limits.maxViewports, required_num_viewports); | ||||
|         is_suitable = false; | ||||
|     } | ||||
|  | ||||
| @@ -284,24 +317,32 @@ bool VKDevice::IsSuitable(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDev | ||||
|         std::make_pair(features.depthClamp, "depthClamp"), | ||||
|         std::make_pair(features.samplerAnisotropy, "samplerAnisotropy"), | ||||
|         std::make_pair(features.largePoints, "largePoints"), | ||||
|         std::make_pair(features.multiViewport, "multiViewport"), | ||||
|         std::make_pair(features.depthBiasClamp, "depthBiasClamp"), | ||||
|         std::make_pair(features.geometryShader, "geometryShader"), | ||||
|         std::make_pair(features.tessellationShader, "tessellationShader"), | ||||
|         std::make_pair(features.fragmentStoresAndAtomics, "fragmentStoresAndAtomics"), | ||||
|         std::make_pair(features.shaderImageGatherExtended, "shaderImageGatherExtended"), | ||||
|         std::make_pair(features.shaderStorageImageWriteWithoutFormat, | ||||
|                        "shaderStorageImageWriteWithoutFormat"), | ||||
|     }; | ||||
|     for (const auto& [supported, name] : feature_report) { | ||||
|         if (supported) { | ||||
|             continue; | ||||
|         } | ||||
|         LOG_INFO(Render_Vulkan, "Missing required feature: {}", name); | ||||
|         LOG_ERROR(Render_Vulkan, "Missing required feature: {}", name); | ||||
|         is_suitable = false; | ||||
|     } | ||||
|  | ||||
|     if (!is_suitable) { | ||||
|         LOG_ERROR(Render_Vulkan, "{} is not suitable", properties.deviceName); | ||||
|     } | ||||
|  | ||||
|     return is_suitable; | ||||
| } | ||||
|  | ||||
| std::vector<const char*> VKDevice::LoadExtensions(const vk::DispatchLoaderDynamic& dldi) { | ||||
|     std::vector<const char*> extensions; | ||||
|     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, | ||||
|                           bool push) { | ||||
| @@ -316,13 +357,30 @@ std::vector<const char*> VKDevice::LoadExtensions(const vk::DispatchLoaderDynami | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     extensions.reserve(13); | ||||
|     extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); | ||||
|     extensions.push_back(VK_KHR_16BIT_STORAGE_EXTENSION_NAME); | ||||
|     extensions.push_back(VK_KHR_8BIT_STORAGE_EXTENSION_NAME); | ||||
|     extensions.push_back(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME); | ||||
|     extensions.push_back(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME); | ||||
|     extensions.push_back(VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME); | ||||
|     extensions.push_back(VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME); | ||||
|  | ||||
|     [[maybe_unused]] const bool nsight = | ||||
|         std::getenv("NVTX_INJECTION64_PATH") || std::getenv("NSIGHT_LAUNCHED"); | ||||
|     bool khr_shader_float16_int8{}; | ||||
|     bool ext_subgroup_size_control{}; | ||||
|     for (const auto& extension : physical.enumerateDeviceExtensionProperties(nullptr, dldi)) { | ||||
|         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); | ||||
|         Test(extension, ext_depth_range_unrestricted, | ||||
|              VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME, true); | ||||
|         Test(extension, ext_index_type_uint8, VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME, true); | ||||
|         Test(extension, ext_shader_viewport_index_layer, | ||||
|              VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME, true); | ||||
|         Test(extension, ext_subgroup_size_control, VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME, | ||||
|              false); | ||||
|     } | ||||
|  | ||||
|     if (khr_shader_float16_int8) { | ||||
| @@ -331,6 +389,23 @@ std::vector<const char*> VKDevice::LoadExtensions(const vk::DispatchLoaderDynami | ||||
|         extensions.push_back(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME); | ||||
|     } | ||||
|  | ||||
|     if (ext_subgroup_size_control) { | ||||
|         const auto features = | ||||
|             GetFeatures<vk::PhysicalDeviceSubgroupSizeControlFeaturesEXT>(physical, dldi); | ||||
|         const auto properties = | ||||
|             GetProperties<vk::PhysicalDeviceSubgroupSizeControlPropertiesEXT>(physical, dldi); | ||||
|  | ||||
|         is_warp_potentially_bigger = properties.maxSubgroupSize > GuestWarpSize; | ||||
|  | ||||
|         if (features.subgroupSizeControl && properties.minSubgroupSize <= GuestWarpSize && | ||||
|             properties.maxSubgroupSize >= GuestWarpSize) { | ||||
|             extensions.push_back(VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME); | ||||
|             guest_warp_stages = properties.requiredSubgroupSizeStages; | ||||
|         } | ||||
|     } else { | ||||
|         is_warp_potentially_bigger = true; | ||||
|     } | ||||
|  | ||||
|     return extensions; | ||||
| } | ||||
|  | ||||
| @@ -357,19 +432,23 @@ void VKDevice::SetupFamilies(const vk::DispatchLoaderDynamic& dldi, vk::SurfaceK | ||||
|     present_family = *present_family_; | ||||
| } | ||||
|  | ||||
| void VKDevice::SetupProperties(const vk::DispatchLoaderDynamic& 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); | ||||
| } | ||||
|  | ||||
| void VKDevice::SetupFeatures(const vk::DispatchLoaderDynamic& dldi) { | ||||
|     const auto supported_features{physical.getFeatures(dldi)}; | ||||
|     is_optimal_astc_supported = IsOptimalAstcSupported(supported_features, dldi); | ||||
| } | ||||
|  | ||||
| void VKDevice::CollectTelemetryParameters() { | ||||
|     const auto driver = GetProperties<vk::PhysicalDeviceDriverPropertiesKHR>(physical, dld); | ||||
|     driver_id = driver.driverID; | ||||
|     vendor_name = driver.driverName; | ||||
|  | ||||
|     const auto extensions = physical.enumerateDeviceExtensionProperties(nullptr, dld); | ||||
|     reported_extensions.reserve(std::size(extensions)); | ||||
|     for (const auto& extension : extensions) { | ||||
|         reported_extensions.push_back(extension.extensionName); | ||||
|     } | ||||
| } | ||||
|  | ||||
| std::vector<vk::DeviceQueueCreateInfo> VKDevice::GetDeviceQueueCreateInfos() const { | ||||
|     static const float QUEUE_PRIORITY = 1.0f; | ||||
|  | ||||
| @@ -384,50 +463,70 @@ std::vector<vk::DeviceQueueCreateInfo> VKDevice::GetDeviceQueueCreateInfos() con | ||||
|  | ||||
| std::unordered_map<vk::Format, vk::FormatProperties> VKDevice::GetFormatProperties( | ||||
|     const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical) { | ||||
|     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}; | ||||
|     static constexpr std::array formats{vk::Format::eA8B8G8R8UnormPack32, | ||||
|                                         vk::Format::eA8B8G8R8SnormPack32, | ||||
|                                         vk::Format::eA8B8G8R8SrgbPack32, | ||||
|                                         vk::Format::eB5G6R5UnormPack16, | ||||
|                                         vk::Format::eA2B10G10R10UnormPack32, | ||||
|                                         vk::Format::eA1R5G5B5UnormPack16, | ||||
|                                         vk::Format::eR32G32B32A32Sfloat, | ||||
|                                         vk::Format::eR32G32B32A32Uint, | ||||
|                                         vk::Format::eR32G32Sfloat, | ||||
|                                         vk::Format::eR32G32Uint, | ||||
|                                         vk::Format::eR16G16B16A16Uint, | ||||
|                                         vk::Format::eR16G16B16A16Unorm, | ||||
|                                         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::eR8Uint, | ||||
|                                         vk::Format::eB10G11R11UfloatPack32, | ||||
|                                         vk::Format::eR32Sfloat, | ||||
|                                         vk::Format::eR32Uint, | ||||
|                                         vk::Format::eR16Sfloat, | ||||
|                                         vk::Format::eR16G16B16A16Sfloat, | ||||
|                                         vk::Format::eB8G8R8A8Unorm, | ||||
|                                         vk::Format::eR4G4B4A4UnormPack16, | ||||
|                                         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::eBc6HUfloatBlock, | ||||
|                                         vk::Format::eBc6HSfloatBlock, | ||||
|                                         vk::Format::eBc1RgbaSrgbBlock, | ||||
|                                         vk::Format::eBc3SrgbBlock, | ||||
|                                         vk::Format::eBc7SrgbBlock, | ||||
|                                         vk::Format::eAstc4x4SrgbBlock, | ||||
|                                         vk::Format::eAstc8x8SrgbBlock, | ||||
|                                         vk::Format::eAstc8x5SrgbBlock, | ||||
|                                         vk::Format::eAstc5x4SrgbBlock, | ||||
|                                         vk::Format::eAstc5x5UnormBlock, | ||||
|                                         vk::Format::eAstc5x5SrgbBlock, | ||||
|                                         vk::Format::eAstc10x8UnormBlock, | ||||
|                                         vk::Format::eAstc10x8SrgbBlock, | ||||
|                                         vk::Format::eAstc6x6UnormBlock, | ||||
|                                         vk::Format::eAstc6x6SrgbBlock, | ||||
|                                         vk::Format::eAstc10x10UnormBlock, | ||||
|                                         vk::Format::eAstc10x10SrgbBlock, | ||||
|                                         vk::Format::eAstc12x12UnormBlock, | ||||
|                                         vk::Format::eAstc12x12SrgbBlock, | ||||
|                                         vk::Format::eAstc8x6UnormBlock, | ||||
|                                         vk::Format::eAstc8x6SrgbBlock, | ||||
|                                         vk::Format::eAstc6x5UnormBlock, | ||||
|                                         vk::Format::eAstc6x5SrgbBlock, | ||||
|                                         vk::Format::eE5B9G9R9UfloatPack32}; | ||||
|     std::unordered_map<vk::Format, vk::FormatProperties> format_properties; | ||||
|     for (const auto format : formats) { | ||||
|         format_properties.emplace(format, physical.getFormatProperties(format, dldi)); | ||||
|   | ||||
| @@ -4,6 +4,8 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <string> | ||||
| #include <string_view> | ||||
| #include <unordered_map> | ||||
| #include <vector> | ||||
| #include "common/common_types.h" | ||||
| @@ -14,6 +16,9 @@ namespace Vulkan { | ||||
| /// Format usage descriptor. | ||||
| enum class FormatType { Linear, Optimal, Buffer }; | ||||
|  | ||||
| /// Subgroup size of the guest emulated hardware (Nvidia has 32 threads per subgroup). | ||||
| const u32 GuestWarpSize = 32; | ||||
|  | ||||
| /// Handles data specific to a physical device. | ||||
| class VKDevice final { | ||||
| public: | ||||
| @@ -71,7 +76,22 @@ public: | ||||
|  | ||||
|     /// Returns true if the device is integrated with the host CPU. | ||||
|     bool IsIntegrated() const { | ||||
|         return device_type == vk::PhysicalDeviceType::eIntegratedGpu; | ||||
|         return properties.deviceType == vk::PhysicalDeviceType::eIntegratedGpu; | ||||
|     } | ||||
|  | ||||
|     /// Returns the current Vulkan API version provided in Vulkan-formatted version numbers. | ||||
|     u32 GetApiVersion() const { | ||||
|         return properties.apiVersion; | ||||
|     } | ||||
|  | ||||
|     /// Returns the current driver version provided in Vulkan-formatted version numbers. | ||||
|     u32 GetDriverVersion() const { | ||||
|         return properties.driverVersion; | ||||
|     } | ||||
|  | ||||
|     /// Returns the device name. | ||||
|     std::string_view GetModelName() const { | ||||
|         return properties.deviceName; | ||||
|     } | ||||
|  | ||||
|     /// Returns the driver ID. | ||||
| @@ -80,18 +100,23 @@ public: | ||||
|     } | ||||
|  | ||||
|     /// Returns uniform buffer alignment requeriment. | ||||
|     u64 GetUniformBufferAlignment() const { | ||||
|         return uniform_buffer_alignment; | ||||
|     vk::DeviceSize GetUniformBufferAlignment() const { | ||||
|         return properties.limits.minUniformBufferOffsetAlignment; | ||||
|     } | ||||
|  | ||||
|     /// Returns storage alignment requeriment. | ||||
|     u64 GetStorageBufferAlignment() const { | ||||
|         return storage_buffer_alignment; | ||||
|     vk::DeviceSize GetStorageBufferAlignment() const { | ||||
|         return properties.limits.minStorageBufferOffsetAlignment; | ||||
|     } | ||||
|  | ||||
|     /// Returns the maximum range for storage buffers. | ||||
|     u64 GetMaxStorageBufferRange() const { | ||||
|         return max_storage_buffer_range; | ||||
|     vk::DeviceSize GetMaxStorageBufferRange() const { | ||||
|         return properties.limits.maxStorageBufferRange; | ||||
|     } | ||||
|  | ||||
|     /// Returns the maximum size for push constants. | ||||
|     vk::DeviceSize GetMaxPushConstantsSize() const { | ||||
|         return properties.limits.maxPushConstantsSize; | ||||
|     } | ||||
|  | ||||
|     /// Returns true if ASTC is natively supported. | ||||
| @@ -104,6 +129,16 @@ public: | ||||
|         return is_float16_supported; | ||||
|     } | ||||
|  | ||||
|     /// Returns true if the device warp size can potentially be bigger than guest's warp size. | ||||
|     bool IsWarpSizePotentiallyBiggerThanGuest() const { | ||||
|         return is_warp_potentially_bigger; | ||||
|     } | ||||
|  | ||||
|     /// Returns true if the device can be forced to use the guest warp size. | ||||
|     bool IsGuestWarpSizeSupported(vk::ShaderStageFlagBits stage) const { | ||||
|         return (guest_warp_stages & stage) != vk::ShaderStageFlags{}; | ||||
|     } | ||||
|  | ||||
|     /// Returns true if the device supports VK_EXT_scalar_block_layout. | ||||
|     bool IsKhrUniformBufferStandardLayoutSupported() const { | ||||
|         return khr_uniform_buffer_standard_layout; | ||||
| @@ -114,6 +149,26 @@ public: | ||||
|         return ext_index_type_uint8; | ||||
|     } | ||||
|  | ||||
|     /// Returns true if the device supports VK_EXT_depth_range_unrestricted. | ||||
|     bool IsExtDepthRangeUnrestrictedSupported() const { | ||||
|         return ext_depth_range_unrestricted; | ||||
|     } | ||||
|  | ||||
|     /// Returns true if the device supports VK_EXT_shader_viewport_index_layer. | ||||
|     bool IsExtShaderViewportIndexLayerSupported() const { | ||||
|         return ext_shader_viewport_index_layer; | ||||
|     } | ||||
|  | ||||
|     /// Returns the vendor name reported from Vulkan. | ||||
|     std::string_view GetVendorName() const { | ||||
|         return vendor_name; | ||||
|     } | ||||
|  | ||||
|     /// Returns the list of available extensions. | ||||
|     const std::vector<std::string>& GetAvailableExtensions() const { | ||||
|         return reported_extensions; | ||||
|     } | ||||
|  | ||||
|     /// Checks if the physical device is suitable. | ||||
|     static bool IsSuitable(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical, | ||||
|                            vk::SurfaceKHR surface); | ||||
| @@ -125,12 +180,12 @@ private: | ||||
|     /// Sets up queue families. | ||||
|     void SetupFamilies(const vk::DispatchLoaderDynamic& dldi, vk::SurfaceKHR surface); | ||||
|  | ||||
|     /// Sets up device properties. | ||||
|     void SetupProperties(const vk::DispatchLoaderDynamic& dldi); | ||||
|  | ||||
|     /// Sets up device features. | ||||
|     void SetupFeatures(const vk::DispatchLoaderDynamic& dldi); | ||||
|  | ||||
|     /// Collects telemetry information from the device. | ||||
|     void CollectTelemetryParameters(); | ||||
|  | ||||
|     /// Returns a list of queue initialization descriptors. | ||||
|     std::vector<vk::DeviceQueueCreateInfo> GetDeviceQueueCreateInfos() const; | ||||
|  | ||||
| @@ -148,23 +203,28 @@ private: | ||||
|  | ||||
|     const vk::PhysicalDevice physical;         ///< Physical device. | ||||
|     vk::DispatchLoaderDynamic dld;             ///< Device function pointers. | ||||
|     vk::PhysicalDeviceProperties properties;   ///< Device properties. | ||||
|     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. | ||||
|     vk::ShaderStageFlags guest_warp_stages{};  ///< Stages where the guest warp size can be forced. | ||||
|     bool is_optimal_astc_supported{};          ///< Support for native ASTC. | ||||
|     bool is_float16_supported{};               ///< Support for float16 arithmetics. | ||||
|     bool is_warp_potentially_bigger{};         ///< Host warp size can be bigger than guest. | ||||
|     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. | ||||
|     bool ext_depth_range_unrestricted{};       ///< Support for VK_EXT_depth_range_unrestricted. | ||||
|     bool ext_shader_viewport_index_layer{};    ///< Support for VK_EXT_shader_viewport_index_layer. | ||||
|  | ||||
|     // Telemetry parameters | ||||
|     std::string vendor_name;                      ///< Device's driver name. | ||||
|     std::vector<std::string> reported_extensions; ///< Reported Vulkan extensions. | ||||
|  | ||||
|     /// Format properties dictionary. | ||||
|     std::unordered_map<vk::Format, vk::FormatProperties> format_properties; | ||||
| }; | ||||
|  | ||||
| } // namespace Vulkan | ||||
|   | ||||
		Reference in New Issue
	
	Block a user