forked from eden-emu/eden
		
	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:
		
						commit
						f1ead11df7
					
				
					 7 changed files with 92 additions and 58 deletions
				
			
		|  | @ -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<vk::Instance, u32> 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 {}; | ||||
|  | @ -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) { | ||||
|         LOG_ERROR(Render_Vulkan, "Failed to create Vulkan instance"); | ||||
|         return {}; | ||||
|  | @ -188,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) { | ||||
|  | @ -285,8 +288,8 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | |||
| 
 | ||||
| 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; | ||||
|     } | ||||
|  | @ -416,7 +419,8 @@ bool RendererVulkan::PickDevices() { | |||
|         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(); | ||||
| } | ||||
| 
 | ||||
|  | @ -426,7 +430,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()); | ||||
| 
 | ||||
|  | @ -445,7 +449,7 @@ void RendererVulkan::Report() const { | |||
| std::vector<std::string> 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 {}; | ||||
|     } | ||||
|  |  | |||
|  | @ -73,6 +73,8 @@ private: | |||
|     vk::InstanceDispatch dld; | ||||
| 
 | ||||
|     vk::Instance instance; | ||||
|     u32 instance_version{}; | ||||
| 
 | ||||
|     vk::SurfaceKHR surface; | ||||
| 
 | ||||
|     VKScreenInfo screen_info; | ||||
|  |  | |||
|  | @ -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, | ||||
|  | @ -187,10 +190,10 @@ std::unordered_map<VkFormat, VkFormatProperties> 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(); | ||||
| } | ||||
|  | @ -597,8 +600,16 @@ bool VKDevice::IsSuitable(vk::PhysicalDevice physical, VkSurfaceKHR surface) { | |||
| 
 | ||||
| std::vector<const char*> VKDevice::LoadExtensions() { | ||||
|     std::vector<const char*> extensions; | ||||
|     const auto Test = [&](const VkExtensionProperties& extension, | ||||
|                           std::optional<std::reference_wrapper<bool>> status, const char* name, | ||||
|     extensions.reserve(7 + REQUIRED_EXTENSIONS.size()); | ||||
|     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) { | ||||
|             if (extension.extensionName != std::string_view(name)) { | ||||
|                 return; | ||||
|  | @ -610,37 +621,23 @@ std::vector<const char*> VKDevice::LoadExtensions() { | |||
|                 status->get() = true; | ||||
|             } | ||||
|         }; | ||||
| 
 | ||||
|     extensions.reserve(7 + REQUIRED_EXTENSIONS.size()); | ||||
|     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, | ||||
|         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); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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.
 | ||||
|  |  | |||
|  | @ -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"); | ||||
|  |  | |||
|  | @ -11,6 +11,7 @@ | |||
| #include <vector> | ||||
| 
 | ||||
| #include "common/common_types.h" | ||||
| #include "common/logging/log.h" | ||||
| 
 | ||||
| #include "video_core/renderer_vulkan/wrapper.h" | ||||
| 
 | ||||
|  | @ -415,18 +416,17 @@ VkResult Free(VkDevice device, VkCommandPool handle, Span<VkCommandBuffer> buffe | |||
|     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 { | ||||
|     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, | ||||
|  | @ -818,6 +818,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<std::vector<VkExtensionProperties>> EnumerateInstanceExtensionProperties( | ||||
|     const InstanceDispatch& dld) { | ||||
|     u32 num; | ||||
|  |  | |||
|  | @ -564,7 +564,7 @@ class Instance : public Handle<VkInstance, NoOwner, InstanceDispatch> { | |||
| 
 | ||||
| public: | ||||
|     /// 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; | ||||
| 
 | ||||
|     /// Enumerates physical devices.
 | ||||
|  | @ -1090,6 +1090,8 @@ private: | |||
|     const DeviceDispatch* dld; | ||||
| }; | ||||
| 
 | ||||
| u32 AvailableVersion(const InstanceDispatch& dld) noexcept; | ||||
| 
 | ||||
| std::optional<std::vector<VkExtensionProperties>> EnumerateInstanceExtensionProperties( | ||||
|     const InstanceDispatch& dld); | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 bunnei
						bunnei