|
|
|
@ -10,6 +10,7 @@ |
|
|
|
#include <string_view>
|
|
|
|
#include <thread>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
#include "common/assert.h"
|
|
|
|
#include "core/settings.h"
|
|
|
|
#include "video_core/renderer_vulkan/declarations.h"
|
|
|
|
@ -35,20 +36,20 @@ void SetNext(void**& next, T& data) { |
|
|
|
} |
|
|
|
|
|
|
|
template <typename T> |
|
|
|
T GetFeatures(vk::PhysicalDevice physical, const vk::DispatchLoaderDynamic& dldi) { |
|
|
|
T GetFeatures(vk::PhysicalDevice physical, const vk::DispatchLoaderDynamic& dld) { |
|
|
|
vk::PhysicalDeviceFeatures2 features; |
|
|
|
T extension_features; |
|
|
|
features.pNext = &extension_features; |
|
|
|
physical.getFeatures2(&features, dldi); |
|
|
|
physical.getFeatures2(&features, dld); |
|
|
|
return extension_features; |
|
|
|
} |
|
|
|
|
|
|
|
template <typename T> |
|
|
|
T GetProperties(vk::PhysicalDevice physical, const vk::DispatchLoaderDynamic& dldi) { |
|
|
|
T GetProperties(vk::PhysicalDevice physical, const vk::DispatchLoaderDynamic& dld) { |
|
|
|
vk::PhysicalDeviceProperties2 properties; |
|
|
|
T extension_properties; |
|
|
|
properties.pNext = &extension_properties; |
|
|
|
physical.getProperties2(&properties, dldi); |
|
|
|
physical.getProperties2(&properties, dld); |
|
|
|
return extension_properties; |
|
|
|
} |
|
|
|
|
|
|
|
@ -78,19 +79,19 @@ vk::FormatFeatureFlags GetFormatFeatures(vk::FormatProperties properties, Format |
|
|
|
|
|
|
|
} // Anonymous namespace
|
|
|
|
|
|
|
|
VKDevice::VKDevice(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical, |
|
|
|
VKDevice::VKDevice(const vk::DispatchLoaderDynamic& dld, vk::PhysicalDevice physical, |
|
|
|
vk::SurfaceKHR surface) |
|
|
|
: physical{physical}, properties{physical.getProperties(dldi)}, |
|
|
|
format_properties{GetFormatProperties(dldi, physical)} { |
|
|
|
SetupFamilies(dldi, surface); |
|
|
|
SetupFeatures(dldi); |
|
|
|
: dld{dld}, physical{physical}, properties{physical.getProperties(dld)}, |
|
|
|
format_properties{GetFormatProperties(dld, physical)} { |
|
|
|
SetupFamilies(surface); |
|
|
|
SetupFeatures(); |
|
|
|
} |
|
|
|
|
|
|
|
VKDevice::~VKDevice() = default; |
|
|
|
|
|
|
|
bool VKDevice::Create(const vk::DispatchLoaderDynamic& dldi, vk::Instance instance) { |
|
|
|
bool VKDevice::Create(vk::Instance instance) { |
|
|
|
const auto queue_cis = GetDeviceQueueCreateInfos(); |
|
|
|
const std::vector extensions = LoadExtensions(dldi); |
|
|
|
const std::vector extensions = LoadExtensions(); |
|
|
|
|
|
|
|
vk::PhysicalDeviceFeatures2 features2; |
|
|
|
void** next = &features2.pNext; |
|
|
|
@ -165,15 +166,13 @@ bool VKDevice::Create(const vk::DispatchLoaderDynamic& dldi, vk::Instance instan |
|
|
|
nullptr); |
|
|
|
device_ci.pNext = &features2; |
|
|
|
|
|
|
|
vk::Device dummy_logical; |
|
|
|
if (physical.createDevice(&device_ci, nullptr, &dummy_logical, dldi) != vk::Result::eSuccess) { |
|
|
|
vk::Device unsafe_logical; |
|
|
|
if (physical.createDevice(&device_ci, nullptr, &unsafe_logical, dld) != vk::Result::eSuccess) { |
|
|
|
LOG_CRITICAL(Render_Vulkan, "Logical device failed to be created!"); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
dld.init(instance, dldi.vkGetInstanceProcAddr, dummy_logical, dldi.vkGetDeviceProcAddr); |
|
|
|
logical = UniqueDevice( |
|
|
|
dummy_logical, vk::ObjectDestroy<vk::NoParent, vk::DispatchLoaderDynamic>(nullptr, dld)); |
|
|
|
dld.init(instance, dld.vkGetInstanceProcAddr, unsafe_logical); |
|
|
|
logical = UniqueDevice(unsafe_logical, {nullptr, dld}); |
|
|
|
|
|
|
|
CollectTelemetryParameters(); |
|
|
|
|
|
|
|
@ -235,8 +234,8 @@ void VKDevice::ReportLoss() const { |
|
|
|
// *(VKGraphicsPipeline*)data[0]
|
|
|
|
} |
|
|
|
|
|
|
|
bool VKDevice::IsOptimalAstcSupported(const vk::PhysicalDeviceFeatures& features, |
|
|
|
const vk::DispatchLoaderDynamic& dldi) const { |
|
|
|
bool VKDevice::IsOptimalAstcSupported(const vk::PhysicalDeviceFeatures& features) const { |
|
|
|
// Disable for now to avoid converting ASTC twice.
|
|
|
|
static constexpr std::array astc_formats = { |
|
|
|
vk::Format::eAstc4x4UnormBlock, vk::Format::eAstc4x4SrgbBlock, |
|
|
|
vk::Format::eAstc5x4UnormBlock, vk::Format::eAstc5x4SrgbBlock, |
|
|
|
@ -260,7 +259,7 @@ bool VKDevice::IsOptimalAstcSupported(const vk::PhysicalDeviceFeatures& features |
|
|
|
vk::FormatFeatureFlagBits::eBlitDst | vk::FormatFeatureFlagBits::eTransferSrc | |
|
|
|
vk::FormatFeatureFlagBits::eTransferDst}; |
|
|
|
for (const auto format : astc_formats) { |
|
|
|
const auto format_properties{physical.getFormatProperties(format, dldi)}; |
|
|
|
const auto format_properties{physical.getFormatProperties(format, dld)}; |
|
|
|
if (!(format_properties.optimalTilingFeatures & format_feature_usage)) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
@ -279,11 +278,9 @@ bool VKDevice::IsFormatSupported(vk::Format wanted_format, vk::FormatFeatureFlag |
|
|
|
return (supported_usage & wanted_usage) == wanted_usage; |
|
|
|
} |
|
|
|
|
|
|
|
bool VKDevice::IsSuitable(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical, |
|
|
|
vk::SurfaceKHR surface) { |
|
|
|
bool is_suitable = true; |
|
|
|
|
|
|
|
constexpr std::array required_extensions = { |
|
|
|
bool VKDevice::IsSuitable(vk::PhysicalDevice physical, vk::SurfaceKHR surface, |
|
|
|
const vk::DispatchLoaderDynamic& dld) { |
|
|
|
static constexpr std::array required_extensions = { |
|
|
|
VK_KHR_SWAPCHAIN_EXTENSION_NAME, |
|
|
|
VK_KHR_16BIT_STORAGE_EXTENSION_NAME, |
|
|
|
VK_KHR_8BIT_STORAGE_EXTENSION_NAME, |
|
|
|
@ -293,9 +290,10 @@ bool VKDevice::IsSuitable(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDev |
|
|
|
VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME, |
|
|
|
VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME, |
|
|
|
}; |
|
|
|
bool is_suitable = true; |
|
|
|
std::bitset<required_extensions.size()> available_extensions{}; |
|
|
|
|
|
|
|
for (const auto& prop : physical.enumerateDeviceExtensionProperties(nullptr, dldi)) { |
|
|
|
for (const auto& prop : physical.enumerateDeviceExtensionProperties(nullptr, dld)) { |
|
|
|
for (std::size_t i = 0; i < required_extensions.size(); ++i) { |
|
|
|
if (available_extensions[i]) { |
|
|
|
continue; |
|
|
|
@ -315,7 +313,7 @@ bool VKDevice::IsSuitable(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDev |
|
|
|
} |
|
|
|
|
|
|
|
bool has_graphics{}, has_present{}; |
|
|
|
const auto queue_family_properties = physical.getQueueFamilyProperties(dldi); |
|
|
|
const auto queue_family_properties = physical.getQueueFamilyProperties(dld); |
|
|
|
for (u32 i = 0; i < static_cast<u32>(queue_family_properties.size()); ++i) { |
|
|
|
const auto& family = queue_family_properties[i]; |
|
|
|
if (family.queueCount == 0) { |
|
|
|
@ -323,7 +321,7 @@ bool VKDevice::IsSuitable(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDev |
|
|
|
} |
|
|
|
has_graphics |= |
|
|
|
(family.queueFlags & vk::QueueFlagBits::eGraphics) != static_cast<vk::QueueFlagBits>(0); |
|
|
|
has_present |= physical.getSurfaceSupportKHR(i, surface, dldi) != 0; |
|
|
|
has_present |= physical.getSurfaceSupportKHR(i, surface, dld) != 0; |
|
|
|
} |
|
|
|
if (!has_graphics || !has_present) { |
|
|
|
LOG_ERROR(Render_Vulkan, "Device lacks a graphics and present queue"); |
|
|
|
@ -331,7 +329,7 @@ bool VKDevice::IsSuitable(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDev |
|
|
|
} |
|
|
|
|
|
|
|
// TODO(Rodrigo): Check if the device matches all requeriments.
|
|
|
|
const auto properties{physical.getProperties(dldi)}; |
|
|
|
const auto properties{physical.getProperties(dld)}; |
|
|
|
const auto& limits{properties.limits}; |
|
|
|
|
|
|
|
constexpr u32 required_ubo_size = 65536; |
|
|
|
@ -348,7 +346,7 @@ bool VKDevice::IsSuitable(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDev |
|
|
|
is_suitable = false; |
|
|
|
} |
|
|
|
|
|
|
|
const auto features{physical.getFeatures(dldi)}; |
|
|
|
const auto features{physical.getFeatures(dld)}; |
|
|
|
const std::array feature_report = { |
|
|
|
std::make_pair(features.vertexPipelineStoresAndAtomics, "vertexPipelineStoresAndAtomics"), |
|
|
|
std::make_pair(features.independentBlend, "independentBlend"), |
|
|
|
@ -380,7 +378,7 @@ bool VKDevice::IsSuitable(const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDev |
|
|
|
return is_suitable; |
|
|
|
} |
|
|
|
|
|
|
|
std::vector<const char*> VKDevice::LoadExtensions(const vk::DispatchLoaderDynamic& dldi) { |
|
|
|
std::vector<const char*> VKDevice::LoadExtensions() { |
|
|
|
std::vector<const char*> extensions; |
|
|
|
const auto Test = [&](const vk::ExtensionProperties& extension, |
|
|
|
std::optional<std::reference_wrapper<bool>> status, const char* name, |
|
|
|
@ -411,7 +409,7 @@ std::vector<const char*> VKDevice::LoadExtensions(const vk::DispatchLoaderDynami |
|
|
|
bool has_khr_shader_float16_int8{}; |
|
|
|
bool has_ext_subgroup_size_control{}; |
|
|
|
bool has_ext_transform_feedback{}; |
|
|
|
for (const auto& extension : physical.enumerateDeviceExtensionProperties(nullptr, dldi)) { |
|
|
|
for (const auto& extension : physical.enumerateDeviceExtensionProperties(nullptr, dld)) { |
|
|
|
Test(extension, khr_uniform_buffer_standard_layout, |
|
|
|
VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_EXTENSION_NAME, true); |
|
|
|
Test(extension, has_khr_shader_float16_int8, VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, |
|
|
|
@ -433,15 +431,15 @@ std::vector<const char*> VKDevice::LoadExtensions(const vk::DispatchLoaderDynami |
|
|
|
|
|
|
|
if (has_khr_shader_float16_int8) { |
|
|
|
is_float16_supported = |
|
|
|
GetFeatures<vk::PhysicalDeviceFloat16Int8FeaturesKHR>(physical, dldi).shaderFloat16; |
|
|
|
GetFeatures<vk::PhysicalDeviceFloat16Int8FeaturesKHR>(physical, dld).shaderFloat16; |
|
|
|
extensions.push_back(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME); |
|
|
|
} |
|
|
|
|
|
|
|
if (has_ext_subgroup_size_control) { |
|
|
|
const auto features = |
|
|
|
GetFeatures<vk::PhysicalDeviceSubgroupSizeControlFeaturesEXT>(physical, dldi); |
|
|
|
GetFeatures<vk::PhysicalDeviceSubgroupSizeControlFeaturesEXT>(physical, dld); |
|
|
|
const auto properties = |
|
|
|
GetProperties<vk::PhysicalDeviceSubgroupSizeControlPropertiesEXT>(physical, dldi); |
|
|
|
GetProperties<vk::PhysicalDeviceSubgroupSizeControlPropertiesEXT>(physical, dld); |
|
|
|
|
|
|
|
is_warp_potentially_bigger = properties.maxSubgroupSize > GuestWarpSize; |
|
|
|
|
|
|
|
@ -456,9 +454,9 @@ std::vector<const char*> VKDevice::LoadExtensions(const vk::DispatchLoaderDynami |
|
|
|
|
|
|
|
if (has_ext_transform_feedback) { |
|
|
|
const auto features = |
|
|
|
GetFeatures<vk::PhysicalDeviceTransformFeedbackFeaturesEXT>(physical, dldi); |
|
|
|
GetFeatures<vk::PhysicalDeviceTransformFeedbackFeaturesEXT>(physical, dld); |
|
|
|
const auto properties = |
|
|
|
GetProperties<vk::PhysicalDeviceTransformFeedbackPropertiesEXT>(physical, dldi); |
|
|
|
GetProperties<vk::PhysicalDeviceTransformFeedbackPropertiesEXT>(physical, dld); |
|
|
|
|
|
|
|
if (features.transformFeedback && features.geometryStreams && |
|
|
|
properties.maxTransformFeedbackStreams >= 4 && properties.maxTransformFeedbackBuffers && |
|
|
|
@ -471,10 +469,10 @@ std::vector<const char*> VKDevice::LoadExtensions(const vk::DispatchLoaderDynami |
|
|
|
return extensions; |
|
|
|
} |
|
|
|
|
|
|
|
void VKDevice::SetupFamilies(const vk::DispatchLoaderDynamic& dldi, vk::SurfaceKHR surface) { |
|
|
|
void VKDevice::SetupFamilies(vk::SurfaceKHR surface) { |
|
|
|
std::optional<u32> graphics_family_, present_family_; |
|
|
|
|
|
|
|
const auto queue_family_properties = physical.getQueueFamilyProperties(dldi); |
|
|
|
const auto queue_family_properties = physical.getQueueFamilyProperties(dld); |
|
|
|
for (u32 i = 0; i < static_cast<u32>(queue_family_properties.size()); ++i) { |
|
|
|
if (graphics_family_ && present_family_) |
|
|
|
break; |
|
|
|
@ -483,10 +481,12 @@ void VKDevice::SetupFamilies(const vk::DispatchLoaderDynamic& dldi, vk::SurfaceK |
|
|
|
if (queue_family.queueCount == 0) |
|
|
|
continue; |
|
|
|
|
|
|
|
if (queue_family.queueFlags & vk::QueueFlagBits::eGraphics) |
|
|
|
if (queue_family.queueFlags & vk::QueueFlagBits::eGraphics) { |
|
|
|
graphics_family_ = i; |
|
|
|
if (physical.getSurfaceSupportKHR(i, surface, dldi)) |
|
|
|
} |
|
|
|
if (physical.getSurfaceSupportKHR(i, surface, dld)) { |
|
|
|
present_family_ = i; |
|
|
|
} |
|
|
|
} |
|
|
|
ASSERT(graphics_family_ && present_family_); |
|
|
|
|
|
|
|
@ -494,10 +494,10 @@ void VKDevice::SetupFamilies(const vk::DispatchLoaderDynamic& dldi, vk::SurfaceK |
|
|
|
present_family = *present_family_; |
|
|
|
} |
|
|
|
|
|
|
|
void VKDevice::SetupFeatures(const vk::DispatchLoaderDynamic& dldi) { |
|
|
|
const auto supported_features{physical.getFeatures(dldi)}; |
|
|
|
void VKDevice::SetupFeatures() { |
|
|
|
const auto supported_features{physical.getFeatures(dld)}; |
|
|
|
is_formatless_image_load_supported = supported_features.shaderStorageImageReadWithoutFormat; |
|
|
|
is_optimal_astc_supported = IsOptimalAstcSupported(supported_features, dldi); |
|
|
|
is_optimal_astc_supported = IsOptimalAstcSupported(supported_features); |
|
|
|
} |
|
|
|
|
|
|
|
void VKDevice::CollectTelemetryParameters() { |
|
|
|
@ -525,7 +525,7 @@ std::vector<vk::DeviceQueueCreateInfo> VKDevice::GetDeviceQueueCreateInfos() con |
|
|
|
} |
|
|
|
|
|
|
|
std::unordered_map<vk::Format, vk::FormatProperties> VKDevice::GetFormatProperties( |
|
|
|
const vk::DispatchLoaderDynamic& dldi, vk::PhysicalDevice physical) { |
|
|
|
const vk::DispatchLoaderDynamic& dld, vk::PhysicalDevice physical) { |
|
|
|
static constexpr std::array formats{vk::Format::eA8B8G8R8UnormPack32, |
|
|
|
vk::Format::eA8B8G8R8UintPack32, |
|
|
|
vk::Format::eA8B8G8R8SnormPack32, |
|
|
|
@ -606,7 +606,7 @@ std::unordered_map<vk::Format, vk::FormatProperties> VKDevice::GetFormatProperti |
|
|
|
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)); |
|
|
|
format_properties.emplace(format, physical.getFormatProperties(format, dld)); |
|
|
|
} |
|
|
|
return format_properties; |
|
|
|
} |
|
|
|
|