summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Rodrigo Locatti2021-01-03 17:38:29 -0300
committerGravatar GitHub2021-01-03 17:38:29 -0300
commit7265e80c12de2d24d759ee6956a2445bf9ac8992 (patch)
tree3236d949fdf894b985a8dcafc580cd233ebd9a68 /src
parentMerge pull request #5278 from MerryMage/cpuopt_unsafe_inaccurate_nan (diff)
parentvulkan_instance: Allow different Vulkan versions and enforce 1.1 (diff)
downloadyuzu-7265e80c12de2d24d759ee6956a2445bf9ac8992.tar.gz
yuzu-7265e80c12de2d24d759ee6956a2445bf9ac8992.tar.xz
yuzu-7265e80c12de2d24d759ee6956a2445bf9ac8992.zip
Merge pull request #5230 from ReinUsesLisp/vulkan-common
vulkan_common: Move reusable Vulkan abstractions to a separate directory
Diffstat (limited to '')
-rw-r--r--src/video_core/CMakeLists.txt12
-rw-r--r--src/video_core/renderer_vulkan/blit_image.cpp2
-rw-r--r--src/video_core/renderer_vulkan/blit_image.h2
-rw-r--r--src/video_core/renderer_vulkan/maxwell_to_vk.cpp2
-rw-r--r--src/video_core/renderer_vulkan/maxwell_to_vk.h2
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp306
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.h11
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_command_pool.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_command_pool.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pass.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pass.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pipeline.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pipeline.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_descriptor_pool.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_descriptor_pool.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_device.cpp146
-rw-r--r--src/video_core/renderer_vulkan/vk_device.h18
-rw-r--r--src/video_core/renderer_vulkan/vk_fence_manager.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_fence_manager.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_master_semaphore.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_master_semaphore.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_memory_manager.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_memory_manager.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_query_cache.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_query_cache.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_scheduler.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_scheduler.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_shader_decompiler.cpp11
-rw-r--r--src/video_core/renderer_vulkan/vk_shader_util.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_shader_util.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_staging_buffer_pool.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_stream_buffer.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_stream_buffer.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_swapchain.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_swapchain.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_update_descriptor.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_update_descriptor.h2
-rw-r--r--src/video_core/vulkan_common/vulkan_debug_callback.cpp45
-rw-r--r--src/video_core/vulkan_common/vulkan_debug_callback.h11
-rw-r--r--src/video_core/vulkan_common/vulkan_instance.cpp151
-rw-r--r--src/video_core/vulkan_common/vulkan_instance.h32
-rw-r--r--src/video_core/vulkan_common/vulkan_library.cpp36
-rw-r--r--src/video_core/vulkan_common/vulkan_library.h13
-rw-r--r--src/video_core/vulkan_common/vulkan_surface.cpp81
-rw-r--r--src/video_core/vulkan_common/vulkan_surface.h18
-rw-r--r--src/video_core/vulkan_common/vulkan_wrapper.cpp (renamed from src/video_core/renderer_vulkan/wrapper.cpp)58
-rw-r--r--src/video_core/vulkan_common/vulkan_wrapper.h (renamed from src/video_core/renderer_vulkan/wrapper.h)23
60 files changed, 574 insertions, 486 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index e050f9aed..4bd48f706 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -167,8 +167,6 @@ add_library(video_core STATIC
167 renderer_vulkan/vk_texture_cache.h 167 renderer_vulkan/vk_texture_cache.h
168 renderer_vulkan/vk_update_descriptor.cpp 168 renderer_vulkan/vk_update_descriptor.cpp
169 renderer_vulkan/vk_update_descriptor.h 169 renderer_vulkan/vk_update_descriptor.h
170 renderer_vulkan/wrapper.cpp
171 renderer_vulkan/wrapper.h
172 shader_cache.h 170 shader_cache.h
173 shader_notify.cpp 171 shader_notify.cpp
174 shader_notify.h 172 shader_notify.h
@@ -257,6 +255,16 @@ add_library(video_core STATIC
257 textures/texture.h 255 textures/texture.h
258 video_core.cpp 256 video_core.cpp
259 video_core.h 257 video_core.h
258 vulkan_common/vulkan_debug_callback.cpp
259 vulkan_common/vulkan_debug_callback.h
260 vulkan_common/vulkan_instance.cpp
261 vulkan_common/vulkan_instance.h
262 vulkan_common/vulkan_library.cpp
263 vulkan_common/vulkan_library.h
264 vulkan_common/vulkan_surface.cpp
265 vulkan_common/vulkan_surface.h
266 vulkan_common/vulkan_wrapper.cpp
267 vulkan_common/vulkan_wrapper.h
260) 268)
261 269
262create_target_directory_groups(video_core) 270create_target_directory_groups(video_core)
diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp
index 87c8e5693..504492cac 100644
--- a/src/video_core/renderer_vulkan/blit_image.cpp
+++ b/src/video_core/renderer_vulkan/blit_image.cpp
@@ -17,8 +17,8 @@
17#include "video_core/renderer_vulkan/vk_state_tracker.h" 17#include "video_core/renderer_vulkan/vk_state_tracker.h"
18#include "video_core/renderer_vulkan/vk_texture_cache.h" 18#include "video_core/renderer_vulkan/vk_texture_cache.h"
19#include "video_core/renderer_vulkan/vk_update_descriptor.h" 19#include "video_core/renderer_vulkan/vk_update_descriptor.h"
20#include "video_core/renderer_vulkan/wrapper.h"
21#include "video_core/surface.h" 20#include "video_core/surface.h"
21#include "video_core/vulkan_common/vulkan_wrapper.h"
22 22
23namespace Vulkan { 23namespace Vulkan {
24 24
diff --git a/src/video_core/renderer_vulkan/blit_image.h b/src/video_core/renderer_vulkan/blit_image.h
index 2c2790bf9..1a4f66336 100644
--- a/src/video_core/renderer_vulkan/blit_image.h
+++ b/src/video_core/renderer_vulkan/blit_image.h
@@ -8,8 +8,8 @@
8 8
9#include "video_core/engines/fermi_2d.h" 9#include "video_core/engines/fermi_2d.h"
10#include "video_core/renderer_vulkan/vk_descriptor_pool.h" 10#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
11#include "video_core/renderer_vulkan/wrapper.h"
12#include "video_core/texture_cache/types.h" 11#include "video_core/texture_cache/types.h"
12#include "video_core/vulkan_common/vulkan_wrapper.h"
13 13
14namespace Vulkan { 14namespace Vulkan {
15 15
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
index 4c988429f..ed4fce714 100644
--- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
+++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
@@ -10,8 +10,8 @@
10#include "video_core/engines/maxwell_3d.h" 10#include "video_core/engines/maxwell_3d.h"
11#include "video_core/renderer_vulkan/maxwell_to_vk.h" 11#include "video_core/renderer_vulkan/maxwell_to_vk.h"
12#include "video_core/renderer_vulkan/vk_device.h" 12#include "video_core/renderer_vulkan/vk_device.h"
13#include "video_core/renderer_vulkan/wrapper.h"
14#include "video_core/surface.h" 13#include "video_core/surface.h"
14#include "video_core/vulkan_common/vulkan_wrapper.h"
15 15
16namespace Vulkan::MaxwellToVK { 16namespace Vulkan::MaxwellToVK {
17 17
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.h b/src/video_core/renderer_vulkan/maxwell_to_vk.h
index 1a90f192e..8cf5aa711 100644
--- a/src/video_core/renderer_vulkan/maxwell_to_vk.h
+++ b/src/video_core/renderer_vulkan/maxwell_to_vk.h
@@ -7,9 +7,9 @@
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "video_core/engines/maxwell_3d.h" 8#include "video_core/engines/maxwell_3d.h"
9#include "video_core/renderer_vulkan/vk_device.h" 9#include "video_core/renderer_vulkan/vk_device.h"
10#include "video_core/renderer_vulkan/wrapper.h"
11#include "video_core/surface.h" 10#include "video_core/surface.h"
12#include "video_core/textures/texture.h" 11#include "video_core/textures/texture.h"
12#include "video_core/vulkan_common/vulkan_wrapper.h"
13 13
14namespace Vulkan::MaxwellToVK { 14namespace Vulkan::MaxwellToVK {
15 15
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index 7f521cb9b..5b35cb407 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -12,8 +12,6 @@
12 12
13#include <fmt/format.h> 13#include <fmt/format.h>
14 14
15#include "common/dynamic_library.h"
16#include "common/file_util.h"
17#include "common/logging/log.h" 15#include "common/logging/log.h"
18#include "common/telemetry.h" 16#include "common/telemetry.h"
19#include "core/core.h" 17#include "core/core.h"
@@ -31,169 +29,14 @@
31#include "video_core/renderer_vulkan/vk_scheduler.h" 29#include "video_core/renderer_vulkan/vk_scheduler.h"
32#include "video_core/renderer_vulkan/vk_state_tracker.h" 30#include "video_core/renderer_vulkan/vk_state_tracker.h"
33#include "video_core/renderer_vulkan/vk_swapchain.h" 31#include "video_core/renderer_vulkan/vk_swapchain.h"
34#include "video_core/renderer_vulkan/wrapper.h" 32#include "video_core/vulkan_common/vulkan_debug_callback.h"
35 33#include "video_core/vulkan_common/vulkan_instance.h"
36// Include these late to avoid polluting previous headers 34#include "video_core/vulkan_common/vulkan_library.h"
37#ifdef _WIN32 35#include "video_core/vulkan_common/vulkan_surface.h"
38#include <windows.h> 36#include "video_core/vulkan_common/vulkan_wrapper.h"
39// ensure include order
40#include <vulkan/vulkan_win32.h>
41#endif
42
43#if !defined(_WIN32) && !defined(__APPLE__)
44#include <X11/Xlib.h>
45#include <vulkan/vulkan_wayland.h>
46#include <vulkan/vulkan_xlib.h>
47#endif
48 37
49namespace Vulkan { 38namespace Vulkan {
50
51namespace { 39namespace {
52
53using Core::Frontend::WindowSystemType;
54
55VkBool32 DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
56 VkDebugUtilsMessageTypeFlagsEXT type,
57 const VkDebugUtilsMessengerCallbackDataEXT* data,
58 [[maybe_unused]] void* user_data) {
59 const char* const message{data->pMessage};
60
61 if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
62 LOG_CRITICAL(Render_Vulkan, "{}", message);
63 } else if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) {
64 LOG_WARNING(Render_Vulkan, "{}", message);
65 } else if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) {
66 LOG_INFO(Render_Vulkan, "{}", message);
67 } else if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) {
68 LOG_DEBUG(Render_Vulkan, "{}", message);
69 }
70 return VK_FALSE;
71}
72
73Common::DynamicLibrary OpenVulkanLibrary() {
74 Common::DynamicLibrary library;
75#ifdef __APPLE__
76 // Check if a path to a specific Vulkan library has been specified.
77 char* libvulkan_env = getenv("LIBVULKAN_PATH");
78 if (!libvulkan_env || !library.Open(libvulkan_env)) {
79 // Use the libvulkan.dylib from the application bundle.
80 const std::string filename =
81 Common::FS::GetBundleDirectory() + "/Contents/Frameworks/libvulkan.dylib";
82 library.Open(filename.c_str());
83 }
84#else
85 std::string filename = Common::DynamicLibrary::GetVersionedFilename("vulkan", 1);
86 if (!library.Open(filename.c_str())) {
87 // Android devices may not have libvulkan.so.1, only libvulkan.so.
88 filename = Common::DynamicLibrary::GetVersionedFilename("vulkan");
89 (void)library.Open(filename.c_str());
90 }
91#endif
92 return library;
93}
94
95std::pair<vk::Instance, u32> CreateInstance(Common::DynamicLibrary& library,
96 vk::InstanceDispatch& dld, WindowSystemType window_type,
97 bool enable_debug_utils, bool enable_layers) {
98 if (!library.IsOpen()) {
99 LOG_ERROR(Render_Vulkan, "Vulkan library not available");
100 return {};
101 }
102 if (!library.GetSymbol("vkGetInstanceProcAddr", &dld.vkGetInstanceProcAddr)) {
103 LOG_ERROR(Render_Vulkan, "vkGetInstanceProcAddr not present in Vulkan");
104 return {};
105 }
106 if (!vk::Load(dld)) {
107 LOG_ERROR(Render_Vulkan, "Failed to load Vulkan function pointers");
108 return {};
109 }
110
111 std::vector<const char*> extensions;
112 extensions.reserve(6);
113 switch (window_type) {
114 case Core::Frontend::WindowSystemType::Headless:
115 break;
116#ifdef _WIN32
117 case Core::Frontend::WindowSystemType::Windows:
118 extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
119 break;
120#endif
121#if !defined(_WIN32) && !defined(__APPLE__)
122 case Core::Frontend::WindowSystemType::X11:
123 extensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
124 break;
125 case Core::Frontend::WindowSystemType::Wayland:
126 extensions.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
127 break;
128#endif
129 default:
130 LOG_ERROR(Render_Vulkan, "Presentation not supported on this platform");
131 break;
132 }
133 if (window_type != Core::Frontend::WindowSystemType::Headless) {
134 extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
135 }
136 if (enable_debug_utils) {
137 extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
138 }
139 extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
140
141 const std::optional properties = vk::EnumerateInstanceExtensionProperties(dld);
142 if (!properties) {
143 LOG_ERROR(Render_Vulkan, "Failed to query extension properties");
144 return {};
145 }
146
147 for (const char* extension : extensions) {
148 const auto it =
149 std::find_if(properties->begin(), properties->end(), [extension](const auto& prop) {
150 return !std::strcmp(extension, prop.extensionName);
151 });
152 if (it == properties->end()) {
153 LOG_ERROR(Render_Vulkan, "Required instance extension {} is not available", extension);
154 return {};
155 }
156 }
157
158 std::vector<const char*> layers;
159 layers.reserve(1);
160 if (enable_layers) {
161 layers.push_back("VK_LAYER_KHRONOS_validation");
162 }
163
164 const std::optional layer_properties = vk::EnumerateInstanceLayerProperties(dld);
165 if (!layer_properties) {
166 LOG_ERROR(Render_Vulkan, "Failed to query layer properties, disabling layers");
167 layers.clear();
168 }
169
170 for (auto layer_it = layers.begin(); layer_it != layers.end();) {
171 const char* const layer = *layer_it;
172 const auto it = std::find_if(
173 layer_properties->begin(), layer_properties->end(),
174 [layer](const VkLayerProperties& prop) { return !std::strcmp(layer, prop.layerName); });
175 if (it == layer_properties->end()) {
176 LOG_ERROR(Render_Vulkan, "Layer {} not available, removing it", layer);
177 layer_it = layers.erase(layer_it);
178 } else {
179 ++layer_it;
180 }
181 }
182
183 // Limit the maximum version of Vulkan to avoid using untested version.
184 const u32 version = std::min(vk::AvailableVersion(dld), static_cast<u32>(VK_API_VERSION_1_1));
185
186 vk::Instance instance = vk::Instance::Create(version, layers, extensions, dld);
187 if (!instance) {
188 LOG_ERROR(Render_Vulkan, "Failed to create Vulkan instance");
189 return {};
190 }
191 if (!vk::Load(*instance, dld)) {
192 LOG_ERROR(Render_Vulkan, "Failed to load Vulkan instance function pointers");
193 }
194 return std::make_pair(std::move(instance), version);
195}
196
197std::string GetReadableVersion(u32 version) { 40std::string GetReadableVersion(u32 version) {
198 return fmt::format("{}.{}.{}", VK_VERSION_MAJOR(version), VK_VERSION_MINOR(version), 41 return fmt::format("{}.{}.{}", VK_VERSION_MAJOR(version), VK_VERSION_MINOR(version),
199 VK_VERSION_PATCH(version)); 42 VK_VERSION_PATCH(version));
@@ -216,7 +59,6 @@ std::string GetDriverVersion(const VKDevice& device) {
216 const u32 minor = version & 0x3fff; 59 const u32 minor = version & 0x3fff;
217 return fmt::format("{}.{}", major, minor); 60 return fmt::format("{}.{}", major, minor);
218 } 61 }
219
220 return GetReadableVersion(version); 62 return GetReadableVersion(version);
221} 63}
222 64
@@ -255,7 +97,6 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
255 if (!framebuffer) { 97 if (!framebuffer) {
256 return; 98 return;
257 } 99 }
258
259 const auto& layout = render_window.GetFramebufferLayout(); 100 const auto& layout = render_window.GetFramebufferLayout();
260 if (layout.width > 0 && layout.height > 0 && render_window.IsShown()) { 101 if (layout.width > 0 && layout.height > 0 && render_window.IsShown()) {
261 const VAddr framebuffer_addr = framebuffer->address + framebuffer->offset; 102 const VAddr framebuffer_addr = framebuffer->address + framebuffer->offset;
@@ -284,14 +125,16 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
284 render_window.OnFrameDisplayed(); 125 render_window.OnFrameDisplayed();
285} 126}
286 127
287bool RendererVulkan::Init() { 128bool RendererVulkan::Init() try {
288 library = OpenVulkanLibrary(); 129 library = OpenLibrary();
289 std::tie(instance, instance_version) = CreateInstance( 130 instance = CreateInstance(library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type,
290 library, dld, render_window.GetWindowInfo().type, true, Settings::values.renderer_debug); 131 true, Settings::values.renderer_debug);
291 if (!instance || !CreateDebugCallback() || !CreateSurface() || !PickDevices()) { 132 if (Settings::values.renderer_debug) {
292 return false; 133 debug_callback = CreateDebugCallback(instance);
293 } 134 }
135 surface = CreateSurface(instance, render_window);
294 136
137 InitializeDevice();
295 Report(); 138 Report();
296 139
297 memory_manager = std::make_unique<VKMemoryManager>(*device); 140 memory_manager = std::make_unique<VKMemoryManager>(*device);
@@ -311,8 +154,11 @@ bool RendererVulkan::Init() {
311 blit_screen = 154 blit_screen =
312 std::make_unique<VKBlitScreen>(cpu_memory, render_window, *rasterizer, *device, 155 std::make_unique<VKBlitScreen>(cpu_memory, render_window, *rasterizer, *device,
313 *memory_manager, *swapchain, *scheduler, screen_info); 156 *memory_manager, *swapchain, *scheduler, screen_info);
314
315 return true; 157 return true;
158
159} catch (const vk::Exception& exception) {
160 LOG_ERROR(Render_Vulkan, "Vulkan initialization failed with error: {}", exception.what());
161 return false;
316} 162}
317 163
318void RendererVulkan::ShutDown() { 164void RendererVulkan::ShutDown() {
@@ -322,7 +168,6 @@ void RendererVulkan::ShutDown() {
322 if (const auto& dev = device->GetLogical()) { 168 if (const auto& dev = device->GetLogical()) {
323 dev.WaitIdle(); 169 dev.WaitIdle();
324 } 170 }
325
326 rasterizer.reset(); 171 rasterizer.reset();
327 blit_screen.reset(); 172 blit_screen.reset();
328 scheduler.reset(); 173 scheduler.reset();
@@ -331,95 +176,15 @@ void RendererVulkan::ShutDown() {
331 device.reset(); 176 device.reset();
332} 177}
333 178
334bool RendererVulkan::CreateDebugCallback() { 179void RendererVulkan::InitializeDevice() {
335 if (!Settings::values.renderer_debug) { 180 const std::vector<VkPhysicalDevice> devices = instance.EnumeratePhysicalDevices();
336 return true;
337 }
338 debug_callback = instance.TryCreateDebugCallback(DebugCallback);
339 if (!debug_callback) {
340 LOG_ERROR(Render_Vulkan, "Failed to create debug callback");
341 return false;
342 }
343 return true;
344}
345
346bool RendererVulkan::CreateSurface() {
347 [[maybe_unused]] const auto& window_info = render_window.GetWindowInfo();
348 VkSurfaceKHR unsafe_surface = nullptr;
349
350#ifdef _WIN32
351 if (window_info.type == Core::Frontend::WindowSystemType::Windows) {
352 const HWND hWnd = static_cast<HWND>(window_info.render_surface);
353 const VkWin32SurfaceCreateInfoKHR win32_ci{VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR,
354 nullptr, 0, nullptr, hWnd};
355 const auto vkCreateWin32SurfaceKHR = reinterpret_cast<PFN_vkCreateWin32SurfaceKHR>(
356 dld.vkGetInstanceProcAddr(*instance, "vkCreateWin32SurfaceKHR"));
357 if (!vkCreateWin32SurfaceKHR ||
358 vkCreateWin32SurfaceKHR(*instance, &win32_ci, nullptr, &unsafe_surface) != VK_SUCCESS) {
359 LOG_ERROR(Render_Vulkan, "Failed to initialize Win32 surface");
360 return false;
361 }
362 }
363#endif
364#if !defined(_WIN32) && !defined(__APPLE__)
365 if (window_info.type == Core::Frontend::WindowSystemType::X11) {
366 const VkXlibSurfaceCreateInfoKHR xlib_ci{
367 VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, nullptr, 0,
368 static_cast<Display*>(window_info.display_connection),
369 reinterpret_cast<Window>(window_info.render_surface)};
370 const auto vkCreateXlibSurfaceKHR = reinterpret_cast<PFN_vkCreateXlibSurfaceKHR>(
371 dld.vkGetInstanceProcAddr(*instance, "vkCreateXlibSurfaceKHR"));
372 if (!vkCreateXlibSurfaceKHR ||
373 vkCreateXlibSurfaceKHR(*instance, &xlib_ci, nullptr, &unsafe_surface) != VK_SUCCESS) {
374 LOG_ERROR(Render_Vulkan, "Failed to initialize Xlib surface");
375 return false;
376 }
377 }
378 if (window_info.type == Core::Frontend::WindowSystemType::Wayland) {
379 const VkWaylandSurfaceCreateInfoKHR wayland_ci{
380 VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, nullptr, 0,
381 static_cast<wl_display*>(window_info.display_connection),
382 static_cast<wl_surface*>(window_info.render_surface)};
383 const auto vkCreateWaylandSurfaceKHR = reinterpret_cast<PFN_vkCreateWaylandSurfaceKHR>(
384 dld.vkGetInstanceProcAddr(*instance, "vkCreateWaylandSurfaceKHR"));
385 if (!vkCreateWaylandSurfaceKHR ||
386 vkCreateWaylandSurfaceKHR(*instance, &wayland_ci, nullptr, &unsafe_surface) !=
387 VK_SUCCESS) {
388 LOG_ERROR(Render_Vulkan, "Failed to initialize Wayland surface");
389 return false;
390 }
391 }
392#endif
393 if (!unsafe_surface) {
394 LOG_ERROR(Render_Vulkan, "Presentation not supported on this platform");
395 return false;
396 }
397
398 surface = vk::SurfaceKHR(unsafe_surface, *instance, dld);
399 return true;
400}
401
402bool RendererVulkan::PickDevices() {
403 const auto devices = instance.EnumeratePhysicalDevices();
404 if (!devices) {
405 LOG_ERROR(Render_Vulkan, "Failed to enumerate physical devices");
406 return false;
407 }
408
409 const s32 device_index = Settings::values.vulkan_device.GetValue(); 181 const s32 device_index = Settings::values.vulkan_device.GetValue();
410 if (device_index < 0 || device_index >= static_cast<s32>(devices->size())) { 182 if (device_index < 0 || device_index >= static_cast<s32>(devices.size())) {
411 LOG_ERROR(Render_Vulkan, "Invalid device index {}!", device_index); 183 LOG_ERROR(Render_Vulkan, "Invalid device index {}!", device_index);
412 return false; 184 throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
413 }
414 const vk::PhysicalDevice physical_device((*devices)[static_cast<std::size_t>(device_index)],
415 dld);
416 if (!VKDevice::IsSuitable(physical_device, *surface)) {
417 return false;
418 } 185 }
419 186 const vk::PhysicalDevice physical_device(devices[static_cast<size_t>(device_index)], dld);
420 device = 187 device = std::make_unique<VKDevice>(*instance, physical_device, *surface, dld);
421 std::make_unique<VKDevice>(*instance, instance_version, physical_device, *surface, dld);
422 return device->Create();
423} 188}
424 189
425void RendererVulkan::Report() const { 190void RendererVulkan::Report() const {
@@ -444,26 +209,21 @@ void RendererVulkan::Report() const {
444 telemetry_session.AddField(field, "GPU_Vulkan_Extensions", extensions); 209 telemetry_session.AddField(field, "GPU_Vulkan_Extensions", extensions);
445} 210}
446 211
447std::vector<std::string> RendererVulkan::EnumerateDevices() { 212std::vector<std::string> RendererVulkan::EnumerateDevices() try {
448 vk::InstanceDispatch dld; 213 vk::InstanceDispatch dld;
449 Common::DynamicLibrary library = OpenVulkanLibrary(); 214 const Common::DynamicLibrary library = OpenLibrary();
450 vk::Instance instance = 215 const vk::Instance instance = CreateInstance(library, dld, VK_API_VERSION_1_0);
451 CreateInstance(library, dld, WindowSystemType::Headless, false, false).first; 216 const std::vector<VkPhysicalDevice> physical_devices = instance.EnumeratePhysicalDevices();
452 if (!instance) {
453 return {};
454 }
455
456 const std::optional physical_devices = instance.EnumeratePhysicalDevices();
457 if (!physical_devices) {
458 return {};
459 }
460
461 std::vector<std::string> names; 217 std::vector<std::string> names;
462 names.reserve(physical_devices->size()); 218 names.reserve(physical_devices.size());
463 for (const auto& device : *physical_devices) { 219 for (const VkPhysicalDevice device : physical_devices) {
464 names.push_back(vk::PhysicalDevice(device, dld).GetProperties().deviceName); 220 names.push_back(vk::PhysicalDevice(device, dld).GetProperties().deviceName);
465 } 221 }
466 return names; 222 return names;
223
224} catch (const vk::Exception& exception) {
225 LOG_ERROR(Render_Vulkan, "Failed to enumerate devices with error: {}", exception.what());
226 return {};
467} 227}
468 228
469} // namespace Vulkan 229} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h
index 74642fba4..f22f50709 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.h
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.h
@@ -11,7 +11,7 @@
11#include "common/dynamic_library.h" 11#include "common/dynamic_library.h"
12 12
13#include "video_core/renderer_base.h" 13#include "video_core/renderer_base.h"
14#include "video_core/renderer_vulkan/wrapper.h" 14#include "video_core/vulkan_common/vulkan_wrapper.h"
15 15
16namespace Core { 16namespace Core {
17class TelemetrySession; 17class TelemetrySession;
@@ -56,11 +56,7 @@ public:
56 static std::vector<std::string> EnumerateDevices(); 56 static std::vector<std::string> EnumerateDevices();
57 57
58private: 58private:
59 bool CreateDebugCallback(); 59 void InitializeDevice();
60
61 bool CreateSurface();
62
63 bool PickDevices();
64 60
65 void Report() const; 61 void Report() const;
66 62
@@ -72,13 +68,12 @@ private:
72 vk::InstanceDispatch dld; 68 vk::InstanceDispatch dld;
73 69
74 vk::Instance instance; 70 vk::Instance instance;
75 u32 instance_version{};
76 71
77 vk::SurfaceKHR surface; 72 vk::SurfaceKHR surface;
78 73
79 VKScreenInfo screen_info; 74 VKScreenInfo screen_info;
80 75
81 vk::DebugCallback debug_callback; 76 vk::DebugUtilsMessenger debug_callback;
82 std::unique_ptr<VKDevice> device; 77 std::unique_ptr<VKDevice> device;
83 std::unique_ptr<VKMemoryManager> memory_manager; 78 std::unique_ptr<VKMemoryManager> memory_manager;
84 std::unique_ptr<StateTracker> state_tracker; 79 std::unique_ptr<StateTracker> state_tracker;
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
index d3a83f22f..a205cd151 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
@@ -27,9 +27,9 @@
27#include "video_core/renderer_vulkan/vk_scheduler.h" 27#include "video_core/renderer_vulkan/vk_scheduler.h"
28#include "video_core/renderer_vulkan/vk_shader_util.h" 28#include "video_core/renderer_vulkan/vk_shader_util.h"
29#include "video_core/renderer_vulkan/vk_swapchain.h" 29#include "video_core/renderer_vulkan/vk_swapchain.h"
30#include "video_core/renderer_vulkan/wrapper.h"
31#include "video_core/surface.h" 30#include "video_core/surface.h"
32#include "video_core/textures/decoders.h" 31#include "video_core/textures/decoders.h"
32#include "video_core/vulkan_common/vulkan_wrapper.h"
33 33
34namespace Vulkan { 34namespace Vulkan {
35 35
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.h b/src/video_core/renderer_vulkan/vk_blit_screen.h
index 2ee374247..cc56c4560 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.h
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.h
@@ -7,7 +7,7 @@
7#include <memory> 7#include <memory>
8 8
9#include "video_core/renderer_vulkan/vk_memory_manager.h" 9#include "video_core/renderer_vulkan/vk_memory_manager.h"
10#include "video_core/renderer_vulkan/wrapper.h" 10#include "video_core/vulkan_common/vulkan_wrapper.h"
11 11
12namespace Core { 12namespace Core {
13class System; 13class System;
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
index 10d296c2f..79131f819 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
@@ -12,7 +12,7 @@
12#include "video_core/renderer_vulkan/vk_device.h" 12#include "video_core/renderer_vulkan/vk_device.h"
13#include "video_core/renderer_vulkan/vk_scheduler.h" 13#include "video_core/renderer_vulkan/vk_scheduler.h"
14#include "video_core/renderer_vulkan/vk_stream_buffer.h" 14#include "video_core/renderer_vulkan/vk_stream_buffer.h"
15#include "video_core/renderer_vulkan/wrapper.h" 15#include "video_core/vulkan_common/vulkan_wrapper.h"
16 16
17namespace Vulkan { 17namespace Vulkan {
18 18
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h
index daf498222..3ab77a00b 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.h
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h
@@ -11,7 +11,7 @@
11#include "video_core/renderer_vulkan/vk_memory_manager.h" 11#include "video_core/renderer_vulkan/vk_memory_manager.h"
12#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" 12#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
13#include "video_core/renderer_vulkan/vk_stream_buffer.h" 13#include "video_core/renderer_vulkan/vk_stream_buffer.h"
14#include "video_core/renderer_vulkan/wrapper.h" 14#include "video_core/vulkan_common/vulkan_wrapper.h"
15 15
16namespace Vulkan { 16namespace Vulkan {
17 17
diff --git a/src/video_core/renderer_vulkan/vk_command_pool.cpp b/src/video_core/renderer_vulkan/vk_command_pool.cpp
index 8f7d6410e..ccae04929 100644
--- a/src/video_core/renderer_vulkan/vk_command_pool.cpp
+++ b/src/video_core/renderer_vulkan/vk_command_pool.cpp
@@ -6,7 +6,7 @@
6 6
7#include "video_core/renderer_vulkan/vk_command_pool.h" 7#include "video_core/renderer_vulkan/vk_command_pool.h"
8#include "video_core/renderer_vulkan/vk_device.h" 8#include "video_core/renderer_vulkan/vk_device.h"
9#include "video_core/renderer_vulkan/wrapper.h" 9#include "video_core/vulkan_common/vulkan_wrapper.h"
10 10
11namespace Vulkan { 11namespace Vulkan {
12 12
diff --git a/src/video_core/renderer_vulkan/vk_command_pool.h b/src/video_core/renderer_vulkan/vk_command_pool.h
index 62a7ce3f1..ce0e34515 100644
--- a/src/video_core/renderer_vulkan/vk_command_pool.h
+++ b/src/video_core/renderer_vulkan/vk_command_pool.h
@@ -8,7 +8,7 @@
8#include <vector> 8#include <vector>
9 9
10#include "video_core/renderer_vulkan/vk_resource_pool.h" 10#include "video_core/renderer_vulkan/vk_resource_pool.h"
11#include "video_core/renderer_vulkan/wrapper.h" 11#include "video_core/vulkan_common/vulkan_wrapper.h"
12 12
13namespace Vulkan { 13namespace Vulkan {
14 14
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.cpp b/src/video_core/renderer_vulkan/vk_compute_pass.cpp
index 2c030e910..5d4543bae 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pass.cpp
+++ b/src/video_core/renderer_vulkan/vk_compute_pass.cpp
@@ -19,7 +19,7 @@
19#include "video_core/renderer_vulkan/vk_scheduler.h" 19#include "video_core/renderer_vulkan/vk_scheduler.h"
20#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" 20#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
21#include "video_core/renderer_vulkan/vk_update_descriptor.h" 21#include "video_core/renderer_vulkan/vk_update_descriptor.h"
22#include "video_core/renderer_vulkan/wrapper.h" 22#include "video_core/vulkan_common/vulkan_wrapper.h"
23 23
24namespace Vulkan { 24namespace Vulkan {
25 25
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.h b/src/video_core/renderer_vulkan/vk_compute_pass.h
index abdf61e2c..1b7502a4f 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pass.h
+++ b/src/video_core/renderer_vulkan/vk_compute_pass.h
@@ -11,7 +11,7 @@
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "video_core/engines/maxwell_3d.h" 12#include "video_core/engines/maxwell_3d.h"
13#include "video_core/renderer_vulkan/vk_descriptor_pool.h" 13#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
14#include "video_core/renderer_vulkan/wrapper.h" 14#include "video_core/vulkan_common/vulkan_wrapper.h"
15 15
16namespace Vulkan { 16namespace Vulkan {
17 17
diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
index 62f44d6da..9966dd14a 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
@@ -11,7 +11,7 @@
11#include "video_core/renderer_vulkan/vk_scheduler.h" 11#include "video_core/renderer_vulkan/vk_scheduler.h"
12#include "video_core/renderer_vulkan/vk_shader_decompiler.h" 12#include "video_core/renderer_vulkan/vk_shader_decompiler.h"
13#include "video_core/renderer_vulkan/vk_update_descriptor.h" 13#include "video_core/renderer_vulkan/vk_update_descriptor.h"
14#include "video_core/renderer_vulkan/wrapper.h" 14#include "video_core/vulkan_common/vulkan_wrapper.h"
15 15
16namespace Vulkan { 16namespace Vulkan {
17 17
diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.h b/src/video_core/renderer_vulkan/vk_compute_pipeline.h
index 49e2113a2..a7197536c 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pipeline.h
+++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.h
@@ -7,7 +7,7 @@
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "video_core/renderer_vulkan/vk_descriptor_pool.h" 8#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
9#include "video_core/renderer_vulkan/vk_shader_decompiler.h" 9#include "video_core/renderer_vulkan/vk_shader_decompiler.h"
10#include "video_core/renderer_vulkan/wrapper.h" 10#include "video_core/vulkan_common/vulkan_wrapper.h"
11 11
12namespace Vulkan { 12namespace Vulkan {
13 13
diff --git a/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp b/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp
index f38e089d5..4dea03239 100644
--- a/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp
+++ b/src/video_core/renderer_vulkan/vk_descriptor_pool.cpp
@@ -9,7 +9,7 @@
9#include "video_core/renderer_vulkan/vk_device.h" 9#include "video_core/renderer_vulkan/vk_device.h"
10#include "video_core/renderer_vulkan/vk_resource_pool.h" 10#include "video_core/renderer_vulkan/vk_resource_pool.h"
11#include "video_core/renderer_vulkan/vk_scheduler.h" 11#include "video_core/renderer_vulkan/vk_scheduler.h"
12#include "video_core/renderer_vulkan/wrapper.h" 12#include "video_core/vulkan_common/vulkan_wrapper.h"
13 13
14namespace Vulkan { 14namespace Vulkan {
15 15
diff --git a/src/video_core/renderer_vulkan/vk_descriptor_pool.h b/src/video_core/renderer_vulkan/vk_descriptor_pool.h
index 544f32a20..2abcaeddd 100644
--- a/src/video_core/renderer_vulkan/vk_descriptor_pool.h
+++ b/src/video_core/renderer_vulkan/vk_descriptor_pool.h
@@ -7,7 +7,7 @@
7#include <vector> 7#include <vector>
8 8
9#include "video_core/renderer_vulkan/vk_resource_pool.h" 9#include "video_core/renderer_vulkan/vk_resource_pool.h"
10#include "video_core/renderer_vulkan/wrapper.h" 10#include "video_core/vulkan_common/vulkan_wrapper.h"
11 11
12namespace Vulkan { 12namespace Vulkan {
13 13
diff --git a/src/video_core/renderer_vulkan/vk_device.cpp b/src/video_core/renderer_vulkan/vk_device.cpp
index 85b4f0dff..9008530d5 100644
--- a/src/video_core/renderer_vulkan/vk_device.cpp
+++ b/src/video_core/renderer_vulkan/vk_device.cpp
@@ -14,7 +14,7 @@
14#include "common/assert.h" 14#include "common/assert.h"
15#include "core/settings.h" 15#include "core/settings.h"
16#include "video_core/renderer_vulkan/vk_device.h" 16#include "video_core/renderer_vulkan/vk_device.h"
17#include "video_core/renderer_vulkan/wrapper.h" 17#include "video_core/vulkan_common/vulkan_wrapper.h"
18 18
19namespace Vulkan { 19namespace Vulkan {
20 20
@@ -206,17 +206,14 @@ std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties(
206 206
207} // Anonymous namespace 207} // Anonymous namespace
208 208
209VKDevice::VKDevice(VkInstance instance_, u32 instance_version_, vk::PhysicalDevice physical_, 209VKDevice::VKDevice(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR surface,
210 VkSurfaceKHR surface, const vk::InstanceDispatch& dld_) 210 const vk::InstanceDispatch& dld_)
211 : instance{instance_}, dld{dld_}, physical{physical_}, properties{physical.GetProperties()}, 211 : instance{instance_}, dld{dld_}, physical{physical_}, properties{physical.GetProperties()},
212 instance_version{instance_version_}, format_properties{GetFormatProperties(physical, dld)} { 212 format_properties{GetFormatProperties(physical, dld)} {
213 CheckSuitability();
213 SetupFamilies(surface); 214 SetupFamilies(surface);
214 SetupFeatures(); 215 SetupFeatures();
215}
216
217VKDevice::~VKDevice() = default;
218 216
219bool VKDevice::Create() {
220 const auto queue_cis = GetDeviceQueueCreateInfos(); 217 const auto queue_cis = GetDeviceQueueCreateInfos();
221 const std::vector extensions = LoadExtensions(); 218 const std::vector extensions = LoadExtensions();
222 219
@@ -426,12 +423,7 @@ bool VKDevice::Create() {
426 }; 423 };
427 first_next = &diagnostics_nv; 424 first_next = &diagnostics_nv;
428 } 425 }
429
430 logical = vk::Device::Create(physical, queue_cis, extensions, first_next, dld); 426 logical = vk::Device::Create(physical, queue_cis, extensions, first_next, dld);
431 if (!logical) {
432 LOG_ERROR(Render_Vulkan, "Failed to create logical device");
433 return false;
434 }
435 427
436 CollectTelemetryParameters(); 428 CollectTelemetryParameters();
437 CollectToolingInfo(); 429 CollectToolingInfo();
@@ -455,9 +447,10 @@ bool VKDevice::Create() {
455 present_queue = logical.GetQueue(present_family); 447 present_queue = logical.GetQueue(present_family);
456 448
457 use_asynchronous_shaders = Settings::values.use_asynchronous_shaders.GetValue(); 449 use_asynchronous_shaders = Settings::values.use_asynchronous_shaders.GetValue();
458 return true;
459} 450}
460 451
452VKDevice::~VKDevice() = default;
453
461VkFormat VKDevice::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags wanted_usage, 454VkFormat VKDevice::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags wanted_usage,
462 FormatType format_type) const { 455 FormatType format_type) const {
463 if (IsFormatSupported(wanted_format, wanted_usage, format_type)) { 456 if (IsFormatSupported(wanted_format, wanted_usage, format_type)) {
@@ -556,64 +549,45 @@ bool VKDevice::IsFormatSupported(VkFormat wanted_format, VkFormatFeatureFlags wa
556 return (supported_usage & wanted_usage) == wanted_usage; 549 return (supported_usage & wanted_usage) == wanted_usage;
557} 550}
558 551
559bool VKDevice::IsSuitable(vk::PhysicalDevice physical, VkSurfaceKHR surface) { 552void VKDevice::CheckSuitability() const {
560 bool is_suitable = true;
561 std::bitset<REQUIRED_EXTENSIONS.size()> available_extensions; 553 std::bitset<REQUIRED_EXTENSIONS.size()> available_extensions;
562 554 for (const VkExtensionProperties& property : physical.EnumerateDeviceExtensionProperties()) {
563 for (const auto& prop : physical.EnumerateDeviceExtensionProperties()) {
564 for (std::size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) { 555 for (std::size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) {
565 if (available_extensions[i]) { 556 if (available_extensions[i]) {
566 continue; 557 continue;
567 } 558 }
568 const std::string_view name{prop.extensionName}; 559 const std::string_view name{property.extensionName};
569 available_extensions[i] = name == REQUIRED_EXTENSIONS[i]; 560 available_extensions[i] = name == REQUIRED_EXTENSIONS[i];
570 } 561 }
571 } 562 }
572 if (!available_extensions.all()) { 563 for (size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) {
573 for (std::size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) { 564 if (available_extensions[i]) {
574 if (available_extensions[i]) {
575 continue;
576 }
577 LOG_ERROR(Render_Vulkan, "Missing required extension: {}", REQUIRED_EXTENSIONS[i]);
578 is_suitable = false;
579 }
580 }
581
582 bool has_graphics{}, has_present{};
583 const std::vector queue_family_properties = physical.GetQueueFamilyProperties();
584 for (u32 i = 0; i < static_cast<u32>(queue_family_properties.size()); ++i) {
585 const auto& family = queue_family_properties[i];
586 if (family.queueCount == 0) {
587 continue; 565 continue;
588 } 566 }
589 has_graphics |= family.queueFlags & VK_QUEUE_GRAPHICS_BIT; 567 LOG_ERROR(Render_Vulkan, "Missing required extension: {}", REQUIRED_EXTENSIONS[i]);
590 has_present |= physical.GetSurfaceSupportKHR(i, surface); 568 throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT);
591 } 569 }
592 if (!has_graphics || !has_present) { 570 struct LimitTuple {
593 LOG_ERROR(Render_Vulkan, "Device lacks a graphics and present queue"); 571 u32 minimum;
594 is_suitable = false; 572 u32 value;
595 } 573 const char* name;
596 574 };
597 // TODO(Rodrigo): Check if the device matches all requeriments. 575 const VkPhysicalDeviceLimits& limits{properties.limits};
598 const auto properties{physical.GetProperties()}; 576 const std::array limits_report{
599 const auto& limits{properties.limits}; 577 LimitTuple{65536, limits.maxUniformBufferRange, "maxUniformBufferRange"},
600 578 LimitTuple{16, limits.maxViewports, "maxViewports"},
601 constexpr u32 required_ubo_size = 65536; 579 LimitTuple{8, limits.maxColorAttachments, "maxColorAttachments"},
602 if (limits.maxUniformBufferRange < required_ubo_size) { 580 LimitTuple{8, limits.maxClipDistances, "maxClipDistances"},
603 LOG_ERROR(Render_Vulkan, "Device UBO size {} is too small, {} is required", 581 };
604 limits.maxUniformBufferRange, required_ubo_size); 582 for (const auto& tuple : limits_report) {
605 is_suitable = false; 583 if (tuple.value < tuple.minimum) {
606 } 584 LOG_ERROR(Render_Vulkan, "{} has to be {} or greater but it is {}", tuple.name,
607 585 tuple.minimum, tuple.value);
608 constexpr u32 required_num_viewports = 16; 586 throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT);
609 if (limits.maxViewports < required_num_viewports) { 587 }
610 LOG_INFO(Render_Vulkan, "Device number of viewports {} is too small, {} is required",
611 limits.maxViewports, required_num_viewports);
612 is_suitable = false;
613 } 588 }
614 589 const VkPhysicalDeviceFeatures features{physical.GetFeatures()};
615 const auto features{physical.GetFeatures()}; 590 const std::array feature_report{
616 const std::array feature_report = {
617 std::make_pair(features.vertexPipelineStoresAndAtomics, "vertexPipelineStoresAndAtomics"), 591 std::make_pair(features.vertexPipelineStoresAndAtomics, "vertexPipelineStoresAndAtomics"),
618 std::make_pair(features.imageCubeArray, "imageCubeArray"), 592 std::make_pair(features.imageCubeArray, "imageCubeArray"),
619 std::make_pair(features.independentBlend, "independentBlend"), 593 std::make_pair(features.independentBlend, "independentBlend"),
@@ -631,19 +605,13 @@ bool VKDevice::IsSuitable(vk::PhysicalDevice physical, VkSurfaceKHR surface) {
631 std::make_pair(features.shaderStorageImageWriteWithoutFormat, 605 std::make_pair(features.shaderStorageImageWriteWithoutFormat,
632 "shaderStorageImageWriteWithoutFormat"), 606 "shaderStorageImageWriteWithoutFormat"),
633 }; 607 };
634 for (const auto& [supported, name] : feature_report) { 608 for (const auto& [is_supported, name] : feature_report) {
635 if (supported) { 609 if (is_supported) {
636 continue; 610 continue;
637 } 611 }
638 LOG_ERROR(Render_Vulkan, "Missing required feature: {}", name); 612 LOG_ERROR(Render_Vulkan, "Missing required feature: {}", name);
639 is_suitable = false; 613 throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT);
640 } 614 }
641
642 if (!is_suitable) {
643 LOG_ERROR(Render_Vulkan, "{} is not suitable", properties.deviceName);
644 }
645
646 return is_suitable;
647} 615}
648 616
649std::vector<const char*> VKDevice::LoadExtensions() { 617std::vector<const char*> VKDevice::LoadExtensions() {
@@ -685,9 +653,7 @@ std::vector<const char*> VKDevice::LoadExtensions() {
685 test(has_ext_custom_border_color, VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME, false); 653 test(has_ext_custom_border_color, VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME, false);
686 test(has_ext_extended_dynamic_state, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, false); 654 test(has_ext_extended_dynamic_state, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, false);
687 test(has_ext_robustness2, VK_EXT_ROBUSTNESS_2_EXTENSION_NAME, false); 655 test(has_ext_robustness2, VK_EXT_ROBUSTNESS_2_EXTENSION_NAME, false);
688 if (instance_version >= VK_API_VERSION_1_1) { 656 test(has_ext_subgroup_size_control, VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME, false);
689 test(has_ext_subgroup_size_control, VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME, false);
690 }
691 if (Settings::values.renderer_debug) { 657 if (Settings::values.renderer_debug) {
692 test(nv_device_diagnostics_config, VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME, 658 test(nv_device_diagnostics_config, VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME,
693 true); 659 true);
@@ -802,28 +768,34 @@ std::vector<const char*> VKDevice::LoadExtensions() {
802} 768}
803 769
804void VKDevice::SetupFamilies(VkSurfaceKHR surface) { 770void VKDevice::SetupFamilies(VkSurfaceKHR surface) {
805 std::optional<u32> graphics_family_, present_family_;
806
807 const std::vector queue_family_properties = physical.GetQueueFamilyProperties(); 771 const std::vector queue_family_properties = physical.GetQueueFamilyProperties();
808 for (u32 i = 0; i < static_cast<u32>(queue_family_properties.size()); ++i) { 772 std::optional<u32> graphics;
809 if (graphics_family_ && present_family_) 773 std::optional<u32> present;
774 for (u32 index = 0; index < static_cast<u32>(queue_family_properties.size()); ++index) {
775 if (graphics && present) {
810 break; 776 break;
811 777 }
812 const auto& queue_family = queue_family_properties[i]; 778 const VkQueueFamilyProperties& queue_family = queue_family_properties[index];
813 if (queue_family.queueCount == 0) 779 if (queue_family.queueCount == 0) {
814 continue; 780 continue;
815 781 }
816 if (queue_family.queueFlags & VK_QUEUE_GRAPHICS_BIT) { 782 if (queue_family.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
817 graphics_family_ = i; 783 graphics = index;
818 } 784 }
819 if (physical.GetSurfaceSupportKHR(i, surface)) { 785 if (physical.GetSurfaceSupportKHR(index, surface)) {
820 present_family_ = i; 786 present = index;
821 } 787 }
822 } 788 }
823 ASSERT(graphics_family_ && present_family_); 789 if (!graphics) {
824 790 LOG_ERROR(Render_Vulkan, "Device lacks a graphics queue");
825 graphics_family = *graphics_family_; 791 throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT);
826 present_family = *present_family_; 792 }
793 if (!present) {
794 LOG_ERROR(Render_Vulkan, "Device lacks a present queue");
795 throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT);
796 }
797 graphics_family = *graphics;
798 present_family = *present;
827} 799}
828 800
829void VKDevice::SetupFeatures() { 801void VKDevice::SetupFeatures() {
diff --git a/src/video_core/renderer_vulkan/vk_device.h b/src/video_core/renderer_vulkan/vk_device.h
index 995dcfc0f..146acbe24 100644
--- a/src/video_core/renderer_vulkan/vk_device.h
+++ b/src/video_core/renderer_vulkan/vk_device.h
@@ -11,7 +11,7 @@
11 11
12#include "common/common_types.h" 12#include "common/common_types.h"
13#include "video_core/renderer_vulkan/nsight_aftermath_tracker.h" 13#include "video_core/renderer_vulkan/nsight_aftermath_tracker.h"
14#include "video_core/renderer_vulkan/wrapper.h" 14#include "video_core/vulkan_common/vulkan_wrapper.h"
15 15
16namespace Vulkan { 16namespace Vulkan {
17 17
@@ -24,13 +24,10 @@ const u32 GuestWarpSize = 32;
24/// Handles data specific to a physical device. 24/// Handles data specific to a physical device.
25class VKDevice final { 25class VKDevice final {
26public: 26public:
27 explicit VKDevice(VkInstance instance, u32 instance_version, vk::PhysicalDevice physical, 27 explicit VKDevice(VkInstance instance, vk::PhysicalDevice physical, VkSurfaceKHR surface,
28 VkSurfaceKHR surface, const vk::InstanceDispatch& dld); 28 const vk::InstanceDispatch& dld);
29 ~VKDevice(); 29 ~VKDevice();
30 30
31 /// Initializes the device. Returns true on success.
32 bool Create();
33
34 /** 31 /**
35 * Returns a format supported by the device for the passed requeriments. 32 * Returns a format supported by the device for the passed requeriments.
36 * @param wanted_format The ideal format to be returned. It may not be the returned format. 33 * @param wanted_format The ideal format to be returned. It may not be the returned format.
@@ -82,11 +79,6 @@ public:
82 return present_family; 79 return present_family;
83 } 80 }
84 81
85 /// Returns the current instance Vulkan API version in Vulkan-formatted version numbers.
86 u32 InstanceApiVersion() const {
87 return instance_version;
88 }
89
90 /// Returns the current Vulkan API version provided in Vulkan-formatted version numbers. 82 /// Returns the current Vulkan API version provided in Vulkan-formatted version numbers.
91 u32 ApiVersion() const { 83 u32 ApiVersion() const {
92 return properties.apiVersion; 84 return properties.apiVersion;
@@ -232,10 +224,10 @@ public:
232 return use_asynchronous_shaders; 224 return use_asynchronous_shaders;
233 } 225 }
234 226
227private:
235 /// Checks if the physical device is suitable. 228 /// Checks if the physical device is suitable.
236 static bool IsSuitable(vk::PhysicalDevice physical, VkSurfaceKHR surface); 229 void CheckSuitability() const;
237 230
238private:
239 /// Loads extensions into a vector and stores available ones in this object. 231 /// Loads extensions into a vector and stores available ones in this object.
240 std::vector<const char*> LoadExtensions(); 232 std::vector<const char*> LoadExtensions();
241 233
diff --git a/src/video_core/renderer_vulkan/vk_fence_manager.cpp b/src/video_core/renderer_vulkan/vk_fence_manager.cpp
index 774a12a53..cd044c187 100644
--- a/src/video_core/renderer_vulkan/vk_fence_manager.cpp
+++ b/src/video_core/renderer_vulkan/vk_fence_manager.cpp
@@ -10,7 +10,7 @@
10#include "video_core/renderer_vulkan/vk_fence_manager.h" 10#include "video_core/renderer_vulkan/vk_fence_manager.h"
11#include "video_core/renderer_vulkan/vk_scheduler.h" 11#include "video_core/renderer_vulkan/vk_scheduler.h"
12#include "video_core/renderer_vulkan/vk_texture_cache.h" 12#include "video_core/renderer_vulkan/vk_texture_cache.h"
13#include "video_core/renderer_vulkan/wrapper.h" 13#include "video_core/vulkan_common/vulkan_wrapper.h"
14 14
15namespace Vulkan { 15namespace Vulkan {
16 16
diff --git a/src/video_core/renderer_vulkan/vk_fence_manager.h b/src/video_core/renderer_vulkan/vk_fence_manager.h
index c2869e8e3..272ae6d29 100644
--- a/src/video_core/renderer_vulkan/vk_fence_manager.h
+++ b/src/video_core/renderer_vulkan/vk_fence_manager.h
@@ -9,7 +9,7 @@
9#include "video_core/fence_manager.h" 9#include "video_core/fence_manager.h"
10#include "video_core/renderer_vulkan/vk_buffer_cache.h" 10#include "video_core/renderer_vulkan/vk_buffer_cache.h"
11#include "video_core/renderer_vulkan/vk_texture_cache.h" 11#include "video_core/renderer_vulkan/vk_texture_cache.h"
12#include "video_core/renderer_vulkan/wrapper.h" 12#include "video_core/vulkan_common/vulkan_wrapper.h"
13 13
14namespace Core { 14namespace Core {
15class System; 15class System;
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
index 7979df3a8..d9c1ed553 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
@@ -17,7 +17,7 @@
17#include "video_core/renderer_vulkan/vk_pipeline_cache.h" 17#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
18#include "video_core/renderer_vulkan/vk_scheduler.h" 18#include "video_core/renderer_vulkan/vk_scheduler.h"
19#include "video_core/renderer_vulkan/vk_update_descriptor.h" 19#include "video_core/renderer_vulkan/vk_update_descriptor.h"
20#include "video_core/renderer_vulkan/wrapper.h" 20#include "video_core/vulkan_common/vulkan_wrapper.h"
21 21
22namespace Vulkan { 22namespace Vulkan {
23 23
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h
index 214d06b4c..3bc93bc2a 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h
@@ -13,7 +13,7 @@
13#include "video_core/renderer_vulkan/fixed_pipeline_state.h" 13#include "video_core/renderer_vulkan/fixed_pipeline_state.h"
14#include "video_core/renderer_vulkan/vk_descriptor_pool.h" 14#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
15#include "video_core/renderer_vulkan/vk_shader_decompiler.h" 15#include "video_core/renderer_vulkan/vk_shader_decompiler.h"
16#include "video_core/renderer_vulkan/wrapper.h" 16#include "video_core/vulkan_common/vulkan_wrapper.h"
17 17
18namespace Vulkan { 18namespace Vulkan {
19 19
diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.cpp b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp
index ae26e558d..ed6ea0805 100644
--- a/src/video_core/renderer_vulkan/vk_master_semaphore.cpp
+++ b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp
@@ -8,7 +8,7 @@
8#include "core/settings.h" 8#include "core/settings.h"
9#include "video_core/renderer_vulkan/vk_device.h" 9#include "video_core/renderer_vulkan/vk_device.h"
10#include "video_core/renderer_vulkan/vk_master_semaphore.h" 10#include "video_core/renderer_vulkan/vk_master_semaphore.h"
11#include "video_core/renderer_vulkan/wrapper.h" 11#include "video_core/vulkan_common/vulkan_wrapper.h"
12 12
13namespace Vulkan { 13namespace Vulkan {
14 14
diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.h b/src/video_core/renderer_vulkan/vk_master_semaphore.h
index 0e93706d7..747d2f3bc 100644
--- a/src/video_core/renderer_vulkan/vk_master_semaphore.h
+++ b/src/video_core/renderer_vulkan/vk_master_semaphore.h
@@ -8,7 +8,7 @@
8#include <thread> 8#include <thread>
9 9
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "video_core/renderer_vulkan/wrapper.h" 11#include "video_core/vulkan_common/vulkan_wrapper.h"
12 12
13namespace Vulkan { 13namespace Vulkan {
14 14
diff --git a/src/video_core/renderer_vulkan/vk_memory_manager.cpp b/src/video_core/renderer_vulkan/vk_memory_manager.cpp
index 56b24b70f..35f859f77 100644
--- a/src/video_core/renderer_vulkan/vk_memory_manager.cpp
+++ b/src/video_core/renderer_vulkan/vk_memory_manager.cpp
@@ -13,7 +13,7 @@
13#include "common/logging/log.h" 13#include "common/logging/log.h"
14#include "video_core/renderer_vulkan/vk_device.h" 14#include "video_core/renderer_vulkan/vk_device.h"
15#include "video_core/renderer_vulkan/vk_memory_manager.h" 15#include "video_core/renderer_vulkan/vk_memory_manager.h"
16#include "video_core/renderer_vulkan/wrapper.h" 16#include "video_core/vulkan_common/vulkan_wrapper.h"
17 17
18namespace Vulkan { 18namespace Vulkan {
19 19
diff --git a/src/video_core/renderer_vulkan/vk_memory_manager.h b/src/video_core/renderer_vulkan/vk_memory_manager.h
index 318f8b43e..20463ecad 100644
--- a/src/video_core/renderer_vulkan/vk_memory_manager.h
+++ b/src/video_core/renderer_vulkan/vk_memory_manager.h
@@ -9,7 +9,7 @@
9#include <utility> 9#include <utility>
10#include <vector> 10#include <vector>
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "video_core/renderer_vulkan/wrapper.h" 12#include "video_core/vulkan_common/vulkan_wrapper.h"
13 13
14namespace Vulkan { 14namespace Vulkan {
15 15
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index 083796d05..b44fd6159 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -25,11 +25,11 @@
25#include "video_core/renderer_vulkan/vk_rasterizer.h" 25#include "video_core/renderer_vulkan/vk_rasterizer.h"
26#include "video_core/renderer_vulkan/vk_scheduler.h" 26#include "video_core/renderer_vulkan/vk_scheduler.h"
27#include "video_core/renderer_vulkan/vk_update_descriptor.h" 27#include "video_core/renderer_vulkan/vk_update_descriptor.h"
28#include "video_core/renderer_vulkan/wrapper.h"
29#include "video_core/shader/compiler_settings.h" 28#include "video_core/shader/compiler_settings.h"
30#include "video_core/shader/memory_util.h" 29#include "video_core/shader/memory_util.h"
31#include "video_core/shader_cache.h" 30#include "video_core/shader_cache.h"
32#include "video_core/shader_notify.h" 31#include "video_core/shader_notify.h"
32#include "video_core/vulkan_common/vulkan_wrapper.h"
33 33
34namespace Vulkan { 34namespace Vulkan {
35 35
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h
index fbaa8257c..5ce1b17f3 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h
@@ -20,12 +20,12 @@
20#include "video_core/renderer_vulkan/fixed_pipeline_state.h" 20#include "video_core/renderer_vulkan/fixed_pipeline_state.h"
21#include "video_core/renderer_vulkan/vk_graphics_pipeline.h" 21#include "video_core/renderer_vulkan/vk_graphics_pipeline.h"
22#include "video_core/renderer_vulkan/vk_shader_decompiler.h" 22#include "video_core/renderer_vulkan/vk_shader_decompiler.h"
23#include "video_core/renderer_vulkan/wrapper.h"
24#include "video_core/shader/async_shaders.h" 23#include "video_core/shader/async_shaders.h"
25#include "video_core/shader/memory_util.h" 24#include "video_core/shader/memory_util.h"
26#include "video_core/shader/registry.h" 25#include "video_core/shader/registry.h"
27#include "video_core/shader/shader_ir.h" 26#include "video_core/shader/shader_ir.h"
28#include "video_core/shader_cache.h" 27#include "video_core/shader_cache.h"
28#include "video_core/vulkan_common/vulkan_wrapper.h"
29 29
30namespace Core { 30namespace Core {
31class System; 31class System;
diff --git a/src/video_core/renderer_vulkan/vk_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp
index 038760de3..7852178b6 100644
--- a/src/video_core/renderer_vulkan/vk_query_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp
@@ -11,7 +11,7 @@
11#include "video_core/renderer_vulkan/vk_query_cache.h" 11#include "video_core/renderer_vulkan/vk_query_cache.h"
12#include "video_core/renderer_vulkan/vk_resource_pool.h" 12#include "video_core/renderer_vulkan/vk_resource_pool.h"
13#include "video_core/renderer_vulkan/vk_scheduler.h" 13#include "video_core/renderer_vulkan/vk_scheduler.h"
14#include "video_core/renderer_vulkan/wrapper.h" 14#include "video_core/vulkan_common/vulkan_wrapper.h"
15 15
16namespace Vulkan { 16namespace Vulkan {
17 17
diff --git a/src/video_core/renderer_vulkan/vk_query_cache.h b/src/video_core/renderer_vulkan/vk_query_cache.h
index 837fe9ebf..b4fb6b3b0 100644
--- a/src/video_core/renderer_vulkan/vk_query_cache.h
+++ b/src/video_core/renderer_vulkan/vk_query_cache.h
@@ -12,7 +12,7 @@
12#include "common/common_types.h" 12#include "common/common_types.h"
13#include "video_core/query_cache.h" 13#include "video_core/query_cache.h"
14#include "video_core/renderer_vulkan/vk_resource_pool.h" 14#include "video_core/renderer_vulkan/vk_resource_pool.h"
15#include "video_core/renderer_vulkan/wrapper.h" 15#include "video_core/vulkan_common/vulkan_wrapper.h"
16 16
17namespace VideoCore { 17namespace VideoCore {
18class RasterizerInterface; 18class RasterizerInterface;
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index 04c5c859c..1c174e7ec 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -36,9 +36,9 @@
36#include "video_core/renderer_vulkan/vk_state_tracker.h" 36#include "video_core/renderer_vulkan/vk_state_tracker.h"
37#include "video_core/renderer_vulkan/vk_texture_cache.h" 37#include "video_core/renderer_vulkan/vk_texture_cache.h"
38#include "video_core/renderer_vulkan/vk_update_descriptor.h" 38#include "video_core/renderer_vulkan/vk_update_descriptor.h"
39#include "video_core/renderer_vulkan/wrapper.h"
40#include "video_core/shader_cache.h" 39#include "video_core/shader_cache.h"
41#include "video_core/texture_cache/texture_cache.h" 40#include "video_core/texture_cache/texture_cache.h"
41#include "video_core/vulkan_common/vulkan_wrapper.h"
42 42
43namespace Vulkan { 43namespace Vulkan {
44 44
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h
index 990f9e031..7b9ec3bb8 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.h
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.h
@@ -29,8 +29,8 @@
29#include "video_core/renderer_vulkan/vk_stream_buffer.h" 29#include "video_core/renderer_vulkan/vk_stream_buffer.h"
30#include "video_core/renderer_vulkan/vk_texture_cache.h" 30#include "video_core/renderer_vulkan/vk_texture_cache.h"
31#include "video_core/renderer_vulkan/vk_update_descriptor.h" 31#include "video_core/renderer_vulkan/vk_update_descriptor.h"
32#include "video_core/renderer_vulkan/wrapper.h"
33#include "video_core/shader/async_shaders.h" 32#include "video_core/shader/async_shaders.h"
33#include "video_core/vulkan_common/vulkan_wrapper.h"
34 34
35namespace Core { 35namespace Core {
36class System; 36class System;
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp
index c104c6fe3..f7b79e74c 100644
--- a/src/video_core/renderer_vulkan/vk_scheduler.cpp
+++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp
@@ -17,7 +17,7 @@
17#include "video_core/renderer_vulkan/vk_scheduler.h" 17#include "video_core/renderer_vulkan/vk_scheduler.h"
18#include "video_core/renderer_vulkan/vk_state_tracker.h" 18#include "video_core/renderer_vulkan/vk_state_tracker.h"
19#include "video_core/renderer_vulkan/vk_texture_cache.h" 19#include "video_core/renderer_vulkan/vk_texture_cache.h"
20#include "video_core/renderer_vulkan/wrapper.h" 20#include "video_core/vulkan_common/vulkan_wrapper.h"
21 21
22namespace Vulkan { 22namespace Vulkan {
23 23
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.h b/src/video_core/renderer_vulkan/vk_scheduler.h
index 0a36c8fad..1172ec622 100644
--- a/src/video_core/renderer_vulkan/vk_scheduler.h
+++ b/src/video_core/renderer_vulkan/vk_scheduler.h
@@ -12,7 +12,7 @@
12#include <utility> 12#include <utility>
13#include "common/common_types.h" 13#include "common/common_types.h"
14#include "common/threadsafe_queue.h" 14#include "common/threadsafe_queue.h"
15#include "video_core/renderer_vulkan/wrapper.h" 15#include "video_core/vulkan_common/vulkan_wrapper.h"
16 16
17namespace Vulkan { 17namespace Vulkan {
18 18
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
index 09d6f9f35..571460c2f 100644
--- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
+++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
@@ -272,19 +272,12 @@ bool IsPrecise(Operation operand) {
272 return false; 272 return false;
273} 273}
274 274
275u32 ShaderVersion(const VKDevice& device) {
276 if (device.InstanceApiVersion() < VK_API_VERSION_1_1) {
277 return 0x00010000;
278 }
279 return 0x00010300;
280}
281
282class SPIRVDecompiler final : public Sirit::Module { 275class SPIRVDecompiler final : public Sirit::Module {
283public: 276public:
284 explicit SPIRVDecompiler(const VKDevice& device_, const ShaderIR& ir_, ShaderType stage_, 277 explicit SPIRVDecompiler(const VKDevice& device_, const ShaderIR& ir_, ShaderType stage_,
285 const Registry& registry_, const Specialization& specialization_) 278 const Registry& registry_, const Specialization& specialization_)
286 : Module(ShaderVersion(device_)), device{device_}, ir{ir_}, stage{stage_}, 279 : Module(0x00010300), device{device_}, ir{ir_}, stage{stage_}, header{ir_.GetHeader()},
287 header{ir_.GetHeader()}, registry{registry_}, specialization{specialization_} { 280 registry{registry_}, specialization{specialization_} {
288 if (stage_ != ShaderType::Compute) { 281 if (stage_ != ShaderType::Compute) {
289 transform_feedback = BuildTransformFeedback(registry_.GetGraphicsInfo()); 282 transform_feedback = BuildTransformFeedback(registry_.GetGraphicsInfo());
290 } 283 }
diff --git a/src/video_core/renderer_vulkan/vk_shader_util.cpp b/src/video_core/renderer_vulkan/vk_shader_util.cpp
index 38a0be7f2..630306077 100644
--- a/src/video_core/renderer_vulkan/vk_shader_util.cpp
+++ b/src/video_core/renderer_vulkan/vk_shader_util.cpp
@@ -9,7 +9,7 @@
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "video_core/renderer_vulkan/vk_device.h" 10#include "video_core/renderer_vulkan/vk_device.h"
11#include "video_core/renderer_vulkan/vk_shader_util.h" 11#include "video_core/renderer_vulkan/vk_shader_util.h"
12#include "video_core/renderer_vulkan/wrapper.h" 12#include "video_core/vulkan_common/vulkan_wrapper.h"
13 13
14namespace Vulkan { 14namespace Vulkan {
15 15
diff --git a/src/video_core/renderer_vulkan/vk_shader_util.h b/src/video_core/renderer_vulkan/vk_shader_util.h
index dce34a140..98ee5e668 100644
--- a/src/video_core/renderer_vulkan/vk_shader_util.h
+++ b/src/video_core/renderer_vulkan/vk_shader_util.h
@@ -7,7 +7,7 @@
7#include <span> 7#include <span>
8 8
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "video_core/renderer_vulkan/wrapper.h" 10#include "video_core/vulkan_common/vulkan_wrapper.h"
11 11
12namespace Vulkan { 12namespace Vulkan {
13 13
diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp
index 2fd3b7f39..e5155e886 100644
--- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp
+++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp
@@ -12,7 +12,7 @@
12#include "video_core/renderer_vulkan/vk_device.h" 12#include "video_core/renderer_vulkan/vk_device.h"
13#include "video_core/renderer_vulkan/vk_scheduler.h" 13#include "video_core/renderer_vulkan/vk_scheduler.h"
14#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" 14#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
15#include "video_core/renderer_vulkan/wrapper.h" 15#include "video_core/vulkan_common/vulkan_wrapper.h"
16 16
17namespace Vulkan { 17namespace Vulkan {
18 18
diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h
index 2dd5049ac..97ed1118a 100644
--- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h
+++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h
@@ -10,7 +10,7 @@
10#include "common/common_types.h" 10#include "common/common_types.h"
11 11
12#include "video_core/renderer_vulkan/vk_memory_manager.h" 12#include "video_core/renderer_vulkan/vk_memory_manager.h"
13#include "video_core/renderer_vulkan/wrapper.h" 13#include "video_core/vulkan_common/vulkan_wrapper.h"
14 14
15namespace Vulkan { 15namespace Vulkan {
16 16
diff --git a/src/video_core/renderer_vulkan/vk_stream_buffer.cpp b/src/video_core/renderer_vulkan/vk_stream_buffer.cpp
index 419cb154d..aae50bf25 100644
--- a/src/video_core/renderer_vulkan/vk_stream_buffer.cpp
+++ b/src/video_core/renderer_vulkan/vk_stream_buffer.cpp
@@ -13,7 +13,7 @@
13#include "video_core/renderer_vulkan/vk_device.h" 13#include "video_core/renderer_vulkan/vk_device.h"
14#include "video_core/renderer_vulkan/vk_scheduler.h" 14#include "video_core/renderer_vulkan/vk_scheduler.h"
15#include "video_core/renderer_vulkan/vk_stream_buffer.h" 15#include "video_core/renderer_vulkan/vk_stream_buffer.h"
16#include "video_core/renderer_vulkan/wrapper.h" 16#include "video_core/vulkan_common/vulkan_wrapper.h"
17 17
18namespace Vulkan { 18namespace Vulkan {
19 19
diff --git a/src/video_core/renderer_vulkan/vk_stream_buffer.h b/src/video_core/renderer_vulkan/vk_stream_buffer.h
index 1428f77bf..aebd68728 100644
--- a/src/video_core/renderer_vulkan/vk_stream_buffer.h
+++ b/src/video_core/renderer_vulkan/vk_stream_buffer.h
@@ -9,7 +9,7 @@
9#include <vector> 9#include <vector>
10 10
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "video_core/renderer_vulkan/wrapper.h" 12#include "video_core/vulkan_common/vulkan_wrapper.h"
13 13
14namespace Vulkan { 14namespace Vulkan {
15 15
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp
index 9636a7c65..458aa4532 100644
--- a/src/video_core/renderer_vulkan/vk_swapchain.cpp
+++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp
@@ -14,7 +14,7 @@
14#include "video_core/renderer_vulkan/vk_device.h" 14#include "video_core/renderer_vulkan/vk_device.h"
15#include "video_core/renderer_vulkan/vk_scheduler.h" 15#include "video_core/renderer_vulkan/vk_scheduler.h"
16#include "video_core/renderer_vulkan/vk_swapchain.h" 16#include "video_core/renderer_vulkan/vk_swapchain.h"
17#include "video_core/renderer_vulkan/wrapper.h" 17#include "video_core/vulkan_common/vulkan_wrapper.h"
18 18
19namespace Vulkan { 19namespace Vulkan {
20 20
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.h b/src/video_core/renderer_vulkan/vk_swapchain.h
index 6b39befdf..25eb20832 100644
--- a/src/video_core/renderer_vulkan/vk_swapchain.h
+++ b/src/video_core/renderer_vulkan/vk_swapchain.h
@@ -7,7 +7,7 @@
7#include <vector> 7#include <vector>
8 8
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "video_core/renderer_vulkan/wrapper.h" 10#include "video_core/vulkan_common/vulkan_wrapper.h"
11 11
12namespace Layout { 12namespace Layout {
13struct FramebufferLayout; 13struct FramebufferLayout;
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index 261808391..e04dd23ef 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -14,7 +14,7 @@
14#include "video_core/renderer_vulkan/vk_scheduler.h" 14#include "video_core/renderer_vulkan/vk_scheduler.h"
15#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" 15#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
16#include "video_core/renderer_vulkan/vk_texture_cache.h" 16#include "video_core/renderer_vulkan/vk_texture_cache.h"
17#include "video_core/renderer_vulkan/wrapper.h" 17#include "video_core/vulkan_common/vulkan_wrapper.h"
18 18
19namespace Vulkan { 19namespace Vulkan {
20 20
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h
index edc3d80c0..576515bcc 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.h
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.h
@@ -8,8 +8,8 @@
8#include <span> 8#include <span>
9 9
10#include "video_core/renderer_vulkan/vk_memory_manager.h" 10#include "video_core/renderer_vulkan/vk_memory_manager.h"
11#include "video_core/renderer_vulkan/wrapper.h"
12#include "video_core/texture_cache/texture_cache.h" 11#include "video_core/texture_cache/texture_cache.h"
12#include "video_core/vulkan_common/vulkan_wrapper.h"
13 13
14namespace Vulkan { 14namespace Vulkan {
15 15
diff --git a/src/video_core/renderer_vulkan/vk_update_descriptor.cpp b/src/video_core/renderer_vulkan/vk_update_descriptor.cpp
index 8826da325..c0603ac22 100644
--- a/src/video_core/renderer_vulkan/vk_update_descriptor.cpp
+++ b/src/video_core/renderer_vulkan/vk_update_descriptor.cpp
@@ -10,7 +10,7 @@
10#include "video_core/renderer_vulkan/vk_device.h" 10#include "video_core/renderer_vulkan/vk_device.h"
11#include "video_core/renderer_vulkan/vk_scheduler.h" 11#include "video_core/renderer_vulkan/vk_scheduler.h"
12#include "video_core/renderer_vulkan/vk_update_descriptor.h" 12#include "video_core/renderer_vulkan/vk_update_descriptor.h"
13#include "video_core/renderer_vulkan/wrapper.h" 13#include "video_core/vulkan_common/vulkan_wrapper.h"
14 14
15namespace Vulkan { 15namespace Vulkan {
16 16
diff --git a/src/video_core/renderer_vulkan/vk_update_descriptor.h b/src/video_core/renderer_vulkan/vk_update_descriptor.h
index f098a8540..d0ae49010 100644
--- a/src/video_core/renderer_vulkan/vk_update_descriptor.h
+++ b/src/video_core/renderer_vulkan/vk_update_descriptor.h
@@ -8,7 +8,7 @@
8#include <boost/container/static_vector.hpp> 8#include <boost/container/static_vector.hpp>
9 9
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "video_core/renderer_vulkan/wrapper.h" 11#include "video_core/vulkan_common/vulkan_wrapper.h"
12 12
13namespace Vulkan { 13namespace Vulkan {
14 14
diff --git a/src/video_core/vulkan_common/vulkan_debug_callback.cpp b/src/video_core/vulkan_common/vulkan_debug_callback.cpp
new file mode 100644
index 000000000..ea7af8ad4
--- /dev/null
+++ b/src/video_core/vulkan_common/vulkan_debug_callback.cpp
@@ -0,0 +1,45 @@
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 <string_view>
6#include "common/logging/log.h"
7#include "video_core/vulkan_common/vulkan_debug_callback.h"
8
9namespace Vulkan {
10namespace {
11VkBool32 Callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
12 VkDebugUtilsMessageTypeFlagsEXT type,
13 const VkDebugUtilsMessengerCallbackDataEXT* data,
14 [[maybe_unused]] void* user_data) {
15 const std::string_view message{data->pMessage};
16 if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
17 LOG_CRITICAL(Render_Vulkan, "{}", message);
18 } else if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) {
19 LOG_WARNING(Render_Vulkan, "{}", message);
20 } else if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) {
21 LOG_INFO(Render_Vulkan, "{}", message);
22 } else if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) {
23 LOG_DEBUG(Render_Vulkan, "{}", message);
24 }
25 return VK_FALSE;
26}
27} // Anonymous namespace
28
29vk::DebugUtilsMessenger CreateDebugCallback(const vk::Instance& instance) {
30 return instance.CreateDebugUtilsMessenger(VkDebugUtilsMessengerCreateInfoEXT{
31 .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
32 .pNext = nullptr,
33 .flags = 0,
34 .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT |
35 VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
36 VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT |
37 VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT,
38 .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
39 VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
40 VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
41 .pfnUserCallback = Callback,
42 });
43}
44
45} // namespace Vulkan
diff --git a/src/video_core/vulkan_common/vulkan_debug_callback.h b/src/video_core/vulkan_common/vulkan_debug_callback.h
new file mode 100644
index 000000000..2efcd244c
--- /dev/null
+++ b/src/video_core/vulkan_common/vulkan_debug_callback.h
@@ -0,0 +1,11 @@
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 "video_core/vulkan_common/vulkan_wrapper.h"
6
7namespace Vulkan {
8
9vk::DebugUtilsMessenger CreateDebugCallback(const vk::Instance& instance);
10
11} // namespace Vulkan
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..889ecda0c
--- /dev/null
+++ b/src/video_core/vulkan_common/vulkan_instance.cpp
@@ -0,0 +1,151 @@
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
114vk::Instance CreateInstance(const Common::DynamicLibrary& library, vk::InstanceDispatch& dld,
115 u32 required_version, Core::Frontend::WindowSystemType window_type,
116 bool enable_debug_utils, bool enable_layers) {
117 if (!library.IsOpen()) {
118 LOG_ERROR(Render_Vulkan, "Vulkan library not available");
119 throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
120 }
121 if (!library.GetSymbol("vkGetInstanceProcAddr", &dld.vkGetInstanceProcAddr)) {
122 LOG_ERROR(Render_Vulkan, "vkGetInstanceProcAddr not present in Vulkan");
123 throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
124 }
125 if (!vk::Load(dld)) {
126 LOG_ERROR(Render_Vulkan, "Failed to load Vulkan function pointers");
127 throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
128 }
129 const std::vector<const char*> extensions = RequiredExtensions(window_type, enable_debug_utils);
130 if (!AreExtensionsSupported(dld, extensions)) {
131 throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT);
132 }
133 std::vector<const char*> layers = Layers(enable_layers);
134 RemoveUnavailableLayers(dld, layers);
135
136 const u32 available_version = vk::AvailableVersion(dld);
137 if (available_version < required_version) {
138 LOG_ERROR(Render_Vulkan, "Vulkan {}.{} is not supported, {}.{} is required",
139 VK_VERSION_MAJOR(available_version), VK_VERSION_MINOR(available_version),
140 VK_VERSION_MAJOR(required_version), VK_VERSION_MINOR(required_version));
141 throw vk::Exception(VK_ERROR_INCOMPATIBLE_DRIVER);
142 }
143 vk::Instance instance = vk::Instance::Create(required_version, layers, extensions, dld);
144 if (!vk::Load(*instance, dld)) {
145 LOG_ERROR(Render_Vulkan, "Failed to load Vulkan instance function pointers");
146 throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
147 }
148 return instance;
149}
150
151} // 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..e5e3a7144
--- /dev/null
+++ b/src/video_core/vulkan_common/vulkan_instance.h
@@ -0,0 +1,32 @@
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 "common/common_types.h"
8#include "common/dynamic_library.h"
9#include "core/frontend/emu_window.h"
10#include "video_core/vulkan_common/vulkan_wrapper.h"
11
12namespace Vulkan {
13
14/**
15 * Create a Vulkan instance
16 *
17 * @param library Dynamic library to load the Vulkan instance from
18 * @param dld Dispatch table to load function pointers into
19 * @param required_version Required Vulkan version (for example, VK_API_VERSION_1_1)
20 * @param window_type Window system type's enabled extension
21 * @param enable_debug_utils Whether to enable VK_EXT_debug_utils_extension_name or not
22 * @param enable_layers Whether to enable Vulkan validation layers or not
23 *
24 * @return A new Vulkan instance
25 * @throw vk::Exception on failure
26 */
27[[nodiscard]] vk::Instance CreateInstance(
28 const Common::DynamicLibrary& library, vk::InstanceDispatch& dld, u32 required_version,
29 Core::Frontend::WindowSystemType window_type = Core::Frontend::WindowSystemType::Headless,
30 bool enable_debug_utils = false, bool enable_layers = false);
31
32} // namespace Vulkan
diff --git a/src/video_core/vulkan_common/vulkan_library.cpp b/src/video_core/vulkan_common/vulkan_library.cpp
new file mode 100644
index 000000000..27c958221
--- /dev/null
+++ b/src/video_core/vulkan_common/vulkan_library.cpp
@@ -0,0 +1,36 @@
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 <cstdlib>
6#include <string>
7
8#include "common/dynamic_library.h"
9#include "common/file_util.h"
10#include "video_core/vulkan_common/vulkan_library.h"
11
12namespace Vulkan {
13
14Common::DynamicLibrary OpenLibrary() {
15 Common::DynamicLibrary library;
16#ifdef __APPLE__
17 // Check if a path to a specific Vulkan library has been specified.
18 char* const libvulkan_env = std::getenv("LIBVULKAN_PATH");
19 if (!libvulkan_env || !library.Open(libvulkan_env)) {
20 // Use the libvulkan.dylib from the application bundle.
21 const std::string filename =
22 Common::FS::GetBundleDirectory() + "/Contents/Frameworks/libvulkan.dylib";
23 library.Open(filename.c_str());
24 }
25#else
26 std::string filename = Common::DynamicLibrary::GetVersionedFilename("vulkan", 1);
27 if (!library.Open(filename.c_str())) {
28 // Android devices may not have libvulkan.so.1, only libvulkan.so.
29 filename = Common::DynamicLibrary::GetVersionedFilename("vulkan");
30 void(library.Open(filename.c_str()));
31 }
32#endif
33 return library;
34}
35
36} // namespace Vulkan
diff --git a/src/video_core/vulkan_common/vulkan_library.h b/src/video_core/vulkan_common/vulkan_library.h
new file mode 100644
index 000000000..8b28b0e17
--- /dev/null
+++ b/src/video_core/vulkan_common/vulkan_library.h
@@ -0,0 +1,13 @@
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 "common/dynamic_library.h"
8
9namespace Vulkan {
10
11Common::DynamicLibrary OpenLibrary();
12
13} // namespace Vulkan
diff --git a/src/video_core/vulkan_common/vulkan_surface.cpp b/src/video_core/vulkan_common/vulkan_surface.cpp
new file mode 100644
index 000000000..3c3238f96
--- /dev/null
+++ b/src/video_core/vulkan_common/vulkan_surface.cpp
@@ -0,0 +1,81 @@
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 "common/logging/log.h"
6#include "core/frontend/emu_window.h"
7#include "video_core/vulkan_common/vulkan_surface.h"
8#include "video_core/vulkan_common/vulkan_wrapper.h"
9
10// Include these late to avoid polluting previous headers
11#ifdef _WIN32
12#include <windows.h>
13// ensure include order
14#include <vulkan/vulkan_win32.h>
15#endif
16
17#if !defined(_WIN32) && !defined(__APPLE__)
18#include <X11/Xlib.h>
19#include <vulkan/vulkan_wayland.h>
20#include <vulkan/vulkan_xlib.h>
21#endif
22
23namespace Vulkan {
24
25vk::SurfaceKHR CreateSurface(const vk::Instance& instance,
26 const Core::Frontend::EmuWindow& emu_window) {
27 [[maybe_unused]] const vk::InstanceDispatch& dld = instance.Dispatch();
28 [[maybe_unused]] const auto& window_info = emu_window.GetWindowInfo();
29 VkSurfaceKHR unsafe_surface = nullptr;
30
31#ifdef _WIN32
32 if (window_info.type == Core::Frontend::WindowSystemType::Windows) {
33 const HWND hWnd = static_cast<HWND>(window_info.render_surface);
34 const VkWin32SurfaceCreateInfoKHR win32_ci{VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR,
35 nullptr, 0, nullptr, hWnd};
36 const auto vkCreateWin32SurfaceKHR = reinterpret_cast<PFN_vkCreateWin32SurfaceKHR>(
37 dld.vkGetInstanceProcAddr(*instance, "vkCreateWin32SurfaceKHR"));
38 if (!vkCreateWin32SurfaceKHR ||
39 vkCreateWin32SurfaceKHR(*instance, &win32_ci, nullptr, &unsafe_surface) != VK_SUCCESS) {
40 LOG_ERROR(Render_Vulkan, "Failed to initialize Win32 surface");
41 throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
42 }
43 }
44#endif
45#if !defined(_WIN32) && !defined(__APPLE__)
46 if (window_info.type == Core::Frontend::WindowSystemType::X11) {
47 const VkXlibSurfaceCreateInfoKHR xlib_ci{
48 VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, nullptr, 0,
49 static_cast<Display*>(window_info.display_connection),
50 reinterpret_cast<Window>(window_info.render_surface)};
51 const auto vkCreateXlibSurfaceKHR = reinterpret_cast<PFN_vkCreateXlibSurfaceKHR>(
52 dld.vkGetInstanceProcAddr(*instance, "vkCreateXlibSurfaceKHR"));
53 if (!vkCreateXlibSurfaceKHR ||
54 vkCreateXlibSurfaceKHR(*instance, &xlib_ci, nullptr, &unsafe_surface) != VK_SUCCESS) {
55 LOG_ERROR(Render_Vulkan, "Failed to initialize Xlib surface");
56 throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
57 }
58 }
59 if (window_info.type == Core::Frontend::WindowSystemType::Wayland) {
60 const VkWaylandSurfaceCreateInfoKHR wayland_ci{
61 VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, nullptr, 0,
62 static_cast<wl_display*>(window_info.display_connection),
63 static_cast<wl_surface*>(window_info.render_surface)};
64 const auto vkCreateWaylandSurfaceKHR = reinterpret_cast<PFN_vkCreateWaylandSurfaceKHR>(
65 dld.vkGetInstanceProcAddr(*instance, "vkCreateWaylandSurfaceKHR"));
66 if (!vkCreateWaylandSurfaceKHR ||
67 vkCreateWaylandSurfaceKHR(*instance, &wayland_ci, nullptr, &unsafe_surface) !=
68 VK_SUCCESS) {
69 LOG_ERROR(Render_Vulkan, "Failed to initialize Wayland surface");
70 throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
71 }
72 }
73#endif
74 if (!unsafe_surface) {
75 LOG_ERROR(Render_Vulkan, "Presentation not supported on this platform");
76 throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
77 }
78 return vk::SurfaceKHR(unsafe_surface, *instance, dld);
79}
80
81} // namespace Vulkan
diff --git a/src/video_core/vulkan_common/vulkan_surface.h b/src/video_core/vulkan_common/vulkan_surface.h
new file mode 100644
index 000000000..05a169e32
--- /dev/null
+++ b/src/video_core/vulkan_common/vulkan_surface.h
@@ -0,0 +1,18 @@
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 "video_core/vulkan_common/vulkan_wrapper.h"
8
9namespace Core::Frontend {
10class EmuWindow;
11}
12
13namespace Vulkan {
14
15[[nodiscard]] vk::SurfaceKHR CreateSurface(const vk::Instance& instance,
16 const Core::Frontend::EmuWindow& emu_window);
17
18} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp
index 2a21e850d..5e15ad607 100644
--- a/src/video_core/renderer_vulkan/wrapper.cpp
+++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp
@@ -13,7 +13,7 @@
13#include "common/common_types.h" 13#include "common/common_types.h"
14#include "common/logging/log.h" 14#include "common/logging/log.h"
15 15
16#include "video_core/renderer_vulkan/wrapper.h" 16#include "video_core/vulkan_common/vulkan_wrapper.h"
17 17
18namespace Vulkan::vk { 18namespace Vulkan::vk {
19 19
@@ -435,7 +435,7 @@ VkResult Free(VkDevice device, VkCommandPool handle, Span<VkCommandBuffer> buffe
435} 435}
436 436
437Instance Instance::Create(u32 version, Span<const char*> layers, Span<const char*> extensions, 437Instance Instance::Create(u32 version, Span<const char*> layers, Span<const char*> extensions,
438 InstanceDispatch& dispatch) noexcept { 438 InstanceDispatch& dispatch) {
439 const VkApplicationInfo application_info{ 439 const VkApplicationInfo application_info{
440 .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, 440 .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
441 .pNext = nullptr, 441 .pNext = nullptr,
@@ -455,55 +455,30 @@ Instance Instance::Create(u32 version, Span<const char*> layers, Span<const char
455 .enabledExtensionCount = extensions.size(), 455 .enabledExtensionCount = extensions.size(),
456 .ppEnabledExtensionNames = extensions.data(), 456 .ppEnabledExtensionNames = extensions.data(),
457 }; 457 };
458
459 VkInstance instance; 458 VkInstance instance;
460 if (dispatch.vkCreateInstance(&ci, nullptr, &instance) != VK_SUCCESS) { 459 Check(dispatch.vkCreateInstance(&ci, nullptr, &instance));
461 // Failed to create the instance.
462 return {};
463 }
464 if (!Proc(dispatch.vkDestroyInstance, dispatch, "vkDestroyInstance", instance)) { 460 if (!Proc(dispatch.vkDestroyInstance, dispatch, "vkDestroyInstance", instance)) {
465 // We successfully created an instance but the destroy function couldn't be loaded. 461 // We successfully created an instance but the destroy function couldn't be loaded.
466 // This is a good moment to panic. 462 // This is a good moment to panic.
467 return {}; 463 throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
468 } 464 }
469
470 return Instance(instance, dispatch); 465 return Instance(instance, dispatch);
471} 466}
472 467
473std::optional<std::vector<VkPhysicalDevice>> Instance::EnumeratePhysicalDevices() { 468std::vector<VkPhysicalDevice> Instance::EnumeratePhysicalDevices() const {
474 u32 num; 469 u32 num;
475 if (dld->vkEnumeratePhysicalDevices(handle, &num, nullptr) != VK_SUCCESS) { 470 Check(dld->vkEnumeratePhysicalDevices(handle, &num, nullptr));
476 return std::nullopt;
477 }
478 std::vector<VkPhysicalDevice> physical_devices(num); 471 std::vector<VkPhysicalDevice> physical_devices(num);
479 if (dld->vkEnumeratePhysicalDevices(handle, &num, physical_devices.data()) != VK_SUCCESS) { 472 Check(dld->vkEnumeratePhysicalDevices(handle, &num, physical_devices.data()));
480 return std::nullopt;
481 }
482 SortPhysicalDevices(physical_devices, *dld); 473 SortPhysicalDevices(physical_devices, *dld);
483 return std::make_optional(std::move(physical_devices)); 474 return physical_devices;
484} 475}
485 476
486DebugCallback Instance::TryCreateDebugCallback( 477DebugUtilsMessenger Instance::CreateDebugUtilsMessenger(
487 PFN_vkDebugUtilsMessengerCallbackEXT callback) noexcept { 478 const VkDebugUtilsMessengerCreateInfoEXT& create_info) const {
488 const VkDebugUtilsMessengerCreateInfoEXT ci{ 479 VkDebugUtilsMessengerEXT object;
489 .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, 480 Check(dld->vkCreateDebugUtilsMessengerEXT(handle, &create_info, nullptr, &object));
490 .pNext = nullptr, 481 return DebugUtilsMessenger(object, handle, *dld);
491 .flags = 0,
492 .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT |
493 VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
494 VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT |
495 VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT,
496 .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
497 VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT,
498 .pfnUserCallback = callback,
499 .pUserData = nullptr,
500 };
501
502 VkDebugUtilsMessengerEXT messenger;
503 if (dld->vkCreateDebugUtilsMessengerEXT(handle, &ci, nullptr, &messenger) != VK_SUCCESS) {
504 return {};
505 }
506 return DebugCallback(messenger, handle, *dld);
507} 482}
508 483
509void Buffer::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const { 484void Buffer::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const {
@@ -605,7 +580,7 @@ void Semaphore::SetObjectNameEXT(const char* name) const {
605 580
606Device Device::Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreateInfo> queues_ci, 581Device Device::Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreateInfo> queues_ci,
607 Span<const char*> enabled_extensions, const void* next, 582 Span<const char*> enabled_extensions, const void* next,
608 DeviceDispatch& dispatch) noexcept { 583 DeviceDispatch& dispatch) {
609 const VkDeviceCreateInfo ci{ 584 const VkDeviceCreateInfo ci{
610 .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, 585 .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
611 .pNext = next, 586 .pNext = next,
@@ -618,11 +593,8 @@ Device Device::Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreate
618 .ppEnabledExtensionNames = enabled_extensions.data(), 593 .ppEnabledExtensionNames = enabled_extensions.data(),
619 .pEnabledFeatures = nullptr, 594 .pEnabledFeatures = nullptr,
620 }; 595 };
621
622 VkDevice device; 596 VkDevice device;
623 if (dispatch.vkCreateDevice(physical_device, &ci, nullptr, &device) != VK_SUCCESS) { 597 Check(dispatch.vkCreateDevice(physical_device, &ci, nullptr, &device));
624 return {};
625 }
626 Load(device, dispatch); 598 Load(device, dispatch);
627 return Device(device, dispatch); 599 return Device(device, dispatch);
628} 600}
diff --git a/src/video_core/renderer_vulkan/wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h
index f9a184e00..912cab46c 100644
--- a/src/video_core/renderer_vulkan/wrapper.h
+++ b/src/video_core/vulkan_common/vulkan_wrapper.h
@@ -555,7 +555,7 @@ private:
555 const DeviceDispatch* dld = nullptr; 555 const DeviceDispatch* dld = nullptr;
556}; 556};
557 557
558using DebugCallback = Handle<VkDebugUtilsMessengerEXT, VkInstance, InstanceDispatch>; 558using DebugUtilsMessenger = Handle<VkDebugUtilsMessengerEXT, VkInstance, InstanceDispatch>;
559using DescriptorSetLayout = Handle<VkDescriptorSetLayout, VkDevice, DeviceDispatch>; 559using DescriptorSetLayout = Handle<VkDescriptorSetLayout, VkDevice, DeviceDispatch>;
560using DescriptorUpdateTemplateKHR = Handle<VkDescriptorUpdateTemplateKHR, VkDevice, DeviceDispatch>; 560using DescriptorUpdateTemplateKHR = Handle<VkDescriptorUpdateTemplateKHR, VkDevice, DeviceDispatch>;
561using Pipeline = Handle<VkPipeline, VkDevice, DeviceDispatch>; 561using Pipeline = Handle<VkPipeline, VkDevice, DeviceDispatch>;
@@ -573,16 +573,25 @@ class Instance : public Handle<VkInstance, NoOwner, InstanceDispatch> {
573 using Handle<VkInstance, NoOwner, InstanceDispatch>::Handle; 573 using Handle<VkInstance, NoOwner, InstanceDispatch>::Handle;
574 574
575public: 575public:
576 /// Creates a Vulkan instance. Use "operator bool" for error handling. 576 /// Creates a Vulkan instance.
577 /// @throw Exception on initialization error.
577 static Instance Create(u32 version, Span<const char*> layers, Span<const char*> extensions, 578 static Instance Create(u32 version, Span<const char*> layers, Span<const char*> extensions,
578 InstanceDispatch& dispatch) noexcept; 579 InstanceDispatch& dispatch);
579 580
580 /// Enumerates physical devices. 581 /// Enumerates physical devices.
581 /// @return Physical devices and an empty handle on failure. 582 /// @return Physical devices and an empty handle on failure.
582 std::optional<std::vector<VkPhysicalDevice>> EnumeratePhysicalDevices(); 583 /// @throw Exception on Vulkan error.
584 std::vector<VkPhysicalDevice> EnumeratePhysicalDevices() const;
583 585
584 /// Tries to create a debug callback messenger. Returns an empty handle on failure. 586 /// Creates a debug callback messenger.
585 DebugCallback TryCreateDebugCallback(PFN_vkDebugUtilsMessengerCallbackEXT callback) noexcept; 587 /// @throw Exception on creation failure.
588 DebugUtilsMessenger CreateDebugUtilsMessenger(
589 const VkDebugUtilsMessengerCreateInfoEXT& create_info) const;
590
591 /// Returns dispatch table.
592 const InstanceDispatch& Dispatch() const noexcept {
593 return *dld;
594 }
586}; 595};
587 596
588class Queue { 597class Queue {
@@ -787,7 +796,7 @@ class Device : public Handle<VkDevice, NoOwner, DeviceDispatch> {
787public: 796public:
788 static Device Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreateInfo> queues_ci, 797 static Device Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreateInfo> queues_ci,
789 Span<const char*> enabled_extensions, const void* next, 798 Span<const char*> enabled_extensions, const void* next,
790 DeviceDispatch& dispatch) noexcept; 799 DeviceDispatch& dispatch);
791 800
792 Queue GetQueue(u32 family_index) const noexcept; 801 Queue GetQueue(u32 family_index) const noexcept;
793 802