summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2020-12-24 22:05:48 -0300
committerGravatar ReinUsesLisp2020-12-31 02:07:33 -0300
commit25f88d99cead2f7f6fdbf5e36e7578472aaa65bd (patch)
treef53fb29591c7a9ab73220b29431337ad2d5596bd /src
parentvulkan_common: Rename renderer_vulkan/wrapper.h to vulkan_common/vulkan_wrapp... (diff)
downloadyuzu-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.txt2
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp112
-rw-r--r--src/video_core/vulkan_common/vulkan_instance.cpp152
-rw-r--r--src/video_core/vulkan_common/vulkan_instance.h21
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
48namespace Vulkan { 49namespace Vulkan {
49
50namespace { 50namespace {
51
52using Core::Frontend::WindowSystemType;
53
54VkBool32 DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, 51VkBool32 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
72std::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
175std::string GetReadableVersion(u32 version) { 69std::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
31namespace Vulkan {
32namespace {
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
94void 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
114std::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
14namespace 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