summaryrefslogtreecommitdiff
path: root/src/video_core/renderer_vulkan
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/video_core/renderer_vulkan
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 'src/video_core/renderer_vulkan')
-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/renderer_vulkan/wrapper.cpp928
-rw-r--r--src/video_core/renderer_vulkan/wrapper.h1213
51 files changed, 146 insertions, 2575 deletions
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/renderer_vulkan/wrapper.cpp b/src/video_core/renderer_vulkan/wrapper.cpp
deleted file mode 100644
index 2a21e850d..000000000
--- a/src/video_core/renderer_vulkan/wrapper.cpp
+++ /dev/null
@@ -1,928 +0,0 @@
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 <exception>
7#include <memory>
8#include <optional>
9#include <string_view>
10#include <utility>
11#include <vector>
12
13#include "common/common_types.h"
14#include "common/logging/log.h"
15
16#include "video_core/renderer_vulkan/wrapper.h"
17
18namespace Vulkan::vk {
19
20namespace {
21
22template <typename Func>
23void SortPhysicalDevices(std::vector<VkPhysicalDevice>& devices, const InstanceDispatch& dld,
24 Func&& func) {
25 // Calling GetProperties calls Vulkan more than needed. But they are supposed to be cheap
26 // functions.
27 std::stable_sort(devices.begin(), devices.end(),
28 [&dld, &func](VkPhysicalDevice lhs, VkPhysicalDevice rhs) {
29 return func(vk::PhysicalDevice(lhs, dld).GetProperties(),
30 vk::PhysicalDevice(rhs, dld).GetProperties());
31 });
32}
33
34void SortPhysicalDevicesPerVendor(std::vector<VkPhysicalDevice>& devices,
35 const InstanceDispatch& dld,
36 std::initializer_list<u32> vendor_ids) {
37 for (auto it = vendor_ids.end(); it != vendor_ids.begin();) {
38 --it;
39 SortPhysicalDevices(devices, dld, [id = *it](const auto& lhs, const auto& rhs) {
40 return lhs.vendorID == id && rhs.vendorID != id;
41 });
42 }
43}
44
45void SortPhysicalDevices(std::vector<VkPhysicalDevice>& devices, const InstanceDispatch& dld) {
46 // Sort by name, this will set a base and make GPUs with higher numbers appear first
47 // (e.g. GTX 1650 will intentionally be listed before a GTX 1080).
48 SortPhysicalDevices(devices, dld, [](const auto& lhs, const auto& rhs) {
49 return std::string_view{lhs.deviceName} > std::string_view{rhs.deviceName};
50 });
51 // Prefer discrete over non-discrete
52 SortPhysicalDevices(devices, dld, [](const auto& lhs, const auto& rhs) {
53 return lhs.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU &&
54 rhs.deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU;
55 });
56 // Prefer Nvidia over AMD, AMD over Intel, Intel over the rest.
57 SortPhysicalDevicesPerVendor(devices, dld, {0x10DE, 0x1002, 0x8086});
58}
59
60template <typename T>
61bool Proc(T& result, const InstanceDispatch& dld, const char* proc_name,
62 VkInstance instance = nullptr) noexcept {
63 result = reinterpret_cast<T>(dld.vkGetInstanceProcAddr(instance, proc_name));
64 return result != nullptr;
65}
66
67template <typename T>
68void Proc(T& result, const DeviceDispatch& dld, const char* proc_name, VkDevice device) noexcept {
69 result = reinterpret_cast<T>(dld.vkGetDeviceProcAddr(device, proc_name));
70}
71
72void Load(VkDevice device, DeviceDispatch& dld) noexcept {
73#define X(name) Proc(dld.name, dld, #name, device)
74 X(vkAcquireNextImageKHR);
75 X(vkAllocateCommandBuffers);
76 X(vkAllocateDescriptorSets);
77 X(vkAllocateMemory);
78 X(vkBeginCommandBuffer);
79 X(vkBindBufferMemory);
80 X(vkBindImageMemory);
81 X(vkCmdBeginQuery);
82 X(vkCmdBeginRenderPass);
83 X(vkCmdBeginTransformFeedbackEXT);
84 X(vkCmdBeginDebugUtilsLabelEXT);
85 X(vkCmdBindDescriptorSets);
86 X(vkCmdBindIndexBuffer);
87 X(vkCmdBindPipeline);
88 X(vkCmdBindTransformFeedbackBuffersEXT);
89 X(vkCmdBindVertexBuffers);
90 X(vkCmdBlitImage);
91 X(vkCmdClearAttachments);
92 X(vkCmdCopyBuffer);
93 X(vkCmdCopyBufferToImage);
94 X(vkCmdCopyImage);
95 X(vkCmdCopyImageToBuffer);
96 X(vkCmdDispatch);
97 X(vkCmdDraw);
98 X(vkCmdDrawIndexed);
99 X(vkCmdEndQuery);
100 X(vkCmdEndRenderPass);
101 X(vkCmdEndTransformFeedbackEXT);
102 X(vkCmdEndDebugUtilsLabelEXT);
103 X(vkCmdFillBuffer);
104 X(vkCmdPipelineBarrier);
105 X(vkCmdPushConstants);
106 X(vkCmdSetBlendConstants);
107 X(vkCmdSetDepthBias);
108 X(vkCmdSetDepthBounds);
109 X(vkCmdSetEvent);
110 X(vkCmdSetScissor);
111 X(vkCmdSetStencilCompareMask);
112 X(vkCmdSetStencilReference);
113 X(vkCmdSetStencilWriteMask);
114 X(vkCmdSetViewport);
115 X(vkCmdWaitEvents);
116 X(vkCmdBindVertexBuffers2EXT);
117 X(vkCmdSetCullModeEXT);
118 X(vkCmdSetDepthBoundsTestEnableEXT);
119 X(vkCmdSetDepthCompareOpEXT);
120 X(vkCmdSetDepthTestEnableEXT);
121 X(vkCmdSetDepthWriteEnableEXT);
122 X(vkCmdSetFrontFaceEXT);
123 X(vkCmdSetPrimitiveTopologyEXT);
124 X(vkCmdSetStencilOpEXT);
125 X(vkCmdSetStencilTestEnableEXT);
126 X(vkCmdResolveImage);
127 X(vkCreateBuffer);
128 X(vkCreateBufferView);
129 X(vkCreateCommandPool);
130 X(vkCreateComputePipelines);
131 X(vkCreateDescriptorPool);
132 X(vkCreateDescriptorSetLayout);
133 X(vkCreateDescriptorUpdateTemplateKHR);
134 X(vkCreateEvent);
135 X(vkCreateFence);
136 X(vkCreateFramebuffer);
137 X(vkCreateGraphicsPipelines);
138 X(vkCreateImage);
139 X(vkCreateImageView);
140 X(vkCreatePipelineLayout);
141 X(vkCreateQueryPool);
142 X(vkCreateRenderPass);
143 X(vkCreateSampler);
144 X(vkCreateSemaphore);
145 X(vkCreateShaderModule);
146 X(vkCreateSwapchainKHR);
147 X(vkDestroyBuffer);
148 X(vkDestroyBufferView);
149 X(vkDestroyCommandPool);
150 X(vkDestroyDescriptorPool);
151 X(vkDestroyDescriptorSetLayout);
152 X(vkDestroyDescriptorUpdateTemplateKHR);
153 X(vkDestroyEvent);
154 X(vkDestroyFence);
155 X(vkDestroyFramebuffer);
156 X(vkDestroyImage);
157 X(vkDestroyImageView);
158 X(vkDestroyPipeline);
159 X(vkDestroyPipelineLayout);
160 X(vkDestroyQueryPool);
161 X(vkDestroyRenderPass);
162 X(vkDestroySampler);
163 X(vkDestroySemaphore);
164 X(vkDestroyShaderModule);
165 X(vkDestroySwapchainKHR);
166 X(vkDeviceWaitIdle);
167 X(vkEndCommandBuffer);
168 X(vkFreeCommandBuffers);
169 X(vkFreeDescriptorSets);
170 X(vkFreeMemory);
171 X(vkGetBufferMemoryRequirements);
172 X(vkGetDeviceQueue);
173 X(vkGetEventStatus);
174 X(vkGetFenceStatus);
175 X(vkGetImageMemoryRequirements);
176 X(vkGetQueryPoolResults);
177 X(vkGetSemaphoreCounterValueKHR);
178 X(vkMapMemory);
179 X(vkQueueSubmit);
180 X(vkResetFences);
181 X(vkResetQueryPoolEXT);
182 X(vkSetDebugUtilsObjectNameEXT);
183 X(vkSetDebugUtilsObjectTagEXT);
184 X(vkUnmapMemory);
185 X(vkUpdateDescriptorSetWithTemplateKHR);
186 X(vkUpdateDescriptorSets);
187 X(vkWaitForFences);
188 X(vkWaitSemaphoresKHR);
189#undef X
190}
191
192template <typename T>
193void SetObjectName(const DeviceDispatch* dld, VkDevice device, T handle, VkObjectType type,
194 const char* name) {
195 const VkDebugUtilsObjectNameInfoEXT name_info{
196 .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
197 .pNext = nullptr,
198 .objectType = VK_OBJECT_TYPE_IMAGE,
199 .objectHandle = reinterpret_cast<u64>(handle),
200 .pObjectName = name,
201 };
202 Check(dld->vkSetDebugUtilsObjectNameEXT(device, &name_info));
203}
204
205} // Anonymous namespace
206
207bool Load(InstanceDispatch& dld) noexcept {
208#define X(name) Proc(dld.name, dld, #name)
209 return X(vkCreateInstance) && X(vkEnumerateInstanceExtensionProperties) &&
210 X(vkEnumerateInstanceLayerProperties);
211#undef X
212}
213
214bool Load(VkInstance instance, InstanceDispatch& dld) noexcept {
215#define X(name) Proc(dld.name, dld, #name, instance)
216 // These functions may fail to load depending on the enabled extensions.
217 // Don't return a failure on these.
218 X(vkCreateDebugUtilsMessengerEXT);
219 X(vkDestroyDebugUtilsMessengerEXT);
220 X(vkDestroySurfaceKHR);
221 X(vkGetPhysicalDeviceFeatures2KHR);
222 X(vkGetPhysicalDeviceProperties2KHR);
223 X(vkGetPhysicalDeviceSurfaceCapabilitiesKHR);
224 X(vkGetPhysicalDeviceSurfaceFormatsKHR);
225 X(vkGetPhysicalDeviceSurfacePresentModesKHR);
226 X(vkGetPhysicalDeviceSurfaceSupportKHR);
227 X(vkGetSwapchainImagesKHR);
228 X(vkQueuePresentKHR);
229
230 return X(vkCreateDevice) && X(vkDestroyDevice) && X(vkDestroyDevice) &&
231 X(vkEnumerateDeviceExtensionProperties) && X(vkEnumeratePhysicalDevices) &&
232 X(vkGetDeviceProcAddr) && X(vkGetPhysicalDeviceFormatProperties) &&
233 X(vkGetPhysicalDeviceMemoryProperties) && X(vkGetPhysicalDeviceProperties) &&
234 X(vkGetPhysicalDeviceQueueFamilyProperties);
235#undef X
236}
237
238const char* Exception::what() const noexcept {
239 return ToString(result);
240}
241
242const char* ToString(VkResult result) noexcept {
243 switch (result) {
244 case VkResult::VK_SUCCESS:
245 return "VK_SUCCESS";
246 case VkResult::VK_NOT_READY:
247 return "VK_NOT_READY";
248 case VkResult::VK_TIMEOUT:
249 return "VK_TIMEOUT";
250 case VkResult::VK_EVENT_SET:
251 return "VK_EVENT_SET";
252 case VkResult::VK_EVENT_RESET:
253 return "VK_EVENT_RESET";
254 case VkResult::VK_INCOMPLETE:
255 return "VK_INCOMPLETE";
256 case VkResult::VK_ERROR_OUT_OF_HOST_MEMORY:
257 return "VK_ERROR_OUT_OF_HOST_MEMORY";
258 case VkResult::VK_ERROR_OUT_OF_DEVICE_MEMORY:
259 return "VK_ERROR_OUT_OF_DEVICE_MEMORY";
260 case VkResult::VK_ERROR_INITIALIZATION_FAILED:
261 return "VK_ERROR_INITIALIZATION_FAILED";
262 case VkResult::VK_ERROR_DEVICE_LOST:
263 return "VK_ERROR_DEVICE_LOST";
264 case VkResult::VK_ERROR_MEMORY_MAP_FAILED:
265 return "VK_ERROR_MEMORY_MAP_FAILED";
266 case VkResult::VK_ERROR_LAYER_NOT_PRESENT:
267 return "VK_ERROR_LAYER_NOT_PRESENT";
268 case VkResult::VK_ERROR_EXTENSION_NOT_PRESENT:
269 return "VK_ERROR_EXTENSION_NOT_PRESENT";
270 case VkResult::VK_ERROR_FEATURE_NOT_PRESENT:
271 return "VK_ERROR_FEATURE_NOT_PRESENT";
272 case VkResult::VK_ERROR_INCOMPATIBLE_DRIVER:
273 return "VK_ERROR_INCOMPATIBLE_DRIVER";
274 case VkResult::VK_ERROR_TOO_MANY_OBJECTS:
275 return "VK_ERROR_TOO_MANY_OBJECTS";
276 case VkResult::VK_ERROR_FORMAT_NOT_SUPPORTED:
277 return "VK_ERROR_FORMAT_NOT_SUPPORTED";
278 case VkResult::VK_ERROR_FRAGMENTED_POOL:
279 return "VK_ERROR_FRAGMENTED_POOL";
280 case VkResult::VK_ERROR_OUT_OF_POOL_MEMORY:
281 return "VK_ERROR_OUT_OF_POOL_MEMORY";
282 case VkResult::VK_ERROR_INVALID_EXTERNAL_HANDLE:
283 return "VK_ERROR_INVALID_EXTERNAL_HANDLE";
284 case VkResult::VK_ERROR_SURFACE_LOST_KHR:
285 return "VK_ERROR_SURFACE_LOST_KHR";
286 case VkResult::VK_ERROR_NATIVE_WINDOW_IN_USE_KHR:
287 return "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR";
288 case VkResult::VK_SUBOPTIMAL_KHR:
289 return "VK_SUBOPTIMAL_KHR";
290 case VkResult::VK_ERROR_OUT_OF_DATE_KHR:
291 return "VK_ERROR_OUT_OF_DATE_KHR";
292 case VkResult::VK_ERROR_INCOMPATIBLE_DISPLAY_KHR:
293 return "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR";
294 case VkResult::VK_ERROR_VALIDATION_FAILED_EXT:
295 return "VK_ERROR_VALIDATION_FAILED_EXT";
296 case VkResult::VK_ERROR_INVALID_SHADER_NV:
297 return "VK_ERROR_INVALID_SHADER_NV";
298 case VkResult::VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT:
299 return "VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT";
300 case VkResult::VK_ERROR_FRAGMENTATION_EXT:
301 return "VK_ERROR_FRAGMENTATION_EXT";
302 case VkResult::VK_ERROR_NOT_PERMITTED_EXT:
303 return "VK_ERROR_NOT_PERMITTED_EXT";
304 case VkResult::VK_ERROR_INVALID_DEVICE_ADDRESS_EXT:
305 return "VK_ERROR_INVALID_DEVICE_ADDRESS_EXT";
306 case VkResult::VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT:
307 return "VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT";
308 case VkResult::VK_ERROR_UNKNOWN:
309 return "VK_ERROR_UNKNOWN";
310 case VkResult::VK_ERROR_INCOMPATIBLE_VERSION_KHR:
311 return "VK_ERROR_INCOMPATIBLE_VERSION_KHR";
312 case VkResult::VK_THREAD_IDLE_KHR:
313 return "VK_THREAD_IDLE_KHR";
314 case VkResult::VK_THREAD_DONE_KHR:
315 return "VK_THREAD_DONE_KHR";
316 case VkResult::VK_OPERATION_DEFERRED_KHR:
317 return "VK_OPERATION_DEFERRED_KHR";
318 case VkResult::VK_OPERATION_NOT_DEFERRED_KHR:
319 return "VK_OPERATION_NOT_DEFERRED_KHR";
320 case VkResult::VK_PIPELINE_COMPILE_REQUIRED_EXT:
321 return "VK_PIPELINE_COMPILE_REQUIRED_EXT";
322 case VkResult::VK_RESULT_MAX_ENUM:
323 return "VK_RESULT_MAX_ENUM";
324 }
325 return "Unknown";
326}
327
328void Destroy(VkInstance instance, const InstanceDispatch& dld) noexcept {
329 dld.vkDestroyInstance(instance, nullptr);
330}
331
332void Destroy(VkDevice device, const InstanceDispatch& dld) noexcept {
333 dld.vkDestroyDevice(device, nullptr);
334}
335
336void Destroy(VkDevice device, VkBuffer handle, const DeviceDispatch& dld) noexcept {
337 dld.vkDestroyBuffer(device, handle, nullptr);
338}
339
340void Destroy(VkDevice device, VkBufferView handle, const DeviceDispatch& dld) noexcept {
341 dld.vkDestroyBufferView(device, handle, nullptr);
342}
343
344void Destroy(VkDevice device, VkCommandPool handle, const DeviceDispatch& dld) noexcept {
345 dld.vkDestroyCommandPool(device, handle, nullptr);
346}
347
348void Destroy(VkDevice device, VkDescriptorPool handle, const DeviceDispatch& dld) noexcept {
349 dld.vkDestroyDescriptorPool(device, handle, nullptr);
350}
351
352void Destroy(VkDevice device, VkDescriptorSetLayout handle, const DeviceDispatch& dld) noexcept {
353 dld.vkDestroyDescriptorSetLayout(device, handle, nullptr);
354}
355
356void Destroy(VkDevice device, VkDescriptorUpdateTemplateKHR handle,
357 const DeviceDispatch& dld) noexcept {
358 dld.vkDestroyDescriptorUpdateTemplateKHR(device, handle, nullptr);
359}
360
361void Destroy(VkDevice device, VkDeviceMemory handle, const DeviceDispatch& dld) noexcept {
362 dld.vkFreeMemory(device, handle, nullptr);
363}
364
365void Destroy(VkDevice device, VkEvent handle, const DeviceDispatch& dld) noexcept {
366 dld.vkDestroyEvent(device, handle, nullptr);
367}
368
369void Destroy(VkDevice device, VkFence handle, const DeviceDispatch& dld) noexcept {
370 dld.vkDestroyFence(device, handle, nullptr);
371}
372
373void Destroy(VkDevice device, VkFramebuffer handle, const DeviceDispatch& dld) noexcept {
374 dld.vkDestroyFramebuffer(device, handle, nullptr);
375}
376
377void Destroy(VkDevice device, VkImage handle, const DeviceDispatch& dld) noexcept {
378 dld.vkDestroyImage(device, handle, nullptr);
379}
380
381void Destroy(VkDevice device, VkImageView handle, const DeviceDispatch& dld) noexcept {
382 dld.vkDestroyImageView(device, handle, nullptr);
383}
384
385void Destroy(VkDevice device, VkPipeline handle, const DeviceDispatch& dld) noexcept {
386 dld.vkDestroyPipeline(device, handle, nullptr);
387}
388
389void Destroy(VkDevice device, VkPipelineLayout handle, const DeviceDispatch& dld) noexcept {
390 dld.vkDestroyPipelineLayout(device, handle, nullptr);
391}
392
393void Destroy(VkDevice device, VkQueryPool handle, const DeviceDispatch& dld) noexcept {
394 dld.vkDestroyQueryPool(device, handle, nullptr);
395}
396
397void Destroy(VkDevice device, VkRenderPass handle, const DeviceDispatch& dld) noexcept {
398 dld.vkDestroyRenderPass(device, handle, nullptr);
399}
400
401void Destroy(VkDevice device, VkSampler handle, const DeviceDispatch& dld) noexcept {
402 dld.vkDestroySampler(device, handle, nullptr);
403}
404
405void Destroy(VkDevice device, VkSwapchainKHR handle, const DeviceDispatch& dld) noexcept {
406 dld.vkDestroySwapchainKHR(device, handle, nullptr);
407}
408
409void Destroy(VkDevice device, VkSemaphore handle, const DeviceDispatch& dld) noexcept {
410 dld.vkDestroySemaphore(device, handle, nullptr);
411}
412
413void Destroy(VkDevice device, VkShaderModule handle, const DeviceDispatch& dld) noexcept {
414 dld.vkDestroyShaderModule(device, handle, nullptr);
415}
416
417void Destroy(VkInstance instance, VkDebugUtilsMessengerEXT handle,
418 const InstanceDispatch& dld) noexcept {
419 dld.vkDestroyDebugUtilsMessengerEXT(instance, handle, nullptr);
420}
421
422void Destroy(VkInstance instance, VkSurfaceKHR handle, const InstanceDispatch& dld) noexcept {
423 dld.vkDestroySurfaceKHR(instance, handle, nullptr);
424}
425
426VkResult Free(VkDevice device, VkDescriptorPool handle, Span<VkDescriptorSet> sets,
427 const DeviceDispatch& dld) noexcept {
428 return dld.vkFreeDescriptorSets(device, handle, sets.size(), sets.data());
429}
430
431VkResult Free(VkDevice device, VkCommandPool handle, Span<VkCommandBuffer> buffers,
432 const DeviceDispatch& dld) noexcept {
433 dld.vkFreeCommandBuffers(device, handle, buffers.size(), buffers.data());
434 return VK_SUCCESS;
435}
436
437Instance Instance::Create(u32 version, Span<const char*> layers, Span<const char*> extensions,
438 InstanceDispatch& dispatch) noexcept {
439 const VkApplicationInfo application_info{
440 .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
441 .pNext = nullptr,
442 .pApplicationName = "yuzu Emulator",
443 .applicationVersion = VK_MAKE_VERSION(0, 1, 0),
444 .pEngineName = "yuzu Emulator",
445 .engineVersion = VK_MAKE_VERSION(0, 1, 0),
446 .apiVersion = version,
447 };
448 const VkInstanceCreateInfo ci{
449 .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
450 .pNext = nullptr,
451 .flags = 0,
452 .pApplicationInfo = &application_info,
453 .enabledLayerCount = layers.size(),
454 .ppEnabledLayerNames = layers.data(),
455 .enabledExtensionCount = extensions.size(),
456 .ppEnabledExtensionNames = extensions.data(),
457 };
458
459 VkInstance instance;
460 if (dispatch.vkCreateInstance(&ci, nullptr, &instance) != VK_SUCCESS) {
461 // Failed to create the instance.
462 return {};
463 }
464 if (!Proc(dispatch.vkDestroyInstance, dispatch, "vkDestroyInstance", instance)) {
465 // We successfully created an instance but the destroy function couldn't be loaded.
466 // This is a good moment to panic.
467 return {};
468 }
469
470 return Instance(instance, dispatch);
471}
472
473std::optional<std::vector<VkPhysicalDevice>> Instance::EnumeratePhysicalDevices() {
474 u32 num;
475 if (dld->vkEnumeratePhysicalDevices(handle, &num, nullptr) != VK_SUCCESS) {
476 return std::nullopt;
477 }
478 std::vector<VkPhysicalDevice> physical_devices(num);
479 if (dld->vkEnumeratePhysicalDevices(handle, &num, physical_devices.data()) != VK_SUCCESS) {
480 return std::nullopt;
481 }
482 SortPhysicalDevices(physical_devices, *dld);
483 return std::make_optional(std::move(physical_devices));
484}
485
486DebugCallback Instance::TryCreateDebugCallback(
487 PFN_vkDebugUtilsMessengerCallbackEXT callback) noexcept {
488 const VkDebugUtilsMessengerCreateInfoEXT ci{
489 .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
490 .pNext = nullptr,
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}
508
509void Buffer::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const {
510 Check(dld->vkBindBufferMemory(owner, handle, memory, offset));
511}
512
513void Buffer::SetObjectNameEXT(const char* name) const {
514 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER, name);
515}
516
517void BufferView::SetObjectNameEXT(const char* name) const {
518 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER_VIEW, name);
519}
520
521void Image::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const {
522 Check(dld->vkBindImageMemory(owner, handle, memory, offset));
523}
524
525void Image::SetObjectNameEXT(const char* name) const {
526 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_IMAGE, name);
527}
528
529void ImageView::SetObjectNameEXT(const char* name) const {
530 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_IMAGE_VIEW, name);
531}
532
533void DeviceMemory::SetObjectNameEXT(const char* name) const {
534 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_DEVICE_MEMORY, name);
535}
536
537void Fence::SetObjectNameEXT(const char* name) const {
538 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_FENCE, name);
539}
540
541void Framebuffer::SetObjectNameEXT(const char* name) const {
542 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_FRAMEBUFFER, name);
543}
544
545DescriptorSets DescriptorPool::Allocate(const VkDescriptorSetAllocateInfo& ai) const {
546 const std::size_t num = ai.descriptorSetCount;
547 std::unique_ptr sets = std::make_unique<VkDescriptorSet[]>(num);
548 switch (const VkResult result = dld->vkAllocateDescriptorSets(owner, &ai, sets.get())) {
549 case VK_SUCCESS:
550 return DescriptorSets(std::move(sets), num, owner, handle, *dld);
551 case VK_ERROR_OUT_OF_POOL_MEMORY:
552 return {};
553 default:
554 throw Exception(result);
555 }
556}
557
558void DescriptorPool::SetObjectNameEXT(const char* name) const {
559 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_DESCRIPTOR_POOL, name);
560}
561
562CommandBuffers CommandPool::Allocate(std::size_t num_buffers, VkCommandBufferLevel level) const {
563 const VkCommandBufferAllocateInfo ai{
564 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
565 .pNext = nullptr,
566 .commandPool = handle,
567 .level = level,
568 .commandBufferCount = static_cast<u32>(num_buffers),
569 };
570
571 std::unique_ptr buffers = std::make_unique<VkCommandBuffer[]>(num_buffers);
572 switch (const VkResult result = dld->vkAllocateCommandBuffers(owner, &ai, buffers.get())) {
573 case VK_SUCCESS:
574 return CommandBuffers(std::move(buffers), num_buffers, owner, handle, *dld);
575 case VK_ERROR_OUT_OF_POOL_MEMORY:
576 return {};
577 default:
578 throw Exception(result);
579 }
580}
581
582void CommandPool::SetObjectNameEXT(const char* name) const {
583 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_COMMAND_POOL, name);
584}
585
586std::vector<VkImage> SwapchainKHR::GetImages() const {
587 u32 num;
588 Check(dld->vkGetSwapchainImagesKHR(owner, handle, &num, nullptr));
589 std::vector<VkImage> images(num);
590 Check(dld->vkGetSwapchainImagesKHR(owner, handle, &num, images.data()));
591 return images;
592}
593
594void Event::SetObjectNameEXT(const char* name) const {
595 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_EVENT, name);
596}
597
598void ShaderModule::SetObjectNameEXT(const char* name) const {
599 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_SHADER_MODULE, name);
600}
601
602void Semaphore::SetObjectNameEXT(const char* name) const {
603 SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_SEMAPHORE, name);
604}
605
606Device Device::Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreateInfo> queues_ci,
607 Span<const char*> enabled_extensions, const void* next,
608 DeviceDispatch& dispatch) noexcept {
609 const VkDeviceCreateInfo ci{
610 .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
611 .pNext = next,
612 .flags = 0,
613 .queueCreateInfoCount = queues_ci.size(),
614 .pQueueCreateInfos = queues_ci.data(),
615 .enabledLayerCount = 0,
616 .ppEnabledLayerNames = nullptr,
617 .enabledExtensionCount = enabled_extensions.size(),
618 .ppEnabledExtensionNames = enabled_extensions.data(),
619 .pEnabledFeatures = nullptr,
620 };
621
622 VkDevice device;
623 if (dispatch.vkCreateDevice(physical_device, &ci, nullptr, &device) != VK_SUCCESS) {
624 return {};
625 }
626 Load(device, dispatch);
627 return Device(device, dispatch);
628}
629
630Queue Device::GetQueue(u32 family_index) const noexcept {
631 VkQueue queue;
632 dld->vkGetDeviceQueue(handle, family_index, 0, &queue);
633 return Queue(queue, *dld);
634}
635
636Buffer Device::CreateBuffer(const VkBufferCreateInfo& ci) const {
637 VkBuffer object;
638 Check(dld->vkCreateBuffer(handle, &ci, nullptr, &object));
639 return Buffer(object, handle, *dld);
640}
641
642BufferView Device::CreateBufferView(const VkBufferViewCreateInfo& ci) const {
643 VkBufferView object;
644 Check(dld->vkCreateBufferView(handle, &ci, nullptr, &object));
645 return BufferView(object, handle, *dld);
646}
647
648Image Device::CreateImage(const VkImageCreateInfo& ci) const {
649 VkImage object;
650 Check(dld->vkCreateImage(handle, &ci, nullptr, &object));
651 return Image(object, handle, *dld);
652}
653
654ImageView Device::CreateImageView(const VkImageViewCreateInfo& ci) const {
655 VkImageView object;
656 Check(dld->vkCreateImageView(handle, &ci, nullptr, &object));
657 return ImageView(object, handle, *dld);
658}
659
660Semaphore Device::CreateSemaphore() const {
661 static constexpr VkSemaphoreCreateInfo ci{
662 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
663 .pNext = nullptr,
664 .flags = 0,
665 };
666 return CreateSemaphore(ci);
667}
668
669Semaphore Device::CreateSemaphore(const VkSemaphoreCreateInfo& ci) const {
670 VkSemaphore object;
671 Check(dld->vkCreateSemaphore(handle, &ci, nullptr, &object));
672 return Semaphore(object, handle, *dld);
673}
674
675Fence Device::CreateFence(const VkFenceCreateInfo& ci) const {
676 VkFence object;
677 Check(dld->vkCreateFence(handle, &ci, nullptr, &object));
678 return Fence(object, handle, *dld);
679}
680
681DescriptorPool Device::CreateDescriptorPool(const VkDescriptorPoolCreateInfo& ci) const {
682 VkDescriptorPool object;
683 Check(dld->vkCreateDescriptorPool(handle, &ci, nullptr, &object));
684 return DescriptorPool(object, handle, *dld);
685}
686
687RenderPass Device::CreateRenderPass(const VkRenderPassCreateInfo& ci) const {
688 VkRenderPass object;
689 Check(dld->vkCreateRenderPass(handle, &ci, nullptr, &object));
690 return RenderPass(object, handle, *dld);
691}
692
693DescriptorSetLayout Device::CreateDescriptorSetLayout(
694 const VkDescriptorSetLayoutCreateInfo& ci) const {
695 VkDescriptorSetLayout object;
696 Check(dld->vkCreateDescriptorSetLayout(handle, &ci, nullptr, &object));
697 return DescriptorSetLayout(object, handle, *dld);
698}
699
700PipelineLayout Device::CreatePipelineLayout(const VkPipelineLayoutCreateInfo& ci) const {
701 VkPipelineLayout object;
702 Check(dld->vkCreatePipelineLayout(handle, &ci, nullptr, &object));
703 return PipelineLayout(object, handle, *dld);
704}
705
706Pipeline Device::CreateGraphicsPipeline(const VkGraphicsPipelineCreateInfo& ci) const {
707 VkPipeline object;
708 Check(dld->vkCreateGraphicsPipelines(handle, nullptr, 1, &ci, nullptr, &object));
709 return Pipeline(object, handle, *dld);
710}
711
712Pipeline Device::CreateComputePipeline(const VkComputePipelineCreateInfo& ci) const {
713 VkPipeline object;
714 Check(dld->vkCreateComputePipelines(handle, nullptr, 1, &ci, nullptr, &object));
715 return Pipeline(object, handle, *dld);
716}
717
718Sampler Device::CreateSampler(const VkSamplerCreateInfo& ci) const {
719 VkSampler object;
720 Check(dld->vkCreateSampler(handle, &ci, nullptr, &object));
721 return Sampler(object, handle, *dld);
722}
723
724Framebuffer Device::CreateFramebuffer(const VkFramebufferCreateInfo& ci) const {
725 VkFramebuffer object;
726 Check(dld->vkCreateFramebuffer(handle, &ci, nullptr, &object));
727 return Framebuffer(object, handle, *dld);
728}
729
730CommandPool Device::CreateCommandPool(const VkCommandPoolCreateInfo& ci) const {
731 VkCommandPool object;
732 Check(dld->vkCreateCommandPool(handle, &ci, nullptr, &object));
733 return CommandPool(object, handle, *dld);
734}
735
736DescriptorUpdateTemplateKHR Device::CreateDescriptorUpdateTemplateKHR(
737 const VkDescriptorUpdateTemplateCreateInfoKHR& ci) const {
738 VkDescriptorUpdateTemplateKHR object;
739 Check(dld->vkCreateDescriptorUpdateTemplateKHR(handle, &ci, nullptr, &object));
740 return DescriptorUpdateTemplateKHR(object, handle, *dld);
741}
742
743QueryPool Device::CreateQueryPool(const VkQueryPoolCreateInfo& ci) const {
744 VkQueryPool object;
745 Check(dld->vkCreateQueryPool(handle, &ci, nullptr, &object));
746 return QueryPool(object, handle, *dld);
747}
748
749ShaderModule Device::CreateShaderModule(const VkShaderModuleCreateInfo& ci) const {
750 VkShaderModule object;
751 Check(dld->vkCreateShaderModule(handle, &ci, nullptr, &object));
752 return ShaderModule(object, handle, *dld);
753}
754
755Event Device::CreateEvent() const {
756 static constexpr VkEventCreateInfo ci{
757 .sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO,
758 .pNext = nullptr,
759 .flags = 0,
760 };
761
762 VkEvent object;
763 Check(dld->vkCreateEvent(handle, &ci, nullptr, &object));
764 return Event(object, handle, *dld);
765}
766
767SwapchainKHR Device::CreateSwapchainKHR(const VkSwapchainCreateInfoKHR& ci) const {
768 VkSwapchainKHR object;
769 Check(dld->vkCreateSwapchainKHR(handle, &ci, nullptr, &object));
770 return SwapchainKHR(object, handle, *dld);
771}
772
773DeviceMemory Device::TryAllocateMemory(const VkMemoryAllocateInfo& ai) const noexcept {
774 VkDeviceMemory memory;
775 if (dld->vkAllocateMemory(handle, &ai, nullptr, &memory) != VK_SUCCESS) {
776 return {};
777 }
778 return DeviceMemory(memory, handle, *dld);
779}
780
781DeviceMemory Device::AllocateMemory(const VkMemoryAllocateInfo& ai) const {
782 VkDeviceMemory memory;
783 Check(dld->vkAllocateMemory(handle, &ai, nullptr, &memory));
784 return DeviceMemory(memory, handle, *dld);
785}
786
787VkMemoryRequirements Device::GetBufferMemoryRequirements(VkBuffer buffer) const noexcept {
788 VkMemoryRequirements requirements;
789 dld->vkGetBufferMemoryRequirements(handle, buffer, &requirements);
790 return requirements;
791}
792
793VkMemoryRequirements Device::GetImageMemoryRequirements(VkImage image) const noexcept {
794 VkMemoryRequirements requirements;
795 dld->vkGetImageMemoryRequirements(handle, image, &requirements);
796 return requirements;
797}
798
799void Device::UpdateDescriptorSets(Span<VkWriteDescriptorSet> writes,
800 Span<VkCopyDescriptorSet> copies) const noexcept {
801 dld->vkUpdateDescriptorSets(handle, writes.size(), writes.data(), copies.size(), copies.data());
802}
803
804VkPhysicalDeviceProperties PhysicalDevice::GetProperties() const noexcept {
805 VkPhysicalDeviceProperties properties;
806 dld->vkGetPhysicalDeviceProperties(physical_device, &properties);
807 return properties;
808}
809
810void PhysicalDevice::GetProperties2KHR(VkPhysicalDeviceProperties2KHR& properties) const noexcept {
811 dld->vkGetPhysicalDeviceProperties2KHR(physical_device, &properties);
812}
813
814VkPhysicalDeviceFeatures PhysicalDevice::GetFeatures() const noexcept {
815 VkPhysicalDeviceFeatures2KHR features2;
816 features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR;
817 features2.pNext = nullptr;
818 dld->vkGetPhysicalDeviceFeatures2KHR(physical_device, &features2);
819 return features2.features;
820}
821
822void PhysicalDevice::GetFeatures2KHR(VkPhysicalDeviceFeatures2KHR& features) const noexcept {
823 dld->vkGetPhysicalDeviceFeatures2KHR(physical_device, &features);
824}
825
826VkFormatProperties PhysicalDevice::GetFormatProperties(VkFormat format) const noexcept {
827 VkFormatProperties properties;
828 dld->vkGetPhysicalDeviceFormatProperties(physical_device, format, &properties);
829 return properties;
830}
831
832std::vector<VkExtensionProperties> PhysicalDevice::EnumerateDeviceExtensionProperties() const {
833 u32 num;
834 dld->vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &num, nullptr);
835 std::vector<VkExtensionProperties> properties(num);
836 dld->vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &num, properties.data());
837 return properties;
838}
839
840std::vector<VkQueueFamilyProperties> PhysicalDevice::GetQueueFamilyProperties() const {
841 u32 num;
842 dld->vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &num, nullptr);
843 std::vector<VkQueueFamilyProperties> properties(num);
844 dld->vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &num, properties.data());
845 return properties;
846}
847
848bool PhysicalDevice::GetSurfaceSupportKHR(u32 queue_family_index, VkSurfaceKHR surface) const {
849 VkBool32 supported;
850 Check(dld->vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, queue_family_index, surface,
851 &supported));
852 return supported == VK_TRUE;
853}
854
855VkSurfaceCapabilitiesKHR PhysicalDevice::GetSurfaceCapabilitiesKHR(VkSurfaceKHR surface) const {
856 VkSurfaceCapabilitiesKHR capabilities;
857 Check(dld->vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, surface, &capabilities));
858 return capabilities;
859}
860
861std::vector<VkSurfaceFormatKHR> PhysicalDevice::GetSurfaceFormatsKHR(VkSurfaceKHR surface) const {
862 u32 num;
863 Check(dld->vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &num, nullptr));
864 std::vector<VkSurfaceFormatKHR> formats(num);
865 Check(
866 dld->vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &num, formats.data()));
867 return formats;
868}
869
870std::vector<VkPresentModeKHR> PhysicalDevice::GetSurfacePresentModesKHR(
871 VkSurfaceKHR surface) const {
872 u32 num;
873 Check(dld->vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &num, nullptr));
874 std::vector<VkPresentModeKHR> modes(num);
875 Check(dld->vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &num,
876 modes.data()));
877 return modes;
878}
879
880VkPhysicalDeviceMemoryProperties PhysicalDevice::GetMemoryProperties() const noexcept {
881 VkPhysicalDeviceMemoryProperties properties;
882 dld->vkGetPhysicalDeviceMemoryProperties(physical_device, &properties);
883 return properties;
884}
885
886u32 AvailableVersion(const InstanceDispatch& dld) noexcept {
887 PFN_vkEnumerateInstanceVersion vkEnumerateInstanceVersion;
888 if (!Proc(vkEnumerateInstanceVersion, dld, "vkEnumerateInstanceVersion")) {
889 // If the procedure is not found, Vulkan 1.0 is assumed
890 return VK_API_VERSION_1_0;
891 }
892 u32 version;
893 if (const VkResult result = vkEnumerateInstanceVersion(&version); result != VK_SUCCESS) {
894 LOG_ERROR(Render_Vulkan, "vkEnumerateInstanceVersion returned {}, assuming Vulkan 1.1",
895 ToString(result));
896 return VK_API_VERSION_1_1;
897 }
898 return version;
899}
900
901std::optional<std::vector<VkExtensionProperties>> EnumerateInstanceExtensionProperties(
902 const InstanceDispatch& dld) {
903 u32 num;
904 if (dld.vkEnumerateInstanceExtensionProperties(nullptr, &num, nullptr) != VK_SUCCESS) {
905 return std::nullopt;
906 }
907 std::vector<VkExtensionProperties> properties(num);
908 if (dld.vkEnumerateInstanceExtensionProperties(nullptr, &num, properties.data()) !=
909 VK_SUCCESS) {
910 return std::nullopt;
911 }
912 return properties;
913}
914
915std::optional<std::vector<VkLayerProperties>> EnumerateInstanceLayerProperties(
916 const InstanceDispatch& dld) {
917 u32 num;
918 if (dld.vkEnumerateInstanceLayerProperties(&num, nullptr) != VK_SUCCESS) {
919 return std::nullopt;
920 }
921 std::vector<VkLayerProperties> properties(num);
922 if (dld.vkEnumerateInstanceLayerProperties(&num, properties.data()) != VK_SUCCESS) {
923 return std::nullopt;
924 }
925 return properties;
926}
927
928} // namespace Vulkan::vk
diff --git a/src/video_core/renderer_vulkan/wrapper.h b/src/video_core/renderer_vulkan/wrapper.h
deleted file mode 100644
index f9a184e00..000000000
--- a/src/video_core/renderer_vulkan/wrapper.h
+++ /dev/null
@@ -1,1213 +0,0 @@
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 <exception>
8#include <iterator>
9#include <limits>
10#include <memory>
11#include <optional>
12#include <span>
13#include <type_traits>
14#include <utility>
15#include <vector>
16
17#define VK_NO_PROTOTYPES
18#include <vulkan/vulkan.h>
19
20#include "common/common_types.h"
21
22#ifdef _MSC_VER
23#pragma warning(disable : 26812) // Disable prefer enum class over enum
24#endif
25
26namespace Vulkan::vk {
27
28/**
29 * Span for Vulkan arrays.
30 * Based on std::span but optimized for array access instead of iterators.
31 * Size returns uint32_t instead of size_t to ease interaction with Vulkan functions.
32 */
33template <typename T>
34class Span {
35public:
36 using value_type = T;
37 using size_type = u32;
38 using difference_type = std::ptrdiff_t;
39 using reference = const T&;
40 using const_reference = const T&;
41 using pointer = const T*;
42 using const_pointer = const T*;
43 using iterator = const T*;
44 using const_iterator = const T*;
45
46 /// Construct an empty span.
47 constexpr Span() noexcept = default;
48
49 /// Construct an empty span
50 constexpr Span(std::nullptr_t) noexcept {}
51
52 /// Construct a span from a single element.
53 constexpr Span(const T& value) noexcept : ptr{&value}, num{1} {}
54
55 /// Construct a span from a range.
56 template <typename Range>
57 // requires std::data(const Range&)
58 // requires std::size(const Range&)
59 constexpr Span(const Range& range) : ptr{std::data(range)}, num{std::size(range)} {}
60
61 /// Construct a span from a pointer and a size.
62 /// This is inteded for subranges.
63 constexpr Span(const T* ptr_, std::size_t num_) noexcept : ptr{ptr_}, num{num_} {}
64
65 /// Returns the data pointer by the span.
66 constexpr const T* data() const noexcept {
67 return ptr;
68 }
69
70 /// Returns the number of elements in the span.
71 /// @note Returns a 32 bits integer because most Vulkan functions expect this type.
72 constexpr u32 size() const noexcept {
73 return static_cast<u32>(num);
74 }
75
76 /// Returns true when the span is empty.
77 constexpr bool empty() const noexcept {
78 return num == 0;
79 }
80
81 /// Returns a reference to the element in the passed index.
82 /// @pre: index < size()
83 constexpr const T& operator[](std::size_t index) const noexcept {
84 return ptr[index];
85 }
86
87 /// Returns an iterator to the beginning of the span.
88 constexpr const T* begin() const noexcept {
89 return ptr;
90 }
91
92 /// Returns an iterator to the end of the span.
93 constexpr const T* end() const noexcept {
94 return ptr + num;
95 }
96
97 /// Returns an iterator to the beginning of the span.
98 constexpr const T* cbegin() const noexcept {
99 return ptr;
100 }
101
102 /// Returns an iterator to the end of the span.
103 constexpr const T* cend() const noexcept {
104 return ptr + num;
105 }
106
107private:
108 const T* ptr = nullptr;
109 std::size_t num = 0;
110};
111
112/// Vulkan exception generated from a VkResult.
113class Exception final : public std::exception {
114public:
115 /// Construct the exception with a result.
116 /// @pre result != VK_SUCCESS
117 explicit Exception(VkResult result_) : result{result_} {}
118 virtual ~Exception() = default;
119
120 const char* what() const noexcept override;
121
122private:
123 VkResult result;
124};
125
126/// Converts a VkResult enum into a rodata string
127const char* ToString(VkResult) noexcept;
128
129/// Throws a Vulkan exception if result is not success.
130inline void Check(VkResult result) {
131 if (result != VK_SUCCESS) {
132 throw Exception(result);
133 }
134}
135
136/// Throws a Vulkan exception if result is an error.
137/// @return result
138inline VkResult Filter(VkResult result) {
139 if (result < 0) {
140 throw Exception(result);
141 }
142 return result;
143}
144
145/// Table holding Vulkan instance function pointers.
146struct InstanceDispatch {
147 PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr;
148
149 PFN_vkCreateInstance vkCreateInstance;
150 PFN_vkDestroyInstance vkDestroyInstance;
151 PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties;
152 PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties;
153
154 PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT;
155 PFN_vkCreateDevice vkCreateDevice;
156 PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT;
157 PFN_vkDestroyDevice vkDestroyDevice;
158 PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR;
159 PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties;
160 PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices;
161 PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr;
162 PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR;
163 PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties;
164 PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties;
165 PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties;
166 PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR;
167 PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties;
168 PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR;
169 PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR;
170 PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR;
171 PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR;
172 PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR;
173 PFN_vkQueuePresentKHR vkQueuePresentKHR;
174};
175
176/// Table holding Vulkan device function pointers.
177struct DeviceDispatch : public InstanceDispatch {
178 PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR;
179 PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers;
180 PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets;
181 PFN_vkAllocateMemory vkAllocateMemory;
182 PFN_vkBeginCommandBuffer vkBeginCommandBuffer;
183 PFN_vkBindBufferMemory vkBindBufferMemory;
184 PFN_vkBindImageMemory vkBindImageMemory;
185 PFN_vkCmdBeginQuery vkCmdBeginQuery;
186 PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass;
187 PFN_vkCmdBeginTransformFeedbackEXT vkCmdBeginTransformFeedbackEXT;
188 PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT;
189 PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets;
190 PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer;
191 PFN_vkCmdBindPipeline vkCmdBindPipeline;
192 PFN_vkCmdBindTransformFeedbackBuffersEXT vkCmdBindTransformFeedbackBuffersEXT;
193 PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers;
194 PFN_vkCmdBlitImage vkCmdBlitImage;
195 PFN_vkCmdClearAttachments vkCmdClearAttachments;
196 PFN_vkCmdCopyBuffer vkCmdCopyBuffer;
197 PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage;
198 PFN_vkCmdCopyImage vkCmdCopyImage;
199 PFN_vkCmdCopyImageToBuffer vkCmdCopyImageToBuffer;
200 PFN_vkCmdDispatch vkCmdDispatch;
201 PFN_vkCmdDraw vkCmdDraw;
202 PFN_vkCmdDrawIndexed vkCmdDrawIndexed;
203 PFN_vkCmdEndQuery vkCmdEndQuery;
204 PFN_vkCmdEndRenderPass vkCmdEndRenderPass;
205 PFN_vkCmdEndTransformFeedbackEXT vkCmdEndTransformFeedbackEXT;
206 PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT;
207 PFN_vkCmdFillBuffer vkCmdFillBuffer;
208 PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier;
209 PFN_vkCmdPushConstants vkCmdPushConstants;
210 PFN_vkCmdSetBlendConstants vkCmdSetBlendConstants;
211 PFN_vkCmdSetDepthBias vkCmdSetDepthBias;
212 PFN_vkCmdSetDepthBounds vkCmdSetDepthBounds;
213 PFN_vkCmdSetEvent vkCmdSetEvent;
214 PFN_vkCmdSetScissor vkCmdSetScissor;
215 PFN_vkCmdSetStencilCompareMask vkCmdSetStencilCompareMask;
216 PFN_vkCmdSetStencilReference vkCmdSetStencilReference;
217 PFN_vkCmdSetStencilWriteMask vkCmdSetStencilWriteMask;
218 PFN_vkCmdSetViewport vkCmdSetViewport;
219 PFN_vkCmdWaitEvents vkCmdWaitEvents;
220 PFN_vkCmdBindVertexBuffers2EXT vkCmdBindVertexBuffers2EXT;
221 PFN_vkCmdSetCullModeEXT vkCmdSetCullModeEXT;
222 PFN_vkCmdSetDepthBoundsTestEnableEXT vkCmdSetDepthBoundsTestEnableEXT;
223 PFN_vkCmdSetDepthCompareOpEXT vkCmdSetDepthCompareOpEXT;
224 PFN_vkCmdSetDepthTestEnableEXT vkCmdSetDepthTestEnableEXT;
225 PFN_vkCmdSetDepthWriteEnableEXT vkCmdSetDepthWriteEnableEXT;
226 PFN_vkCmdSetFrontFaceEXT vkCmdSetFrontFaceEXT;
227 PFN_vkCmdSetPrimitiveTopologyEXT vkCmdSetPrimitiveTopologyEXT;
228 PFN_vkCmdSetStencilOpEXT vkCmdSetStencilOpEXT;
229 PFN_vkCmdSetStencilTestEnableEXT vkCmdSetStencilTestEnableEXT;
230 PFN_vkCmdResolveImage vkCmdResolveImage;
231 PFN_vkCreateBuffer vkCreateBuffer;
232 PFN_vkCreateBufferView vkCreateBufferView;
233 PFN_vkCreateCommandPool vkCreateCommandPool;
234 PFN_vkCreateComputePipelines vkCreateComputePipelines;
235 PFN_vkCreateDescriptorPool vkCreateDescriptorPool;
236 PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout;
237 PFN_vkCreateDescriptorUpdateTemplateKHR vkCreateDescriptorUpdateTemplateKHR;
238 PFN_vkCreateEvent vkCreateEvent;
239 PFN_vkCreateFence vkCreateFence;
240 PFN_vkCreateFramebuffer vkCreateFramebuffer;
241 PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines;
242 PFN_vkCreateImage vkCreateImage;
243 PFN_vkCreateImageView vkCreateImageView;
244 PFN_vkCreatePipelineLayout vkCreatePipelineLayout;
245 PFN_vkCreateQueryPool vkCreateQueryPool;
246 PFN_vkCreateRenderPass vkCreateRenderPass;
247 PFN_vkCreateSampler vkCreateSampler;
248 PFN_vkCreateSemaphore vkCreateSemaphore;
249 PFN_vkCreateShaderModule vkCreateShaderModule;
250 PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR;
251 PFN_vkDestroyBuffer vkDestroyBuffer;
252 PFN_vkDestroyBufferView vkDestroyBufferView;
253 PFN_vkDestroyCommandPool vkDestroyCommandPool;
254 PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool;
255 PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout;
256 PFN_vkDestroyDescriptorUpdateTemplateKHR vkDestroyDescriptorUpdateTemplateKHR;
257 PFN_vkDestroyEvent vkDestroyEvent;
258 PFN_vkDestroyFence vkDestroyFence;
259 PFN_vkDestroyFramebuffer vkDestroyFramebuffer;
260 PFN_vkDestroyImage vkDestroyImage;
261 PFN_vkDestroyImageView vkDestroyImageView;
262 PFN_vkDestroyPipeline vkDestroyPipeline;
263 PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout;
264 PFN_vkDestroyQueryPool vkDestroyQueryPool;
265 PFN_vkDestroyRenderPass vkDestroyRenderPass;
266 PFN_vkDestroySampler vkDestroySampler;
267 PFN_vkDestroySemaphore vkDestroySemaphore;
268 PFN_vkDestroyShaderModule vkDestroyShaderModule;
269 PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR;
270 PFN_vkDeviceWaitIdle vkDeviceWaitIdle;
271 PFN_vkEndCommandBuffer vkEndCommandBuffer;
272 PFN_vkFreeCommandBuffers vkFreeCommandBuffers;
273 PFN_vkFreeDescriptorSets vkFreeDescriptorSets;
274 PFN_vkFreeMemory vkFreeMemory;
275 PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements;
276 PFN_vkGetDeviceQueue vkGetDeviceQueue;
277 PFN_vkGetEventStatus vkGetEventStatus;
278 PFN_vkGetFenceStatus vkGetFenceStatus;
279 PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements;
280 PFN_vkGetQueryPoolResults vkGetQueryPoolResults;
281 PFN_vkGetSemaphoreCounterValueKHR vkGetSemaphoreCounterValueKHR;
282 PFN_vkMapMemory vkMapMemory;
283 PFN_vkQueueSubmit vkQueueSubmit;
284 PFN_vkResetFences vkResetFences;
285 PFN_vkResetQueryPoolEXT vkResetQueryPoolEXT;
286 PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT;
287 PFN_vkSetDebugUtilsObjectTagEXT vkSetDebugUtilsObjectTagEXT;
288 PFN_vkUnmapMemory vkUnmapMemory;
289 PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR;
290 PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets;
291 PFN_vkWaitForFences vkWaitForFences;
292 PFN_vkWaitSemaphoresKHR vkWaitSemaphoresKHR;
293};
294
295/// Loads instance agnostic function pointers.
296/// @return True on success, false on error.
297bool Load(InstanceDispatch&) noexcept;
298
299/// Loads instance function pointers.
300/// @return True on success, false on error.
301bool Load(VkInstance, InstanceDispatch&) noexcept;
302
303void Destroy(VkInstance, const InstanceDispatch&) noexcept;
304void Destroy(VkDevice, const InstanceDispatch&) noexcept;
305
306void Destroy(VkDevice, VkBuffer, const DeviceDispatch&) noexcept;
307void Destroy(VkDevice, VkBufferView, const DeviceDispatch&) noexcept;
308void Destroy(VkDevice, VkCommandPool, const DeviceDispatch&) noexcept;
309void Destroy(VkDevice, VkDescriptorPool, const DeviceDispatch&) noexcept;
310void Destroy(VkDevice, VkDescriptorSetLayout, const DeviceDispatch&) noexcept;
311void Destroy(VkDevice, VkDescriptorUpdateTemplateKHR, const DeviceDispatch&) noexcept;
312void Destroy(VkDevice, VkDeviceMemory, const DeviceDispatch&) noexcept;
313void Destroy(VkDevice, VkEvent, const DeviceDispatch&) noexcept;
314void Destroy(VkDevice, VkFence, const DeviceDispatch&) noexcept;
315void Destroy(VkDevice, VkFramebuffer, const DeviceDispatch&) noexcept;
316void Destroy(VkDevice, VkImage, const DeviceDispatch&) noexcept;
317void Destroy(VkDevice, VkImageView, const DeviceDispatch&) noexcept;
318void Destroy(VkDevice, VkPipeline, const DeviceDispatch&) noexcept;
319void Destroy(VkDevice, VkPipelineLayout, const DeviceDispatch&) noexcept;
320void Destroy(VkDevice, VkQueryPool, const DeviceDispatch&) noexcept;
321void Destroy(VkDevice, VkRenderPass, const DeviceDispatch&) noexcept;
322void Destroy(VkDevice, VkSampler, const DeviceDispatch&) noexcept;
323void Destroy(VkDevice, VkSwapchainKHR, const DeviceDispatch&) noexcept;
324void Destroy(VkDevice, VkSemaphore, const DeviceDispatch&) noexcept;
325void Destroy(VkDevice, VkShaderModule, const DeviceDispatch&) noexcept;
326void Destroy(VkInstance, VkDebugUtilsMessengerEXT, const InstanceDispatch&) noexcept;
327void Destroy(VkInstance, VkSurfaceKHR, const InstanceDispatch&) noexcept;
328
329VkResult Free(VkDevice, VkDescriptorPool, Span<VkDescriptorSet>, const DeviceDispatch&) noexcept;
330VkResult Free(VkDevice, VkCommandPool, Span<VkCommandBuffer>, const DeviceDispatch&) noexcept;
331
332template <typename Type, typename OwnerType, typename Dispatch>
333class Handle;
334
335/// Handle with an owning type.
336/// Analogue to std::unique_ptr.
337template <typename Type, typename OwnerType, typename Dispatch>
338class Handle {
339public:
340 /// Construct a handle and hold it's ownership.
341 explicit Handle(Type handle_, OwnerType owner_, const Dispatch& dld_) noexcept
342 : handle{handle_}, owner{owner_}, dld{&dld_} {}
343
344 /// Construct an empty handle.
345 Handle() = default;
346
347 /// Copying Vulkan objects is not supported and will never be.
348 Handle(const Handle&) = delete;
349 Handle& operator=(const Handle&) = delete;
350
351 /// Construct a handle transfering the ownership from another handle.
352 Handle(Handle&& rhs) noexcept
353 : handle{std::exchange(rhs.handle, nullptr)}, owner{rhs.owner}, dld{rhs.dld} {}
354
355 /// Assign the current handle transfering the ownership from another handle.
356 /// Destroys any previously held object.
357 Handle& operator=(Handle&& rhs) noexcept {
358 Release();
359 handle = std::exchange(rhs.handle, nullptr);
360 owner = rhs.owner;
361 dld = rhs.dld;
362 return *this;
363 }
364
365 /// Destroys the current handle if it existed.
366 ~Handle() noexcept {
367 Release();
368 }
369
370 /// Destroys any held object.
371 void reset() noexcept {
372 Release();
373 handle = nullptr;
374 }
375
376 /// Returns the address of the held object.
377 /// Intended for Vulkan structures that expect a pointer to an array.
378 const Type* address() const noexcept {
379 return std::addressof(handle);
380 }
381
382 /// Returns the held Vulkan handle.
383 Type operator*() const noexcept {
384 return handle;
385 }
386
387 /// Returns true when there's a held object.
388 explicit operator bool() const noexcept {
389 return handle != nullptr;
390 }
391
392protected:
393 Type handle = nullptr;
394 OwnerType owner = nullptr;
395 const Dispatch* dld = nullptr;
396
397private:
398 /// Destroys the held object if it exists.
399 void Release() noexcept {
400 if (handle) {
401 Destroy(owner, handle, *dld);
402 }
403 }
404};
405
406/// Dummy type used to specify a handle has no owner.
407struct NoOwner {};
408
409/// Handle without an owning type.
410/// Analogue to std::unique_ptr
411template <typename Type, typename Dispatch>
412class Handle<Type, NoOwner, Dispatch> {
413public:
414 /// Construct a handle and hold it's ownership.
415 explicit Handle(Type handle_, const Dispatch& dld_) noexcept : handle{handle_}, dld{&dld_} {}
416
417 /// Construct an empty handle.
418 Handle() noexcept = default;
419
420 /// Copying Vulkan objects is not supported and will never be.
421 Handle(const Handle&) = delete;
422 Handle& operator=(const Handle&) = delete;
423
424 /// Construct a handle transfering ownership from another handle.
425 Handle(Handle&& rhs) noexcept : handle{std::exchange(rhs.handle, nullptr)}, dld{rhs.dld} {}
426
427 /// Assign the current handle transfering the ownership from another handle.
428 /// Destroys any previously held object.
429 Handle& operator=(Handle&& rhs) noexcept {
430 Release();
431 handle = std::exchange(rhs.handle, nullptr);
432 dld = rhs.dld;
433 return *this;
434 }
435
436 /// Destroys the current handle if it existed.
437 ~Handle() noexcept {
438 Release();
439 }
440
441 /// Destroys any held object.
442 void reset() noexcept {
443 Release();
444 handle = nullptr;
445 }
446
447 /// Returns the address of the held object.
448 /// Intended for Vulkan structures that expect a pointer to an array.
449 const Type* address() const noexcept {
450 return std::addressof(handle);
451 }
452
453 /// Returns the held Vulkan handle.
454 Type operator*() const noexcept {
455 return handle;
456 }
457
458 /// Returns true when there's a held object.
459 operator bool() const noexcept {
460 return handle != nullptr;
461 }
462
463protected:
464 Type handle = nullptr;
465 const Dispatch* dld = nullptr;
466
467private:
468 /// Destroys the held object if it exists.
469 void Release() noexcept {
470 if (handle) {
471 Destroy(handle, *dld);
472 }
473 }
474};
475
476/// Array of a pool allocation.
477/// Analogue to std::vector
478template <typename AllocationType, typename PoolType>
479class PoolAllocations {
480public:
481 /// Construct an empty allocation.
482 PoolAllocations() = default;
483
484 /// Construct an allocation. Errors are reported through IsOutOfPoolMemory().
485 explicit PoolAllocations(std::unique_ptr<AllocationType[]> allocations_, std::size_t num_,
486 VkDevice device_, PoolType pool_, const DeviceDispatch& dld_) noexcept
487 : allocations{std::move(allocations_)}, num{num_}, device{device_}, pool{pool_},
488 dld{&dld_} {}
489
490 /// Copying Vulkan allocations is not supported and will never be.
491 PoolAllocations(const PoolAllocations&) = delete;
492 PoolAllocations& operator=(const PoolAllocations&) = delete;
493
494 /// Construct an allocation transfering ownership from another allocation.
495 PoolAllocations(PoolAllocations&& rhs) noexcept
496 : allocations{std::move(rhs.allocations)}, num{rhs.num}, device{rhs.device}, pool{rhs.pool},
497 dld{rhs.dld} {}
498
499 /// Assign an allocation transfering ownership from another allocation.
500 /// Releases any previously held allocation.
501 PoolAllocations& operator=(PoolAllocations&& rhs) noexcept {
502 Release();
503 allocations = std::move(rhs.allocations);
504 num = rhs.num;
505 device = rhs.device;
506 pool = rhs.pool;
507 dld = rhs.dld;
508 return *this;
509 }
510
511 /// Destroys any held allocation.
512 ~PoolAllocations() {
513 Release();
514 }
515
516 /// Returns the number of allocations.
517 std::size_t size() const noexcept {
518 return num;
519 }
520
521 /// Returns a pointer to the array of allocations.
522 AllocationType const* data() const noexcept {
523 return allocations.get();
524 }
525
526 /// Returns the allocation in the specified index.
527 /// @pre index < size()
528 AllocationType operator[](std::size_t index) const noexcept {
529 return allocations[index];
530 }
531
532 /// True when a pool fails to construct.
533 bool IsOutOfPoolMemory() const noexcept {
534 return !device;
535 }
536
537private:
538 /// Destroys the held allocations if they exist.
539 void Release() noexcept {
540 if (!allocations) {
541 return;
542 }
543 const Span<AllocationType> span(allocations.get(), num);
544 const VkResult result = Free(device, pool, span, *dld);
545 // There's no way to report errors from a destructor.
546 if (result != VK_SUCCESS) {
547 std::terminate();
548 }
549 }
550
551 std::unique_ptr<AllocationType[]> allocations;
552 std::size_t num = 0;
553 VkDevice device = nullptr;
554 PoolType pool = nullptr;
555 const DeviceDispatch* dld = nullptr;
556};
557
558using DebugCallback = Handle<VkDebugUtilsMessengerEXT, VkInstance, InstanceDispatch>;
559using DescriptorSetLayout = Handle<VkDescriptorSetLayout, VkDevice, DeviceDispatch>;
560using DescriptorUpdateTemplateKHR = Handle<VkDescriptorUpdateTemplateKHR, VkDevice, DeviceDispatch>;
561using Pipeline = Handle<VkPipeline, VkDevice, DeviceDispatch>;
562using PipelineLayout = Handle<VkPipelineLayout, VkDevice, DeviceDispatch>;
563using QueryPool = Handle<VkQueryPool, VkDevice, DeviceDispatch>;
564using RenderPass = Handle<VkRenderPass, VkDevice, DeviceDispatch>;
565using Sampler = Handle<VkSampler, VkDevice, DeviceDispatch>;
566using SurfaceKHR = Handle<VkSurfaceKHR, VkInstance, InstanceDispatch>;
567
568using DescriptorSets = PoolAllocations<VkDescriptorSet, VkDescriptorPool>;
569using CommandBuffers = PoolAllocations<VkCommandBuffer, VkCommandPool>;
570
571/// Vulkan instance owning handle.
572class Instance : public Handle<VkInstance, NoOwner, InstanceDispatch> {
573 using Handle<VkInstance, NoOwner, InstanceDispatch>::Handle;
574
575public:
576 /// Creates a Vulkan instance. Use "operator bool" for error handling.
577 static Instance Create(u32 version, Span<const char*> layers, Span<const char*> extensions,
578 InstanceDispatch& dispatch) noexcept;
579
580 /// Enumerates physical devices.
581 /// @return Physical devices and an empty handle on failure.
582 std::optional<std::vector<VkPhysicalDevice>> EnumeratePhysicalDevices();
583
584 /// Tries to create a debug callback messenger. Returns an empty handle on failure.
585 DebugCallback TryCreateDebugCallback(PFN_vkDebugUtilsMessengerCallbackEXT callback) noexcept;
586};
587
588class Queue {
589public:
590 /// Construct an empty queue handle.
591 constexpr Queue() noexcept = default;
592
593 /// Construct a queue handle.
594 constexpr Queue(VkQueue queue_, const DeviceDispatch& dld_) noexcept
595 : queue{queue_}, dld{&dld_} {}
596
597 VkResult Submit(Span<VkSubmitInfo> submit_infos,
598 VkFence fence = VK_NULL_HANDLE) const noexcept {
599 return dld->vkQueueSubmit(queue, submit_infos.size(), submit_infos.data(), fence);
600 }
601
602 VkResult Present(const VkPresentInfoKHR& present_info) const noexcept {
603 return dld->vkQueuePresentKHR(queue, &present_info);
604 }
605
606private:
607 VkQueue queue = nullptr;
608 const DeviceDispatch* dld = nullptr;
609};
610
611class Buffer : public Handle<VkBuffer, VkDevice, DeviceDispatch> {
612 using Handle<VkBuffer, VkDevice, DeviceDispatch>::Handle;
613
614public:
615 /// Attaches a memory allocation.
616 void BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const;
617
618 /// Set object name.
619 void SetObjectNameEXT(const char* name) const;
620};
621
622class BufferView : public Handle<VkBufferView, VkDevice, DeviceDispatch> {
623 using Handle<VkBufferView, VkDevice, DeviceDispatch>::Handle;
624
625public:
626 /// Set object name.
627 void SetObjectNameEXT(const char* name) const;
628};
629
630class Image : public Handle<VkImage, VkDevice, DeviceDispatch> {
631 using Handle<VkImage, VkDevice, DeviceDispatch>::Handle;
632
633public:
634 /// Attaches a memory allocation.
635 void BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const;
636
637 /// Set object name.
638 void SetObjectNameEXT(const char* name) const;
639};
640
641class ImageView : public Handle<VkImageView, VkDevice, DeviceDispatch> {
642 using Handle<VkImageView, VkDevice, DeviceDispatch>::Handle;
643
644public:
645 /// Set object name.
646 void SetObjectNameEXT(const char* name) const;
647};
648
649class DeviceMemory : public Handle<VkDeviceMemory, VkDevice, DeviceDispatch> {
650 using Handle<VkDeviceMemory, VkDevice, DeviceDispatch>::Handle;
651
652public:
653 /// Set object name.
654 void SetObjectNameEXT(const char* name) const;
655
656 u8* Map(VkDeviceSize offset, VkDeviceSize size) const {
657 void* data;
658 Check(dld->vkMapMemory(owner, handle, offset, size, 0, &data));
659 return static_cast<u8*>(data);
660 }
661
662 void Unmap() const noexcept {
663 dld->vkUnmapMemory(owner, handle);
664 }
665};
666
667class Fence : public Handle<VkFence, VkDevice, DeviceDispatch> {
668 using Handle<VkFence, VkDevice, DeviceDispatch>::Handle;
669
670public:
671 /// Set object name.
672 void SetObjectNameEXT(const char* name) const;
673
674 VkResult Wait(u64 timeout = std::numeric_limits<u64>::max()) const noexcept {
675 return dld->vkWaitForFences(owner, 1, &handle, true, timeout);
676 }
677
678 VkResult GetStatus() const noexcept {
679 return dld->vkGetFenceStatus(owner, handle);
680 }
681
682 void Reset() const {
683 Check(dld->vkResetFences(owner, 1, &handle));
684 }
685};
686
687class Framebuffer : public Handle<VkFramebuffer, VkDevice, DeviceDispatch> {
688 using Handle<VkFramebuffer, VkDevice, DeviceDispatch>::Handle;
689
690public:
691 /// Set object name.
692 void SetObjectNameEXT(const char* name) const;
693};
694
695class DescriptorPool : public Handle<VkDescriptorPool, VkDevice, DeviceDispatch> {
696 using Handle<VkDescriptorPool, VkDevice, DeviceDispatch>::Handle;
697
698public:
699 DescriptorSets Allocate(const VkDescriptorSetAllocateInfo& ai) const;
700
701 /// Set object name.
702 void SetObjectNameEXT(const char* name) const;
703};
704
705class CommandPool : public Handle<VkCommandPool, VkDevice, DeviceDispatch> {
706 using Handle<VkCommandPool, VkDevice, DeviceDispatch>::Handle;
707
708public:
709 CommandBuffers Allocate(std::size_t num_buffers,
710 VkCommandBufferLevel level = VK_COMMAND_BUFFER_LEVEL_PRIMARY) const;
711
712 /// Set object name.
713 void SetObjectNameEXT(const char* name) const;
714};
715
716class SwapchainKHR : public Handle<VkSwapchainKHR, VkDevice, DeviceDispatch> {
717 using Handle<VkSwapchainKHR, VkDevice, DeviceDispatch>::Handle;
718
719public:
720 std::vector<VkImage> GetImages() const;
721};
722
723class Event : public Handle<VkEvent, VkDevice, DeviceDispatch> {
724 using Handle<VkEvent, VkDevice, DeviceDispatch>::Handle;
725
726public:
727 /// Set object name.
728 void SetObjectNameEXT(const char* name) const;
729
730 VkResult GetStatus() const noexcept {
731 return dld->vkGetEventStatus(owner, handle);
732 }
733};
734
735class ShaderModule : public Handle<VkShaderModule, VkDevice, DeviceDispatch> {
736 using Handle<VkShaderModule, VkDevice, DeviceDispatch>::Handle;
737
738public:
739 /// Set object name.
740 void SetObjectNameEXT(const char* name) const;
741};
742
743class Semaphore : public Handle<VkSemaphore, VkDevice, DeviceDispatch> {
744 using Handle<VkSemaphore, VkDevice, DeviceDispatch>::Handle;
745
746public:
747 /// Set object name.
748 void SetObjectNameEXT(const char* name) const;
749
750 [[nodiscard]] u64 GetCounter() const {
751 u64 value;
752 Check(dld->vkGetSemaphoreCounterValueKHR(owner, handle, &value));
753 return value;
754 }
755
756 /**
757 * Waits for a timeline semaphore on the host.
758 *
759 * @param value Value to wait
760 * @param timeout Time in nanoseconds to timeout
761 * @return True on successful wait, false on timeout
762 */
763 bool Wait(u64 value, u64 timeout = std::numeric_limits<u64>::max()) const {
764 const VkSemaphoreWaitInfoKHR wait_info{
765 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO_KHR,
766 .pNext = nullptr,
767 .flags = 0,
768 .semaphoreCount = 1,
769 .pSemaphores = &handle,
770 .pValues = &value,
771 };
772 const VkResult result = dld->vkWaitSemaphoresKHR(owner, &wait_info, timeout);
773 switch (result) {
774 case VK_SUCCESS:
775 return true;
776 case VK_TIMEOUT:
777 return false;
778 default:
779 throw Exception(result);
780 }
781 }
782};
783
784class Device : public Handle<VkDevice, NoOwner, DeviceDispatch> {
785 using Handle<VkDevice, NoOwner, DeviceDispatch>::Handle;
786
787public:
788 static Device Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreateInfo> queues_ci,
789 Span<const char*> enabled_extensions, const void* next,
790 DeviceDispatch& dispatch) noexcept;
791
792 Queue GetQueue(u32 family_index) const noexcept;
793
794 Buffer CreateBuffer(const VkBufferCreateInfo& ci) const;
795
796 BufferView CreateBufferView(const VkBufferViewCreateInfo& ci) const;
797
798 Image CreateImage(const VkImageCreateInfo& ci) const;
799
800 ImageView CreateImageView(const VkImageViewCreateInfo& ci) const;
801
802 Semaphore CreateSemaphore() const;
803
804 Semaphore CreateSemaphore(const VkSemaphoreCreateInfo& ci) const;
805
806 Fence CreateFence(const VkFenceCreateInfo& ci) const;
807
808 DescriptorPool CreateDescriptorPool(const VkDescriptorPoolCreateInfo& ci) const;
809
810 RenderPass CreateRenderPass(const VkRenderPassCreateInfo& ci) const;
811
812 DescriptorSetLayout CreateDescriptorSetLayout(const VkDescriptorSetLayoutCreateInfo& ci) const;
813
814 PipelineLayout CreatePipelineLayout(const VkPipelineLayoutCreateInfo& ci) const;
815
816 Pipeline CreateGraphicsPipeline(const VkGraphicsPipelineCreateInfo& ci) const;
817
818 Pipeline CreateComputePipeline(const VkComputePipelineCreateInfo& ci) const;
819
820 Sampler CreateSampler(const VkSamplerCreateInfo& ci) const;
821
822 Framebuffer CreateFramebuffer(const VkFramebufferCreateInfo& ci) const;
823
824 CommandPool CreateCommandPool(const VkCommandPoolCreateInfo& ci) const;
825
826 DescriptorUpdateTemplateKHR CreateDescriptorUpdateTemplateKHR(
827 const VkDescriptorUpdateTemplateCreateInfoKHR& ci) const;
828
829 QueryPool CreateQueryPool(const VkQueryPoolCreateInfo& ci) const;
830
831 ShaderModule CreateShaderModule(const VkShaderModuleCreateInfo& ci) const;
832
833 Event CreateEvent() const;
834
835 SwapchainKHR CreateSwapchainKHR(const VkSwapchainCreateInfoKHR& ci) const;
836
837 DeviceMemory TryAllocateMemory(const VkMemoryAllocateInfo& ai) const noexcept;
838
839 DeviceMemory AllocateMemory(const VkMemoryAllocateInfo& ai) const;
840
841 VkMemoryRequirements GetBufferMemoryRequirements(VkBuffer buffer) const noexcept;
842
843 VkMemoryRequirements GetImageMemoryRequirements(VkImage image) const noexcept;
844
845 void UpdateDescriptorSets(Span<VkWriteDescriptorSet> writes,
846 Span<VkCopyDescriptorSet> copies) const noexcept;
847
848 void UpdateDescriptorSet(VkDescriptorSet set, VkDescriptorUpdateTemplateKHR update_template,
849 const void* data) const noexcept {
850 dld->vkUpdateDescriptorSetWithTemplateKHR(handle, set, update_template, data);
851 }
852
853 VkResult AcquireNextImageKHR(VkSwapchainKHR swapchain, u64 timeout, VkSemaphore semaphore,
854 VkFence fence, u32* image_index) const noexcept {
855 return dld->vkAcquireNextImageKHR(handle, swapchain, timeout, semaphore, fence,
856 image_index);
857 }
858
859 VkResult WaitIdle() const noexcept {
860 return dld->vkDeviceWaitIdle(handle);
861 }
862
863 void ResetQueryPoolEXT(VkQueryPool query_pool, u32 first, u32 count) const noexcept {
864 dld->vkResetQueryPoolEXT(handle, query_pool, first, count);
865 }
866
867 VkResult GetQueryResults(VkQueryPool query_pool, u32 first, u32 count, std::size_t data_size,
868 void* data, VkDeviceSize stride,
869 VkQueryResultFlags flags) const noexcept {
870 return dld->vkGetQueryPoolResults(handle, query_pool, first, count, data_size, data, stride,
871 flags);
872 }
873};
874
875class PhysicalDevice {
876public:
877 constexpr PhysicalDevice() noexcept = default;
878
879 constexpr PhysicalDevice(VkPhysicalDevice physical_device_,
880 const InstanceDispatch& dld_) noexcept
881 : physical_device{physical_device_}, dld{&dld_} {}
882
883 constexpr operator VkPhysicalDevice() const noexcept {
884 return physical_device;
885 }
886
887 VkPhysicalDeviceProperties GetProperties() const noexcept;
888
889 void GetProperties2KHR(VkPhysicalDeviceProperties2KHR&) const noexcept;
890
891 VkPhysicalDeviceFeatures GetFeatures() const noexcept;
892
893 void GetFeatures2KHR(VkPhysicalDeviceFeatures2KHR&) const noexcept;
894
895 VkFormatProperties GetFormatProperties(VkFormat) const noexcept;
896
897 std::vector<VkExtensionProperties> EnumerateDeviceExtensionProperties() const;
898
899 std::vector<VkQueueFamilyProperties> GetQueueFamilyProperties() const;
900
901 bool GetSurfaceSupportKHR(u32 queue_family_index, VkSurfaceKHR) const;
902
903 VkSurfaceCapabilitiesKHR GetSurfaceCapabilitiesKHR(VkSurfaceKHR) const;
904
905 std::vector<VkSurfaceFormatKHR> GetSurfaceFormatsKHR(VkSurfaceKHR) const;
906
907 std::vector<VkPresentModeKHR> GetSurfacePresentModesKHR(VkSurfaceKHR) const;
908
909 VkPhysicalDeviceMemoryProperties GetMemoryProperties() const noexcept;
910
911private:
912 VkPhysicalDevice physical_device = nullptr;
913 const InstanceDispatch* dld = nullptr;
914};
915
916class CommandBuffer {
917public:
918 CommandBuffer() noexcept = default;
919
920 explicit CommandBuffer(VkCommandBuffer handle_, const DeviceDispatch& dld_) noexcept
921 : handle{handle_}, dld{&dld_} {}
922
923 const VkCommandBuffer* address() const noexcept {
924 return &handle;
925 }
926
927 void Begin(const VkCommandBufferBeginInfo& begin_info) const {
928 Check(dld->vkBeginCommandBuffer(handle, &begin_info));
929 }
930
931 void End() const {
932 Check(dld->vkEndCommandBuffer(handle));
933 }
934
935 void BeginRenderPass(const VkRenderPassBeginInfo& renderpass_bi,
936 VkSubpassContents contents) const noexcept {
937 dld->vkCmdBeginRenderPass(handle, &renderpass_bi, contents);
938 }
939
940 void EndRenderPass() const noexcept {
941 dld->vkCmdEndRenderPass(handle);
942 }
943
944 void BeginQuery(VkQueryPool query_pool, u32 query, VkQueryControlFlags flags) const noexcept {
945 dld->vkCmdBeginQuery(handle, query_pool, query, flags);
946 }
947
948 void EndQuery(VkQueryPool query_pool, u32 query) const noexcept {
949 dld->vkCmdEndQuery(handle, query_pool, query);
950 }
951
952 void BindDescriptorSets(VkPipelineBindPoint bind_point, VkPipelineLayout layout, u32 first,
953 Span<VkDescriptorSet> sets, Span<u32> dynamic_offsets) const noexcept {
954 dld->vkCmdBindDescriptorSets(handle, bind_point, layout, first, sets.size(), sets.data(),
955 dynamic_offsets.size(), dynamic_offsets.data());
956 }
957
958 void BindPipeline(VkPipelineBindPoint bind_point, VkPipeline pipeline) const noexcept {
959 dld->vkCmdBindPipeline(handle, bind_point, pipeline);
960 }
961
962 void BindIndexBuffer(VkBuffer buffer, VkDeviceSize offset,
963 VkIndexType index_type) const noexcept {
964 dld->vkCmdBindIndexBuffer(handle, buffer, offset, index_type);
965 }
966
967 void BindVertexBuffers(u32 first, u32 count, const VkBuffer* buffers,
968 const VkDeviceSize* offsets) const noexcept {
969 dld->vkCmdBindVertexBuffers(handle, first, count, buffers, offsets);
970 }
971
972 void BindVertexBuffer(u32 binding, VkBuffer buffer, VkDeviceSize offset) const noexcept {
973 BindVertexBuffers(binding, 1, &buffer, &offset);
974 }
975
976 void Draw(u32 vertex_count, u32 instance_count, u32 first_vertex,
977 u32 first_instance) const noexcept {
978 dld->vkCmdDraw(handle, vertex_count, instance_count, first_vertex, first_instance);
979 }
980
981 void DrawIndexed(u32 index_count, u32 instance_count, u32 first_index, u32 vertex_offset,
982 u32 first_instance) const noexcept {
983 dld->vkCmdDrawIndexed(handle, index_count, instance_count, first_index, vertex_offset,
984 first_instance);
985 }
986
987 void ClearAttachments(Span<VkClearAttachment> attachments,
988 Span<VkClearRect> rects) const noexcept {
989 dld->vkCmdClearAttachments(handle, attachments.size(), attachments.data(), rects.size(),
990 rects.data());
991 }
992
993 void BlitImage(VkImage src_image, VkImageLayout src_layout, VkImage dst_image,
994 VkImageLayout dst_layout, Span<VkImageBlit> regions,
995 VkFilter filter) const noexcept {
996 dld->vkCmdBlitImage(handle, src_image, src_layout, dst_image, dst_layout, regions.size(),
997 regions.data(), filter);
998 }
999
1000 void ResolveImage(VkImage src_image, VkImageLayout src_layout, VkImage dst_image,
1001 VkImageLayout dst_layout, Span<VkImageResolve> regions) {
1002 dld->vkCmdResolveImage(handle, src_image, src_layout, dst_image, dst_layout, regions.size(),
1003 regions.data());
1004 }
1005
1006 void Dispatch(u32 x, u32 y, u32 z) const noexcept {
1007 dld->vkCmdDispatch(handle, x, y, z);
1008 }
1009
1010 void PipelineBarrier(VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask,
1011 VkDependencyFlags dependency_flags, Span<VkMemoryBarrier> memory_barriers,
1012 Span<VkBufferMemoryBarrier> buffer_barriers,
1013 Span<VkImageMemoryBarrier> image_barriers) const noexcept {
1014 dld->vkCmdPipelineBarrier(handle, src_stage_mask, dst_stage_mask, dependency_flags,
1015 memory_barriers.size(), memory_barriers.data(),
1016 buffer_barriers.size(), buffer_barriers.data(),
1017 image_barriers.size(), image_barriers.data());
1018 }
1019
1020 void PipelineBarrier(VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask,
1021 VkDependencyFlags dependency_flags = 0) const noexcept {
1022 PipelineBarrier(src_stage_mask, dst_stage_mask, dependency_flags, {}, {}, {});
1023 }
1024
1025 void PipelineBarrier(VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask,
1026 VkDependencyFlags dependency_flags,
1027 const VkBufferMemoryBarrier& buffer_barrier) const noexcept {
1028 PipelineBarrier(src_stage_mask, dst_stage_mask, dependency_flags, {}, buffer_barrier, {});
1029 }
1030
1031 void PipelineBarrier(VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask,
1032 VkDependencyFlags dependency_flags,
1033 const VkImageMemoryBarrier& image_barrier) const noexcept {
1034 PipelineBarrier(src_stage_mask, dst_stage_mask, dependency_flags, {}, {}, image_barrier);
1035 }
1036
1037 void CopyBufferToImage(VkBuffer src_buffer, VkImage dst_image, VkImageLayout dst_image_layout,
1038 Span<VkBufferImageCopy> regions) const noexcept {
1039 dld->vkCmdCopyBufferToImage(handle, src_buffer, dst_image, dst_image_layout, regions.size(),
1040 regions.data());
1041 }
1042
1043 void CopyBuffer(VkBuffer src_buffer, VkBuffer dst_buffer,
1044 Span<VkBufferCopy> regions) const noexcept {
1045 dld->vkCmdCopyBuffer(handle, src_buffer, dst_buffer, regions.size(), regions.data());
1046 }
1047
1048 void CopyImage(VkImage src_image, VkImageLayout src_layout, VkImage dst_image,
1049 VkImageLayout dst_layout, Span<VkImageCopy> regions) const noexcept {
1050 dld->vkCmdCopyImage(handle, src_image, src_layout, dst_image, dst_layout, regions.size(),
1051 regions.data());
1052 }
1053
1054 void CopyImageToBuffer(VkImage src_image, VkImageLayout src_layout, VkBuffer dst_buffer,
1055 Span<VkBufferImageCopy> regions) const noexcept {
1056 dld->vkCmdCopyImageToBuffer(handle, src_image, src_layout, dst_buffer, regions.size(),
1057 regions.data());
1058 }
1059
1060 void FillBuffer(VkBuffer dst_buffer, VkDeviceSize dst_offset, VkDeviceSize size,
1061 u32 data) const noexcept {
1062 dld->vkCmdFillBuffer(handle, dst_buffer, dst_offset, size, data);
1063 }
1064
1065 void PushConstants(VkPipelineLayout layout, VkShaderStageFlags flags, u32 offset, u32 size,
1066 const void* values) const noexcept {
1067 dld->vkCmdPushConstants(handle, layout, flags, offset, size, values);
1068 }
1069
1070 template <typename T>
1071 void PushConstants(VkPipelineLayout layout, VkShaderStageFlags flags,
1072 const T& data) const noexcept {
1073 static_assert(std::is_trivially_copyable_v<T>, "<data> is not trivially copyable");
1074 dld->vkCmdPushConstants(handle, layout, flags, 0, static_cast<u32>(sizeof(T)), &data);
1075 }
1076
1077 void SetViewport(u32 first, Span<VkViewport> viewports) const noexcept {
1078 dld->vkCmdSetViewport(handle, first, viewports.size(), viewports.data());
1079 }
1080
1081 void SetScissor(u32 first, Span<VkRect2D> scissors) const noexcept {
1082 dld->vkCmdSetScissor(handle, first, scissors.size(), scissors.data());
1083 }
1084
1085 void SetBlendConstants(const float blend_constants[4]) const noexcept {
1086 dld->vkCmdSetBlendConstants(handle, blend_constants);
1087 }
1088
1089 void SetStencilCompareMask(VkStencilFaceFlags face_mask, u32 compare_mask) const noexcept {
1090 dld->vkCmdSetStencilCompareMask(handle, face_mask, compare_mask);
1091 }
1092
1093 void SetStencilReference(VkStencilFaceFlags face_mask, u32 reference) const noexcept {
1094 dld->vkCmdSetStencilReference(handle, face_mask, reference);
1095 }
1096
1097 void SetStencilWriteMask(VkStencilFaceFlags face_mask, u32 write_mask) const noexcept {
1098 dld->vkCmdSetStencilWriteMask(handle, face_mask, write_mask);
1099 }
1100
1101 void SetDepthBias(float constant_factor, float clamp, float slope_factor) const noexcept {
1102 dld->vkCmdSetDepthBias(handle, constant_factor, clamp, slope_factor);
1103 }
1104
1105 void SetDepthBounds(float min_depth_bounds, float max_depth_bounds) const noexcept {
1106 dld->vkCmdSetDepthBounds(handle, min_depth_bounds, max_depth_bounds);
1107 }
1108
1109 void SetEvent(VkEvent event, VkPipelineStageFlags stage_flags) const noexcept {
1110 dld->vkCmdSetEvent(handle, event, stage_flags);
1111 }
1112
1113 void WaitEvents(Span<VkEvent> events, VkPipelineStageFlags src_stage_mask,
1114 VkPipelineStageFlags dst_stage_mask, Span<VkMemoryBarrier> memory_barriers,
1115 Span<VkBufferMemoryBarrier> buffer_barriers,
1116 Span<VkImageMemoryBarrier> image_barriers) const noexcept {
1117 dld->vkCmdWaitEvents(handle, events.size(), events.data(), src_stage_mask, dst_stage_mask,
1118 memory_barriers.size(), memory_barriers.data(), buffer_barriers.size(),
1119 buffer_barriers.data(), image_barriers.size(), image_barriers.data());
1120 }
1121
1122 void BindVertexBuffers2EXT(u32 first_binding, u32 binding_count, const VkBuffer* buffers,
1123 const VkDeviceSize* offsets, const VkDeviceSize* sizes,
1124 const VkDeviceSize* strides) const noexcept {
1125 dld->vkCmdBindVertexBuffers2EXT(handle, first_binding, binding_count, buffers, offsets,
1126 sizes, strides);
1127 }
1128
1129 void SetCullModeEXT(VkCullModeFlags cull_mode) const noexcept {
1130 dld->vkCmdSetCullModeEXT(handle, cull_mode);
1131 }
1132
1133 void SetDepthBoundsTestEnableEXT(bool enable) const noexcept {
1134 dld->vkCmdSetDepthBoundsTestEnableEXT(handle, enable ? VK_TRUE : VK_FALSE);
1135 }
1136
1137 void SetDepthCompareOpEXT(VkCompareOp compare_op) const noexcept {
1138 dld->vkCmdSetDepthCompareOpEXT(handle, compare_op);
1139 }
1140
1141 void SetDepthTestEnableEXT(bool enable) const noexcept {
1142 dld->vkCmdSetDepthTestEnableEXT(handle, enable ? VK_TRUE : VK_FALSE);
1143 }
1144
1145 void SetDepthWriteEnableEXT(bool enable) const noexcept {
1146 dld->vkCmdSetDepthWriteEnableEXT(handle, enable ? VK_TRUE : VK_FALSE);
1147 }
1148
1149 void SetFrontFaceEXT(VkFrontFace front_face) const noexcept {
1150 dld->vkCmdSetFrontFaceEXT(handle, front_face);
1151 }
1152
1153 void SetPrimitiveTopologyEXT(VkPrimitiveTopology primitive_topology) const noexcept {
1154 dld->vkCmdSetPrimitiveTopologyEXT(handle, primitive_topology);
1155 }
1156
1157 void SetStencilOpEXT(VkStencilFaceFlags face_mask, VkStencilOp fail_op, VkStencilOp pass_op,
1158 VkStencilOp depth_fail_op, VkCompareOp compare_op) const noexcept {
1159 dld->vkCmdSetStencilOpEXT(handle, face_mask, fail_op, pass_op, depth_fail_op, compare_op);
1160 }
1161
1162 void SetStencilTestEnableEXT(bool enable) const noexcept {
1163 dld->vkCmdSetStencilTestEnableEXT(handle, enable ? VK_TRUE : VK_FALSE);
1164 }
1165
1166 void BindTransformFeedbackBuffersEXT(u32 first, u32 count, const VkBuffer* buffers,
1167 const VkDeviceSize* offsets,
1168 const VkDeviceSize* sizes) const noexcept {
1169 dld->vkCmdBindTransformFeedbackBuffersEXT(handle, first, count, buffers, offsets, sizes);
1170 }
1171
1172 void BeginTransformFeedbackEXT(u32 first_counter_buffer, u32 counter_buffers_count,
1173 const VkBuffer* counter_buffers,
1174 const VkDeviceSize* counter_buffer_offsets) const noexcept {
1175 dld->vkCmdBeginTransformFeedbackEXT(handle, first_counter_buffer, counter_buffers_count,
1176 counter_buffers, counter_buffer_offsets);
1177 }
1178
1179 void EndTransformFeedbackEXT(u32 first_counter_buffer, u32 counter_buffers_count,
1180 const VkBuffer* counter_buffers,
1181 const VkDeviceSize* counter_buffer_offsets) const noexcept {
1182 dld->vkCmdEndTransformFeedbackEXT(handle, first_counter_buffer, counter_buffers_count,
1183 counter_buffers, counter_buffer_offsets);
1184 }
1185
1186 void BeginDebugUtilsLabelEXT(const char* label, std::span<float, 4> color) const noexcept {
1187 const VkDebugUtilsLabelEXT label_info{
1188 .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT,
1189 .pNext = nullptr,
1190 .pLabelName = label,
1191 .color{color[0], color[1], color[2], color[3]},
1192 };
1193 dld->vkCmdBeginDebugUtilsLabelEXT(handle, &label_info);
1194 }
1195
1196 void EndDebugUtilsLabelEXT() const noexcept {
1197 dld->vkCmdEndDebugUtilsLabelEXT(handle);
1198 }
1199
1200private:
1201 VkCommandBuffer handle;
1202 const DeviceDispatch* dld;
1203};
1204
1205u32 AvailableVersion(const InstanceDispatch& dld) noexcept;
1206
1207std::optional<std::vector<VkExtensionProperties>> EnumerateInstanceExtensionProperties(
1208 const InstanceDispatch& dld);
1209
1210std::optional<std::vector<VkLayerProperties>> EnumerateInstanceLayerProperties(
1211 const InstanceDispatch& dld);
1212
1213} // namespace Vulkan::vk