Vulkan: update initialization

Co-authored-by: bylaws <bylaws@users.noreply.github.com>
This commit is contained in:
Liam 2022-11-22 19:14:46 -05:00
parent 168c9ee341
commit 2956a33463
15 changed files with 194 additions and 104 deletions

View file

@ -74,23 +74,14 @@ enum class NvidiaArchitecture {
};
constexpr std::array REQUIRED_EXTENSIONS{
VK_KHR_MAINTENANCE1_EXTENSION_NAME,
VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME,
VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME,
VK_KHR_16BIT_STORAGE_EXTENSION_NAME,
VK_KHR_8BIT_STORAGE_EXTENSION_NAME,
VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME,
VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME,
VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME,
VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME,
VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME,
VK_KHR_VARIABLE_POINTERS_EXTENSION_NAME,
VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME,
VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME,
VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME,
VK_EXT_ROBUSTNESS_2_EXTENSION_NAME,
// Core in 1.2, but required due to use of extension methods,
// and well-supported by drivers
VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME,
VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME,
VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME,
VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME,
#ifdef _WIN32
VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME,
#endif
@ -99,6 +90,17 @@ constexpr std::array REQUIRED_EXTENSIONS{
#endif
};
constexpr std::array REQUIRED_EXTENSIONS_BEFORE_1_2{
VK_KHR_8BIT_STORAGE_EXTENSION_NAME,
VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME,
VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME,
VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME,
};
constexpr std::array REQUIRED_EXTENSIONS_BEFORE_1_3{
VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME,
};
template <typename T>
void SetNext(void**& next, T& data) {
*next = &data;
@ -327,7 +329,8 @@ NvidiaArchitecture GetNvidiaArchitecture(vk::PhysicalDevice physical,
Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR surface,
const vk::InstanceDispatch& dld_)
: instance{instance_}, dld{dld_}, physical{physical_}, properties{physical.GetProperties()},
supported_extensions{GetSupportedExtensions(physical)},
instance_version{properties.apiVersion}, supported_extensions{GetSupportedExtensions(
physical)},
format_properties(GetFormatProperties(physical)) {
CheckSuitability(surface != nullptr);
SetupFamilies(surface);
@ -451,8 +454,8 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
};
SetNext(next, variable_pointers);
VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT demote{
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT,
VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures demote{
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES,
.pNext = nullptr,
.shaderDemoteToHelperInvocation = true,
};
@ -896,28 +899,51 @@ std::string Device::GetDriverName() const {
}
}
static std::vector<const char*> ExtensionsRequiredForInstanceVersion(u32 available_version) {
std::vector<const char*> extensions{REQUIRED_EXTENSIONS.begin(), REQUIRED_EXTENSIONS.end()};
if (available_version < VK_API_VERSION_1_2) {
extensions.insert(extensions.end(), REQUIRED_EXTENSIONS_BEFORE_1_2.begin(),
REQUIRED_EXTENSIONS_BEFORE_1_2.end());
}
if (available_version < VK_API_VERSION_1_3) {
extensions.insert(extensions.end(), REQUIRED_EXTENSIONS_BEFORE_1_3.begin(),
REQUIRED_EXTENSIONS_BEFORE_1_3.end());
}
return extensions;
}
void Device::CheckSuitability(bool requires_swapchain) const {
std::bitset<REQUIRED_EXTENSIONS.size()> available_extensions;
bool has_swapchain = false;
for (const VkExtensionProperties& property : physical.EnumerateDeviceExtensionProperties()) {
const std::string_view name{property.extensionName};
for (size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) {
if (available_extensions[i]) {
continue;
}
available_extensions[i] = name == REQUIRED_EXTENSIONS[i];
}
has_swapchain = has_swapchain || name == VK_KHR_SWAPCHAIN_EXTENSION_NAME;
std::vector<const char*> required_extensions =
ExtensionsRequiredForInstanceVersion(instance_version);
std::vector<const char*> available_extensions;
if (requires_swapchain) {
required_extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
}
for (size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) {
if (available_extensions[i]) {
continue;
}
LOG_ERROR(Render_Vulkan, "Missing required extension: {}", REQUIRED_EXTENSIONS[i]);
throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT);
auto extension_properties = physical.EnumerateDeviceExtensionProperties();
for (const VkExtensionProperties& property : extension_properties) {
available_extensions.push_back(property.extensionName);
}
if (requires_swapchain && !has_swapchain) {
LOG_ERROR(Render_Vulkan, "Missing required extension: VK_KHR_swapchain");
bool has_all_required_extensions = true;
for (const char* requirement_name : required_extensions) {
const bool found =
std::ranges::any_of(available_extensions, [&](const char* extension_name) {
return std::strcmp(requirement_name, extension_name) == 0;
});
if (!found) {
LOG_ERROR(Render_Vulkan, "Missing required extension: {}", requirement_name);
has_all_required_extensions = false;
}
}
if (!has_all_required_extensions) {
throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT);
}
@ -940,9 +966,8 @@ void Device::CheckSuitability(bool requires_swapchain) const {
throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT);
}
}
VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT demote{};
demote.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT;
VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures demote{};
demote.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES;
demote.pNext = nullptr;
VkPhysicalDeviceVariablePointerFeaturesKHR variable_pointers{};
@ -960,7 +985,7 @@ void Device::CheckSuitability(bool requires_swapchain) const {
physical.GetFeatures2KHR(features2);
const VkPhysicalDeviceFeatures& features{features2.features};
const std::array feature_report{
std::vector feature_report{
std::make_pair(features.robustBufferAccess, "robustBufferAccess"),
std::make_pair(features.vertexPipelineStoresAndAtomics, "vertexPipelineStoresAndAtomics"),
std::make_pair(features.imageCubeArray, "imageCubeArray"),
@ -983,27 +1008,30 @@ void Device::CheckSuitability(bool requires_swapchain) const {
"shaderStorageImageWriteWithoutFormat"),
std::make_pair(features.shaderClipDistance, "shaderClipDistance"),
std::make_pair(features.shaderCullDistance, "shaderCullDistance"),
std::make_pair(demote.shaderDemoteToHelperInvocation, "shaderDemoteToHelperInvocation"),
std::make_pair(variable_pointers.variablePointers, "variablePointers"),
std::make_pair(variable_pointers.variablePointersStorageBuffer,
"variablePointersStorageBuffer"),
std::make_pair(robustness2.robustBufferAccess2, "robustBufferAccess2"),
std::make_pair(robustness2.robustImageAccess2, "robustImageAccess2"),
std::make_pair(robustness2.nullDescriptor, "nullDescriptor"),
std::make_pair(demote.shaderDemoteToHelperInvocation, "shaderDemoteToHelperInvocation"),
};
bool has_all_required_features = true;
for (const auto& [is_supported, name] : feature_report) {
if (is_supported) {
continue;
if (!is_supported) {
LOG_ERROR(Render_Vulkan, "Missing required feature: {}", name);
has_all_required_features = false;
}
LOG_ERROR(Render_Vulkan, "Missing required feature: {}", name);
}
if (!has_all_required_features) {
throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT);
}
}
std::vector<const char*> Device::LoadExtensions(bool requires_surface) {
std::vector<const char*> extensions;
extensions.reserve(8 + REQUIRED_EXTENSIONS.size());
extensions.insert(extensions.begin(), REQUIRED_EXTENSIONS.begin(), REQUIRED_EXTENSIONS.end());
std::vector<const char*> extensions = ExtensionsRequiredForInstanceVersion(instance_version);
if (requires_surface) {
extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
}

View file

@ -211,11 +211,6 @@ public:
return khr_uniform_buffer_standard_layout;
}
/// Returns true if the device supports VK_KHR_spirv_1_4.
bool IsKhrSpirv1_4Supported() const {
return khr_spirv_1_4;
}
/// Returns true if the device supports VK_KHR_push_descriptor.
bool IsKhrPushDescriptorSupported() const {
return khr_push_descriptor;
@ -316,6 +311,17 @@ public:
return ext_shader_atomic_int64;
}
/// Returns the minimum supported version of SPIR-V.
u32 SupportedSpirvVersion() const {
if (instance_version >= VK_API_VERSION_1_3) {
return 0x00010600U;
}
if (khr_spirv_1_4) {
return 0x00010400U;
}
return 0x00010000U;
}
/// Returns true when a known debugging tool is attached.
bool HasDebuggingToolAttached() const {
return has_renderdoc || has_nsight_graphics;

View file

@ -14,13 +14,15 @@
#include "video_core/vulkan_common/vulkan_wrapper.h"
// Include these late to avoid polluting previous headers
#ifdef _WIN32
#if defined(_WIN32)
#include <windows.h>
// ensure include order
#include <vulkan/vulkan_win32.h>
#endif
#if !defined(_WIN32) && !defined(__APPLE__)
#elif defined(__APPLE__)
#include <vulkan/vulkan_macos.h>
#elif defined(__ANDROID__)
#include <vulkan/vulkan_android.h>
#else
#include <X11/Xlib.h>
#include <vulkan/vulkan_wayland.h>
#include <vulkan/vulkan_xlib.h>
@ -39,8 +41,15 @@ namespace {
case Core::Frontend::WindowSystemType::Windows:
extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
break;
#endif
#if !defined(_WIN32) && !defined(__APPLE__)
#elif defined(__APPLE__)
case Core::Frontend::WindowSystemType::Cocoa:
extensions.push_back(VK_MVK_MACOS_SURFACE_EXTENSION_NAME);
break;
#elif defined(__ANDROID__)
case Core::Frontend::WindowSystemType::Android:
extensions.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
break;
#else
case Core::Frontend::WindowSystemType::X11:
extensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
break;
@ -59,6 +68,10 @@ namespace {
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
}
extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
#ifdef __APPLE__
extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
#endif
return extensions;
}
@ -140,7 +153,7 @@ vk::Instance CreateInstance(const Common::DynamicLibrary& library, vk::InstanceD
}
vk::Instance instance =
std::async([&] {
return vk::Instance::Create(required_version, layers, extensions, dld);
return vk::Instance::Create(available_version, layers, extensions, dld);
}).get();
if (!vk::Load(*instance, dld)) {
LOG_ERROR(Render_Vulkan, "Failed to load Vulkan instance function pointers");

View file

@ -11,9 +11,11 @@
#include <windows.h>
// ensure include order
#include <vulkan/vulkan_win32.h>
#endif
#if !defined(_WIN32) && !defined(__APPLE__)
#elif defined(__APPLE__)
#include <vulkan/vulkan_macos.h>
#elif defined(__ANDROID__)
#include <vulkan/vulkan_android.h>
#else
#include <X11/Xlib.h>
#include <vulkan/vulkan_wayland.h>
#include <vulkan/vulkan_xlib.h>
@ -40,8 +42,33 @@ vk::SurfaceKHR CreateSurface(const vk::Instance& instance,
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
}
}
#endif
#if !defined(_WIN32) && !defined(__APPLE__)
#elif defined(__APPLE__)
if (window_info.type == Core::Frontend::WindowSystemType::Cocoa) {
const VkMacOSSurfaceCreateInfoMVK mvk_ci{VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK,
nullptr, 0, window_info.render_surface};
const auto vkCreateMacOSSurfaceMVK = reinterpret_cast<PFN_vkCreateMacOSSurfaceMVK>(
dld.vkGetInstanceProcAddr(*instance, "vkCreateMacOSSurfaceMVK"));
if (!vkCreateMacOSSurfaceMVK ||
vkCreateMacOSSurfaceMVK(*instance, &mvk_ci, nullptr, &unsafe_surface) != VK_SUCCESS) {
LOG_ERROR(Render_Vulkan, "Failed to initialize Metal surface");
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
}
}
#elif defined(__ANDROID__)
if (window_info.type == Core::Frontend::WindowSystemType::Android) {
const VkAndroidSurfaceCreateInfoKHR android_ci{
VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR, nullptr, 0,
reinterpret_cast<ANativeWindow*>(window_info.render_surface)};
const auto vkCreateAndroidSurfaceKHR = reinterpret_cast<PFN_vkCreateAndroidSurfaceKHR>(
dld.vkGetInstanceProcAddr(*instance, "vkCreateAndroidSurfaceKHR"));
if (!vkCreateAndroidSurfaceKHR ||
vkCreateAndroidSurfaceKHR(*instance, &android_ci, nullptr, &unsafe_surface) !=
VK_SUCCESS) {
LOG_ERROR(Render_Vulkan, "Failed to initialize Android surface");
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
}
}
#else
if (window_info.type == Core::Frontend::WindowSystemType::X11) {
const VkXlibSurfaceCreateInfoKHR xlib_ci{
VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, nullptr, 0,
@ -70,6 +97,7 @@ vk::SurfaceKHR CreateSurface(const vk::Instance& instance,
}
}
#endif
if (!unsafe_surface) {
LOG_ERROR(Render_Vulkan, "Presentation not supported on this platform");
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);