From 29a0ca23918092d252f440b2f55f68bb3c991366 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Mon, 29 Jun 2020 02:34:17 -0300 Subject: [PATCH 1/2] renderer_vulkan: Create a Vulkan 1.0 instance when 1.1 is not available This commit doesn't make yuzu compatible with Vulkan 1.0 yet, it only creates an 1.0 instance. --- .../renderer_vulkan/renderer_vulkan.cpp | 5 +++- src/video_core/renderer_vulkan/wrapper.cpp | 23 +++++++++++++++---- src/video_core/renderer_vulkan/wrapper.h | 4 +++- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 6e49699d0..6f9eadbeb 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -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(VK_API_VERSION_1_1)); + + vk::Instance instance = vk::Instance::Create(version, layers, extensions, dld); if (!instance) { LOG_ERROR(Render_Vulkan, "Failed to create Vulkan instance"); return {}; diff --git a/src/video_core/renderer_vulkan/wrapper.cpp b/src/video_core/renderer_vulkan/wrapper.cpp index 013865aa4..56055af1b 100644 --- a/src/video_core/renderer_vulkan/wrapper.cpp +++ b/src/video_core/renderer_vulkan/wrapper.cpp @@ -10,6 +10,7 @@ #include #include "common/common_types.h" +#include "common/logging/log.h" #include "video_core/renderer_vulkan/wrapper.h" @@ -375,18 +376,17 @@ VkResult Free(VkDevice device, VkCommandPool handle, Span buffe return VK_SUCCESS; } -Instance Instance::Create(Span layers, Span extensions, +Instance Instance::Create(u32 version, Span layers, Span extensions, InstanceDispatch& dld) noexcept { - static constexpr VkApplicationInfo application_info{ + const VkApplicationInfo application_info{ .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, .pNext = nullptr, .pApplicationName = "yuzu Emulator", .applicationVersion = VK_MAKE_VERSION(0, 1, 0), .pEngineName = "yuzu Emulator", .engineVersion = VK_MAKE_VERSION(0, 1, 0), - .apiVersion = VK_API_VERSION_1_1, + .apiVersion = version, }; - const VkInstanceCreateInfo ci{ .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, .pNext = nullptr, @@ -775,6 +775,21 @@ VkPhysicalDeviceMemoryProperties PhysicalDevice::GetMemoryProperties() const noe 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> EnumerateInstanceExtensionProperties( const InstanceDispatch& dld) { u32 num; diff --git a/src/video_core/renderer_vulkan/wrapper.h b/src/video_core/renderer_vulkan/wrapper.h index b9d3fedc1..748a94d2f 100644 --- a/src/video_core/renderer_vulkan/wrapper.h +++ b/src/video_core/renderer_vulkan/wrapper.h @@ -563,7 +563,7 @@ class Instance : public Handle { public: /// Creates a Vulkan instance. Use "operator bool" for error handling. - static Instance Create(Span layers, Span extensions, + static Instance Create(u32 version, Span layers, Span extensions, InstanceDispatch& dld) noexcept; /// Enumerates physical devices. @@ -1048,6 +1048,8 @@ private: const DeviceDispatch* dld; }; +u32 AvailableVersion(const InstanceDispatch& dld) noexcept; + std::optional> EnumerateInstanceExtensionProperties( const InstanceDispatch& dld); From c5a78f4480369ad6325c51549509361c10d2cea5 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Mon, 29 Jun 2020 02:48:29 -0300 Subject: [PATCH 2/2] vk_device: Use Vulkan 1.0 properly Enable the required capabilities to use Vulkan 1.0 without validation errors and disable those that are not compatible with it. --- .../renderer_vulkan/renderer_vulkan.cpp | 19 ++--- .../renderer_vulkan/renderer_vulkan.h | 2 + src/video_core/renderer_vulkan/vk_device.cpp | 73 +++++++++---------- src/video_core/renderer_vulkan/vk_device.h | 12 ++- .../renderer_vulkan/vk_shader_decompiler.cpp | 12 ++- 5 files changed, 66 insertions(+), 52 deletions(-) diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 6f9eadbeb..7ffc90cd0 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -92,9 +92,9 @@ Common::DynamicLibrary OpenVulkanLibrary() { return library; } -vk::Instance CreateInstance(Common::DynamicLibrary& library, vk::InstanceDispatch& dld, - WindowSystemType window_type = WindowSystemType::Headless, - bool enable_layers = false) { +std::pair CreateInstance( + Common::DynamicLibrary& library, vk::InstanceDispatch& dld, + WindowSystemType window_type = WindowSystemType::Headless, bool enable_layers = false) { if (!library.IsOpen()) { LOG_ERROR(Render_Vulkan, "Vulkan library not available"); return {}; @@ -191,7 +191,7 @@ vk::Instance CreateInstance(Common::DynamicLibrary& library, vk::InstanceDispatc if (!vk::Load(*instance, dld)) { 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) { @@ -289,8 +289,8 @@ bool RendererVulkan::TryPresent(int /*timeout_ms*/) { bool RendererVulkan::Init() { library = OpenVulkanLibrary(); - instance = CreateInstance(library, dld, render_window.GetWindowInfo().type, - Settings::values.renderer_debug); + std::tie(instance, instance_version) = CreateInstance( + library, dld, render_window.GetWindowInfo().type, Settings::values.renderer_debug); if (!instance || !CreateDebugCallback() || !CreateSurface() || !PickDevices()) { return false; } @@ -423,7 +423,8 @@ bool RendererVulkan::PickDevices() { return false; } - device = std::make_unique(*instance, physical_device, *surface, dld); + device = + std::make_unique(*instance, instance_version, physical_device, *surface, dld); return device->Create(); } @@ -433,7 +434,7 @@ void RendererVulkan::Report() const { const std::string driver_version = GetDriverVersion(*device); 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()); @@ -453,7 +454,7 @@ void RendererVulkan::Report() const { std::vector RendererVulkan::EnumerateDevices() { vk::InstanceDispatch dld; Common::DynamicLibrary library = OpenVulkanLibrary(); - vk::Instance instance = CreateInstance(library, dld); + vk::Instance instance = CreateInstance(library, dld).first; if (!instance) { return {}; } diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index 522b5bff8..9617a93e9 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h @@ -63,6 +63,8 @@ private: vk::InstanceDispatch dld; vk::Instance instance; + u32 instance_version{}; + vk::SurfaceKHR surface; VKScreenInfo screen_info; diff --git a/src/video_core/renderer_vulkan/vk_device.cpp b/src/video_core/renderer_vulkan/vk_device.cpp index ebcfaa0e3..90916ee0e 100644 --- a/src/video_core/renderer_vulkan/vk_device.cpp +++ b/src/video_core/renderer_vulkan/vk_device.cpp @@ -38,6 +38,9 @@ constexpr std::array Depth16UnormS8_UINT{ constexpr std::array REQUIRED_EXTENSIONS{ 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_8BIT_STORAGE_EXTENSION_NAME, VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, @@ -171,10 +174,10 @@ std::unordered_map GetFormatProperties( } // Anonymous namespace -VKDevice::VKDevice(VkInstance instance, vk::PhysicalDevice physical, VkSurfaceKHR surface, - const vk::InstanceDispatch& dld) - : dld{dld}, physical{physical}, properties{physical.GetProperties()}, - format_properties{GetFormatProperties(physical, dld)} { +VKDevice::VKDevice(VkInstance instance_, u32 instance_version_, vk::PhysicalDevice physical_, + VkSurfaceKHR surface, const vk::InstanceDispatch& dld_) + : dld{dld_}, physical{physical_}, properties{physical.GetProperties()}, + instance_version{instance_version_}, format_properties{GetFormatProperties(physical, dld)} { SetupFamilies(surface); SetupFeatures(); } @@ -565,20 +568,6 @@ bool VKDevice::IsSuitable(vk::PhysicalDevice physical, VkSurfaceKHR surface) { std::vector VKDevice::LoadExtensions() { std::vector extensions; - const auto Test = [&](const VkExtensionProperties& extension, - std::optional> status, const char* name, - bool push) { - if (extension.extensionName != std::string_view(name)) { - return; - } - if (push) { - extensions.push_back(name); - } - if (status) { - status->get() = true; - } - }; - extensions.reserve(7 + REQUIRED_EXTENSIONS.size()); extensions.insert(extensions.begin(), REQUIRED_EXTENSIONS.begin(), REQUIRED_EXTENSIONS.end()); @@ -587,28 +576,36 @@ std::vector VKDevice::LoadExtensions() { 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, + for (const VkExtensionProperties& extension : physical.EnumerateDeviceExtensionProperties()) { + const auto test = [&](std::optional> status, const char* name, + bool push) { + if (extension.extensionName != std::string_view(name)) { + return; + } + if (push) { + extensions.push_back(name); + } + if (status) { + status->get() = true; + } + }; + test(nv_viewport_swizzle, VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME, true); + test(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, - 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, has_ext_subgroup_size_control, VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME, - false); - Test(extension, has_ext_transform_feedback, VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME, - 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); + test(has_khr_shader_float16_int8, VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, false); + test(ext_depth_range_unrestricted, VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME, true); + test(ext_index_type_uint8, VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME, true); + test(ext_shader_viewport_index_layer, VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME, + true); + test(has_ext_transform_feedback, VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME, false); + test(has_ext_custom_border_color, VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME, false); + test(has_ext_extended_dynamic_state, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, false); + if (instance_version >= VK_API_VERSION_1_1) { + test(has_ext_subgroup_size_control, VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME, false); + } if (Settings::values.renderer_debug) { - Test(extension, nv_device_diagnostics_config, - VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME, true); + test(nv_device_diagnostics_config, VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME, + true); } } diff --git a/src/video_core/renderer_vulkan/vk_device.h b/src/video_core/renderer_vulkan/vk_device.h index 26a233db1..4286673d9 100644 --- a/src/video_core/renderer_vulkan/vk_device.h +++ b/src/video_core/renderer_vulkan/vk_device.h @@ -24,8 +24,8 @@ const u32 GuestWarpSize = 32; /// Handles data specific to a physical device. class VKDevice final { public: - explicit VKDevice(VkInstance instance, vk::PhysicalDevice physical, VkSurfaceKHR surface, - const vk::InstanceDispatch& dld); + explicit VKDevice(VkInstance instance, u32 instance_version, vk::PhysicalDevice physical, + VkSurfaceKHR surface, const vk::InstanceDispatch& dld); ~VKDevice(); /// Initializes the device. Returns true on success. @@ -82,8 +82,13 @@ public: 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. - u32 GetApiVersion() const { + u32 ApiVersion() const { return properties.apiVersion; } @@ -239,6 +244,7 @@ private: vk::Device logical; ///< Logical device. vk::Queue graphics_queue; ///< Main graphics queue. vk::Queue present_queue; ///< Main present queue. + u32 instance_version{}; ///< Vulkan onstance version. u32 graphics_family{}; ///< Main graphics queue family index. u32 present_family{}; ///< Main present queue family index. VkDriverIdKHR driver_id{}; ///< Driver ID. diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp index cd7d7a4e4..a20452b87 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp @@ -272,12 +272,19 @@ bool IsPrecise(Operation operand) { 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 { public: explicit SPIRVDecompiler(const VKDevice& device, const ShaderIR& ir, ShaderType stage, const Registry& registry, const Specialization& specialization) - : Module(0x00010300), device{device}, ir{ir}, stage{stage}, header{ir.GetHeader()}, - registry{registry}, specialization{specialization} { + : Module(ShaderVersion(device)), device{device}, ir{ir}, stage{stage}, + header{ir.GetHeader()}, registry{registry}, specialization{specialization} { if (stage != ShaderType::Compute) { transform_feedback = BuildTransformFeedback(registry.GetGraphicsInfo()); } @@ -293,6 +300,7 @@ public: AddCapability(spv::Capability::DrawParameters); AddCapability(spv::Capability::SubgroupBallotKHR); AddCapability(spv::Capability::SubgroupVoteKHR); + AddExtension("SPV_KHR_16bit_storage"); AddExtension("SPV_KHR_shader_ballot"); AddExtension("SPV_KHR_subgroup_vote"); AddExtension("SPV_KHR_storage_buffer_storage_class");