Merge pull request #4204 from ReinUsesLisp/vulkan-1.0

renderer_vulkan: Create and properly use Vulkan 1.0 instances when 1.1 is not available
This commit is contained in:
bunnei 2020-10-19 14:18:54 -07:00 committed by GitHub
commit f1ead11df7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 92 additions and 58 deletions

View file

@ -92,9 +92,9 @@ Common::DynamicLibrary OpenVulkanLibrary() {
return library; return library;
} }
vk::Instance CreateInstance(Common::DynamicLibrary& library, vk::InstanceDispatch& dld, std::pair<vk::Instance, u32> CreateInstance(
WindowSystemType window_type = WindowSystemType::Headless, Common::DynamicLibrary& library, vk::InstanceDispatch& dld,
bool enable_layers = false) { WindowSystemType window_type = WindowSystemType::Headless, bool enable_layers = false) {
if (!library.IsOpen()) { if (!library.IsOpen()) {
LOG_ERROR(Render_Vulkan, "Vulkan library not available"); LOG_ERROR(Render_Vulkan, "Vulkan library not available");
return {}; return {};
@ -180,7 +180,10 @@ vk::Instance CreateInstance(Common::DynamicLibrary& library, vk::InstanceDispatc
} }
} }
vk::Instance instance = vk::Instance::Create(layers, extensions, dld); // Limit the maximum version of Vulkan to avoid using untested version.
const u32 version = std::min(vk::AvailableVersion(dld), static_cast<u32>(VK_API_VERSION_1_1));
vk::Instance instance = vk::Instance::Create(version, layers, extensions, dld);
if (!instance) { if (!instance) {
LOG_ERROR(Render_Vulkan, "Failed to create Vulkan instance"); LOG_ERROR(Render_Vulkan, "Failed to create Vulkan instance");
return {}; return {};
@ -188,7 +191,7 @@ vk::Instance CreateInstance(Common::DynamicLibrary& library, vk::InstanceDispatc
if (!vk::Load(*instance, dld)) { if (!vk::Load(*instance, dld)) {
LOG_ERROR(Render_Vulkan, "Failed to load Vulkan instance function pointers"); LOG_ERROR(Render_Vulkan, "Failed to load Vulkan instance function pointers");
} }
return instance; return std::make_pair(std::move(instance), version);
} }
std::string GetReadableVersion(u32 version) { std::string GetReadableVersion(u32 version) {
@ -285,8 +288,8 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
bool RendererVulkan::Init() { bool RendererVulkan::Init() {
library = OpenVulkanLibrary(); library = OpenVulkanLibrary();
instance = CreateInstance(library, dld, render_window.GetWindowInfo().type, std::tie(instance, instance_version) = CreateInstance(
Settings::values.renderer_debug); library, dld, render_window.GetWindowInfo().type, Settings::values.renderer_debug);
if (!instance || !CreateDebugCallback() || !CreateSurface() || !PickDevices()) { if (!instance || !CreateDebugCallback() || !CreateSurface() || !PickDevices()) {
return false; return false;
} }
@ -416,7 +419,8 @@ bool RendererVulkan::PickDevices() {
return false; return false;
} }
device = std::make_unique<VKDevice>(*instance, physical_device, *surface, dld); device =
std::make_unique<VKDevice>(*instance, instance_version, physical_device, *surface, dld);
return device->Create(); return device->Create();
} }
@ -426,7 +430,7 @@ void RendererVulkan::Report() const {
const std::string driver_version = GetDriverVersion(*device); const std::string driver_version = GetDriverVersion(*device);
const std::string driver_name = fmt::format("{} {}", vendor_name, driver_version); const std::string driver_name = fmt::format("{} {}", vendor_name, driver_version);
const std::string api_version = GetReadableVersion(device->GetApiVersion()); const std::string api_version = GetReadableVersion(device->ApiVersion());
const std::string extensions = BuildCommaSeparatedExtensions(device->GetAvailableExtensions()); const std::string extensions = BuildCommaSeparatedExtensions(device->GetAvailableExtensions());
@ -445,7 +449,7 @@ void RendererVulkan::Report() const {
std::vector<std::string> RendererVulkan::EnumerateDevices() { std::vector<std::string> RendererVulkan::EnumerateDevices() {
vk::InstanceDispatch dld; vk::InstanceDispatch dld;
Common::DynamicLibrary library = OpenVulkanLibrary(); Common::DynamicLibrary library = OpenVulkanLibrary();
vk::Instance instance = CreateInstance(library, dld); vk::Instance instance = CreateInstance(library, dld).first;
if (!instance) { if (!instance) {
return {}; return {};
} }

View file

@ -73,6 +73,8 @@ private:
vk::InstanceDispatch dld; vk::InstanceDispatch dld;
vk::Instance instance; vk::Instance instance;
u32 instance_version{};
vk::SurfaceKHR surface; vk::SurfaceKHR surface;
VKScreenInfo screen_info; VKScreenInfo screen_info;

View file

@ -38,6 +38,9 @@ constexpr std::array Depth16UnormS8_UINT{
constexpr std::array REQUIRED_EXTENSIONS{ constexpr std::array REQUIRED_EXTENSIONS{
VK_KHR_SWAPCHAIN_EXTENSION_NAME, VK_KHR_SWAPCHAIN_EXTENSION_NAME,
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_16BIT_STORAGE_EXTENSION_NAME,
VK_KHR_8BIT_STORAGE_EXTENSION_NAME, VK_KHR_8BIT_STORAGE_EXTENSION_NAME,
VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME,
@ -187,10 +190,10 @@ std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties(
} // Anonymous namespace } // Anonymous namespace
VKDevice::VKDevice(VkInstance instance, vk::PhysicalDevice physical, VkSurfaceKHR surface, VKDevice::VKDevice(VkInstance instance_, u32 instance_version_, vk::PhysicalDevice physical_,
const vk::InstanceDispatch& dld) VkSurfaceKHR surface, const vk::InstanceDispatch& dld_)
: dld{dld}, physical{physical}, properties{physical.GetProperties()}, : dld{dld_}, physical{physical_}, properties{physical.GetProperties()},
format_properties{GetFormatProperties(physical, dld)} { instance_version{instance_version_}, format_properties{GetFormatProperties(physical, dld)} {
SetupFamilies(surface); SetupFamilies(surface);
SetupFeatures(); SetupFeatures();
} }
@ -597,8 +600,16 @@ bool VKDevice::IsSuitable(vk::PhysicalDevice physical, VkSurfaceKHR surface) {
std::vector<const char*> VKDevice::LoadExtensions() { std::vector<const char*> VKDevice::LoadExtensions() {
std::vector<const char*> extensions; std::vector<const char*> extensions;
const auto Test = [&](const VkExtensionProperties& extension, extensions.reserve(7 + REQUIRED_EXTENSIONS.size());
std::optional<std::reference_wrapper<bool>> status, const char* name, extensions.insert(extensions.begin(), REQUIRED_EXTENSIONS.begin(), REQUIRED_EXTENSIONS.end());
bool has_khr_shader_float16_int8{};
bool has_ext_subgroup_size_control{};
bool has_ext_transform_feedback{};
bool has_ext_custom_border_color{};
bool has_ext_extended_dynamic_state{};
for (const VkExtensionProperties& extension : physical.EnumerateDeviceExtensionProperties()) {
const auto test = [&](std::optional<std::reference_wrapper<bool>> status, const char* name,
bool push) { bool push) {
if (extension.extensionName != std::string_view(name)) { if (extension.extensionName != std::string_view(name)) {
return; return;
@ -610,37 +621,23 @@ std::vector<const char*> VKDevice::LoadExtensions() {
status->get() = true; status->get() = true;
} }
}; };
test(nv_viewport_swizzle, VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME, true);
extensions.reserve(7 + REQUIRED_EXTENSIONS.size()); test(khr_uniform_buffer_standard_layout,
extensions.insert(extensions.begin(), REQUIRED_EXTENSIONS.begin(), REQUIRED_EXTENSIONS.end());
bool has_khr_shader_float16_int8{};
bool has_ext_subgroup_size_control{};
bool has_ext_transform_feedback{};
bool has_ext_custom_border_color{};
bool has_ext_extended_dynamic_state{};
for (const auto& extension : physical.EnumerateDeviceExtensionProperties()) {
Test(extension, nv_viewport_swizzle, VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME, true);
Test(extension, khr_uniform_buffer_standard_layout,
VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_EXTENSION_NAME, true); VK_KHR_UNIFORM_BUFFER_STANDARD_LAYOUT_EXTENSION_NAME, true);
Test(extension, has_khr_shader_float16_int8, VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, test(has_khr_shader_float16_int8, VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, false);
false); test(ext_depth_range_unrestricted, VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME, true);
Test(extension, ext_depth_range_unrestricted, test(ext_index_type_uint8, VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME, true);
VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME, true); test(ext_shader_viewport_index_layer, VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME,
Test(extension, ext_index_type_uint8, VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME, true); true);
Test(extension, ext_shader_viewport_index_layer, test(has_ext_transform_feedback, VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME, false);
VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME, true); test(has_ext_custom_border_color, VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME, false);
Test(extension, has_ext_subgroup_size_control, VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME, test(has_ext_extended_dynamic_state, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, false);
false); if (instance_version >= VK_API_VERSION_1_1) {
Test(extension, has_ext_transform_feedback, VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME, test(has_ext_subgroup_size_control, VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME, false);
false); }
Test(extension, has_ext_custom_border_color, VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME,
false);
Test(extension, has_ext_extended_dynamic_state,
VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, false);
if (Settings::values.renderer_debug) { if (Settings::values.renderer_debug) {
Test(extension, nv_device_diagnostics_config, test(nv_device_diagnostics_config, VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME,
VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME, true); true);
} }
} }

View file

@ -24,8 +24,8 @@ const u32 GuestWarpSize = 32;
/// Handles data specific to a physical device. /// Handles data specific to a physical device.
class VKDevice final { class VKDevice final {
public: public:
explicit VKDevice(VkInstance instance, vk::PhysicalDevice physical, VkSurfaceKHR surface, explicit VKDevice(VkInstance instance, u32 instance_version, vk::PhysicalDevice physical,
const vk::InstanceDispatch& dld); VkSurfaceKHR surface, const vk::InstanceDispatch& dld);
~VKDevice(); ~VKDevice();
/// Initializes the device. Returns true on success. /// Initializes the device. Returns true on success.
@ -82,8 +82,13 @@ public:
return present_family; return present_family;
} }
/// Returns the current instance Vulkan API version in Vulkan-formatted version numbers.
u32 InstanceApiVersion() const {
return instance_version;
}
/// Returns the current Vulkan API version provided in Vulkan-formatted version numbers. /// Returns the current Vulkan API version provided in Vulkan-formatted version numbers.
u32 GetApiVersion() const { u32 ApiVersion() const {
return properties.apiVersion; return properties.apiVersion;
} }
@ -239,6 +244,7 @@ private:
vk::Device logical; ///< Logical device. vk::Device logical; ///< Logical device.
vk::Queue graphics_queue; ///< Main graphics queue. vk::Queue graphics_queue; ///< Main graphics queue.
vk::Queue present_queue; ///< Main present queue. vk::Queue present_queue; ///< Main present queue.
u32 instance_version{}; ///< Vulkan onstance version.
u32 graphics_family{}; ///< Main graphics queue family index. u32 graphics_family{}; ///< Main graphics queue family index.
u32 present_family{}; ///< Main present queue family index. u32 present_family{}; ///< Main present queue family index.
VkDriverIdKHR driver_id{}; ///< Driver ID. VkDriverIdKHR driver_id{}; ///< Driver ID.

View file

@ -272,12 +272,19 @@ bool IsPrecise(Operation operand) {
return false; return false;
} }
u32 ShaderVersion(const VKDevice& device) {
if (device.InstanceApiVersion() < VK_API_VERSION_1_1) {
return 0x00010000;
}
return 0x00010300;
}
class SPIRVDecompiler final : public Sirit::Module { class SPIRVDecompiler final : public Sirit::Module {
public: public:
explicit SPIRVDecompiler(const VKDevice& device, const ShaderIR& ir, ShaderType stage, explicit SPIRVDecompiler(const VKDevice& device, const ShaderIR& ir, ShaderType stage,
const Registry& registry, const Specialization& specialization) const Registry& registry, const Specialization& specialization)
: Module(0x00010300), device{device}, ir{ir}, stage{stage}, header{ir.GetHeader()}, : Module(ShaderVersion(device)), device{device}, ir{ir}, stage{stage},
registry{registry}, specialization{specialization} { header{ir.GetHeader()}, registry{registry}, specialization{specialization} {
if (stage != ShaderType::Compute) { if (stage != ShaderType::Compute) {
transform_feedback = BuildTransformFeedback(registry.GetGraphicsInfo()); transform_feedback = BuildTransformFeedback(registry.GetGraphicsInfo());
} }
@ -293,6 +300,7 @@ public:
AddCapability(spv::Capability::DrawParameters); AddCapability(spv::Capability::DrawParameters);
AddCapability(spv::Capability::SubgroupBallotKHR); AddCapability(spv::Capability::SubgroupBallotKHR);
AddCapability(spv::Capability::SubgroupVoteKHR); AddCapability(spv::Capability::SubgroupVoteKHR);
AddExtension("SPV_KHR_16bit_storage");
AddExtension("SPV_KHR_shader_ballot"); AddExtension("SPV_KHR_shader_ballot");
AddExtension("SPV_KHR_subgroup_vote"); AddExtension("SPV_KHR_subgroup_vote");
AddExtension("SPV_KHR_storage_buffer_storage_class"); AddExtension("SPV_KHR_storage_buffer_storage_class");

View file

@ -11,6 +11,7 @@
#include <vector> #include <vector>
#include "common/common_types.h" #include "common/common_types.h"
#include "common/logging/log.h"
#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/renderer_vulkan/wrapper.h"
@ -415,18 +416,17 @@ VkResult Free(VkDevice device, VkCommandPool handle, Span<VkCommandBuffer> buffe
return VK_SUCCESS; return VK_SUCCESS;
} }
Instance Instance::Create(Span<const char*> layers, Span<const char*> extensions, Instance Instance::Create(u32 version, Span<const char*> layers, Span<const char*> extensions,
InstanceDispatch& dld) noexcept { InstanceDispatch& dld) noexcept {
static constexpr VkApplicationInfo application_info{ const VkApplicationInfo application_info{
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
.pNext = nullptr, .pNext = nullptr,
.pApplicationName = "yuzu Emulator", .pApplicationName = "yuzu Emulator",
.applicationVersion = VK_MAKE_VERSION(0, 1, 0), .applicationVersion = VK_MAKE_VERSION(0, 1, 0),
.pEngineName = "yuzu Emulator", .pEngineName = "yuzu Emulator",
.engineVersion = VK_MAKE_VERSION(0, 1, 0), .engineVersion = VK_MAKE_VERSION(0, 1, 0),
.apiVersion = VK_API_VERSION_1_1, .apiVersion = version,
}; };
const VkInstanceCreateInfo ci{ const VkInstanceCreateInfo ci{
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
.pNext = nullptr, .pNext = nullptr,
@ -818,6 +818,21 @@ VkPhysicalDeviceMemoryProperties PhysicalDevice::GetMemoryProperties() const noe
return properties; return properties;
} }
u32 AvailableVersion(const InstanceDispatch& dld) noexcept {
PFN_vkEnumerateInstanceVersion vkEnumerateInstanceVersion;
if (!Proc(vkEnumerateInstanceVersion, dld, "vkEnumerateInstanceVersion")) {
// If the procedure is not found, Vulkan 1.0 is assumed
return VK_API_VERSION_1_0;
}
u32 version;
if (const VkResult result = vkEnumerateInstanceVersion(&version); result != VK_SUCCESS) {
LOG_ERROR(Render_Vulkan, "vkEnumerateInstanceVersion returned {}, assuming Vulkan 1.1",
ToString(result));
return VK_API_VERSION_1_1;
}
return version;
}
std::optional<std::vector<VkExtensionProperties>> EnumerateInstanceExtensionProperties( std::optional<std::vector<VkExtensionProperties>> EnumerateInstanceExtensionProperties(
const InstanceDispatch& dld) { const InstanceDispatch& dld) {
u32 num; u32 num;

View file

@ -564,7 +564,7 @@ class Instance : public Handle<VkInstance, NoOwner, InstanceDispatch> {
public: public:
/// Creates a Vulkan instance. Use "operator bool" for error handling. /// Creates a Vulkan instance. Use "operator bool" for error handling.
static Instance Create(Span<const char*> layers, Span<const char*> extensions, static Instance Create(u32 version, Span<const char*> layers, Span<const char*> extensions,
InstanceDispatch& dld) noexcept; InstanceDispatch& dld) noexcept;
/// Enumerates physical devices. /// Enumerates physical devices.
@ -1090,6 +1090,8 @@ private:
const DeviceDispatch* dld; const DeviceDispatch* dld;
}; };
u32 AvailableVersion(const InstanceDispatch& dld) noexcept;
std::optional<std::vector<VkExtensionProperties>> EnumerateInstanceExtensionProperties( std::optional<std::vector<VkExtensionProperties>> EnumerateInstanceExtensionProperties(
const InstanceDispatch& dld); const InstanceDispatch& dld);