diff options
| author | 2020-12-24 22:05:48 -0300 | |
|---|---|---|
| committer | 2020-12-31 02:07:33 -0300 | |
| commit | 25f88d99cead2f7f6fdbf5e36e7578472aaa65bd (patch) | |
| tree | f53fb29591c7a9ab73220b29431337ad2d5596bd /src | |
| parent | vulkan_common: Rename renderer_vulkan/wrapper.h to vulkan_common/vulkan_wrapp... (diff) | |
| download | yuzu-25f88d99cead2f7f6fdbf5e36e7578472aaa65bd.tar.gz yuzu-25f88d99cead2f7f6fdbf5e36e7578472aaa65bd.tar.xz yuzu-25f88d99cead2f7f6fdbf5e36e7578472aaa65bd.zip | |
renderer_vulkan: Move instance initialization to a separate file
Simplify Vulkan's backend initialization code by moving it to a separate
file, allowing us to initialize a Vulkan instance from different
backends.
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/renderer_vulkan.cpp | 112 | ||||
| -rw-r--r-- | src/video_core/vulkan_common/vulkan_instance.cpp | 152 | ||||
| -rw-r--r-- | src/video_core/vulkan_common/vulkan_instance.h | 21 |
4 files changed, 176 insertions, 111 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index e19632bb1..f8c36947a 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -258,6 +258,8 @@ add_library(video_core STATIC | |||
| 258 | textures/texture.h | 258 | textures/texture.h |
| 259 | video_core.cpp | 259 | video_core.cpp |
| 260 | video_core.h | 260 | video_core.h |
| 261 | vulkan_common/vulkan_instance.cpp | ||
| 262 | vulkan_common/vulkan_instance.h | ||
| 261 | vulkan_common/vulkan_library.cpp | 263 | vulkan_common/vulkan_library.cpp |
| 262 | vulkan_common/vulkan_library.h | 264 | vulkan_common/vulkan_library.h |
| 263 | vulkan_common/vulkan_wrapper.cpp | 265 | vulkan_common/vulkan_wrapper.cpp |
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 6e267f89d..82619bc61 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include "video_core/renderer_vulkan/vk_scheduler.h" | 29 | #include "video_core/renderer_vulkan/vk_scheduler.h" |
| 30 | #include "video_core/renderer_vulkan/vk_state_tracker.h" | 30 | #include "video_core/renderer_vulkan/vk_state_tracker.h" |
| 31 | #include "video_core/renderer_vulkan/vk_swapchain.h" | 31 | #include "video_core/renderer_vulkan/vk_swapchain.h" |
| 32 | #include "video_core/vulkan_common/vulkan_instance.h" | ||
| 32 | #include "video_core/vulkan_common/vulkan_library.h" | 33 | #include "video_core/vulkan_common/vulkan_library.h" |
| 33 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 34 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 34 | 35 | ||
| @@ -46,11 +47,7 @@ | |||
| 46 | #endif | 47 | #endif |
| 47 | 48 | ||
| 48 | namespace Vulkan { | 49 | namespace Vulkan { |
| 49 | |||
| 50 | namespace { | 50 | namespace { |
| 51 | |||
| 52 | using Core::Frontend::WindowSystemType; | ||
| 53 | |||
| 54 | VkBool32 DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, | 51 | VkBool32 DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, |
| 55 | VkDebugUtilsMessageTypeFlagsEXT type, | 52 | VkDebugUtilsMessageTypeFlagsEXT type, |
| 56 | const VkDebugUtilsMessengerCallbackDataEXT* data, | 53 | const VkDebugUtilsMessengerCallbackDataEXT* data, |
| @@ -69,109 +66,6 @@ VkBool32 DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, | |||
| 69 | return VK_FALSE; | 66 | return VK_FALSE; |
| 70 | } | 67 | } |
| 71 | 68 | ||
| 72 | std::pair<vk::Instance, u32> CreateInstance( | ||
| 73 | Common::DynamicLibrary& library, vk::InstanceDispatch& dld, | ||
| 74 | WindowSystemType window_type = WindowSystemType::Headless, bool enable_debug_utils = false, | ||
| 75 | bool enable_layers = false) { | ||
| 76 | if (!library.IsOpen()) { | ||
| 77 | LOG_ERROR(Render_Vulkan, "Vulkan library not available"); | ||
| 78 | return {}; | ||
| 79 | } | ||
| 80 | if (!library.GetSymbol("vkGetInstanceProcAddr", &dld.vkGetInstanceProcAddr)) { | ||
| 81 | LOG_ERROR(Render_Vulkan, "vkGetInstanceProcAddr not present in Vulkan"); | ||
| 82 | return {}; | ||
| 83 | } | ||
| 84 | if (!vk::Load(dld)) { | ||
| 85 | LOG_ERROR(Render_Vulkan, "Failed to load Vulkan function pointers"); | ||
| 86 | return {}; | ||
| 87 | } | ||
| 88 | |||
| 89 | std::vector<const char*> extensions; | ||
| 90 | extensions.reserve(6); | ||
| 91 | switch (window_type) { | ||
| 92 | case Core::Frontend::WindowSystemType::Headless: | ||
| 93 | break; | ||
| 94 | #ifdef _WIN32 | ||
| 95 | case Core::Frontend::WindowSystemType::Windows: | ||
| 96 | extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); | ||
| 97 | break; | ||
| 98 | #endif | ||
| 99 | #if !defined(_WIN32) && !defined(__APPLE__) | ||
| 100 | case Core::Frontend::WindowSystemType::X11: | ||
| 101 | extensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); | ||
| 102 | break; | ||
| 103 | case Core::Frontend::WindowSystemType::Wayland: | ||
| 104 | extensions.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME); | ||
| 105 | break; | ||
| 106 | #endif | ||
| 107 | default: | ||
| 108 | LOG_ERROR(Render_Vulkan, "Presentation not supported on this platform"); | ||
| 109 | break; | ||
| 110 | } | ||
| 111 | if (window_type != Core::Frontend::WindowSystemType::Headless) { | ||
| 112 | extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME); | ||
| 113 | } | ||
| 114 | if (enable_debug_utils) { | ||
| 115 | extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); | ||
| 116 | } | ||
| 117 | extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); | ||
| 118 | |||
| 119 | const std::optional properties = vk::EnumerateInstanceExtensionProperties(dld); | ||
| 120 | if (!properties) { | ||
| 121 | LOG_ERROR(Render_Vulkan, "Failed to query extension properties"); | ||
| 122 | return {}; | ||
| 123 | } | ||
| 124 | |||
| 125 | for (const char* extension : extensions) { | ||
| 126 | const auto it = | ||
| 127 | std::find_if(properties->begin(), properties->end(), [extension](const auto& prop) { | ||
| 128 | return !std::strcmp(extension, prop.extensionName); | ||
| 129 | }); | ||
| 130 | if (it == properties->end()) { | ||
| 131 | LOG_ERROR(Render_Vulkan, "Required instance extension {} is not available", extension); | ||
| 132 | return {}; | ||
| 133 | } | ||
| 134 | } | ||
| 135 | |||
| 136 | std::vector<const char*> layers; | ||
| 137 | layers.reserve(1); | ||
| 138 | if (enable_layers) { | ||
| 139 | layers.push_back("VK_LAYER_KHRONOS_validation"); | ||
| 140 | } | ||
| 141 | |||
| 142 | const std::optional layer_properties = vk::EnumerateInstanceLayerProperties(dld); | ||
| 143 | if (!layer_properties) { | ||
| 144 | LOG_ERROR(Render_Vulkan, "Failed to query layer properties, disabling layers"); | ||
| 145 | layers.clear(); | ||
| 146 | } | ||
| 147 | |||
| 148 | for (auto layer_it = layers.begin(); layer_it != layers.end();) { | ||
| 149 | const char* const layer = *layer_it; | ||
| 150 | const auto it = std::find_if( | ||
| 151 | layer_properties->begin(), layer_properties->end(), | ||
| 152 | [layer](const VkLayerProperties& prop) { return !std::strcmp(layer, prop.layerName); }); | ||
| 153 | if (it == layer_properties->end()) { | ||
| 154 | LOG_ERROR(Render_Vulkan, "Layer {} not available, removing it", layer); | ||
| 155 | layer_it = layers.erase(layer_it); | ||
| 156 | } else { | ||
| 157 | ++layer_it; | ||
| 158 | } | ||
| 159 | } | ||
| 160 | |||
| 161 | // Limit the maximum version of Vulkan to avoid using untested version. | ||
| 162 | const u32 version = std::min(vk::AvailableVersion(dld), static_cast<u32>(VK_API_VERSION_1_1)); | ||
| 163 | |||
| 164 | vk::Instance instance = vk::Instance::Create(version, layers, extensions, dld); | ||
| 165 | if (!instance) { | ||
| 166 | LOG_ERROR(Render_Vulkan, "Failed to create Vulkan instance"); | ||
| 167 | return {}; | ||
| 168 | } | ||
| 169 | if (!vk::Load(*instance, dld)) { | ||
| 170 | LOG_ERROR(Render_Vulkan, "Failed to load Vulkan instance function pointers"); | ||
| 171 | } | ||
| 172 | return std::make_pair(std::move(instance), version); | ||
| 173 | } | ||
| 174 | |||
| 175 | std::string GetReadableVersion(u32 version) { | 69 | std::string GetReadableVersion(u32 version) { |
| 176 | return fmt::format("{}.{}.{}", VK_VERSION_MAJOR(version), VK_VERSION_MINOR(version), | 70 | return fmt::format("{}.{}.{}", VK_VERSION_MAJOR(version), VK_VERSION_MINOR(version), |
| 177 | VK_VERSION_PATCH(version)); | 71 | VK_VERSION_PATCH(version)); |
| @@ -194,7 +88,6 @@ std::string GetDriverVersion(const VKDevice& device) { | |||
| 194 | const u32 minor = version & 0x3fff; | 88 | const u32 minor = version & 0x3fff; |
| 195 | return fmt::format("{}.{}", major, minor); | 89 | return fmt::format("{}.{}", major, minor); |
| 196 | } | 90 | } |
| 197 | |||
| 198 | return GetReadableVersion(version); | 91 | return GetReadableVersion(version); |
| 199 | } | 92 | } |
| 200 | 93 | ||
| @@ -233,7 +126,6 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | |||
| 233 | if (!framebuffer) { | 126 | if (!framebuffer) { |
| 234 | return; | 127 | return; |
| 235 | } | 128 | } |
| 236 | |||
| 237 | const auto& layout = render_window.GetFramebufferLayout(); | 129 | const auto& layout = render_window.GetFramebufferLayout(); |
| 238 | if (layout.width > 0 && layout.height > 0 && render_window.IsShown()) { | 130 | if (layout.width > 0 && layout.height > 0 && render_window.IsShown()) { |
| 239 | const VAddr framebuffer_addr = framebuffer->address + framebuffer->offset; | 131 | const VAddr framebuffer_addr = framebuffer->address + framebuffer->offset; |
| @@ -429,12 +321,10 @@ std::vector<std::string> RendererVulkan::EnumerateDevices() { | |||
| 429 | if (!instance) { | 321 | if (!instance) { |
| 430 | return {}; | 322 | return {}; |
| 431 | } | 323 | } |
| 432 | |||
| 433 | const std::optional physical_devices = instance.EnumeratePhysicalDevices(); | 324 | const std::optional physical_devices = instance.EnumeratePhysicalDevices(); |
| 434 | if (!physical_devices) { | 325 | if (!physical_devices) { |
| 435 | return {}; | 326 | return {}; |
| 436 | } | 327 | } |
| 437 | |||
| 438 | std::vector<std::string> names; | 328 | std::vector<std::string> names; |
| 439 | names.reserve(physical_devices->size()); | 329 | names.reserve(physical_devices->size()); |
| 440 | for (const auto& device : *physical_devices) { | 330 | for (const auto& device : *physical_devices) { |
diff --git a/src/video_core/vulkan_common/vulkan_instance.cpp b/src/video_core/vulkan_common/vulkan_instance.cpp new file mode 100644 index 000000000..c19f93e0a --- /dev/null +++ b/src/video_core/vulkan_common/vulkan_instance.cpp | |||
| @@ -0,0 +1,152 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include <optional> | ||
| 7 | #include <span> | ||
| 8 | #include <utility> | ||
| 9 | #include <vector> | ||
| 10 | |||
| 11 | #include "common/common_types.h" | ||
| 12 | #include "common/dynamic_library.h" | ||
| 13 | #include "common/logging/log.h" | ||
| 14 | #include "core/frontend/emu_window.h" | ||
| 15 | #include "video_core/vulkan_common/vulkan_instance.h" | ||
| 16 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 17 | |||
| 18 | // Include these late to avoid polluting previous headers | ||
| 19 | #ifdef _WIN32 | ||
| 20 | #include <windows.h> | ||
| 21 | // ensure include order | ||
| 22 | #include <vulkan/vulkan_win32.h> | ||
| 23 | #endif | ||
| 24 | |||
| 25 | #if !defined(_WIN32) && !defined(__APPLE__) | ||
| 26 | #include <X11/Xlib.h> | ||
| 27 | #include <vulkan/vulkan_wayland.h> | ||
| 28 | #include <vulkan/vulkan_xlib.h> | ||
| 29 | #endif | ||
| 30 | |||
| 31 | namespace Vulkan { | ||
| 32 | namespace { | ||
| 33 | [[nodiscard]] std::vector<const char*> RequiredExtensions( | ||
| 34 | Core::Frontend::WindowSystemType window_type, bool enable_debug_utils) { | ||
| 35 | std::vector<const char*> extensions; | ||
| 36 | extensions.reserve(6); | ||
| 37 | switch (window_type) { | ||
| 38 | case Core::Frontend::WindowSystemType::Headless: | ||
| 39 | break; | ||
| 40 | #ifdef _WIN32 | ||
| 41 | case Core::Frontend::WindowSystemType::Windows: | ||
| 42 | extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); | ||
| 43 | break; | ||
| 44 | #endif | ||
| 45 | #if !defined(_WIN32) && !defined(__APPLE__) | ||
| 46 | case Core::Frontend::WindowSystemType::X11: | ||
| 47 | extensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); | ||
| 48 | break; | ||
| 49 | case Core::Frontend::WindowSystemType::Wayland: | ||
| 50 | extensions.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME); | ||
| 51 | break; | ||
| 52 | #endif | ||
| 53 | default: | ||
| 54 | LOG_ERROR(Render_Vulkan, "Presentation not supported on this platform"); | ||
| 55 | break; | ||
| 56 | } | ||
| 57 | if (window_type != Core::Frontend::WindowSystemType::Headless) { | ||
| 58 | extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME); | ||
| 59 | } | ||
| 60 | if (enable_debug_utils) { | ||
| 61 | extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); | ||
| 62 | } | ||
| 63 | extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); | ||
| 64 | return extensions; | ||
| 65 | } | ||
| 66 | |||
| 67 | [[nodiscard]] bool AreExtensionsSupported(const vk::InstanceDispatch& dld, | ||
| 68 | std::span<const char* const> extensions) { | ||
| 69 | const std::optional properties = vk::EnumerateInstanceExtensionProperties(dld); | ||
| 70 | if (!properties) { | ||
| 71 | LOG_ERROR(Render_Vulkan, "Failed to query extension properties"); | ||
| 72 | return false; | ||
| 73 | } | ||
| 74 | for (const char* extension : extensions) { | ||
| 75 | const auto it = std::ranges::find_if(*properties, [extension](const auto& prop) { | ||
| 76 | return std::strcmp(extension, prop.extensionName) == 0; | ||
| 77 | }); | ||
| 78 | if (it == properties->end()) { | ||
| 79 | LOG_ERROR(Render_Vulkan, "Required instance extension {} is not available", extension); | ||
| 80 | return false; | ||
| 81 | } | ||
| 82 | } | ||
| 83 | return true; | ||
| 84 | } | ||
| 85 | |||
| 86 | [[nodiscard]] std::vector<const char*> Layers(bool enable_layers) { | ||
| 87 | std::vector<const char*> layers; | ||
| 88 | if (enable_layers) { | ||
| 89 | layers.push_back("VK_LAYER_KHRONOS_validation"); | ||
| 90 | } | ||
| 91 | return layers; | ||
| 92 | } | ||
| 93 | |||
| 94 | void RemoveUnavailableLayers(const vk::InstanceDispatch& dld, std::vector<const char*>& layers) { | ||
| 95 | const std::optional layer_properties = vk::EnumerateInstanceLayerProperties(dld); | ||
| 96 | if (!layer_properties) { | ||
| 97 | LOG_ERROR(Render_Vulkan, "Failed to query layer properties, disabling layers"); | ||
| 98 | layers.clear(); | ||
| 99 | } | ||
| 100 | std::erase_if(layers, [&layer_properties](const char* layer) { | ||
| 101 | const auto comp = [layer](const VkLayerProperties& layer_property) { | ||
| 102 | return std::strcmp(layer, layer_property.layerName) == 0; | ||
| 103 | }; | ||
| 104 | const auto it = std::ranges::find_if(*layer_properties, comp); | ||
| 105 | if (it == layer_properties->end()) { | ||
| 106 | LOG_ERROR(Render_Vulkan, "Layer {} not available, removing it", layer); | ||
| 107 | return true; | ||
| 108 | } | ||
| 109 | return false; | ||
| 110 | }); | ||
| 111 | } | ||
| 112 | } // Anonymous namespace | ||
| 113 | |||
| 114 | std::pair<vk::Instance, u32> CreateInstance(Common::DynamicLibrary& library, | ||
| 115 | vk::InstanceDispatch& dld, | ||
| 116 | Core::Frontend::WindowSystemType window_type, | ||
| 117 | bool enable_debug_utils, bool enable_layers) { | ||
| 118 | if (!library.IsOpen()) { | ||
| 119 | LOG_ERROR(Render_Vulkan, "Vulkan library not available"); | ||
| 120 | return {}; | ||
| 121 | } | ||
| 122 | if (!library.GetSymbol("vkGetInstanceProcAddr", &dld.vkGetInstanceProcAddr)) { | ||
| 123 | LOG_ERROR(Render_Vulkan, "vkGetInstanceProcAddr not present in Vulkan"); | ||
| 124 | return {}; | ||
| 125 | } | ||
| 126 | if (!vk::Load(dld)) { | ||
| 127 | LOG_ERROR(Render_Vulkan, "Failed to load Vulkan function pointers"); | ||
| 128 | return {}; | ||
| 129 | } | ||
| 130 | const std::vector<const char*> extensions = RequiredExtensions(window_type, enable_debug_utils); | ||
| 131 | if (!AreExtensionsSupported(dld, extensions)) { | ||
| 132 | return {}; | ||
| 133 | } | ||
| 134 | |||
| 135 | std::vector<const char*> layers = Layers(enable_layers); | ||
| 136 | RemoveUnavailableLayers(dld, layers); | ||
| 137 | |||
| 138 | // Limit the maximum version of Vulkan to avoid using untested version. | ||
| 139 | const u32 version = std::min(vk::AvailableVersion(dld), VK_API_VERSION_1_1); | ||
| 140 | |||
| 141 | vk::Instance instance = vk::Instance::Create(version, layers, extensions, dld); | ||
| 142 | if (!instance) { | ||
| 143 | LOG_ERROR(Render_Vulkan, "Failed to create Vulkan instance"); | ||
| 144 | return {}; | ||
| 145 | } | ||
| 146 | if (!vk::Load(*instance, dld)) { | ||
| 147 | LOG_ERROR(Render_Vulkan, "Failed to load Vulkan instance function pointers"); | ||
| 148 | } | ||
| 149 | return std::make_pair(std::move(instance), version); | ||
| 150 | } | ||
| 151 | |||
| 152 | } // namespace Vulkan | ||
diff --git a/src/video_core/vulkan_common/vulkan_instance.h b/src/video_core/vulkan_common/vulkan_instance.h new file mode 100644 index 000000000..ff2be0a48 --- /dev/null +++ b/src/video_core/vulkan_common/vulkan_instance.h | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <utility> | ||
| 8 | |||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "common/dynamic_library.h" | ||
| 11 | #include "core/frontend/emu_window.h" | ||
| 12 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 13 | |||
| 14 | namespace Vulkan { | ||
| 15 | |||
| 16 | [[nodiscard]] std::pair<vk::Instance, u32> CreateInstance( | ||
| 17 | Common::DynamicLibrary& library, vk::InstanceDispatch& dld, | ||
| 18 | Core::Frontend::WindowSystemType window_type = Core::Frontend::WindowSystemType::Headless, | ||
| 19 | bool enable_debug_utils = false, bool enable_layers = false); | ||
| 20 | |||
| 21 | } // namespace Vulkan | ||