From d93742142243dea1355012b9f0ce7f5ac8a2dc02 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Thu, 24 Dec 2020 21:24:34 -0300 Subject: vulkan_common: Move dynamic library load to a separate file Allows us to initialize a Vulkan dynamic library from different backends without duplicating code. --- src/video_core/CMakeLists.txt | 2 ++ src/video_core/renderer_vulkan/renderer_vulkan.cpp | 39 +++++----------------- src/video_core/vulkan_common/vulkan_library.cpp | 36 ++++++++++++++++++++ src/video_core/vulkan_common/vulkan_library.h | 13 ++++++++ 4 files changed, 59 insertions(+), 31 deletions(-) create mode 100644 src/video_core/vulkan_common/vulkan_library.cpp create mode 100644 src/video_core/vulkan_common/vulkan_library.h diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 948e167c3..d967fe07b 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -260,6 +260,8 @@ add_library(video_core STATIC textures/texture.h video_core.cpp video_core.h + vulkan_common/vulkan_library.cpp + vulkan_common/vulkan_library.h ) create_target_directory_groups(video_core) diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 7f521cb9b..7a34c95ab 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -12,8 +12,6 @@ #include -#include "common/dynamic_library.h" -#include "common/file_util.h" #include "common/logging/log.h" #include "common/telemetry.h" #include "core/core.h" @@ -32,6 +30,7 @@ #include "video_core/renderer_vulkan/vk_state_tracker.h" #include "video_core/renderer_vulkan/vk_swapchain.h" #include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_library.h" // Include these late to avoid polluting previous headers #ifdef _WIN32 @@ -70,31 +69,10 @@ VkBool32 DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, return VK_FALSE; } -Common::DynamicLibrary OpenVulkanLibrary() { - Common::DynamicLibrary library; -#ifdef __APPLE__ - // Check if a path to a specific Vulkan library has been specified. - char* libvulkan_env = getenv("LIBVULKAN_PATH"); - if (!libvulkan_env || !library.Open(libvulkan_env)) { - // Use the libvulkan.dylib from the application bundle. - const std::string filename = - Common::FS::GetBundleDirectory() + "/Contents/Frameworks/libvulkan.dylib"; - library.Open(filename.c_str()); - } -#else - std::string filename = Common::DynamicLibrary::GetVersionedFilename("vulkan", 1); - if (!library.Open(filename.c_str())) { - // Android devices may not have libvulkan.so.1, only libvulkan.so. - filename = Common::DynamicLibrary::GetVersionedFilename("vulkan"); - (void)library.Open(filename.c_str()); - } -#endif - return library; -} - -std::pair CreateInstance(Common::DynamicLibrary& library, - vk::InstanceDispatch& dld, WindowSystemType window_type, - bool enable_debug_utils, bool enable_layers) { +std::pair CreateInstance( + Common::DynamicLibrary& library, vk::InstanceDispatch& dld, + WindowSystemType window_type = WindowSystemType::Headless, bool enable_debug_utils = false, + bool enable_layers = false) { if (!library.IsOpen()) { LOG_ERROR(Render_Vulkan, "Vulkan library not available"); return {}; @@ -285,7 +263,7 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { } bool RendererVulkan::Init() { - library = OpenVulkanLibrary(); + library = OpenLibrary(); std::tie(instance, instance_version) = CreateInstance( library, dld, render_window.GetWindowInfo().type, true, Settings::values.renderer_debug); if (!instance || !CreateDebugCallback() || !CreateSurface() || !PickDevices()) { @@ -446,9 +424,8 @@ void RendererVulkan::Report() const { std::vector RendererVulkan::EnumerateDevices() { vk::InstanceDispatch dld; - Common::DynamicLibrary library = OpenVulkanLibrary(); - vk::Instance instance = - CreateInstance(library, dld, WindowSystemType::Headless, false, false).first; + Common::DynamicLibrary library = OpenLibrary(); + vk::Instance instance = CreateInstance(library, dld).first; if (!instance) { return {}; } diff --git a/src/video_core/vulkan_common/vulkan_library.cpp b/src/video_core/vulkan_common/vulkan_library.cpp new file mode 100644 index 000000000..27c958221 --- /dev/null +++ b/src/video_core/vulkan_common/vulkan_library.cpp @@ -0,0 +1,36 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include + +#include "common/dynamic_library.h" +#include "common/file_util.h" +#include "video_core/vulkan_common/vulkan_library.h" + +namespace Vulkan { + +Common::DynamicLibrary OpenLibrary() { + Common::DynamicLibrary library; +#ifdef __APPLE__ + // Check if a path to a specific Vulkan library has been specified. + char* const libvulkan_env = std::getenv("LIBVULKAN_PATH"); + if (!libvulkan_env || !library.Open(libvulkan_env)) { + // Use the libvulkan.dylib from the application bundle. + const std::string filename = + Common::FS::GetBundleDirectory() + "/Contents/Frameworks/libvulkan.dylib"; + library.Open(filename.c_str()); + } +#else + std::string filename = Common::DynamicLibrary::GetVersionedFilename("vulkan", 1); + if (!library.Open(filename.c_str())) { + // Android devices may not have libvulkan.so.1, only libvulkan.so. + filename = Common::DynamicLibrary::GetVersionedFilename("vulkan"); + void(library.Open(filename.c_str())); + } +#endif + return library; +} + +} // namespace Vulkan diff --git a/src/video_core/vulkan_common/vulkan_library.h b/src/video_core/vulkan_common/vulkan_library.h new file mode 100644 index 000000000..8b28b0e17 --- /dev/null +++ b/src/video_core/vulkan_common/vulkan_library.h @@ -0,0 +1,13 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "common/dynamic_library.h" + +namespace Vulkan { + +Common::DynamicLibrary OpenLibrary(); + +} // namespace Vulkan -- cgit v1.2.3 From d1435009ed914cc50533a71b1e25132376c28586 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Thu, 24 Dec 2020 21:30:11 -0300 Subject: vulkan_common: Rename renderer_vulkan/wrapper.h to vulkan_common/vulkan_wrapper.h Allows sharing Vulkan wrapper code between different rendering backends. --- src/video_core/CMakeLists.txt | 4 +- src/video_core/renderer_vulkan/blit_image.cpp | 2 +- src/video_core/renderer_vulkan/blit_image.h | 2 +- src/video_core/renderer_vulkan/maxwell_to_vk.cpp | 2 +- src/video_core/renderer_vulkan/maxwell_to_vk.h | 2 +- src/video_core/renderer_vulkan/renderer_vulkan.cpp | 2 +- src/video_core/renderer_vulkan/renderer_vulkan.h | 2 +- src/video_core/renderer_vulkan/vk_blit_screen.cpp | 2 +- src/video_core/renderer_vulkan/vk_blit_screen.h | 2 +- src/video_core/renderer_vulkan/vk_buffer_cache.cpp | 2 +- src/video_core/renderer_vulkan/vk_buffer_cache.h | 2 +- src/video_core/renderer_vulkan/vk_command_pool.cpp | 2 +- src/video_core/renderer_vulkan/vk_command_pool.h | 2 +- src/video_core/renderer_vulkan/vk_compute_pass.cpp | 2 +- src/video_core/renderer_vulkan/vk_compute_pass.h | 2 +- .../renderer_vulkan/vk_compute_pipeline.cpp | 2 +- .../renderer_vulkan/vk_compute_pipeline.h | 2 +- .../renderer_vulkan/vk_descriptor_pool.cpp | 2 +- .../renderer_vulkan/vk_descriptor_pool.h | 2 +- src/video_core/renderer_vulkan/vk_device.cpp | 2 +- src/video_core/renderer_vulkan/vk_device.h | 2 +- .../renderer_vulkan/vk_fence_manager.cpp | 2 +- src/video_core/renderer_vulkan/vk_fence_manager.h | 2 +- .../renderer_vulkan/vk_graphics_pipeline.cpp | 2 +- .../renderer_vulkan/vk_graphics_pipeline.h | 2 +- .../renderer_vulkan/vk_master_semaphore.cpp | 2 +- .../renderer_vulkan/vk_master_semaphore.h | 2 +- .../renderer_vulkan/vk_memory_manager.cpp | 2 +- src/video_core/renderer_vulkan/vk_memory_manager.h | 2 +- .../renderer_vulkan/vk_pipeline_cache.cpp | 2 +- src/video_core/renderer_vulkan/vk_pipeline_cache.h | 2 +- src/video_core/renderer_vulkan/vk_query_cache.cpp | 2 +- src/video_core/renderer_vulkan/vk_query_cache.h | 2 +- src/video_core/renderer_vulkan/vk_rasterizer.cpp | 2 +- src/video_core/renderer_vulkan/vk_rasterizer.h | 2 +- src/video_core/renderer_vulkan/vk_scheduler.cpp | 2 +- src/video_core/renderer_vulkan/vk_scheduler.h | 2 +- src/video_core/renderer_vulkan/vk_shader_util.cpp | 2 +- src/video_core/renderer_vulkan/vk_shader_util.h | 2 +- .../renderer_vulkan/vk_staging_buffer_pool.cpp | 2 +- .../renderer_vulkan/vk_staging_buffer_pool.h | 2 +- .../renderer_vulkan/vk_stream_buffer.cpp | 2 +- src/video_core/renderer_vulkan/vk_stream_buffer.h | 2 +- src/video_core/renderer_vulkan/vk_swapchain.cpp | 2 +- src/video_core/renderer_vulkan/vk_swapchain.h | 2 +- .../renderer_vulkan/vk_texture_cache.cpp | 2 +- src/video_core/renderer_vulkan/vk_texture_cache.h | 2 +- .../renderer_vulkan/vk_update_descriptor.cpp | 2 +- .../renderer_vulkan/vk_update_descriptor.h | 2 +- src/video_core/renderer_vulkan/wrapper.cpp | 928 --------------- src/video_core/renderer_vulkan/wrapper.h | 1213 -------------------- src/video_core/vulkan_common/vulkan_wrapper.cpp | 928 +++++++++++++++ src/video_core/vulkan_common/vulkan_wrapper.h | 1213 ++++++++++++++++++++ 53 files changed, 2191 insertions(+), 2191 deletions(-) delete mode 100644 src/video_core/renderer_vulkan/wrapper.cpp delete mode 100644 src/video_core/renderer_vulkan/wrapper.h create mode 100644 src/video_core/vulkan_common/vulkan_wrapper.cpp create mode 100644 src/video_core/vulkan_common/vulkan_wrapper.h diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index d967fe07b..e19632bb1 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -170,8 +170,6 @@ add_library(video_core STATIC renderer_vulkan/vk_texture_cache.h renderer_vulkan/vk_update_descriptor.cpp renderer_vulkan/vk_update_descriptor.h - renderer_vulkan/wrapper.cpp - renderer_vulkan/wrapper.h shader_cache.h shader_notify.cpp shader_notify.h @@ -262,6 +260,8 @@ add_library(video_core STATIC video_core.h vulkan_common/vulkan_library.cpp vulkan_common/vulkan_library.h + vulkan_common/vulkan_wrapper.cpp + vulkan_common/vulkan_wrapper.h ) create_target_directory_groups(video_core) diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp index 87c8e5693..504492cac 100644 --- a/src/video_core/renderer_vulkan/blit_image.cpp +++ b/src/video_core/renderer_vulkan/blit_image.cpp @@ -17,8 +17,8 @@ #include "video_core/renderer_vulkan/vk_state_tracker.h" #include "video_core/renderer_vulkan/vk_texture_cache.h" #include "video_core/renderer_vulkan/vk_update_descriptor.h" -#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/surface.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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 @@ #include "video_core/engines/fermi_2d.h" #include "video_core/renderer_vulkan/vk_descriptor_pool.h" -#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/texture_cache/types.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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 @@ #include "video_core/engines/maxwell_3d.h" #include "video_core/renderer_vulkan/maxwell_to_vk.h" #include "video_core/renderer_vulkan/vk_device.h" -#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/surface.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan::MaxwellToVK { 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 @@ #include "common/common_types.h" #include "video_core/engines/maxwell_3d.h" #include "video_core/renderer_vulkan/vk_device.h" -#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/surface.h" #include "video_core/textures/texture.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan::MaxwellToVK { diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 7a34c95ab..6e267f89d 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -29,8 +29,8 @@ #include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_state_tracker.h" #include "video_core/renderer_vulkan/vk_swapchain.h" -#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/vulkan_common/vulkan_library.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" // Include these late to avoid polluting previous headers #ifdef _WIN32 diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index 74642fba4..4a0abfaad 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h @@ -11,7 +11,7 @@ #include "common/dynamic_library.h" #include "video_core/renderer_base.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Core { class TelemetrySession; 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 @@ #include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_shader_util.h" #include "video_core/renderer_vulkan/vk_swapchain.h" -#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/surface.h" #include "video_core/textures/decoders.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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 @@ #include #include "video_core/renderer_vulkan/vk_memory_manager.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Core { class 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 @@ #include "video_core/renderer_vulkan/vk_device.h" #include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_stream_buffer.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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 @@ #include "video_core/renderer_vulkan/vk_memory_manager.h" #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" #include "video_core/renderer_vulkan/vk_stream_buffer.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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 @@ #include "video_core/renderer_vulkan/vk_command_pool.h" #include "video_core/renderer_vulkan/vk_device.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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 @@ #include #include "video_core/renderer_vulkan/vk_resource_pool.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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 @@ #include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" #include "video_core/renderer_vulkan/vk_update_descriptor.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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 @@ #include "common/common_types.h" #include "video_core/engines/maxwell_3d.h" #include "video_core/renderer_vulkan/vk_descriptor_pool.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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 @@ #include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_shader_decompiler.h" #include "video_core/renderer_vulkan/vk_update_descriptor.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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 @@ #include "common/common_types.h" #include "video_core/renderer_vulkan/vk_descriptor_pool.h" #include "video_core/renderer_vulkan/vk_shader_decompiler.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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 @@ #include "video_core/renderer_vulkan/vk_device.h" #include "video_core/renderer_vulkan/vk_resource_pool.h" #include "video_core/renderer_vulkan/vk_scheduler.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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 @@ #include #include "video_core/renderer_vulkan/vk_resource_pool.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { diff --git a/src/video_core/renderer_vulkan/vk_device.cpp b/src/video_core/renderer_vulkan/vk_device.cpp index 370a63f74..f3dd6eae1 100644 --- a/src/video_core/renderer_vulkan/vk_device.cpp +++ b/src/video_core/renderer_vulkan/vk_device.cpp @@ -14,7 +14,7 @@ #include "common/assert.h" #include "core/settings.h" #include "video_core/renderer_vulkan/vk_device.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { diff --git a/src/video_core/renderer_vulkan/vk_device.h b/src/video_core/renderer_vulkan/vk_device.h index 995dcfc0f..9673f47c7 100644 --- a/src/video_core/renderer_vulkan/vk_device.h +++ b/src/video_core/renderer_vulkan/vk_device.h @@ -11,7 +11,7 @@ #include "common/common_types.h" #include "video_core/renderer_vulkan/nsight_aftermath_tracker.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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 @@ #include "video_core/renderer_vulkan/vk_fence_manager.h" #include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_texture_cache.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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 @@ #include "video_core/fence_manager.h" #include "video_core/renderer_vulkan/vk_buffer_cache.h" #include "video_core/renderer_vulkan/vk_texture_cache.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Core { class 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 @@ #include "video_core/renderer_vulkan/vk_pipeline_cache.h" #include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_update_descriptor.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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 @@ #include "video_core/renderer_vulkan/fixed_pipeline_state.h" #include "video_core/renderer_vulkan/vk_descriptor_pool.h" #include "video_core/renderer_vulkan/vk_shader_decompiler.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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 @@ #include "core/settings.h" #include "video_core/renderer_vulkan/vk_device.h" #include "video_core/renderer_vulkan/vk_master_semaphore.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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 @@ #include #include "common/common_types.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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 @@ #include "common/logging/log.h" #include "video_core/renderer_vulkan/vk_device.h" #include "video_core/renderer_vulkan/vk_memory_manager.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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 @@ #include #include #include "common/common_types.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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 @@ #include "video_core/renderer_vulkan/vk_rasterizer.h" #include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_update_descriptor.h" -#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/shader/compiler_settings.h" #include "video_core/shader/memory_util.h" #include "video_core/shader_cache.h" #include "video_core/shader_notify.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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 @@ #include "video_core/renderer_vulkan/fixed_pipeline_state.h" #include "video_core/renderer_vulkan/vk_graphics_pipeline.h" #include "video_core/renderer_vulkan/vk_shader_decompiler.h" -#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/shader/async_shaders.h" #include "video_core/shader/memory_util.h" #include "video_core/shader/registry.h" #include "video_core/shader/shader_ir.h" #include "video_core/shader_cache.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Core { class 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 @@ #include "video_core/renderer_vulkan/vk_query_cache.h" #include "video_core/renderer_vulkan/vk_resource_pool.h" #include "video_core/renderer_vulkan/vk_scheduler.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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 @@ #include "common/common_types.h" #include "video_core/query_cache.h" #include "video_core/renderer_vulkan/vk_resource_pool.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace VideoCore { class 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 @@ #include "video_core/renderer_vulkan/vk_state_tracker.h" #include "video_core/renderer_vulkan/vk_texture_cache.h" #include "video_core/renderer_vulkan/vk_update_descriptor.h" -#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/shader_cache.h" #include "video_core/texture_cache/texture_cache.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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 @@ #include "video_core/renderer_vulkan/vk_stream_buffer.h" #include "video_core/renderer_vulkan/vk_texture_cache.h" #include "video_core/renderer_vulkan/vk_update_descriptor.h" -#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/shader/async_shaders.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Core { class 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 @@ #include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_state_tracker.h" #include "video_core/renderer_vulkan/vk_texture_cache.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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 @@ #include #include "common/common_types.h" #include "common/threadsafe_queue.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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 @@ #include "common/common_types.h" #include "video_core/renderer_vulkan/vk_device.h" #include "video_core/renderer_vulkan/vk_shader_util.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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 @@ #include #include "common/common_types.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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 @@ #include "video_core/renderer_vulkan/vk_device.h" #include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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 @@ #include "common/common_types.h" #include "video_core/renderer_vulkan/vk_memory_manager.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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 @@ #include "video_core/renderer_vulkan/vk_device.h" #include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_stream_buffer.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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 @@ #include #include "common/common_types.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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 @@ #include "video_core/renderer_vulkan/vk_device.h" #include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_swapchain.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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 @@ #include #include "common/common_types.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Layout { struct 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 @@ #include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" #include "video_core/renderer_vulkan/vk_texture_cache.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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 @@ #include #include "video_core/renderer_vulkan/vk_memory_manager.h" -#include "video_core/renderer_vulkan/wrapper.h" #include "video_core/texture_cache/texture_cache.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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 @@ #include "video_core/renderer_vulkan/vk_device.h" #include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_update_descriptor.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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 @@ #include #include "common/common_types.h" -#include "video_core/renderer_vulkan/wrapper.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { 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 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include -#include -#include -#include -#include -#include - -#include "common/common_types.h" -#include "common/logging/log.h" - -#include "video_core/renderer_vulkan/wrapper.h" - -namespace Vulkan::vk { - -namespace { - -template -void SortPhysicalDevices(std::vector& devices, const InstanceDispatch& dld, - Func&& func) { - // Calling GetProperties calls Vulkan more than needed. But they are supposed to be cheap - // functions. - std::stable_sort(devices.begin(), devices.end(), - [&dld, &func](VkPhysicalDevice lhs, VkPhysicalDevice rhs) { - return func(vk::PhysicalDevice(lhs, dld).GetProperties(), - vk::PhysicalDevice(rhs, dld).GetProperties()); - }); -} - -void SortPhysicalDevicesPerVendor(std::vector& devices, - const InstanceDispatch& dld, - std::initializer_list vendor_ids) { - for (auto it = vendor_ids.end(); it != vendor_ids.begin();) { - --it; - SortPhysicalDevices(devices, dld, [id = *it](const auto& lhs, const auto& rhs) { - return lhs.vendorID == id && rhs.vendorID != id; - }); - } -} - -void SortPhysicalDevices(std::vector& devices, const InstanceDispatch& dld) { - // Sort by name, this will set a base and make GPUs with higher numbers appear first - // (e.g. GTX 1650 will intentionally be listed before a GTX 1080). - SortPhysicalDevices(devices, dld, [](const auto& lhs, const auto& rhs) { - return std::string_view{lhs.deviceName} > std::string_view{rhs.deviceName}; - }); - // Prefer discrete over non-discrete - SortPhysicalDevices(devices, dld, [](const auto& lhs, const auto& rhs) { - return lhs.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU && - rhs.deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU; - }); - // Prefer Nvidia over AMD, AMD over Intel, Intel over the rest. - SortPhysicalDevicesPerVendor(devices, dld, {0x10DE, 0x1002, 0x8086}); -} - -template -bool Proc(T& result, const InstanceDispatch& dld, const char* proc_name, - VkInstance instance = nullptr) noexcept { - result = reinterpret_cast(dld.vkGetInstanceProcAddr(instance, proc_name)); - return result != nullptr; -} - -template -void Proc(T& result, const DeviceDispatch& dld, const char* proc_name, VkDevice device) noexcept { - result = reinterpret_cast(dld.vkGetDeviceProcAddr(device, proc_name)); -} - -void Load(VkDevice device, DeviceDispatch& dld) noexcept { -#define X(name) Proc(dld.name, dld, #name, device) - X(vkAcquireNextImageKHR); - X(vkAllocateCommandBuffers); - X(vkAllocateDescriptorSets); - X(vkAllocateMemory); - X(vkBeginCommandBuffer); - X(vkBindBufferMemory); - X(vkBindImageMemory); - X(vkCmdBeginQuery); - X(vkCmdBeginRenderPass); - X(vkCmdBeginTransformFeedbackEXT); - X(vkCmdBeginDebugUtilsLabelEXT); - X(vkCmdBindDescriptorSets); - X(vkCmdBindIndexBuffer); - X(vkCmdBindPipeline); - X(vkCmdBindTransformFeedbackBuffersEXT); - X(vkCmdBindVertexBuffers); - X(vkCmdBlitImage); - X(vkCmdClearAttachments); - X(vkCmdCopyBuffer); - X(vkCmdCopyBufferToImage); - X(vkCmdCopyImage); - X(vkCmdCopyImageToBuffer); - X(vkCmdDispatch); - X(vkCmdDraw); - X(vkCmdDrawIndexed); - X(vkCmdEndQuery); - X(vkCmdEndRenderPass); - X(vkCmdEndTransformFeedbackEXT); - X(vkCmdEndDebugUtilsLabelEXT); - X(vkCmdFillBuffer); - X(vkCmdPipelineBarrier); - X(vkCmdPushConstants); - X(vkCmdSetBlendConstants); - X(vkCmdSetDepthBias); - X(vkCmdSetDepthBounds); - X(vkCmdSetEvent); - X(vkCmdSetScissor); - X(vkCmdSetStencilCompareMask); - X(vkCmdSetStencilReference); - X(vkCmdSetStencilWriteMask); - X(vkCmdSetViewport); - X(vkCmdWaitEvents); - X(vkCmdBindVertexBuffers2EXT); - X(vkCmdSetCullModeEXT); - X(vkCmdSetDepthBoundsTestEnableEXT); - X(vkCmdSetDepthCompareOpEXT); - X(vkCmdSetDepthTestEnableEXT); - X(vkCmdSetDepthWriteEnableEXT); - X(vkCmdSetFrontFaceEXT); - X(vkCmdSetPrimitiveTopologyEXT); - X(vkCmdSetStencilOpEXT); - X(vkCmdSetStencilTestEnableEXT); - X(vkCmdResolveImage); - X(vkCreateBuffer); - X(vkCreateBufferView); - X(vkCreateCommandPool); - X(vkCreateComputePipelines); - X(vkCreateDescriptorPool); - X(vkCreateDescriptorSetLayout); - X(vkCreateDescriptorUpdateTemplateKHR); - X(vkCreateEvent); - X(vkCreateFence); - X(vkCreateFramebuffer); - X(vkCreateGraphicsPipelines); - X(vkCreateImage); - X(vkCreateImageView); - X(vkCreatePipelineLayout); - X(vkCreateQueryPool); - X(vkCreateRenderPass); - X(vkCreateSampler); - X(vkCreateSemaphore); - X(vkCreateShaderModule); - X(vkCreateSwapchainKHR); - X(vkDestroyBuffer); - X(vkDestroyBufferView); - X(vkDestroyCommandPool); - X(vkDestroyDescriptorPool); - X(vkDestroyDescriptorSetLayout); - X(vkDestroyDescriptorUpdateTemplateKHR); - X(vkDestroyEvent); - X(vkDestroyFence); - X(vkDestroyFramebuffer); - X(vkDestroyImage); - X(vkDestroyImageView); - X(vkDestroyPipeline); - X(vkDestroyPipelineLayout); - X(vkDestroyQueryPool); - X(vkDestroyRenderPass); - X(vkDestroySampler); - X(vkDestroySemaphore); - X(vkDestroyShaderModule); - X(vkDestroySwapchainKHR); - X(vkDeviceWaitIdle); - X(vkEndCommandBuffer); - X(vkFreeCommandBuffers); - X(vkFreeDescriptorSets); - X(vkFreeMemory); - X(vkGetBufferMemoryRequirements); - X(vkGetDeviceQueue); - X(vkGetEventStatus); - X(vkGetFenceStatus); - X(vkGetImageMemoryRequirements); - X(vkGetQueryPoolResults); - X(vkGetSemaphoreCounterValueKHR); - X(vkMapMemory); - X(vkQueueSubmit); - X(vkResetFences); - X(vkResetQueryPoolEXT); - X(vkSetDebugUtilsObjectNameEXT); - X(vkSetDebugUtilsObjectTagEXT); - X(vkUnmapMemory); - X(vkUpdateDescriptorSetWithTemplateKHR); - X(vkUpdateDescriptorSets); - X(vkWaitForFences); - X(vkWaitSemaphoresKHR); -#undef X -} - -template -void SetObjectName(const DeviceDispatch* dld, VkDevice device, T handle, VkObjectType type, - const char* name) { - const VkDebugUtilsObjectNameInfoEXT name_info{ - .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, - .pNext = nullptr, - .objectType = VK_OBJECT_TYPE_IMAGE, - .objectHandle = reinterpret_cast(handle), - .pObjectName = name, - }; - Check(dld->vkSetDebugUtilsObjectNameEXT(device, &name_info)); -} - -} // Anonymous namespace - -bool Load(InstanceDispatch& dld) noexcept { -#define X(name) Proc(dld.name, dld, #name) - return X(vkCreateInstance) && X(vkEnumerateInstanceExtensionProperties) && - X(vkEnumerateInstanceLayerProperties); -#undef X -} - -bool Load(VkInstance instance, InstanceDispatch& dld) noexcept { -#define X(name) Proc(dld.name, dld, #name, instance) - // These functions may fail to load depending on the enabled extensions. - // Don't return a failure on these. - X(vkCreateDebugUtilsMessengerEXT); - X(vkDestroyDebugUtilsMessengerEXT); - X(vkDestroySurfaceKHR); - X(vkGetPhysicalDeviceFeatures2KHR); - X(vkGetPhysicalDeviceProperties2KHR); - X(vkGetPhysicalDeviceSurfaceCapabilitiesKHR); - X(vkGetPhysicalDeviceSurfaceFormatsKHR); - X(vkGetPhysicalDeviceSurfacePresentModesKHR); - X(vkGetPhysicalDeviceSurfaceSupportKHR); - X(vkGetSwapchainImagesKHR); - X(vkQueuePresentKHR); - - return X(vkCreateDevice) && X(vkDestroyDevice) && X(vkDestroyDevice) && - X(vkEnumerateDeviceExtensionProperties) && X(vkEnumeratePhysicalDevices) && - X(vkGetDeviceProcAddr) && X(vkGetPhysicalDeviceFormatProperties) && - X(vkGetPhysicalDeviceMemoryProperties) && X(vkGetPhysicalDeviceProperties) && - X(vkGetPhysicalDeviceQueueFamilyProperties); -#undef X -} - -const char* Exception::what() const noexcept { - return ToString(result); -} - -const char* ToString(VkResult result) noexcept { - switch (result) { - case VkResult::VK_SUCCESS: - return "VK_SUCCESS"; - case VkResult::VK_NOT_READY: - return "VK_NOT_READY"; - case VkResult::VK_TIMEOUT: - return "VK_TIMEOUT"; - case VkResult::VK_EVENT_SET: - return "VK_EVENT_SET"; - case VkResult::VK_EVENT_RESET: - return "VK_EVENT_RESET"; - case VkResult::VK_INCOMPLETE: - return "VK_INCOMPLETE"; - case VkResult::VK_ERROR_OUT_OF_HOST_MEMORY: - return "VK_ERROR_OUT_OF_HOST_MEMORY"; - case VkResult::VK_ERROR_OUT_OF_DEVICE_MEMORY: - return "VK_ERROR_OUT_OF_DEVICE_MEMORY"; - case VkResult::VK_ERROR_INITIALIZATION_FAILED: - return "VK_ERROR_INITIALIZATION_FAILED"; - case VkResult::VK_ERROR_DEVICE_LOST: - return "VK_ERROR_DEVICE_LOST"; - case VkResult::VK_ERROR_MEMORY_MAP_FAILED: - return "VK_ERROR_MEMORY_MAP_FAILED"; - case VkResult::VK_ERROR_LAYER_NOT_PRESENT: - return "VK_ERROR_LAYER_NOT_PRESENT"; - case VkResult::VK_ERROR_EXTENSION_NOT_PRESENT: - return "VK_ERROR_EXTENSION_NOT_PRESENT"; - case VkResult::VK_ERROR_FEATURE_NOT_PRESENT: - return "VK_ERROR_FEATURE_NOT_PRESENT"; - case VkResult::VK_ERROR_INCOMPATIBLE_DRIVER: - return "VK_ERROR_INCOMPATIBLE_DRIVER"; - case VkResult::VK_ERROR_TOO_MANY_OBJECTS: - return "VK_ERROR_TOO_MANY_OBJECTS"; - case VkResult::VK_ERROR_FORMAT_NOT_SUPPORTED: - return "VK_ERROR_FORMAT_NOT_SUPPORTED"; - case VkResult::VK_ERROR_FRAGMENTED_POOL: - return "VK_ERROR_FRAGMENTED_POOL"; - case VkResult::VK_ERROR_OUT_OF_POOL_MEMORY: - return "VK_ERROR_OUT_OF_POOL_MEMORY"; - case VkResult::VK_ERROR_INVALID_EXTERNAL_HANDLE: - return "VK_ERROR_INVALID_EXTERNAL_HANDLE"; - case VkResult::VK_ERROR_SURFACE_LOST_KHR: - return "VK_ERROR_SURFACE_LOST_KHR"; - case VkResult::VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: - return "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR"; - case VkResult::VK_SUBOPTIMAL_KHR: - return "VK_SUBOPTIMAL_KHR"; - case VkResult::VK_ERROR_OUT_OF_DATE_KHR: - return "VK_ERROR_OUT_OF_DATE_KHR"; - case VkResult::VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: - return "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR"; - case VkResult::VK_ERROR_VALIDATION_FAILED_EXT: - return "VK_ERROR_VALIDATION_FAILED_EXT"; - case VkResult::VK_ERROR_INVALID_SHADER_NV: - return "VK_ERROR_INVALID_SHADER_NV"; - case VkResult::VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT: - return "VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT"; - case VkResult::VK_ERROR_FRAGMENTATION_EXT: - return "VK_ERROR_FRAGMENTATION_EXT"; - case VkResult::VK_ERROR_NOT_PERMITTED_EXT: - return "VK_ERROR_NOT_PERMITTED_EXT"; - case VkResult::VK_ERROR_INVALID_DEVICE_ADDRESS_EXT: - return "VK_ERROR_INVALID_DEVICE_ADDRESS_EXT"; - case VkResult::VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT: - return "VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT"; - case VkResult::VK_ERROR_UNKNOWN: - return "VK_ERROR_UNKNOWN"; - case VkResult::VK_ERROR_INCOMPATIBLE_VERSION_KHR: - return "VK_ERROR_INCOMPATIBLE_VERSION_KHR"; - case VkResult::VK_THREAD_IDLE_KHR: - return "VK_THREAD_IDLE_KHR"; - case VkResult::VK_THREAD_DONE_KHR: - return "VK_THREAD_DONE_KHR"; - case VkResult::VK_OPERATION_DEFERRED_KHR: - return "VK_OPERATION_DEFERRED_KHR"; - case VkResult::VK_OPERATION_NOT_DEFERRED_KHR: - return "VK_OPERATION_NOT_DEFERRED_KHR"; - case VkResult::VK_PIPELINE_COMPILE_REQUIRED_EXT: - return "VK_PIPELINE_COMPILE_REQUIRED_EXT"; - case VkResult::VK_RESULT_MAX_ENUM: - return "VK_RESULT_MAX_ENUM"; - } - return "Unknown"; -} - -void Destroy(VkInstance instance, const InstanceDispatch& dld) noexcept { - dld.vkDestroyInstance(instance, nullptr); -} - -void Destroy(VkDevice device, const InstanceDispatch& dld) noexcept { - dld.vkDestroyDevice(device, nullptr); -} - -void Destroy(VkDevice device, VkBuffer handle, const DeviceDispatch& dld) noexcept { - dld.vkDestroyBuffer(device, handle, nullptr); -} - -void Destroy(VkDevice device, VkBufferView handle, const DeviceDispatch& dld) noexcept { - dld.vkDestroyBufferView(device, handle, nullptr); -} - -void Destroy(VkDevice device, VkCommandPool handle, const DeviceDispatch& dld) noexcept { - dld.vkDestroyCommandPool(device, handle, nullptr); -} - -void Destroy(VkDevice device, VkDescriptorPool handle, const DeviceDispatch& dld) noexcept { - dld.vkDestroyDescriptorPool(device, handle, nullptr); -} - -void Destroy(VkDevice device, VkDescriptorSetLayout handle, const DeviceDispatch& dld) noexcept { - dld.vkDestroyDescriptorSetLayout(device, handle, nullptr); -} - -void Destroy(VkDevice device, VkDescriptorUpdateTemplateKHR handle, - const DeviceDispatch& dld) noexcept { - dld.vkDestroyDescriptorUpdateTemplateKHR(device, handle, nullptr); -} - -void Destroy(VkDevice device, VkDeviceMemory handle, const DeviceDispatch& dld) noexcept { - dld.vkFreeMemory(device, handle, nullptr); -} - -void Destroy(VkDevice device, VkEvent handle, const DeviceDispatch& dld) noexcept { - dld.vkDestroyEvent(device, handle, nullptr); -} - -void Destroy(VkDevice device, VkFence handle, const DeviceDispatch& dld) noexcept { - dld.vkDestroyFence(device, handle, nullptr); -} - -void Destroy(VkDevice device, VkFramebuffer handle, const DeviceDispatch& dld) noexcept { - dld.vkDestroyFramebuffer(device, handle, nullptr); -} - -void Destroy(VkDevice device, VkImage handle, const DeviceDispatch& dld) noexcept { - dld.vkDestroyImage(device, handle, nullptr); -} - -void Destroy(VkDevice device, VkImageView handle, const DeviceDispatch& dld) noexcept { - dld.vkDestroyImageView(device, handle, nullptr); -} - -void Destroy(VkDevice device, VkPipeline handle, const DeviceDispatch& dld) noexcept { - dld.vkDestroyPipeline(device, handle, nullptr); -} - -void Destroy(VkDevice device, VkPipelineLayout handle, const DeviceDispatch& dld) noexcept { - dld.vkDestroyPipelineLayout(device, handle, nullptr); -} - -void Destroy(VkDevice device, VkQueryPool handle, const DeviceDispatch& dld) noexcept { - dld.vkDestroyQueryPool(device, handle, nullptr); -} - -void Destroy(VkDevice device, VkRenderPass handle, const DeviceDispatch& dld) noexcept { - dld.vkDestroyRenderPass(device, handle, nullptr); -} - -void Destroy(VkDevice device, VkSampler handle, const DeviceDispatch& dld) noexcept { - dld.vkDestroySampler(device, handle, nullptr); -} - -void Destroy(VkDevice device, VkSwapchainKHR handle, const DeviceDispatch& dld) noexcept { - dld.vkDestroySwapchainKHR(device, handle, nullptr); -} - -void Destroy(VkDevice device, VkSemaphore handle, const DeviceDispatch& dld) noexcept { - dld.vkDestroySemaphore(device, handle, nullptr); -} - -void Destroy(VkDevice device, VkShaderModule handle, const DeviceDispatch& dld) noexcept { - dld.vkDestroyShaderModule(device, handle, nullptr); -} - -void Destroy(VkInstance instance, VkDebugUtilsMessengerEXT handle, - const InstanceDispatch& dld) noexcept { - dld.vkDestroyDebugUtilsMessengerEXT(instance, handle, nullptr); -} - -void Destroy(VkInstance instance, VkSurfaceKHR handle, const InstanceDispatch& dld) noexcept { - dld.vkDestroySurfaceKHR(instance, handle, nullptr); -} - -VkResult Free(VkDevice device, VkDescriptorPool handle, Span sets, - const DeviceDispatch& dld) noexcept { - return dld.vkFreeDescriptorSets(device, handle, sets.size(), sets.data()); -} - -VkResult Free(VkDevice device, VkCommandPool handle, Span buffers, - const DeviceDispatch& dld) noexcept { - dld.vkFreeCommandBuffers(device, handle, buffers.size(), buffers.data()); - return VK_SUCCESS; -} - -Instance Instance::Create(u32 version, Span layers, Span extensions, - InstanceDispatch& dispatch) noexcept { - const VkApplicationInfo application_info{ - .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, - .pNext = nullptr, - .pApplicationName = "yuzu Emulator", - .applicationVersion = VK_MAKE_VERSION(0, 1, 0), - .pEngineName = "yuzu Emulator", - .engineVersion = VK_MAKE_VERSION(0, 1, 0), - .apiVersion = version, - }; - const VkInstanceCreateInfo ci{ - .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, - .pNext = nullptr, - .flags = 0, - .pApplicationInfo = &application_info, - .enabledLayerCount = layers.size(), - .ppEnabledLayerNames = layers.data(), - .enabledExtensionCount = extensions.size(), - .ppEnabledExtensionNames = extensions.data(), - }; - - VkInstance instance; - if (dispatch.vkCreateInstance(&ci, nullptr, &instance) != VK_SUCCESS) { - // Failed to create the instance. - return {}; - } - if (!Proc(dispatch.vkDestroyInstance, dispatch, "vkDestroyInstance", instance)) { - // We successfully created an instance but the destroy function couldn't be loaded. - // This is a good moment to panic. - return {}; - } - - return Instance(instance, dispatch); -} - -std::optional> Instance::EnumeratePhysicalDevices() { - u32 num; - if (dld->vkEnumeratePhysicalDevices(handle, &num, nullptr) != VK_SUCCESS) { - return std::nullopt; - } - std::vector physical_devices(num); - if (dld->vkEnumeratePhysicalDevices(handle, &num, physical_devices.data()) != VK_SUCCESS) { - return std::nullopt; - } - SortPhysicalDevices(physical_devices, *dld); - return std::make_optional(std::move(physical_devices)); -} - -DebugCallback Instance::TryCreateDebugCallback( - PFN_vkDebugUtilsMessengerCallbackEXT callback) noexcept { - const VkDebugUtilsMessengerCreateInfoEXT ci{ - .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, - .pNext = nullptr, - .flags = 0, - .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT, - .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT, - .pfnUserCallback = callback, - .pUserData = nullptr, - }; - - VkDebugUtilsMessengerEXT messenger; - if (dld->vkCreateDebugUtilsMessengerEXT(handle, &ci, nullptr, &messenger) != VK_SUCCESS) { - return {}; - } - return DebugCallback(messenger, handle, *dld); -} - -void Buffer::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const { - Check(dld->vkBindBufferMemory(owner, handle, memory, offset)); -} - -void Buffer::SetObjectNameEXT(const char* name) const { - SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER, name); -} - -void BufferView::SetObjectNameEXT(const char* name) const { - SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER_VIEW, name); -} - -void Image::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const { - Check(dld->vkBindImageMemory(owner, handle, memory, offset)); -} - -void Image::SetObjectNameEXT(const char* name) const { - SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_IMAGE, name); -} - -void ImageView::SetObjectNameEXT(const char* name) const { - SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_IMAGE_VIEW, name); -} - -void DeviceMemory::SetObjectNameEXT(const char* name) const { - SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_DEVICE_MEMORY, name); -} - -void Fence::SetObjectNameEXT(const char* name) const { - SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_FENCE, name); -} - -void Framebuffer::SetObjectNameEXT(const char* name) const { - SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_FRAMEBUFFER, name); -} - -DescriptorSets DescriptorPool::Allocate(const VkDescriptorSetAllocateInfo& ai) const { - const std::size_t num = ai.descriptorSetCount; - std::unique_ptr sets = std::make_unique(num); - switch (const VkResult result = dld->vkAllocateDescriptorSets(owner, &ai, sets.get())) { - case VK_SUCCESS: - return DescriptorSets(std::move(sets), num, owner, handle, *dld); - case VK_ERROR_OUT_OF_POOL_MEMORY: - return {}; - default: - throw Exception(result); - } -} - -void DescriptorPool::SetObjectNameEXT(const char* name) const { - SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_DESCRIPTOR_POOL, name); -} - -CommandBuffers CommandPool::Allocate(std::size_t num_buffers, VkCommandBufferLevel level) const { - const VkCommandBufferAllocateInfo ai{ - .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, - .pNext = nullptr, - .commandPool = handle, - .level = level, - .commandBufferCount = static_cast(num_buffers), - }; - - std::unique_ptr buffers = std::make_unique(num_buffers); - switch (const VkResult result = dld->vkAllocateCommandBuffers(owner, &ai, buffers.get())) { - case VK_SUCCESS: - return CommandBuffers(std::move(buffers), num_buffers, owner, handle, *dld); - case VK_ERROR_OUT_OF_POOL_MEMORY: - return {}; - default: - throw Exception(result); - } -} - -void CommandPool::SetObjectNameEXT(const char* name) const { - SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_COMMAND_POOL, name); -} - -std::vector SwapchainKHR::GetImages() const { - u32 num; - Check(dld->vkGetSwapchainImagesKHR(owner, handle, &num, nullptr)); - std::vector images(num); - Check(dld->vkGetSwapchainImagesKHR(owner, handle, &num, images.data())); - return images; -} - -void Event::SetObjectNameEXT(const char* name) const { - SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_EVENT, name); -} - -void ShaderModule::SetObjectNameEXT(const char* name) const { - SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_SHADER_MODULE, name); -} - -void Semaphore::SetObjectNameEXT(const char* name) const { - SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_SEMAPHORE, name); -} - -Device Device::Create(VkPhysicalDevice physical_device, Span queues_ci, - Span enabled_extensions, const void* next, - DeviceDispatch& dispatch) noexcept { - const VkDeviceCreateInfo ci{ - .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, - .pNext = next, - .flags = 0, - .queueCreateInfoCount = queues_ci.size(), - .pQueueCreateInfos = queues_ci.data(), - .enabledLayerCount = 0, - .ppEnabledLayerNames = nullptr, - .enabledExtensionCount = enabled_extensions.size(), - .ppEnabledExtensionNames = enabled_extensions.data(), - .pEnabledFeatures = nullptr, - }; - - VkDevice device; - if (dispatch.vkCreateDevice(physical_device, &ci, nullptr, &device) != VK_SUCCESS) { - return {}; - } - Load(device, dispatch); - return Device(device, dispatch); -} - -Queue Device::GetQueue(u32 family_index) const noexcept { - VkQueue queue; - dld->vkGetDeviceQueue(handle, family_index, 0, &queue); - return Queue(queue, *dld); -} - -Buffer Device::CreateBuffer(const VkBufferCreateInfo& ci) const { - VkBuffer object; - Check(dld->vkCreateBuffer(handle, &ci, nullptr, &object)); - return Buffer(object, handle, *dld); -} - -BufferView Device::CreateBufferView(const VkBufferViewCreateInfo& ci) const { - VkBufferView object; - Check(dld->vkCreateBufferView(handle, &ci, nullptr, &object)); - return BufferView(object, handle, *dld); -} - -Image Device::CreateImage(const VkImageCreateInfo& ci) const { - VkImage object; - Check(dld->vkCreateImage(handle, &ci, nullptr, &object)); - return Image(object, handle, *dld); -} - -ImageView Device::CreateImageView(const VkImageViewCreateInfo& ci) const { - VkImageView object; - Check(dld->vkCreateImageView(handle, &ci, nullptr, &object)); - return ImageView(object, handle, *dld); -} - -Semaphore Device::CreateSemaphore() const { - static constexpr VkSemaphoreCreateInfo ci{ - .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, - .pNext = nullptr, - .flags = 0, - }; - return CreateSemaphore(ci); -} - -Semaphore Device::CreateSemaphore(const VkSemaphoreCreateInfo& ci) const { - VkSemaphore object; - Check(dld->vkCreateSemaphore(handle, &ci, nullptr, &object)); - return Semaphore(object, handle, *dld); -} - -Fence Device::CreateFence(const VkFenceCreateInfo& ci) const { - VkFence object; - Check(dld->vkCreateFence(handle, &ci, nullptr, &object)); - return Fence(object, handle, *dld); -} - -DescriptorPool Device::CreateDescriptorPool(const VkDescriptorPoolCreateInfo& ci) const { - VkDescriptorPool object; - Check(dld->vkCreateDescriptorPool(handle, &ci, nullptr, &object)); - return DescriptorPool(object, handle, *dld); -} - -RenderPass Device::CreateRenderPass(const VkRenderPassCreateInfo& ci) const { - VkRenderPass object; - Check(dld->vkCreateRenderPass(handle, &ci, nullptr, &object)); - return RenderPass(object, handle, *dld); -} - -DescriptorSetLayout Device::CreateDescriptorSetLayout( - const VkDescriptorSetLayoutCreateInfo& ci) const { - VkDescriptorSetLayout object; - Check(dld->vkCreateDescriptorSetLayout(handle, &ci, nullptr, &object)); - return DescriptorSetLayout(object, handle, *dld); -} - -PipelineLayout Device::CreatePipelineLayout(const VkPipelineLayoutCreateInfo& ci) const { - VkPipelineLayout object; - Check(dld->vkCreatePipelineLayout(handle, &ci, nullptr, &object)); - return PipelineLayout(object, handle, *dld); -} - -Pipeline Device::CreateGraphicsPipeline(const VkGraphicsPipelineCreateInfo& ci) const { - VkPipeline object; - Check(dld->vkCreateGraphicsPipelines(handle, nullptr, 1, &ci, nullptr, &object)); - return Pipeline(object, handle, *dld); -} - -Pipeline Device::CreateComputePipeline(const VkComputePipelineCreateInfo& ci) const { - VkPipeline object; - Check(dld->vkCreateComputePipelines(handle, nullptr, 1, &ci, nullptr, &object)); - return Pipeline(object, handle, *dld); -} - -Sampler Device::CreateSampler(const VkSamplerCreateInfo& ci) const { - VkSampler object; - Check(dld->vkCreateSampler(handle, &ci, nullptr, &object)); - return Sampler(object, handle, *dld); -} - -Framebuffer Device::CreateFramebuffer(const VkFramebufferCreateInfo& ci) const { - VkFramebuffer object; - Check(dld->vkCreateFramebuffer(handle, &ci, nullptr, &object)); - return Framebuffer(object, handle, *dld); -} - -CommandPool Device::CreateCommandPool(const VkCommandPoolCreateInfo& ci) const { - VkCommandPool object; - Check(dld->vkCreateCommandPool(handle, &ci, nullptr, &object)); - return CommandPool(object, handle, *dld); -} - -DescriptorUpdateTemplateKHR Device::CreateDescriptorUpdateTemplateKHR( - const VkDescriptorUpdateTemplateCreateInfoKHR& ci) const { - VkDescriptorUpdateTemplateKHR object; - Check(dld->vkCreateDescriptorUpdateTemplateKHR(handle, &ci, nullptr, &object)); - return DescriptorUpdateTemplateKHR(object, handle, *dld); -} - -QueryPool Device::CreateQueryPool(const VkQueryPoolCreateInfo& ci) const { - VkQueryPool object; - Check(dld->vkCreateQueryPool(handle, &ci, nullptr, &object)); - return QueryPool(object, handle, *dld); -} - -ShaderModule Device::CreateShaderModule(const VkShaderModuleCreateInfo& ci) const { - VkShaderModule object; - Check(dld->vkCreateShaderModule(handle, &ci, nullptr, &object)); - return ShaderModule(object, handle, *dld); -} - -Event Device::CreateEvent() const { - static constexpr VkEventCreateInfo ci{ - .sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO, - .pNext = nullptr, - .flags = 0, - }; - - VkEvent object; - Check(dld->vkCreateEvent(handle, &ci, nullptr, &object)); - return Event(object, handle, *dld); -} - -SwapchainKHR Device::CreateSwapchainKHR(const VkSwapchainCreateInfoKHR& ci) const { - VkSwapchainKHR object; - Check(dld->vkCreateSwapchainKHR(handle, &ci, nullptr, &object)); - return SwapchainKHR(object, handle, *dld); -} - -DeviceMemory Device::TryAllocateMemory(const VkMemoryAllocateInfo& ai) const noexcept { - VkDeviceMemory memory; - if (dld->vkAllocateMemory(handle, &ai, nullptr, &memory) != VK_SUCCESS) { - return {}; - } - return DeviceMemory(memory, handle, *dld); -} - -DeviceMemory Device::AllocateMemory(const VkMemoryAllocateInfo& ai) const { - VkDeviceMemory memory; - Check(dld->vkAllocateMemory(handle, &ai, nullptr, &memory)); - return DeviceMemory(memory, handle, *dld); -} - -VkMemoryRequirements Device::GetBufferMemoryRequirements(VkBuffer buffer) const noexcept { - VkMemoryRequirements requirements; - dld->vkGetBufferMemoryRequirements(handle, buffer, &requirements); - return requirements; -} - -VkMemoryRequirements Device::GetImageMemoryRequirements(VkImage image) const noexcept { - VkMemoryRequirements requirements; - dld->vkGetImageMemoryRequirements(handle, image, &requirements); - return requirements; -} - -void Device::UpdateDescriptorSets(Span writes, - Span copies) const noexcept { - dld->vkUpdateDescriptorSets(handle, writes.size(), writes.data(), copies.size(), copies.data()); -} - -VkPhysicalDeviceProperties PhysicalDevice::GetProperties() const noexcept { - VkPhysicalDeviceProperties properties; - dld->vkGetPhysicalDeviceProperties(physical_device, &properties); - return properties; -} - -void PhysicalDevice::GetProperties2KHR(VkPhysicalDeviceProperties2KHR& properties) const noexcept { - dld->vkGetPhysicalDeviceProperties2KHR(physical_device, &properties); -} - -VkPhysicalDeviceFeatures PhysicalDevice::GetFeatures() const noexcept { - VkPhysicalDeviceFeatures2KHR features2; - features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR; - features2.pNext = nullptr; - dld->vkGetPhysicalDeviceFeatures2KHR(physical_device, &features2); - return features2.features; -} - -void PhysicalDevice::GetFeatures2KHR(VkPhysicalDeviceFeatures2KHR& features) const noexcept { - dld->vkGetPhysicalDeviceFeatures2KHR(physical_device, &features); -} - -VkFormatProperties PhysicalDevice::GetFormatProperties(VkFormat format) const noexcept { - VkFormatProperties properties; - dld->vkGetPhysicalDeviceFormatProperties(physical_device, format, &properties); - return properties; -} - -std::vector PhysicalDevice::EnumerateDeviceExtensionProperties() const { - u32 num; - dld->vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &num, nullptr); - std::vector properties(num); - dld->vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &num, properties.data()); - return properties; -} - -std::vector PhysicalDevice::GetQueueFamilyProperties() const { - u32 num; - dld->vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &num, nullptr); - std::vector properties(num); - dld->vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &num, properties.data()); - return properties; -} - -bool PhysicalDevice::GetSurfaceSupportKHR(u32 queue_family_index, VkSurfaceKHR surface) const { - VkBool32 supported; - Check(dld->vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, queue_family_index, surface, - &supported)); - return supported == VK_TRUE; -} - -VkSurfaceCapabilitiesKHR PhysicalDevice::GetSurfaceCapabilitiesKHR(VkSurfaceKHR surface) const { - VkSurfaceCapabilitiesKHR capabilities; - Check(dld->vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, surface, &capabilities)); - return capabilities; -} - -std::vector PhysicalDevice::GetSurfaceFormatsKHR(VkSurfaceKHR surface) const { - u32 num; - Check(dld->vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &num, nullptr)); - std::vector formats(num); - Check( - dld->vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &num, formats.data())); - return formats; -} - -std::vector PhysicalDevice::GetSurfacePresentModesKHR( - VkSurfaceKHR surface) const { - u32 num; - Check(dld->vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &num, nullptr)); - std::vector modes(num); - Check(dld->vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &num, - modes.data())); - return modes; -} - -VkPhysicalDeviceMemoryProperties PhysicalDevice::GetMemoryProperties() const noexcept { - VkPhysicalDeviceMemoryProperties properties; - dld->vkGetPhysicalDeviceMemoryProperties(physical_device, &properties); - return properties; -} - -u32 AvailableVersion(const InstanceDispatch& dld) noexcept { - PFN_vkEnumerateInstanceVersion vkEnumerateInstanceVersion; - if (!Proc(vkEnumerateInstanceVersion, dld, "vkEnumerateInstanceVersion")) { - // If the procedure is not found, Vulkan 1.0 is assumed - return VK_API_VERSION_1_0; - } - u32 version; - if (const VkResult result = vkEnumerateInstanceVersion(&version); result != VK_SUCCESS) { - LOG_ERROR(Render_Vulkan, "vkEnumerateInstanceVersion returned {}, assuming Vulkan 1.1", - ToString(result)); - return VK_API_VERSION_1_1; - } - return version; -} - -std::optional> EnumerateInstanceExtensionProperties( - const InstanceDispatch& dld) { - u32 num; - if (dld.vkEnumerateInstanceExtensionProperties(nullptr, &num, nullptr) != VK_SUCCESS) { - return std::nullopt; - } - std::vector properties(num); - if (dld.vkEnumerateInstanceExtensionProperties(nullptr, &num, properties.data()) != - VK_SUCCESS) { - return std::nullopt; - } - return properties; -} - -std::optional> EnumerateInstanceLayerProperties( - const InstanceDispatch& dld) { - u32 num; - if (dld.vkEnumerateInstanceLayerProperties(&num, nullptr) != VK_SUCCESS) { - return std::nullopt; - } - std::vector properties(num); - if (dld.vkEnumerateInstanceLayerProperties(&num, properties.data()) != VK_SUCCESS) { - return std::nullopt; - } - return properties; -} - -} // 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 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define VK_NO_PROTOTYPES -#include - -#include "common/common_types.h" - -#ifdef _MSC_VER -#pragma warning(disable : 26812) // Disable prefer enum class over enum -#endif - -namespace Vulkan::vk { - -/** - * Span for Vulkan arrays. - * Based on std::span but optimized for array access instead of iterators. - * Size returns uint32_t instead of size_t to ease interaction with Vulkan functions. - */ -template -class Span { -public: - using value_type = T; - using size_type = u32; - using difference_type = std::ptrdiff_t; - using reference = const T&; - using const_reference = const T&; - using pointer = const T*; - using const_pointer = const T*; - using iterator = const T*; - using const_iterator = const T*; - - /// Construct an empty span. - constexpr Span() noexcept = default; - - /// Construct an empty span - constexpr Span(std::nullptr_t) noexcept {} - - /// Construct a span from a single element. - constexpr Span(const T& value) noexcept : ptr{&value}, num{1} {} - - /// Construct a span from a range. - template - // requires std::data(const Range&) - // requires std::size(const Range&) - constexpr Span(const Range& range) : ptr{std::data(range)}, num{std::size(range)} {} - - /// Construct a span from a pointer and a size. - /// This is inteded for subranges. - constexpr Span(const T* ptr_, std::size_t num_) noexcept : ptr{ptr_}, num{num_} {} - - /// Returns the data pointer by the span. - constexpr const T* data() const noexcept { - return ptr; - } - - /// Returns the number of elements in the span. - /// @note Returns a 32 bits integer because most Vulkan functions expect this type. - constexpr u32 size() const noexcept { - return static_cast(num); - } - - /// Returns true when the span is empty. - constexpr bool empty() const noexcept { - return num == 0; - } - - /// Returns a reference to the element in the passed index. - /// @pre: index < size() - constexpr const T& operator[](std::size_t index) const noexcept { - return ptr[index]; - } - - /// Returns an iterator to the beginning of the span. - constexpr const T* begin() const noexcept { - return ptr; - } - - /// Returns an iterator to the end of the span. - constexpr const T* end() const noexcept { - return ptr + num; - } - - /// Returns an iterator to the beginning of the span. - constexpr const T* cbegin() const noexcept { - return ptr; - } - - /// Returns an iterator to the end of the span. - constexpr const T* cend() const noexcept { - return ptr + num; - } - -private: - const T* ptr = nullptr; - std::size_t num = 0; -}; - -/// Vulkan exception generated from a VkResult. -class Exception final : public std::exception { -public: - /// Construct the exception with a result. - /// @pre result != VK_SUCCESS - explicit Exception(VkResult result_) : result{result_} {} - virtual ~Exception() = default; - - const char* what() const noexcept override; - -private: - VkResult result; -}; - -/// Converts a VkResult enum into a rodata string -const char* ToString(VkResult) noexcept; - -/// Throws a Vulkan exception if result is not success. -inline void Check(VkResult result) { - if (result != VK_SUCCESS) { - throw Exception(result); - } -} - -/// Throws a Vulkan exception if result is an error. -/// @return result -inline VkResult Filter(VkResult result) { - if (result < 0) { - throw Exception(result); - } - return result; -} - -/// Table holding Vulkan instance function pointers. -struct InstanceDispatch { - PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; - - PFN_vkCreateInstance vkCreateInstance; - PFN_vkDestroyInstance vkDestroyInstance; - PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties; - PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties; - - PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT; - PFN_vkCreateDevice vkCreateDevice; - PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT; - PFN_vkDestroyDevice vkDestroyDevice; - PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR; - PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties; - PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices; - PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr; - PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; - PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties; - PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties; - PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties; - PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; - PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties; - PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR; - PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR; - PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR; - PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR; - PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; - PFN_vkQueuePresentKHR vkQueuePresentKHR; -}; - -/// Table holding Vulkan device function pointers. -struct DeviceDispatch : public InstanceDispatch { - PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; - PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers; - PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets; - PFN_vkAllocateMemory vkAllocateMemory; - PFN_vkBeginCommandBuffer vkBeginCommandBuffer; - PFN_vkBindBufferMemory vkBindBufferMemory; - PFN_vkBindImageMemory vkBindImageMemory; - PFN_vkCmdBeginQuery vkCmdBeginQuery; - PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass; - PFN_vkCmdBeginTransformFeedbackEXT vkCmdBeginTransformFeedbackEXT; - PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT; - PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets; - PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer; - PFN_vkCmdBindPipeline vkCmdBindPipeline; - PFN_vkCmdBindTransformFeedbackBuffersEXT vkCmdBindTransformFeedbackBuffersEXT; - PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers; - PFN_vkCmdBlitImage vkCmdBlitImage; - PFN_vkCmdClearAttachments vkCmdClearAttachments; - PFN_vkCmdCopyBuffer vkCmdCopyBuffer; - PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage; - PFN_vkCmdCopyImage vkCmdCopyImage; - PFN_vkCmdCopyImageToBuffer vkCmdCopyImageToBuffer; - PFN_vkCmdDispatch vkCmdDispatch; - PFN_vkCmdDraw vkCmdDraw; - PFN_vkCmdDrawIndexed vkCmdDrawIndexed; - PFN_vkCmdEndQuery vkCmdEndQuery; - PFN_vkCmdEndRenderPass vkCmdEndRenderPass; - PFN_vkCmdEndTransformFeedbackEXT vkCmdEndTransformFeedbackEXT; - PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT; - PFN_vkCmdFillBuffer vkCmdFillBuffer; - PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier; - PFN_vkCmdPushConstants vkCmdPushConstants; - PFN_vkCmdSetBlendConstants vkCmdSetBlendConstants; - PFN_vkCmdSetDepthBias vkCmdSetDepthBias; - PFN_vkCmdSetDepthBounds vkCmdSetDepthBounds; - PFN_vkCmdSetEvent vkCmdSetEvent; - PFN_vkCmdSetScissor vkCmdSetScissor; - PFN_vkCmdSetStencilCompareMask vkCmdSetStencilCompareMask; - PFN_vkCmdSetStencilReference vkCmdSetStencilReference; - PFN_vkCmdSetStencilWriteMask vkCmdSetStencilWriteMask; - PFN_vkCmdSetViewport vkCmdSetViewport; - PFN_vkCmdWaitEvents vkCmdWaitEvents; - PFN_vkCmdBindVertexBuffers2EXT vkCmdBindVertexBuffers2EXT; - PFN_vkCmdSetCullModeEXT vkCmdSetCullModeEXT; - PFN_vkCmdSetDepthBoundsTestEnableEXT vkCmdSetDepthBoundsTestEnableEXT; - PFN_vkCmdSetDepthCompareOpEXT vkCmdSetDepthCompareOpEXT; - PFN_vkCmdSetDepthTestEnableEXT vkCmdSetDepthTestEnableEXT; - PFN_vkCmdSetDepthWriteEnableEXT vkCmdSetDepthWriteEnableEXT; - PFN_vkCmdSetFrontFaceEXT vkCmdSetFrontFaceEXT; - PFN_vkCmdSetPrimitiveTopologyEXT vkCmdSetPrimitiveTopologyEXT; - PFN_vkCmdSetStencilOpEXT vkCmdSetStencilOpEXT; - PFN_vkCmdSetStencilTestEnableEXT vkCmdSetStencilTestEnableEXT; - PFN_vkCmdResolveImage vkCmdResolveImage; - PFN_vkCreateBuffer vkCreateBuffer; - PFN_vkCreateBufferView vkCreateBufferView; - PFN_vkCreateCommandPool vkCreateCommandPool; - PFN_vkCreateComputePipelines vkCreateComputePipelines; - PFN_vkCreateDescriptorPool vkCreateDescriptorPool; - PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout; - PFN_vkCreateDescriptorUpdateTemplateKHR vkCreateDescriptorUpdateTemplateKHR; - PFN_vkCreateEvent vkCreateEvent; - PFN_vkCreateFence vkCreateFence; - PFN_vkCreateFramebuffer vkCreateFramebuffer; - PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines; - PFN_vkCreateImage vkCreateImage; - PFN_vkCreateImageView vkCreateImageView; - PFN_vkCreatePipelineLayout vkCreatePipelineLayout; - PFN_vkCreateQueryPool vkCreateQueryPool; - PFN_vkCreateRenderPass vkCreateRenderPass; - PFN_vkCreateSampler vkCreateSampler; - PFN_vkCreateSemaphore vkCreateSemaphore; - PFN_vkCreateShaderModule vkCreateShaderModule; - PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR; - PFN_vkDestroyBuffer vkDestroyBuffer; - PFN_vkDestroyBufferView vkDestroyBufferView; - PFN_vkDestroyCommandPool vkDestroyCommandPool; - PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool; - PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout; - PFN_vkDestroyDescriptorUpdateTemplateKHR vkDestroyDescriptorUpdateTemplateKHR; - PFN_vkDestroyEvent vkDestroyEvent; - PFN_vkDestroyFence vkDestroyFence; - PFN_vkDestroyFramebuffer vkDestroyFramebuffer; - PFN_vkDestroyImage vkDestroyImage; - PFN_vkDestroyImageView vkDestroyImageView; - PFN_vkDestroyPipeline vkDestroyPipeline; - PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout; - PFN_vkDestroyQueryPool vkDestroyQueryPool; - PFN_vkDestroyRenderPass vkDestroyRenderPass; - PFN_vkDestroySampler vkDestroySampler; - PFN_vkDestroySemaphore vkDestroySemaphore; - PFN_vkDestroyShaderModule vkDestroyShaderModule; - PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR; - PFN_vkDeviceWaitIdle vkDeviceWaitIdle; - PFN_vkEndCommandBuffer vkEndCommandBuffer; - PFN_vkFreeCommandBuffers vkFreeCommandBuffers; - PFN_vkFreeDescriptorSets vkFreeDescriptorSets; - PFN_vkFreeMemory vkFreeMemory; - PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements; - PFN_vkGetDeviceQueue vkGetDeviceQueue; - PFN_vkGetEventStatus vkGetEventStatus; - PFN_vkGetFenceStatus vkGetFenceStatus; - PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements; - PFN_vkGetQueryPoolResults vkGetQueryPoolResults; - PFN_vkGetSemaphoreCounterValueKHR vkGetSemaphoreCounterValueKHR; - PFN_vkMapMemory vkMapMemory; - PFN_vkQueueSubmit vkQueueSubmit; - PFN_vkResetFences vkResetFences; - PFN_vkResetQueryPoolEXT vkResetQueryPoolEXT; - PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT; - PFN_vkSetDebugUtilsObjectTagEXT vkSetDebugUtilsObjectTagEXT; - PFN_vkUnmapMemory vkUnmapMemory; - PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR; - PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets; - PFN_vkWaitForFences vkWaitForFences; - PFN_vkWaitSemaphoresKHR vkWaitSemaphoresKHR; -}; - -/// Loads instance agnostic function pointers. -/// @return True on success, false on error. -bool Load(InstanceDispatch&) noexcept; - -/// Loads instance function pointers. -/// @return True on success, false on error. -bool Load(VkInstance, InstanceDispatch&) noexcept; - -void Destroy(VkInstance, const InstanceDispatch&) noexcept; -void Destroy(VkDevice, const InstanceDispatch&) noexcept; - -void Destroy(VkDevice, VkBuffer, const DeviceDispatch&) noexcept; -void Destroy(VkDevice, VkBufferView, const DeviceDispatch&) noexcept; -void Destroy(VkDevice, VkCommandPool, const DeviceDispatch&) noexcept; -void Destroy(VkDevice, VkDescriptorPool, const DeviceDispatch&) noexcept; -void Destroy(VkDevice, VkDescriptorSetLayout, const DeviceDispatch&) noexcept; -void Destroy(VkDevice, VkDescriptorUpdateTemplateKHR, const DeviceDispatch&) noexcept; -void Destroy(VkDevice, VkDeviceMemory, const DeviceDispatch&) noexcept; -void Destroy(VkDevice, VkEvent, const DeviceDispatch&) noexcept; -void Destroy(VkDevice, VkFence, const DeviceDispatch&) noexcept; -void Destroy(VkDevice, VkFramebuffer, const DeviceDispatch&) noexcept; -void Destroy(VkDevice, VkImage, const DeviceDispatch&) noexcept; -void Destroy(VkDevice, VkImageView, const DeviceDispatch&) noexcept; -void Destroy(VkDevice, VkPipeline, const DeviceDispatch&) noexcept; -void Destroy(VkDevice, VkPipelineLayout, const DeviceDispatch&) noexcept; -void Destroy(VkDevice, VkQueryPool, const DeviceDispatch&) noexcept; -void Destroy(VkDevice, VkRenderPass, const DeviceDispatch&) noexcept; -void Destroy(VkDevice, VkSampler, const DeviceDispatch&) noexcept; -void Destroy(VkDevice, VkSwapchainKHR, const DeviceDispatch&) noexcept; -void Destroy(VkDevice, VkSemaphore, const DeviceDispatch&) noexcept; -void Destroy(VkDevice, VkShaderModule, const DeviceDispatch&) noexcept; -void Destroy(VkInstance, VkDebugUtilsMessengerEXT, const InstanceDispatch&) noexcept; -void Destroy(VkInstance, VkSurfaceKHR, const InstanceDispatch&) noexcept; - -VkResult Free(VkDevice, VkDescriptorPool, Span, const DeviceDispatch&) noexcept; -VkResult Free(VkDevice, VkCommandPool, Span, const DeviceDispatch&) noexcept; - -template -class Handle; - -/// Handle with an owning type. -/// Analogue to std::unique_ptr. -template -class Handle { -public: - /// Construct a handle and hold it's ownership. - explicit Handle(Type handle_, OwnerType owner_, const Dispatch& dld_) noexcept - : handle{handle_}, owner{owner_}, dld{&dld_} {} - - /// Construct an empty handle. - Handle() = default; - - /// Copying Vulkan objects is not supported and will never be. - Handle(const Handle&) = delete; - Handle& operator=(const Handle&) = delete; - - /// Construct a handle transfering the ownership from another handle. - Handle(Handle&& rhs) noexcept - : handle{std::exchange(rhs.handle, nullptr)}, owner{rhs.owner}, dld{rhs.dld} {} - - /// Assign the current handle transfering the ownership from another handle. - /// Destroys any previously held object. - Handle& operator=(Handle&& rhs) noexcept { - Release(); - handle = std::exchange(rhs.handle, nullptr); - owner = rhs.owner; - dld = rhs.dld; - return *this; - } - - /// Destroys the current handle if it existed. - ~Handle() noexcept { - Release(); - } - - /// Destroys any held object. - void reset() noexcept { - Release(); - handle = nullptr; - } - - /// Returns the address of the held object. - /// Intended for Vulkan structures that expect a pointer to an array. - const Type* address() const noexcept { - return std::addressof(handle); - } - - /// Returns the held Vulkan handle. - Type operator*() const noexcept { - return handle; - } - - /// Returns true when there's a held object. - explicit operator bool() const noexcept { - return handle != nullptr; - } - -protected: - Type handle = nullptr; - OwnerType owner = nullptr; - const Dispatch* dld = nullptr; - -private: - /// Destroys the held object if it exists. - void Release() noexcept { - if (handle) { - Destroy(owner, handle, *dld); - } - } -}; - -/// Dummy type used to specify a handle has no owner. -struct NoOwner {}; - -/// Handle without an owning type. -/// Analogue to std::unique_ptr -template -class Handle { -public: - /// Construct a handle and hold it's ownership. - explicit Handle(Type handle_, const Dispatch& dld_) noexcept : handle{handle_}, dld{&dld_} {} - - /// Construct an empty handle. - Handle() noexcept = default; - - /// Copying Vulkan objects is not supported and will never be. - Handle(const Handle&) = delete; - Handle& operator=(const Handle&) = delete; - - /// Construct a handle transfering ownership from another handle. - Handle(Handle&& rhs) noexcept : handle{std::exchange(rhs.handle, nullptr)}, dld{rhs.dld} {} - - /// Assign the current handle transfering the ownership from another handle. - /// Destroys any previously held object. - Handle& operator=(Handle&& rhs) noexcept { - Release(); - handle = std::exchange(rhs.handle, nullptr); - dld = rhs.dld; - return *this; - } - - /// Destroys the current handle if it existed. - ~Handle() noexcept { - Release(); - } - - /// Destroys any held object. - void reset() noexcept { - Release(); - handle = nullptr; - } - - /// Returns the address of the held object. - /// Intended for Vulkan structures that expect a pointer to an array. - const Type* address() const noexcept { - return std::addressof(handle); - } - - /// Returns the held Vulkan handle. - Type operator*() const noexcept { - return handle; - } - - /// Returns true when there's a held object. - operator bool() const noexcept { - return handle != nullptr; - } - -protected: - Type handle = nullptr; - const Dispatch* dld = nullptr; - -private: - /// Destroys the held object if it exists. - void Release() noexcept { - if (handle) { - Destroy(handle, *dld); - } - } -}; - -/// Array of a pool allocation. -/// Analogue to std::vector -template -class PoolAllocations { -public: - /// Construct an empty allocation. - PoolAllocations() = default; - - /// Construct an allocation. Errors are reported through IsOutOfPoolMemory(). - explicit PoolAllocations(std::unique_ptr allocations_, std::size_t num_, - VkDevice device_, PoolType pool_, const DeviceDispatch& dld_) noexcept - : allocations{std::move(allocations_)}, num{num_}, device{device_}, pool{pool_}, - dld{&dld_} {} - - /// Copying Vulkan allocations is not supported and will never be. - PoolAllocations(const PoolAllocations&) = delete; - PoolAllocations& operator=(const PoolAllocations&) = delete; - - /// Construct an allocation transfering ownership from another allocation. - PoolAllocations(PoolAllocations&& rhs) noexcept - : allocations{std::move(rhs.allocations)}, num{rhs.num}, device{rhs.device}, pool{rhs.pool}, - dld{rhs.dld} {} - - /// Assign an allocation transfering ownership from another allocation. - /// Releases any previously held allocation. - PoolAllocations& operator=(PoolAllocations&& rhs) noexcept { - Release(); - allocations = std::move(rhs.allocations); - num = rhs.num; - device = rhs.device; - pool = rhs.pool; - dld = rhs.dld; - return *this; - } - - /// Destroys any held allocation. - ~PoolAllocations() { - Release(); - } - - /// Returns the number of allocations. - std::size_t size() const noexcept { - return num; - } - - /// Returns a pointer to the array of allocations. - AllocationType const* data() const noexcept { - return allocations.get(); - } - - /// Returns the allocation in the specified index. - /// @pre index < size() - AllocationType operator[](std::size_t index) const noexcept { - return allocations[index]; - } - - /// True when a pool fails to construct. - bool IsOutOfPoolMemory() const noexcept { - return !device; - } - -private: - /// Destroys the held allocations if they exist. - void Release() noexcept { - if (!allocations) { - return; - } - const Span span(allocations.get(), num); - const VkResult result = Free(device, pool, span, *dld); - // There's no way to report errors from a destructor. - if (result != VK_SUCCESS) { - std::terminate(); - } - } - - std::unique_ptr allocations; - std::size_t num = 0; - VkDevice device = nullptr; - PoolType pool = nullptr; - const DeviceDispatch* dld = nullptr; -}; - -using DebugCallback = Handle; -using DescriptorSetLayout = Handle; -using DescriptorUpdateTemplateKHR = Handle; -using Pipeline = Handle; -using PipelineLayout = Handle; -using QueryPool = Handle; -using RenderPass = Handle; -using Sampler = Handle; -using SurfaceKHR = Handle; - -using DescriptorSets = PoolAllocations; -using CommandBuffers = PoolAllocations; - -/// Vulkan instance owning handle. -class Instance : public Handle { - using Handle::Handle; - -public: - /// Creates a Vulkan instance. Use "operator bool" for error handling. - static Instance Create(u32 version, Span layers, Span extensions, - InstanceDispatch& dispatch) noexcept; - - /// Enumerates physical devices. - /// @return Physical devices and an empty handle on failure. - std::optional> EnumeratePhysicalDevices(); - - /// Tries to create a debug callback messenger. Returns an empty handle on failure. - DebugCallback TryCreateDebugCallback(PFN_vkDebugUtilsMessengerCallbackEXT callback) noexcept; -}; - -class Queue { -public: - /// Construct an empty queue handle. - constexpr Queue() noexcept = default; - - /// Construct a queue handle. - constexpr Queue(VkQueue queue_, const DeviceDispatch& dld_) noexcept - : queue{queue_}, dld{&dld_} {} - - VkResult Submit(Span submit_infos, - VkFence fence = VK_NULL_HANDLE) const noexcept { - return dld->vkQueueSubmit(queue, submit_infos.size(), submit_infos.data(), fence); - } - - VkResult Present(const VkPresentInfoKHR& present_info) const noexcept { - return dld->vkQueuePresentKHR(queue, &present_info); - } - -private: - VkQueue queue = nullptr; - const DeviceDispatch* dld = nullptr; -}; - -class Buffer : public Handle { - using Handle::Handle; - -public: - /// Attaches a memory allocation. - void BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const; - - /// Set object name. - void SetObjectNameEXT(const char* name) const; -}; - -class BufferView : public Handle { - using Handle::Handle; - -public: - /// Set object name. - void SetObjectNameEXT(const char* name) const; -}; - -class Image : public Handle { - using Handle::Handle; - -public: - /// Attaches a memory allocation. - void BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const; - - /// Set object name. - void SetObjectNameEXT(const char* name) const; -}; - -class ImageView : public Handle { - using Handle::Handle; - -public: - /// Set object name. - void SetObjectNameEXT(const char* name) const; -}; - -class DeviceMemory : public Handle { - using Handle::Handle; - -public: - /// Set object name. - void SetObjectNameEXT(const char* name) const; - - u8* Map(VkDeviceSize offset, VkDeviceSize size) const { - void* data; - Check(dld->vkMapMemory(owner, handle, offset, size, 0, &data)); - return static_cast(data); - } - - void Unmap() const noexcept { - dld->vkUnmapMemory(owner, handle); - } -}; - -class Fence : public Handle { - using Handle::Handle; - -public: - /// Set object name. - void SetObjectNameEXT(const char* name) const; - - VkResult Wait(u64 timeout = std::numeric_limits::max()) const noexcept { - return dld->vkWaitForFences(owner, 1, &handle, true, timeout); - } - - VkResult GetStatus() const noexcept { - return dld->vkGetFenceStatus(owner, handle); - } - - void Reset() const { - Check(dld->vkResetFences(owner, 1, &handle)); - } -}; - -class Framebuffer : public Handle { - using Handle::Handle; - -public: - /// Set object name. - void SetObjectNameEXT(const char* name) const; -}; - -class DescriptorPool : public Handle { - using Handle::Handle; - -public: - DescriptorSets Allocate(const VkDescriptorSetAllocateInfo& ai) const; - - /// Set object name. - void SetObjectNameEXT(const char* name) const; -}; - -class CommandPool : public Handle { - using Handle::Handle; - -public: - CommandBuffers Allocate(std::size_t num_buffers, - VkCommandBufferLevel level = VK_COMMAND_BUFFER_LEVEL_PRIMARY) const; - - /// Set object name. - void SetObjectNameEXT(const char* name) const; -}; - -class SwapchainKHR : public Handle { - using Handle::Handle; - -public: - std::vector GetImages() const; -}; - -class Event : public Handle { - using Handle::Handle; - -public: - /// Set object name. - void SetObjectNameEXT(const char* name) const; - - VkResult GetStatus() const noexcept { - return dld->vkGetEventStatus(owner, handle); - } -}; - -class ShaderModule : public Handle { - using Handle::Handle; - -public: - /// Set object name. - void SetObjectNameEXT(const char* name) const; -}; - -class Semaphore : public Handle { - using Handle::Handle; - -public: - /// Set object name. - void SetObjectNameEXT(const char* name) const; - - [[nodiscard]] u64 GetCounter() const { - u64 value; - Check(dld->vkGetSemaphoreCounterValueKHR(owner, handle, &value)); - return value; - } - - /** - * Waits for a timeline semaphore on the host. - * - * @param value Value to wait - * @param timeout Time in nanoseconds to timeout - * @return True on successful wait, false on timeout - */ - bool Wait(u64 value, u64 timeout = std::numeric_limits::max()) const { - const VkSemaphoreWaitInfoKHR wait_info{ - .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO_KHR, - .pNext = nullptr, - .flags = 0, - .semaphoreCount = 1, - .pSemaphores = &handle, - .pValues = &value, - }; - const VkResult result = dld->vkWaitSemaphoresKHR(owner, &wait_info, timeout); - switch (result) { - case VK_SUCCESS: - return true; - case VK_TIMEOUT: - return false; - default: - throw Exception(result); - } - } -}; - -class Device : public Handle { - using Handle::Handle; - -public: - static Device Create(VkPhysicalDevice physical_device, Span queues_ci, - Span enabled_extensions, const void* next, - DeviceDispatch& dispatch) noexcept; - - Queue GetQueue(u32 family_index) const noexcept; - - Buffer CreateBuffer(const VkBufferCreateInfo& ci) const; - - BufferView CreateBufferView(const VkBufferViewCreateInfo& ci) const; - - Image CreateImage(const VkImageCreateInfo& ci) const; - - ImageView CreateImageView(const VkImageViewCreateInfo& ci) const; - - Semaphore CreateSemaphore() const; - - Semaphore CreateSemaphore(const VkSemaphoreCreateInfo& ci) const; - - Fence CreateFence(const VkFenceCreateInfo& ci) const; - - DescriptorPool CreateDescriptorPool(const VkDescriptorPoolCreateInfo& ci) const; - - RenderPass CreateRenderPass(const VkRenderPassCreateInfo& ci) const; - - DescriptorSetLayout CreateDescriptorSetLayout(const VkDescriptorSetLayoutCreateInfo& ci) const; - - PipelineLayout CreatePipelineLayout(const VkPipelineLayoutCreateInfo& ci) const; - - Pipeline CreateGraphicsPipeline(const VkGraphicsPipelineCreateInfo& ci) const; - - Pipeline CreateComputePipeline(const VkComputePipelineCreateInfo& ci) const; - - Sampler CreateSampler(const VkSamplerCreateInfo& ci) const; - - Framebuffer CreateFramebuffer(const VkFramebufferCreateInfo& ci) const; - - CommandPool CreateCommandPool(const VkCommandPoolCreateInfo& ci) const; - - DescriptorUpdateTemplateKHR CreateDescriptorUpdateTemplateKHR( - const VkDescriptorUpdateTemplateCreateInfoKHR& ci) const; - - QueryPool CreateQueryPool(const VkQueryPoolCreateInfo& ci) const; - - ShaderModule CreateShaderModule(const VkShaderModuleCreateInfo& ci) const; - - Event CreateEvent() const; - - SwapchainKHR CreateSwapchainKHR(const VkSwapchainCreateInfoKHR& ci) const; - - DeviceMemory TryAllocateMemory(const VkMemoryAllocateInfo& ai) const noexcept; - - DeviceMemory AllocateMemory(const VkMemoryAllocateInfo& ai) const; - - VkMemoryRequirements GetBufferMemoryRequirements(VkBuffer buffer) const noexcept; - - VkMemoryRequirements GetImageMemoryRequirements(VkImage image) const noexcept; - - void UpdateDescriptorSets(Span writes, - Span copies) const noexcept; - - void UpdateDescriptorSet(VkDescriptorSet set, VkDescriptorUpdateTemplateKHR update_template, - const void* data) const noexcept { - dld->vkUpdateDescriptorSetWithTemplateKHR(handle, set, update_template, data); - } - - VkResult AcquireNextImageKHR(VkSwapchainKHR swapchain, u64 timeout, VkSemaphore semaphore, - VkFence fence, u32* image_index) const noexcept { - return dld->vkAcquireNextImageKHR(handle, swapchain, timeout, semaphore, fence, - image_index); - } - - VkResult WaitIdle() const noexcept { - return dld->vkDeviceWaitIdle(handle); - } - - void ResetQueryPoolEXT(VkQueryPool query_pool, u32 first, u32 count) const noexcept { - dld->vkResetQueryPoolEXT(handle, query_pool, first, count); - } - - VkResult GetQueryResults(VkQueryPool query_pool, u32 first, u32 count, std::size_t data_size, - void* data, VkDeviceSize stride, - VkQueryResultFlags flags) const noexcept { - return dld->vkGetQueryPoolResults(handle, query_pool, first, count, data_size, data, stride, - flags); - } -}; - -class PhysicalDevice { -public: - constexpr PhysicalDevice() noexcept = default; - - constexpr PhysicalDevice(VkPhysicalDevice physical_device_, - const InstanceDispatch& dld_) noexcept - : physical_device{physical_device_}, dld{&dld_} {} - - constexpr operator VkPhysicalDevice() const noexcept { - return physical_device; - } - - VkPhysicalDeviceProperties GetProperties() const noexcept; - - void GetProperties2KHR(VkPhysicalDeviceProperties2KHR&) const noexcept; - - VkPhysicalDeviceFeatures GetFeatures() const noexcept; - - void GetFeatures2KHR(VkPhysicalDeviceFeatures2KHR&) const noexcept; - - VkFormatProperties GetFormatProperties(VkFormat) const noexcept; - - std::vector EnumerateDeviceExtensionProperties() const; - - std::vector GetQueueFamilyProperties() const; - - bool GetSurfaceSupportKHR(u32 queue_family_index, VkSurfaceKHR) const; - - VkSurfaceCapabilitiesKHR GetSurfaceCapabilitiesKHR(VkSurfaceKHR) const; - - std::vector GetSurfaceFormatsKHR(VkSurfaceKHR) const; - - std::vector GetSurfacePresentModesKHR(VkSurfaceKHR) const; - - VkPhysicalDeviceMemoryProperties GetMemoryProperties() const noexcept; - -private: - VkPhysicalDevice physical_device = nullptr; - const InstanceDispatch* dld = nullptr; -}; - -class CommandBuffer { -public: - CommandBuffer() noexcept = default; - - explicit CommandBuffer(VkCommandBuffer handle_, const DeviceDispatch& dld_) noexcept - : handle{handle_}, dld{&dld_} {} - - const VkCommandBuffer* address() const noexcept { - return &handle; - } - - void Begin(const VkCommandBufferBeginInfo& begin_info) const { - Check(dld->vkBeginCommandBuffer(handle, &begin_info)); - } - - void End() const { - Check(dld->vkEndCommandBuffer(handle)); - } - - void BeginRenderPass(const VkRenderPassBeginInfo& renderpass_bi, - VkSubpassContents contents) const noexcept { - dld->vkCmdBeginRenderPass(handle, &renderpass_bi, contents); - } - - void EndRenderPass() const noexcept { - dld->vkCmdEndRenderPass(handle); - } - - void BeginQuery(VkQueryPool query_pool, u32 query, VkQueryControlFlags flags) const noexcept { - dld->vkCmdBeginQuery(handle, query_pool, query, flags); - } - - void EndQuery(VkQueryPool query_pool, u32 query) const noexcept { - dld->vkCmdEndQuery(handle, query_pool, query); - } - - void BindDescriptorSets(VkPipelineBindPoint bind_point, VkPipelineLayout layout, u32 first, - Span sets, Span dynamic_offsets) const noexcept { - dld->vkCmdBindDescriptorSets(handle, bind_point, layout, first, sets.size(), sets.data(), - dynamic_offsets.size(), dynamic_offsets.data()); - } - - void BindPipeline(VkPipelineBindPoint bind_point, VkPipeline pipeline) const noexcept { - dld->vkCmdBindPipeline(handle, bind_point, pipeline); - } - - void BindIndexBuffer(VkBuffer buffer, VkDeviceSize offset, - VkIndexType index_type) const noexcept { - dld->vkCmdBindIndexBuffer(handle, buffer, offset, index_type); - } - - void BindVertexBuffers(u32 first, u32 count, const VkBuffer* buffers, - const VkDeviceSize* offsets) const noexcept { - dld->vkCmdBindVertexBuffers(handle, first, count, buffers, offsets); - } - - void BindVertexBuffer(u32 binding, VkBuffer buffer, VkDeviceSize offset) const noexcept { - BindVertexBuffers(binding, 1, &buffer, &offset); - } - - void Draw(u32 vertex_count, u32 instance_count, u32 first_vertex, - u32 first_instance) const noexcept { - dld->vkCmdDraw(handle, vertex_count, instance_count, first_vertex, first_instance); - } - - void DrawIndexed(u32 index_count, u32 instance_count, u32 first_index, u32 vertex_offset, - u32 first_instance) const noexcept { - dld->vkCmdDrawIndexed(handle, index_count, instance_count, first_index, vertex_offset, - first_instance); - } - - void ClearAttachments(Span attachments, - Span rects) const noexcept { - dld->vkCmdClearAttachments(handle, attachments.size(), attachments.data(), rects.size(), - rects.data()); - } - - void BlitImage(VkImage src_image, VkImageLayout src_layout, VkImage dst_image, - VkImageLayout dst_layout, Span regions, - VkFilter filter) const noexcept { - dld->vkCmdBlitImage(handle, src_image, src_layout, dst_image, dst_layout, regions.size(), - regions.data(), filter); - } - - void ResolveImage(VkImage src_image, VkImageLayout src_layout, VkImage dst_image, - VkImageLayout dst_layout, Span regions) { - dld->vkCmdResolveImage(handle, src_image, src_layout, dst_image, dst_layout, regions.size(), - regions.data()); - } - - void Dispatch(u32 x, u32 y, u32 z) const noexcept { - dld->vkCmdDispatch(handle, x, y, z); - } - - void PipelineBarrier(VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask, - VkDependencyFlags dependency_flags, Span memory_barriers, - Span buffer_barriers, - Span image_barriers) const noexcept { - dld->vkCmdPipelineBarrier(handle, src_stage_mask, dst_stage_mask, dependency_flags, - memory_barriers.size(), memory_barriers.data(), - buffer_barriers.size(), buffer_barriers.data(), - image_barriers.size(), image_barriers.data()); - } - - void PipelineBarrier(VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask, - VkDependencyFlags dependency_flags = 0) const noexcept { - PipelineBarrier(src_stage_mask, dst_stage_mask, dependency_flags, {}, {}, {}); - } - - void PipelineBarrier(VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask, - VkDependencyFlags dependency_flags, - const VkBufferMemoryBarrier& buffer_barrier) const noexcept { - PipelineBarrier(src_stage_mask, dst_stage_mask, dependency_flags, {}, buffer_barrier, {}); - } - - void PipelineBarrier(VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask, - VkDependencyFlags dependency_flags, - const VkImageMemoryBarrier& image_barrier) const noexcept { - PipelineBarrier(src_stage_mask, dst_stage_mask, dependency_flags, {}, {}, image_barrier); - } - - void CopyBufferToImage(VkBuffer src_buffer, VkImage dst_image, VkImageLayout dst_image_layout, - Span regions) const noexcept { - dld->vkCmdCopyBufferToImage(handle, src_buffer, dst_image, dst_image_layout, regions.size(), - regions.data()); - } - - void CopyBuffer(VkBuffer src_buffer, VkBuffer dst_buffer, - Span regions) const noexcept { - dld->vkCmdCopyBuffer(handle, src_buffer, dst_buffer, regions.size(), regions.data()); - } - - void CopyImage(VkImage src_image, VkImageLayout src_layout, VkImage dst_image, - VkImageLayout dst_layout, Span regions) const noexcept { - dld->vkCmdCopyImage(handle, src_image, src_layout, dst_image, dst_layout, regions.size(), - regions.data()); - } - - void CopyImageToBuffer(VkImage src_image, VkImageLayout src_layout, VkBuffer dst_buffer, - Span regions) const noexcept { - dld->vkCmdCopyImageToBuffer(handle, src_image, src_layout, dst_buffer, regions.size(), - regions.data()); - } - - void FillBuffer(VkBuffer dst_buffer, VkDeviceSize dst_offset, VkDeviceSize size, - u32 data) const noexcept { - dld->vkCmdFillBuffer(handle, dst_buffer, dst_offset, size, data); - } - - void PushConstants(VkPipelineLayout layout, VkShaderStageFlags flags, u32 offset, u32 size, - const void* values) const noexcept { - dld->vkCmdPushConstants(handle, layout, flags, offset, size, values); - } - - template - void PushConstants(VkPipelineLayout layout, VkShaderStageFlags flags, - const T& data) const noexcept { - static_assert(std::is_trivially_copyable_v, " is not trivially copyable"); - dld->vkCmdPushConstants(handle, layout, flags, 0, static_cast(sizeof(T)), &data); - } - - void SetViewport(u32 first, Span viewports) const noexcept { - dld->vkCmdSetViewport(handle, first, viewports.size(), viewports.data()); - } - - void SetScissor(u32 first, Span scissors) const noexcept { - dld->vkCmdSetScissor(handle, first, scissors.size(), scissors.data()); - } - - void SetBlendConstants(const float blend_constants[4]) const noexcept { - dld->vkCmdSetBlendConstants(handle, blend_constants); - } - - void SetStencilCompareMask(VkStencilFaceFlags face_mask, u32 compare_mask) const noexcept { - dld->vkCmdSetStencilCompareMask(handle, face_mask, compare_mask); - } - - void SetStencilReference(VkStencilFaceFlags face_mask, u32 reference) const noexcept { - dld->vkCmdSetStencilReference(handle, face_mask, reference); - } - - void SetStencilWriteMask(VkStencilFaceFlags face_mask, u32 write_mask) const noexcept { - dld->vkCmdSetStencilWriteMask(handle, face_mask, write_mask); - } - - void SetDepthBias(float constant_factor, float clamp, float slope_factor) const noexcept { - dld->vkCmdSetDepthBias(handle, constant_factor, clamp, slope_factor); - } - - void SetDepthBounds(float min_depth_bounds, float max_depth_bounds) const noexcept { - dld->vkCmdSetDepthBounds(handle, min_depth_bounds, max_depth_bounds); - } - - void SetEvent(VkEvent event, VkPipelineStageFlags stage_flags) const noexcept { - dld->vkCmdSetEvent(handle, event, stage_flags); - } - - void WaitEvents(Span events, VkPipelineStageFlags src_stage_mask, - VkPipelineStageFlags dst_stage_mask, Span memory_barriers, - Span buffer_barriers, - Span image_barriers) const noexcept { - dld->vkCmdWaitEvents(handle, events.size(), events.data(), src_stage_mask, dst_stage_mask, - memory_barriers.size(), memory_barriers.data(), buffer_barriers.size(), - buffer_barriers.data(), image_barriers.size(), image_barriers.data()); - } - - void BindVertexBuffers2EXT(u32 first_binding, u32 binding_count, const VkBuffer* buffers, - const VkDeviceSize* offsets, const VkDeviceSize* sizes, - const VkDeviceSize* strides) const noexcept { - dld->vkCmdBindVertexBuffers2EXT(handle, first_binding, binding_count, buffers, offsets, - sizes, strides); - } - - void SetCullModeEXT(VkCullModeFlags cull_mode) const noexcept { - dld->vkCmdSetCullModeEXT(handle, cull_mode); - } - - void SetDepthBoundsTestEnableEXT(bool enable) const noexcept { - dld->vkCmdSetDepthBoundsTestEnableEXT(handle, enable ? VK_TRUE : VK_FALSE); - } - - void SetDepthCompareOpEXT(VkCompareOp compare_op) const noexcept { - dld->vkCmdSetDepthCompareOpEXT(handle, compare_op); - } - - void SetDepthTestEnableEXT(bool enable) const noexcept { - dld->vkCmdSetDepthTestEnableEXT(handle, enable ? VK_TRUE : VK_FALSE); - } - - void SetDepthWriteEnableEXT(bool enable) const noexcept { - dld->vkCmdSetDepthWriteEnableEXT(handle, enable ? VK_TRUE : VK_FALSE); - } - - void SetFrontFaceEXT(VkFrontFace front_face) const noexcept { - dld->vkCmdSetFrontFaceEXT(handle, front_face); - } - - void SetPrimitiveTopologyEXT(VkPrimitiveTopology primitive_topology) const noexcept { - dld->vkCmdSetPrimitiveTopologyEXT(handle, primitive_topology); - } - - void SetStencilOpEXT(VkStencilFaceFlags face_mask, VkStencilOp fail_op, VkStencilOp pass_op, - VkStencilOp depth_fail_op, VkCompareOp compare_op) const noexcept { - dld->vkCmdSetStencilOpEXT(handle, face_mask, fail_op, pass_op, depth_fail_op, compare_op); - } - - void SetStencilTestEnableEXT(bool enable) const noexcept { - dld->vkCmdSetStencilTestEnableEXT(handle, enable ? VK_TRUE : VK_FALSE); - } - - void BindTransformFeedbackBuffersEXT(u32 first, u32 count, const VkBuffer* buffers, - const VkDeviceSize* offsets, - const VkDeviceSize* sizes) const noexcept { - dld->vkCmdBindTransformFeedbackBuffersEXT(handle, first, count, buffers, offsets, sizes); - } - - void BeginTransformFeedbackEXT(u32 first_counter_buffer, u32 counter_buffers_count, - const VkBuffer* counter_buffers, - const VkDeviceSize* counter_buffer_offsets) const noexcept { - dld->vkCmdBeginTransformFeedbackEXT(handle, first_counter_buffer, counter_buffers_count, - counter_buffers, counter_buffer_offsets); - } - - void EndTransformFeedbackEXT(u32 first_counter_buffer, u32 counter_buffers_count, - const VkBuffer* counter_buffers, - const VkDeviceSize* counter_buffer_offsets) const noexcept { - dld->vkCmdEndTransformFeedbackEXT(handle, first_counter_buffer, counter_buffers_count, - counter_buffers, counter_buffer_offsets); - } - - void BeginDebugUtilsLabelEXT(const char* label, std::span color) const noexcept { - const VkDebugUtilsLabelEXT label_info{ - .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT, - .pNext = nullptr, - .pLabelName = label, - .color{color[0], color[1], color[2], color[3]}, - }; - dld->vkCmdBeginDebugUtilsLabelEXT(handle, &label_info); - } - - void EndDebugUtilsLabelEXT() const noexcept { - dld->vkCmdEndDebugUtilsLabelEXT(handle); - } - -private: - VkCommandBuffer handle; - const DeviceDispatch* dld; -}; - -u32 AvailableVersion(const InstanceDispatch& dld) noexcept; - -std::optional> EnumerateInstanceExtensionProperties( - const InstanceDispatch& dld); - -std::optional> EnumerateInstanceLayerProperties( - const InstanceDispatch& dld); - -} // namespace Vulkan::vk diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp new file mode 100644 index 000000000..478402bbd --- /dev/null +++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp @@ -0,0 +1,928 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include +#include +#include +#include +#include + +#include "common/common_types.h" +#include "common/logging/log.h" + +#include "video_core/vulkan_common/vulkan_wrapper.h" + +namespace Vulkan::vk { + +namespace { + +template +void SortPhysicalDevices(std::vector& devices, const InstanceDispatch& dld, + Func&& func) { + // Calling GetProperties calls Vulkan more than needed. But they are supposed to be cheap + // functions. + std::stable_sort(devices.begin(), devices.end(), + [&dld, &func](VkPhysicalDevice lhs, VkPhysicalDevice rhs) { + return func(vk::PhysicalDevice(lhs, dld).GetProperties(), + vk::PhysicalDevice(rhs, dld).GetProperties()); + }); +} + +void SortPhysicalDevicesPerVendor(std::vector& devices, + const InstanceDispatch& dld, + std::initializer_list vendor_ids) { + for (auto it = vendor_ids.end(); it != vendor_ids.begin();) { + --it; + SortPhysicalDevices(devices, dld, [id = *it](const auto& lhs, const auto& rhs) { + return lhs.vendorID == id && rhs.vendorID != id; + }); + } +} + +void SortPhysicalDevices(std::vector& devices, const InstanceDispatch& dld) { + // Sort by name, this will set a base and make GPUs with higher numbers appear first + // (e.g. GTX 1650 will intentionally be listed before a GTX 1080). + SortPhysicalDevices(devices, dld, [](const auto& lhs, const auto& rhs) { + return std::string_view{lhs.deviceName} > std::string_view{rhs.deviceName}; + }); + // Prefer discrete over non-discrete + SortPhysicalDevices(devices, dld, [](const auto& lhs, const auto& rhs) { + return lhs.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU && + rhs.deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU; + }); + // Prefer Nvidia over AMD, AMD over Intel, Intel over the rest. + SortPhysicalDevicesPerVendor(devices, dld, {0x10DE, 0x1002, 0x8086}); +} + +template +bool Proc(T& result, const InstanceDispatch& dld, const char* proc_name, + VkInstance instance = nullptr) noexcept { + result = reinterpret_cast(dld.vkGetInstanceProcAddr(instance, proc_name)); + return result != nullptr; +} + +template +void Proc(T& result, const DeviceDispatch& dld, const char* proc_name, VkDevice device) noexcept { + result = reinterpret_cast(dld.vkGetDeviceProcAddr(device, proc_name)); +} + +void Load(VkDevice device, DeviceDispatch& dld) noexcept { +#define X(name) Proc(dld.name, dld, #name, device) + X(vkAcquireNextImageKHR); + X(vkAllocateCommandBuffers); + X(vkAllocateDescriptorSets); + X(vkAllocateMemory); + X(vkBeginCommandBuffer); + X(vkBindBufferMemory); + X(vkBindImageMemory); + X(vkCmdBeginQuery); + X(vkCmdBeginRenderPass); + X(vkCmdBeginTransformFeedbackEXT); + X(vkCmdBeginDebugUtilsLabelEXT); + X(vkCmdBindDescriptorSets); + X(vkCmdBindIndexBuffer); + X(vkCmdBindPipeline); + X(vkCmdBindTransformFeedbackBuffersEXT); + X(vkCmdBindVertexBuffers); + X(vkCmdBlitImage); + X(vkCmdClearAttachments); + X(vkCmdCopyBuffer); + X(vkCmdCopyBufferToImage); + X(vkCmdCopyImage); + X(vkCmdCopyImageToBuffer); + X(vkCmdDispatch); + X(vkCmdDraw); + X(vkCmdDrawIndexed); + X(vkCmdEndQuery); + X(vkCmdEndRenderPass); + X(vkCmdEndTransformFeedbackEXT); + X(vkCmdEndDebugUtilsLabelEXT); + X(vkCmdFillBuffer); + X(vkCmdPipelineBarrier); + X(vkCmdPushConstants); + X(vkCmdSetBlendConstants); + X(vkCmdSetDepthBias); + X(vkCmdSetDepthBounds); + X(vkCmdSetEvent); + X(vkCmdSetScissor); + X(vkCmdSetStencilCompareMask); + X(vkCmdSetStencilReference); + X(vkCmdSetStencilWriteMask); + X(vkCmdSetViewport); + X(vkCmdWaitEvents); + X(vkCmdBindVertexBuffers2EXT); + X(vkCmdSetCullModeEXT); + X(vkCmdSetDepthBoundsTestEnableEXT); + X(vkCmdSetDepthCompareOpEXT); + X(vkCmdSetDepthTestEnableEXT); + X(vkCmdSetDepthWriteEnableEXT); + X(vkCmdSetFrontFaceEXT); + X(vkCmdSetPrimitiveTopologyEXT); + X(vkCmdSetStencilOpEXT); + X(vkCmdSetStencilTestEnableEXT); + X(vkCmdResolveImage); + X(vkCreateBuffer); + X(vkCreateBufferView); + X(vkCreateCommandPool); + X(vkCreateComputePipelines); + X(vkCreateDescriptorPool); + X(vkCreateDescriptorSetLayout); + X(vkCreateDescriptorUpdateTemplateKHR); + X(vkCreateEvent); + X(vkCreateFence); + X(vkCreateFramebuffer); + X(vkCreateGraphicsPipelines); + X(vkCreateImage); + X(vkCreateImageView); + X(vkCreatePipelineLayout); + X(vkCreateQueryPool); + X(vkCreateRenderPass); + X(vkCreateSampler); + X(vkCreateSemaphore); + X(vkCreateShaderModule); + X(vkCreateSwapchainKHR); + X(vkDestroyBuffer); + X(vkDestroyBufferView); + X(vkDestroyCommandPool); + X(vkDestroyDescriptorPool); + X(vkDestroyDescriptorSetLayout); + X(vkDestroyDescriptorUpdateTemplateKHR); + X(vkDestroyEvent); + X(vkDestroyFence); + X(vkDestroyFramebuffer); + X(vkDestroyImage); + X(vkDestroyImageView); + X(vkDestroyPipeline); + X(vkDestroyPipelineLayout); + X(vkDestroyQueryPool); + X(vkDestroyRenderPass); + X(vkDestroySampler); + X(vkDestroySemaphore); + X(vkDestroyShaderModule); + X(vkDestroySwapchainKHR); + X(vkDeviceWaitIdle); + X(vkEndCommandBuffer); + X(vkFreeCommandBuffers); + X(vkFreeDescriptorSets); + X(vkFreeMemory); + X(vkGetBufferMemoryRequirements); + X(vkGetDeviceQueue); + X(vkGetEventStatus); + X(vkGetFenceStatus); + X(vkGetImageMemoryRequirements); + X(vkGetQueryPoolResults); + X(vkGetSemaphoreCounterValueKHR); + X(vkMapMemory); + X(vkQueueSubmit); + X(vkResetFences); + X(vkResetQueryPoolEXT); + X(vkSetDebugUtilsObjectNameEXT); + X(vkSetDebugUtilsObjectTagEXT); + X(vkUnmapMemory); + X(vkUpdateDescriptorSetWithTemplateKHR); + X(vkUpdateDescriptorSets); + X(vkWaitForFences); + X(vkWaitSemaphoresKHR); +#undef X +} + +template +void SetObjectName(const DeviceDispatch* dld, VkDevice device, T handle, VkObjectType type, + const char* name) { + const VkDebugUtilsObjectNameInfoEXT name_info{ + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, + .pNext = nullptr, + .objectType = VK_OBJECT_TYPE_IMAGE, + .objectHandle = reinterpret_cast(handle), + .pObjectName = name, + }; + Check(dld->vkSetDebugUtilsObjectNameEXT(device, &name_info)); +} + +} // Anonymous namespace + +bool Load(InstanceDispatch& dld) noexcept { +#define X(name) Proc(dld.name, dld, #name) + return X(vkCreateInstance) && X(vkEnumerateInstanceExtensionProperties) && + X(vkEnumerateInstanceLayerProperties); +#undef X +} + +bool Load(VkInstance instance, InstanceDispatch& dld) noexcept { +#define X(name) Proc(dld.name, dld, #name, instance) + // These functions may fail to load depending on the enabled extensions. + // Don't return a failure on these. + X(vkCreateDebugUtilsMessengerEXT); + X(vkDestroyDebugUtilsMessengerEXT); + X(vkDestroySurfaceKHR); + X(vkGetPhysicalDeviceFeatures2KHR); + X(vkGetPhysicalDeviceProperties2KHR); + X(vkGetPhysicalDeviceSurfaceCapabilitiesKHR); + X(vkGetPhysicalDeviceSurfaceFormatsKHR); + X(vkGetPhysicalDeviceSurfacePresentModesKHR); + X(vkGetPhysicalDeviceSurfaceSupportKHR); + X(vkGetSwapchainImagesKHR); + X(vkQueuePresentKHR); + + return X(vkCreateDevice) && X(vkDestroyDevice) && X(vkDestroyDevice) && + X(vkEnumerateDeviceExtensionProperties) && X(vkEnumeratePhysicalDevices) && + X(vkGetDeviceProcAddr) && X(vkGetPhysicalDeviceFormatProperties) && + X(vkGetPhysicalDeviceMemoryProperties) && X(vkGetPhysicalDeviceProperties) && + X(vkGetPhysicalDeviceQueueFamilyProperties); +#undef X +} + +const char* Exception::what() const noexcept { + return ToString(result); +} + +const char* ToString(VkResult result) noexcept { + switch (result) { + case VkResult::VK_SUCCESS: + return "VK_SUCCESS"; + case VkResult::VK_NOT_READY: + return "VK_NOT_READY"; + case VkResult::VK_TIMEOUT: + return "VK_TIMEOUT"; + case VkResult::VK_EVENT_SET: + return "VK_EVENT_SET"; + case VkResult::VK_EVENT_RESET: + return "VK_EVENT_RESET"; + case VkResult::VK_INCOMPLETE: + return "VK_INCOMPLETE"; + case VkResult::VK_ERROR_OUT_OF_HOST_MEMORY: + return "VK_ERROR_OUT_OF_HOST_MEMORY"; + case VkResult::VK_ERROR_OUT_OF_DEVICE_MEMORY: + return "VK_ERROR_OUT_OF_DEVICE_MEMORY"; + case VkResult::VK_ERROR_INITIALIZATION_FAILED: + return "VK_ERROR_INITIALIZATION_FAILED"; + case VkResult::VK_ERROR_DEVICE_LOST: + return "VK_ERROR_DEVICE_LOST"; + case VkResult::VK_ERROR_MEMORY_MAP_FAILED: + return "VK_ERROR_MEMORY_MAP_FAILED"; + case VkResult::VK_ERROR_LAYER_NOT_PRESENT: + return "VK_ERROR_LAYER_NOT_PRESENT"; + case VkResult::VK_ERROR_EXTENSION_NOT_PRESENT: + return "VK_ERROR_EXTENSION_NOT_PRESENT"; + case VkResult::VK_ERROR_FEATURE_NOT_PRESENT: + return "VK_ERROR_FEATURE_NOT_PRESENT"; + case VkResult::VK_ERROR_INCOMPATIBLE_DRIVER: + return "VK_ERROR_INCOMPATIBLE_DRIVER"; + case VkResult::VK_ERROR_TOO_MANY_OBJECTS: + return "VK_ERROR_TOO_MANY_OBJECTS"; + case VkResult::VK_ERROR_FORMAT_NOT_SUPPORTED: + return "VK_ERROR_FORMAT_NOT_SUPPORTED"; + case VkResult::VK_ERROR_FRAGMENTED_POOL: + return "VK_ERROR_FRAGMENTED_POOL"; + case VkResult::VK_ERROR_OUT_OF_POOL_MEMORY: + return "VK_ERROR_OUT_OF_POOL_MEMORY"; + case VkResult::VK_ERROR_INVALID_EXTERNAL_HANDLE: + return "VK_ERROR_INVALID_EXTERNAL_HANDLE"; + case VkResult::VK_ERROR_SURFACE_LOST_KHR: + return "VK_ERROR_SURFACE_LOST_KHR"; + case VkResult::VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: + return "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR"; + case VkResult::VK_SUBOPTIMAL_KHR: + return "VK_SUBOPTIMAL_KHR"; + case VkResult::VK_ERROR_OUT_OF_DATE_KHR: + return "VK_ERROR_OUT_OF_DATE_KHR"; + case VkResult::VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: + return "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR"; + case VkResult::VK_ERROR_VALIDATION_FAILED_EXT: + return "VK_ERROR_VALIDATION_FAILED_EXT"; + case VkResult::VK_ERROR_INVALID_SHADER_NV: + return "VK_ERROR_INVALID_SHADER_NV"; + case VkResult::VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT: + return "VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT"; + case VkResult::VK_ERROR_FRAGMENTATION_EXT: + return "VK_ERROR_FRAGMENTATION_EXT"; + case VkResult::VK_ERROR_NOT_PERMITTED_EXT: + return "VK_ERROR_NOT_PERMITTED_EXT"; + case VkResult::VK_ERROR_INVALID_DEVICE_ADDRESS_EXT: + return "VK_ERROR_INVALID_DEVICE_ADDRESS_EXT"; + case VkResult::VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT: + return "VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT"; + case VkResult::VK_ERROR_UNKNOWN: + return "VK_ERROR_UNKNOWN"; + case VkResult::VK_ERROR_INCOMPATIBLE_VERSION_KHR: + return "VK_ERROR_INCOMPATIBLE_VERSION_KHR"; + case VkResult::VK_THREAD_IDLE_KHR: + return "VK_THREAD_IDLE_KHR"; + case VkResult::VK_THREAD_DONE_KHR: + return "VK_THREAD_DONE_KHR"; + case VkResult::VK_OPERATION_DEFERRED_KHR: + return "VK_OPERATION_DEFERRED_KHR"; + case VkResult::VK_OPERATION_NOT_DEFERRED_KHR: + return "VK_OPERATION_NOT_DEFERRED_KHR"; + case VkResult::VK_PIPELINE_COMPILE_REQUIRED_EXT: + return "VK_PIPELINE_COMPILE_REQUIRED_EXT"; + case VkResult::VK_RESULT_MAX_ENUM: + return "VK_RESULT_MAX_ENUM"; + } + return "Unknown"; +} + +void Destroy(VkInstance instance, const InstanceDispatch& dld) noexcept { + dld.vkDestroyInstance(instance, nullptr); +} + +void Destroy(VkDevice device, const InstanceDispatch& dld) noexcept { + dld.vkDestroyDevice(device, nullptr); +} + +void Destroy(VkDevice device, VkBuffer handle, const DeviceDispatch& dld) noexcept { + dld.vkDestroyBuffer(device, handle, nullptr); +} + +void Destroy(VkDevice device, VkBufferView handle, const DeviceDispatch& dld) noexcept { + dld.vkDestroyBufferView(device, handle, nullptr); +} + +void Destroy(VkDevice device, VkCommandPool handle, const DeviceDispatch& dld) noexcept { + dld.vkDestroyCommandPool(device, handle, nullptr); +} + +void Destroy(VkDevice device, VkDescriptorPool handle, const DeviceDispatch& dld) noexcept { + dld.vkDestroyDescriptorPool(device, handle, nullptr); +} + +void Destroy(VkDevice device, VkDescriptorSetLayout handle, const DeviceDispatch& dld) noexcept { + dld.vkDestroyDescriptorSetLayout(device, handle, nullptr); +} + +void Destroy(VkDevice device, VkDescriptorUpdateTemplateKHR handle, + const DeviceDispatch& dld) noexcept { + dld.vkDestroyDescriptorUpdateTemplateKHR(device, handle, nullptr); +} + +void Destroy(VkDevice device, VkDeviceMemory handle, const DeviceDispatch& dld) noexcept { + dld.vkFreeMemory(device, handle, nullptr); +} + +void Destroy(VkDevice device, VkEvent handle, const DeviceDispatch& dld) noexcept { + dld.vkDestroyEvent(device, handle, nullptr); +} + +void Destroy(VkDevice device, VkFence handle, const DeviceDispatch& dld) noexcept { + dld.vkDestroyFence(device, handle, nullptr); +} + +void Destroy(VkDevice device, VkFramebuffer handle, const DeviceDispatch& dld) noexcept { + dld.vkDestroyFramebuffer(device, handle, nullptr); +} + +void Destroy(VkDevice device, VkImage handle, const DeviceDispatch& dld) noexcept { + dld.vkDestroyImage(device, handle, nullptr); +} + +void Destroy(VkDevice device, VkImageView handle, const DeviceDispatch& dld) noexcept { + dld.vkDestroyImageView(device, handle, nullptr); +} + +void Destroy(VkDevice device, VkPipeline handle, const DeviceDispatch& dld) noexcept { + dld.vkDestroyPipeline(device, handle, nullptr); +} + +void Destroy(VkDevice device, VkPipelineLayout handle, const DeviceDispatch& dld) noexcept { + dld.vkDestroyPipelineLayout(device, handle, nullptr); +} + +void Destroy(VkDevice device, VkQueryPool handle, const DeviceDispatch& dld) noexcept { + dld.vkDestroyQueryPool(device, handle, nullptr); +} + +void Destroy(VkDevice device, VkRenderPass handle, const DeviceDispatch& dld) noexcept { + dld.vkDestroyRenderPass(device, handle, nullptr); +} + +void Destroy(VkDevice device, VkSampler handle, const DeviceDispatch& dld) noexcept { + dld.vkDestroySampler(device, handle, nullptr); +} + +void Destroy(VkDevice device, VkSwapchainKHR handle, const DeviceDispatch& dld) noexcept { + dld.vkDestroySwapchainKHR(device, handle, nullptr); +} + +void Destroy(VkDevice device, VkSemaphore handle, const DeviceDispatch& dld) noexcept { + dld.vkDestroySemaphore(device, handle, nullptr); +} + +void Destroy(VkDevice device, VkShaderModule handle, const DeviceDispatch& dld) noexcept { + dld.vkDestroyShaderModule(device, handle, nullptr); +} + +void Destroy(VkInstance instance, VkDebugUtilsMessengerEXT handle, + const InstanceDispatch& dld) noexcept { + dld.vkDestroyDebugUtilsMessengerEXT(instance, handle, nullptr); +} + +void Destroy(VkInstance instance, VkSurfaceKHR handle, const InstanceDispatch& dld) noexcept { + dld.vkDestroySurfaceKHR(instance, handle, nullptr); +} + +VkResult Free(VkDevice device, VkDescriptorPool handle, Span sets, + const DeviceDispatch& dld) noexcept { + return dld.vkFreeDescriptorSets(device, handle, sets.size(), sets.data()); +} + +VkResult Free(VkDevice device, VkCommandPool handle, Span buffers, + const DeviceDispatch& dld) noexcept { + dld.vkFreeCommandBuffers(device, handle, buffers.size(), buffers.data()); + return VK_SUCCESS; +} + +Instance Instance::Create(u32 version, Span layers, Span extensions, + InstanceDispatch& dispatch) noexcept { + const VkApplicationInfo application_info{ + .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, + .pNext = nullptr, + .pApplicationName = "yuzu Emulator", + .applicationVersion = VK_MAKE_VERSION(0, 1, 0), + .pEngineName = "yuzu Emulator", + .engineVersion = VK_MAKE_VERSION(0, 1, 0), + .apiVersion = version, + }; + const VkInstanceCreateInfo ci{ + .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .pApplicationInfo = &application_info, + .enabledLayerCount = layers.size(), + .ppEnabledLayerNames = layers.data(), + .enabledExtensionCount = extensions.size(), + .ppEnabledExtensionNames = extensions.data(), + }; + + VkInstance instance; + if (dispatch.vkCreateInstance(&ci, nullptr, &instance) != VK_SUCCESS) { + // Failed to create the instance. + return {}; + } + if (!Proc(dispatch.vkDestroyInstance, dispatch, "vkDestroyInstance", instance)) { + // We successfully created an instance but the destroy function couldn't be loaded. + // This is a good moment to panic. + return {}; + } + + return Instance(instance, dispatch); +} + +std::optional> Instance::EnumeratePhysicalDevices() { + u32 num; + if (dld->vkEnumeratePhysicalDevices(handle, &num, nullptr) != VK_SUCCESS) { + return std::nullopt; + } + std::vector physical_devices(num); + if (dld->vkEnumeratePhysicalDevices(handle, &num, physical_devices.data()) != VK_SUCCESS) { + return std::nullopt; + } + SortPhysicalDevices(physical_devices, *dld); + return std::make_optional(std::move(physical_devices)); +} + +DebugCallback Instance::TryCreateDebugCallback( + PFN_vkDebugUtilsMessengerCallbackEXT callback) noexcept { + const VkDebugUtilsMessengerCreateInfoEXT ci{ + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, + .pNext = nullptr, + .flags = 0, + .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT, + .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT, + .pfnUserCallback = callback, + .pUserData = nullptr, + }; + + VkDebugUtilsMessengerEXT messenger; + if (dld->vkCreateDebugUtilsMessengerEXT(handle, &ci, nullptr, &messenger) != VK_SUCCESS) { + return {}; + } + return DebugCallback(messenger, handle, *dld); +} + +void Buffer::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const { + Check(dld->vkBindBufferMemory(owner, handle, memory, offset)); +} + +void Buffer::SetObjectNameEXT(const char* name) const { + SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER, name); +} + +void BufferView::SetObjectNameEXT(const char* name) const { + SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_BUFFER_VIEW, name); +} + +void Image::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const { + Check(dld->vkBindImageMemory(owner, handle, memory, offset)); +} + +void Image::SetObjectNameEXT(const char* name) const { + SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_IMAGE, name); +} + +void ImageView::SetObjectNameEXT(const char* name) const { + SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_IMAGE_VIEW, name); +} + +void DeviceMemory::SetObjectNameEXT(const char* name) const { + SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_DEVICE_MEMORY, name); +} + +void Fence::SetObjectNameEXT(const char* name) const { + SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_FENCE, name); +} + +void Framebuffer::SetObjectNameEXT(const char* name) const { + SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_FRAMEBUFFER, name); +} + +DescriptorSets DescriptorPool::Allocate(const VkDescriptorSetAllocateInfo& ai) const { + const std::size_t num = ai.descriptorSetCount; + std::unique_ptr sets = std::make_unique(num); + switch (const VkResult result = dld->vkAllocateDescriptorSets(owner, &ai, sets.get())) { + case VK_SUCCESS: + return DescriptorSets(std::move(sets), num, owner, handle, *dld); + case VK_ERROR_OUT_OF_POOL_MEMORY: + return {}; + default: + throw Exception(result); + } +} + +void DescriptorPool::SetObjectNameEXT(const char* name) const { + SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_DESCRIPTOR_POOL, name); +} + +CommandBuffers CommandPool::Allocate(std::size_t num_buffers, VkCommandBufferLevel level) const { + const VkCommandBufferAllocateInfo ai{ + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + .pNext = nullptr, + .commandPool = handle, + .level = level, + .commandBufferCount = static_cast(num_buffers), + }; + + std::unique_ptr buffers = std::make_unique(num_buffers); + switch (const VkResult result = dld->vkAllocateCommandBuffers(owner, &ai, buffers.get())) { + case VK_SUCCESS: + return CommandBuffers(std::move(buffers), num_buffers, owner, handle, *dld); + case VK_ERROR_OUT_OF_POOL_MEMORY: + return {}; + default: + throw Exception(result); + } +} + +void CommandPool::SetObjectNameEXT(const char* name) const { + SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_COMMAND_POOL, name); +} + +std::vector SwapchainKHR::GetImages() const { + u32 num; + Check(dld->vkGetSwapchainImagesKHR(owner, handle, &num, nullptr)); + std::vector images(num); + Check(dld->vkGetSwapchainImagesKHR(owner, handle, &num, images.data())); + return images; +} + +void Event::SetObjectNameEXT(const char* name) const { + SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_EVENT, name); +} + +void ShaderModule::SetObjectNameEXT(const char* name) const { + SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_SHADER_MODULE, name); +} + +void Semaphore::SetObjectNameEXT(const char* name) const { + SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_SEMAPHORE, name); +} + +Device Device::Create(VkPhysicalDevice physical_device, Span queues_ci, + Span enabled_extensions, const void* next, + DeviceDispatch& dispatch) noexcept { + const VkDeviceCreateInfo ci{ + .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, + .pNext = next, + .flags = 0, + .queueCreateInfoCount = queues_ci.size(), + .pQueueCreateInfos = queues_ci.data(), + .enabledLayerCount = 0, + .ppEnabledLayerNames = nullptr, + .enabledExtensionCount = enabled_extensions.size(), + .ppEnabledExtensionNames = enabled_extensions.data(), + .pEnabledFeatures = nullptr, + }; + + VkDevice device; + if (dispatch.vkCreateDevice(physical_device, &ci, nullptr, &device) != VK_SUCCESS) { + return {}; + } + Load(device, dispatch); + return Device(device, dispatch); +} + +Queue Device::GetQueue(u32 family_index) const noexcept { + VkQueue queue; + dld->vkGetDeviceQueue(handle, family_index, 0, &queue); + return Queue(queue, *dld); +} + +Buffer Device::CreateBuffer(const VkBufferCreateInfo& ci) const { + VkBuffer object; + Check(dld->vkCreateBuffer(handle, &ci, nullptr, &object)); + return Buffer(object, handle, *dld); +} + +BufferView Device::CreateBufferView(const VkBufferViewCreateInfo& ci) const { + VkBufferView object; + Check(dld->vkCreateBufferView(handle, &ci, nullptr, &object)); + return BufferView(object, handle, *dld); +} + +Image Device::CreateImage(const VkImageCreateInfo& ci) const { + VkImage object; + Check(dld->vkCreateImage(handle, &ci, nullptr, &object)); + return Image(object, handle, *dld); +} + +ImageView Device::CreateImageView(const VkImageViewCreateInfo& ci) const { + VkImageView object; + Check(dld->vkCreateImageView(handle, &ci, nullptr, &object)); + return ImageView(object, handle, *dld); +} + +Semaphore Device::CreateSemaphore() const { + static constexpr VkSemaphoreCreateInfo ci{ + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + }; + return CreateSemaphore(ci); +} + +Semaphore Device::CreateSemaphore(const VkSemaphoreCreateInfo& ci) const { + VkSemaphore object; + Check(dld->vkCreateSemaphore(handle, &ci, nullptr, &object)); + return Semaphore(object, handle, *dld); +} + +Fence Device::CreateFence(const VkFenceCreateInfo& ci) const { + VkFence object; + Check(dld->vkCreateFence(handle, &ci, nullptr, &object)); + return Fence(object, handle, *dld); +} + +DescriptorPool Device::CreateDescriptorPool(const VkDescriptorPoolCreateInfo& ci) const { + VkDescriptorPool object; + Check(dld->vkCreateDescriptorPool(handle, &ci, nullptr, &object)); + return DescriptorPool(object, handle, *dld); +} + +RenderPass Device::CreateRenderPass(const VkRenderPassCreateInfo& ci) const { + VkRenderPass object; + Check(dld->vkCreateRenderPass(handle, &ci, nullptr, &object)); + return RenderPass(object, handle, *dld); +} + +DescriptorSetLayout Device::CreateDescriptorSetLayout( + const VkDescriptorSetLayoutCreateInfo& ci) const { + VkDescriptorSetLayout object; + Check(dld->vkCreateDescriptorSetLayout(handle, &ci, nullptr, &object)); + return DescriptorSetLayout(object, handle, *dld); +} + +PipelineLayout Device::CreatePipelineLayout(const VkPipelineLayoutCreateInfo& ci) const { + VkPipelineLayout object; + Check(dld->vkCreatePipelineLayout(handle, &ci, nullptr, &object)); + return PipelineLayout(object, handle, *dld); +} + +Pipeline Device::CreateGraphicsPipeline(const VkGraphicsPipelineCreateInfo& ci) const { + VkPipeline object; + Check(dld->vkCreateGraphicsPipelines(handle, nullptr, 1, &ci, nullptr, &object)); + return Pipeline(object, handle, *dld); +} + +Pipeline Device::CreateComputePipeline(const VkComputePipelineCreateInfo& ci) const { + VkPipeline object; + Check(dld->vkCreateComputePipelines(handle, nullptr, 1, &ci, nullptr, &object)); + return Pipeline(object, handle, *dld); +} + +Sampler Device::CreateSampler(const VkSamplerCreateInfo& ci) const { + VkSampler object; + Check(dld->vkCreateSampler(handle, &ci, nullptr, &object)); + return Sampler(object, handle, *dld); +} + +Framebuffer Device::CreateFramebuffer(const VkFramebufferCreateInfo& ci) const { + VkFramebuffer object; + Check(dld->vkCreateFramebuffer(handle, &ci, nullptr, &object)); + return Framebuffer(object, handle, *dld); +} + +CommandPool Device::CreateCommandPool(const VkCommandPoolCreateInfo& ci) const { + VkCommandPool object; + Check(dld->vkCreateCommandPool(handle, &ci, nullptr, &object)); + return CommandPool(object, handle, *dld); +} + +DescriptorUpdateTemplateKHR Device::CreateDescriptorUpdateTemplateKHR( + const VkDescriptorUpdateTemplateCreateInfoKHR& ci) const { + VkDescriptorUpdateTemplateKHR object; + Check(dld->vkCreateDescriptorUpdateTemplateKHR(handle, &ci, nullptr, &object)); + return DescriptorUpdateTemplateKHR(object, handle, *dld); +} + +QueryPool Device::CreateQueryPool(const VkQueryPoolCreateInfo& ci) const { + VkQueryPool object; + Check(dld->vkCreateQueryPool(handle, &ci, nullptr, &object)); + return QueryPool(object, handle, *dld); +} + +ShaderModule Device::CreateShaderModule(const VkShaderModuleCreateInfo& ci) const { + VkShaderModule object; + Check(dld->vkCreateShaderModule(handle, &ci, nullptr, &object)); + return ShaderModule(object, handle, *dld); +} + +Event Device::CreateEvent() const { + static constexpr VkEventCreateInfo ci{ + .sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + }; + + VkEvent object; + Check(dld->vkCreateEvent(handle, &ci, nullptr, &object)); + return Event(object, handle, *dld); +} + +SwapchainKHR Device::CreateSwapchainKHR(const VkSwapchainCreateInfoKHR& ci) const { + VkSwapchainKHR object; + Check(dld->vkCreateSwapchainKHR(handle, &ci, nullptr, &object)); + return SwapchainKHR(object, handle, *dld); +} + +DeviceMemory Device::TryAllocateMemory(const VkMemoryAllocateInfo& ai) const noexcept { + VkDeviceMemory memory; + if (dld->vkAllocateMemory(handle, &ai, nullptr, &memory) != VK_SUCCESS) { + return {}; + } + return DeviceMemory(memory, handle, *dld); +} + +DeviceMemory Device::AllocateMemory(const VkMemoryAllocateInfo& ai) const { + VkDeviceMemory memory; + Check(dld->vkAllocateMemory(handle, &ai, nullptr, &memory)); + return DeviceMemory(memory, handle, *dld); +} + +VkMemoryRequirements Device::GetBufferMemoryRequirements(VkBuffer buffer) const noexcept { + VkMemoryRequirements requirements; + dld->vkGetBufferMemoryRequirements(handle, buffer, &requirements); + return requirements; +} + +VkMemoryRequirements Device::GetImageMemoryRequirements(VkImage image) const noexcept { + VkMemoryRequirements requirements; + dld->vkGetImageMemoryRequirements(handle, image, &requirements); + return requirements; +} + +void Device::UpdateDescriptorSets(Span writes, + Span copies) const noexcept { + dld->vkUpdateDescriptorSets(handle, writes.size(), writes.data(), copies.size(), copies.data()); +} + +VkPhysicalDeviceProperties PhysicalDevice::GetProperties() const noexcept { + VkPhysicalDeviceProperties properties; + dld->vkGetPhysicalDeviceProperties(physical_device, &properties); + return properties; +} + +void PhysicalDevice::GetProperties2KHR(VkPhysicalDeviceProperties2KHR& properties) const noexcept { + dld->vkGetPhysicalDeviceProperties2KHR(physical_device, &properties); +} + +VkPhysicalDeviceFeatures PhysicalDevice::GetFeatures() const noexcept { + VkPhysicalDeviceFeatures2KHR features2; + features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR; + features2.pNext = nullptr; + dld->vkGetPhysicalDeviceFeatures2KHR(physical_device, &features2); + return features2.features; +} + +void PhysicalDevice::GetFeatures2KHR(VkPhysicalDeviceFeatures2KHR& features) const noexcept { + dld->vkGetPhysicalDeviceFeatures2KHR(physical_device, &features); +} + +VkFormatProperties PhysicalDevice::GetFormatProperties(VkFormat format) const noexcept { + VkFormatProperties properties; + dld->vkGetPhysicalDeviceFormatProperties(physical_device, format, &properties); + return properties; +} + +std::vector PhysicalDevice::EnumerateDeviceExtensionProperties() const { + u32 num; + dld->vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &num, nullptr); + std::vector properties(num); + dld->vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &num, properties.data()); + return properties; +} + +std::vector PhysicalDevice::GetQueueFamilyProperties() const { + u32 num; + dld->vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &num, nullptr); + std::vector properties(num); + dld->vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &num, properties.data()); + return properties; +} + +bool PhysicalDevice::GetSurfaceSupportKHR(u32 queue_family_index, VkSurfaceKHR surface) const { + VkBool32 supported; + Check(dld->vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, queue_family_index, surface, + &supported)); + return supported == VK_TRUE; +} + +VkSurfaceCapabilitiesKHR PhysicalDevice::GetSurfaceCapabilitiesKHR(VkSurfaceKHR surface) const { + VkSurfaceCapabilitiesKHR capabilities; + Check(dld->vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, surface, &capabilities)); + return capabilities; +} + +std::vector PhysicalDevice::GetSurfaceFormatsKHR(VkSurfaceKHR surface) const { + u32 num; + Check(dld->vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &num, nullptr)); + std::vector formats(num); + Check( + dld->vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &num, formats.data())); + return formats; +} + +std::vector PhysicalDevice::GetSurfacePresentModesKHR( + VkSurfaceKHR surface) const { + u32 num; + Check(dld->vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &num, nullptr)); + std::vector modes(num); + Check(dld->vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &num, + modes.data())); + return modes; +} + +VkPhysicalDeviceMemoryProperties PhysicalDevice::GetMemoryProperties() const noexcept { + VkPhysicalDeviceMemoryProperties properties; + dld->vkGetPhysicalDeviceMemoryProperties(physical_device, &properties); + return properties; +} + +u32 AvailableVersion(const InstanceDispatch& dld) noexcept { + PFN_vkEnumerateInstanceVersion vkEnumerateInstanceVersion; + if (!Proc(vkEnumerateInstanceVersion, dld, "vkEnumerateInstanceVersion")) { + // If the procedure is not found, Vulkan 1.0 is assumed + return VK_API_VERSION_1_0; + } + u32 version; + if (const VkResult result = vkEnumerateInstanceVersion(&version); result != VK_SUCCESS) { + LOG_ERROR(Render_Vulkan, "vkEnumerateInstanceVersion returned {}, assuming Vulkan 1.1", + ToString(result)); + return VK_API_VERSION_1_1; + } + return version; +} + +std::optional> EnumerateInstanceExtensionProperties( + const InstanceDispatch& dld) { + u32 num; + if (dld.vkEnumerateInstanceExtensionProperties(nullptr, &num, nullptr) != VK_SUCCESS) { + return std::nullopt; + } + std::vector properties(num); + if (dld.vkEnumerateInstanceExtensionProperties(nullptr, &num, properties.data()) != + VK_SUCCESS) { + return std::nullopt; + } + return properties; +} + +std::optional> EnumerateInstanceLayerProperties( + const InstanceDispatch& dld) { + u32 num; + if (dld.vkEnumerateInstanceLayerProperties(&num, nullptr) != VK_SUCCESS) { + return std::nullopt; + } + std::vector properties(num); + if (dld.vkEnumerateInstanceLayerProperties(&num, properties.data()) != VK_SUCCESS) { + return std::nullopt; + } + return properties; +} + +} // namespace Vulkan::vk diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h new file mode 100644 index 000000000..f9a184e00 --- /dev/null +++ b/src/video_core/vulkan_common/vulkan_wrapper.h @@ -0,0 +1,1213 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define VK_NO_PROTOTYPES +#include + +#include "common/common_types.h" + +#ifdef _MSC_VER +#pragma warning(disable : 26812) // Disable prefer enum class over enum +#endif + +namespace Vulkan::vk { + +/** + * Span for Vulkan arrays. + * Based on std::span but optimized for array access instead of iterators. + * Size returns uint32_t instead of size_t to ease interaction with Vulkan functions. + */ +template +class Span { +public: + using value_type = T; + using size_type = u32; + using difference_type = std::ptrdiff_t; + using reference = const T&; + using const_reference = const T&; + using pointer = const T*; + using const_pointer = const T*; + using iterator = const T*; + using const_iterator = const T*; + + /// Construct an empty span. + constexpr Span() noexcept = default; + + /// Construct an empty span + constexpr Span(std::nullptr_t) noexcept {} + + /// Construct a span from a single element. + constexpr Span(const T& value) noexcept : ptr{&value}, num{1} {} + + /// Construct a span from a range. + template + // requires std::data(const Range&) + // requires std::size(const Range&) + constexpr Span(const Range& range) : ptr{std::data(range)}, num{std::size(range)} {} + + /// Construct a span from a pointer and a size. + /// This is inteded for subranges. + constexpr Span(const T* ptr_, std::size_t num_) noexcept : ptr{ptr_}, num{num_} {} + + /// Returns the data pointer by the span. + constexpr const T* data() const noexcept { + return ptr; + } + + /// Returns the number of elements in the span. + /// @note Returns a 32 bits integer because most Vulkan functions expect this type. + constexpr u32 size() const noexcept { + return static_cast(num); + } + + /// Returns true when the span is empty. + constexpr bool empty() const noexcept { + return num == 0; + } + + /// Returns a reference to the element in the passed index. + /// @pre: index < size() + constexpr const T& operator[](std::size_t index) const noexcept { + return ptr[index]; + } + + /// Returns an iterator to the beginning of the span. + constexpr const T* begin() const noexcept { + return ptr; + } + + /// Returns an iterator to the end of the span. + constexpr const T* end() const noexcept { + return ptr + num; + } + + /// Returns an iterator to the beginning of the span. + constexpr const T* cbegin() const noexcept { + return ptr; + } + + /// Returns an iterator to the end of the span. + constexpr const T* cend() const noexcept { + return ptr + num; + } + +private: + const T* ptr = nullptr; + std::size_t num = 0; +}; + +/// Vulkan exception generated from a VkResult. +class Exception final : public std::exception { +public: + /// Construct the exception with a result. + /// @pre result != VK_SUCCESS + explicit Exception(VkResult result_) : result{result_} {} + virtual ~Exception() = default; + + const char* what() const noexcept override; + +private: + VkResult result; +}; + +/// Converts a VkResult enum into a rodata string +const char* ToString(VkResult) noexcept; + +/// Throws a Vulkan exception if result is not success. +inline void Check(VkResult result) { + if (result != VK_SUCCESS) { + throw Exception(result); + } +} + +/// Throws a Vulkan exception if result is an error. +/// @return result +inline VkResult Filter(VkResult result) { + if (result < 0) { + throw Exception(result); + } + return result; +} + +/// Table holding Vulkan instance function pointers. +struct InstanceDispatch { + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; + + PFN_vkCreateInstance vkCreateInstance; + PFN_vkDestroyInstance vkDestroyInstance; + PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties; + PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties; + + PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT; + PFN_vkCreateDevice vkCreateDevice; + PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT; + PFN_vkDestroyDevice vkDestroyDevice; + PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR; + PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties; + PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices; + PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr; + PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; + PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties; + PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties; + PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties; + PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; + PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties; + PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR; + PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR; + PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR; + PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR; + PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; + PFN_vkQueuePresentKHR vkQueuePresentKHR; +}; + +/// Table holding Vulkan device function pointers. +struct DeviceDispatch : public InstanceDispatch { + PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; + PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers; + PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets; + PFN_vkAllocateMemory vkAllocateMemory; + PFN_vkBeginCommandBuffer vkBeginCommandBuffer; + PFN_vkBindBufferMemory vkBindBufferMemory; + PFN_vkBindImageMemory vkBindImageMemory; + PFN_vkCmdBeginQuery vkCmdBeginQuery; + PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass; + PFN_vkCmdBeginTransformFeedbackEXT vkCmdBeginTransformFeedbackEXT; + PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT; + PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets; + PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer; + PFN_vkCmdBindPipeline vkCmdBindPipeline; + PFN_vkCmdBindTransformFeedbackBuffersEXT vkCmdBindTransformFeedbackBuffersEXT; + PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers; + PFN_vkCmdBlitImage vkCmdBlitImage; + PFN_vkCmdClearAttachments vkCmdClearAttachments; + PFN_vkCmdCopyBuffer vkCmdCopyBuffer; + PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage; + PFN_vkCmdCopyImage vkCmdCopyImage; + PFN_vkCmdCopyImageToBuffer vkCmdCopyImageToBuffer; + PFN_vkCmdDispatch vkCmdDispatch; + PFN_vkCmdDraw vkCmdDraw; + PFN_vkCmdDrawIndexed vkCmdDrawIndexed; + PFN_vkCmdEndQuery vkCmdEndQuery; + PFN_vkCmdEndRenderPass vkCmdEndRenderPass; + PFN_vkCmdEndTransformFeedbackEXT vkCmdEndTransformFeedbackEXT; + PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT; + PFN_vkCmdFillBuffer vkCmdFillBuffer; + PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier; + PFN_vkCmdPushConstants vkCmdPushConstants; + PFN_vkCmdSetBlendConstants vkCmdSetBlendConstants; + PFN_vkCmdSetDepthBias vkCmdSetDepthBias; + PFN_vkCmdSetDepthBounds vkCmdSetDepthBounds; + PFN_vkCmdSetEvent vkCmdSetEvent; + PFN_vkCmdSetScissor vkCmdSetScissor; + PFN_vkCmdSetStencilCompareMask vkCmdSetStencilCompareMask; + PFN_vkCmdSetStencilReference vkCmdSetStencilReference; + PFN_vkCmdSetStencilWriteMask vkCmdSetStencilWriteMask; + PFN_vkCmdSetViewport vkCmdSetViewport; + PFN_vkCmdWaitEvents vkCmdWaitEvents; + PFN_vkCmdBindVertexBuffers2EXT vkCmdBindVertexBuffers2EXT; + PFN_vkCmdSetCullModeEXT vkCmdSetCullModeEXT; + PFN_vkCmdSetDepthBoundsTestEnableEXT vkCmdSetDepthBoundsTestEnableEXT; + PFN_vkCmdSetDepthCompareOpEXT vkCmdSetDepthCompareOpEXT; + PFN_vkCmdSetDepthTestEnableEXT vkCmdSetDepthTestEnableEXT; + PFN_vkCmdSetDepthWriteEnableEXT vkCmdSetDepthWriteEnableEXT; + PFN_vkCmdSetFrontFaceEXT vkCmdSetFrontFaceEXT; + PFN_vkCmdSetPrimitiveTopologyEXT vkCmdSetPrimitiveTopologyEXT; + PFN_vkCmdSetStencilOpEXT vkCmdSetStencilOpEXT; + PFN_vkCmdSetStencilTestEnableEXT vkCmdSetStencilTestEnableEXT; + PFN_vkCmdResolveImage vkCmdResolveImage; + PFN_vkCreateBuffer vkCreateBuffer; + PFN_vkCreateBufferView vkCreateBufferView; + PFN_vkCreateCommandPool vkCreateCommandPool; + PFN_vkCreateComputePipelines vkCreateComputePipelines; + PFN_vkCreateDescriptorPool vkCreateDescriptorPool; + PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout; + PFN_vkCreateDescriptorUpdateTemplateKHR vkCreateDescriptorUpdateTemplateKHR; + PFN_vkCreateEvent vkCreateEvent; + PFN_vkCreateFence vkCreateFence; + PFN_vkCreateFramebuffer vkCreateFramebuffer; + PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines; + PFN_vkCreateImage vkCreateImage; + PFN_vkCreateImageView vkCreateImageView; + PFN_vkCreatePipelineLayout vkCreatePipelineLayout; + PFN_vkCreateQueryPool vkCreateQueryPool; + PFN_vkCreateRenderPass vkCreateRenderPass; + PFN_vkCreateSampler vkCreateSampler; + PFN_vkCreateSemaphore vkCreateSemaphore; + PFN_vkCreateShaderModule vkCreateShaderModule; + PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR; + PFN_vkDestroyBuffer vkDestroyBuffer; + PFN_vkDestroyBufferView vkDestroyBufferView; + PFN_vkDestroyCommandPool vkDestroyCommandPool; + PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool; + PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout; + PFN_vkDestroyDescriptorUpdateTemplateKHR vkDestroyDescriptorUpdateTemplateKHR; + PFN_vkDestroyEvent vkDestroyEvent; + PFN_vkDestroyFence vkDestroyFence; + PFN_vkDestroyFramebuffer vkDestroyFramebuffer; + PFN_vkDestroyImage vkDestroyImage; + PFN_vkDestroyImageView vkDestroyImageView; + PFN_vkDestroyPipeline vkDestroyPipeline; + PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout; + PFN_vkDestroyQueryPool vkDestroyQueryPool; + PFN_vkDestroyRenderPass vkDestroyRenderPass; + PFN_vkDestroySampler vkDestroySampler; + PFN_vkDestroySemaphore vkDestroySemaphore; + PFN_vkDestroyShaderModule vkDestroyShaderModule; + PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR; + PFN_vkDeviceWaitIdle vkDeviceWaitIdle; + PFN_vkEndCommandBuffer vkEndCommandBuffer; + PFN_vkFreeCommandBuffers vkFreeCommandBuffers; + PFN_vkFreeDescriptorSets vkFreeDescriptorSets; + PFN_vkFreeMemory vkFreeMemory; + PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements; + PFN_vkGetDeviceQueue vkGetDeviceQueue; + PFN_vkGetEventStatus vkGetEventStatus; + PFN_vkGetFenceStatus vkGetFenceStatus; + PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements; + PFN_vkGetQueryPoolResults vkGetQueryPoolResults; + PFN_vkGetSemaphoreCounterValueKHR vkGetSemaphoreCounterValueKHR; + PFN_vkMapMemory vkMapMemory; + PFN_vkQueueSubmit vkQueueSubmit; + PFN_vkResetFences vkResetFences; + PFN_vkResetQueryPoolEXT vkResetQueryPoolEXT; + PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT; + PFN_vkSetDebugUtilsObjectTagEXT vkSetDebugUtilsObjectTagEXT; + PFN_vkUnmapMemory vkUnmapMemory; + PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR; + PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets; + PFN_vkWaitForFences vkWaitForFences; + PFN_vkWaitSemaphoresKHR vkWaitSemaphoresKHR; +}; + +/// Loads instance agnostic function pointers. +/// @return True on success, false on error. +bool Load(InstanceDispatch&) noexcept; + +/// Loads instance function pointers. +/// @return True on success, false on error. +bool Load(VkInstance, InstanceDispatch&) noexcept; + +void Destroy(VkInstance, const InstanceDispatch&) noexcept; +void Destroy(VkDevice, const InstanceDispatch&) noexcept; + +void Destroy(VkDevice, VkBuffer, const DeviceDispatch&) noexcept; +void Destroy(VkDevice, VkBufferView, const DeviceDispatch&) noexcept; +void Destroy(VkDevice, VkCommandPool, const DeviceDispatch&) noexcept; +void Destroy(VkDevice, VkDescriptorPool, const DeviceDispatch&) noexcept; +void Destroy(VkDevice, VkDescriptorSetLayout, const DeviceDispatch&) noexcept; +void Destroy(VkDevice, VkDescriptorUpdateTemplateKHR, const DeviceDispatch&) noexcept; +void Destroy(VkDevice, VkDeviceMemory, const DeviceDispatch&) noexcept; +void Destroy(VkDevice, VkEvent, const DeviceDispatch&) noexcept; +void Destroy(VkDevice, VkFence, const DeviceDispatch&) noexcept; +void Destroy(VkDevice, VkFramebuffer, const DeviceDispatch&) noexcept; +void Destroy(VkDevice, VkImage, const DeviceDispatch&) noexcept; +void Destroy(VkDevice, VkImageView, const DeviceDispatch&) noexcept; +void Destroy(VkDevice, VkPipeline, const DeviceDispatch&) noexcept; +void Destroy(VkDevice, VkPipelineLayout, const DeviceDispatch&) noexcept; +void Destroy(VkDevice, VkQueryPool, const DeviceDispatch&) noexcept; +void Destroy(VkDevice, VkRenderPass, const DeviceDispatch&) noexcept; +void Destroy(VkDevice, VkSampler, const DeviceDispatch&) noexcept; +void Destroy(VkDevice, VkSwapchainKHR, const DeviceDispatch&) noexcept; +void Destroy(VkDevice, VkSemaphore, const DeviceDispatch&) noexcept; +void Destroy(VkDevice, VkShaderModule, const DeviceDispatch&) noexcept; +void Destroy(VkInstance, VkDebugUtilsMessengerEXT, const InstanceDispatch&) noexcept; +void Destroy(VkInstance, VkSurfaceKHR, const InstanceDispatch&) noexcept; + +VkResult Free(VkDevice, VkDescriptorPool, Span, const DeviceDispatch&) noexcept; +VkResult Free(VkDevice, VkCommandPool, Span, const DeviceDispatch&) noexcept; + +template +class Handle; + +/// Handle with an owning type. +/// Analogue to std::unique_ptr. +template +class Handle { +public: + /// Construct a handle and hold it's ownership. + explicit Handle(Type handle_, OwnerType owner_, const Dispatch& dld_) noexcept + : handle{handle_}, owner{owner_}, dld{&dld_} {} + + /// Construct an empty handle. + Handle() = default; + + /// Copying Vulkan objects is not supported and will never be. + Handle(const Handle&) = delete; + Handle& operator=(const Handle&) = delete; + + /// Construct a handle transfering the ownership from another handle. + Handle(Handle&& rhs) noexcept + : handle{std::exchange(rhs.handle, nullptr)}, owner{rhs.owner}, dld{rhs.dld} {} + + /// Assign the current handle transfering the ownership from another handle. + /// Destroys any previously held object. + Handle& operator=(Handle&& rhs) noexcept { + Release(); + handle = std::exchange(rhs.handle, nullptr); + owner = rhs.owner; + dld = rhs.dld; + return *this; + } + + /// Destroys the current handle if it existed. + ~Handle() noexcept { + Release(); + } + + /// Destroys any held object. + void reset() noexcept { + Release(); + handle = nullptr; + } + + /// Returns the address of the held object. + /// Intended for Vulkan structures that expect a pointer to an array. + const Type* address() const noexcept { + return std::addressof(handle); + } + + /// Returns the held Vulkan handle. + Type operator*() const noexcept { + return handle; + } + + /// Returns true when there's a held object. + explicit operator bool() const noexcept { + return handle != nullptr; + } + +protected: + Type handle = nullptr; + OwnerType owner = nullptr; + const Dispatch* dld = nullptr; + +private: + /// Destroys the held object if it exists. + void Release() noexcept { + if (handle) { + Destroy(owner, handle, *dld); + } + } +}; + +/// Dummy type used to specify a handle has no owner. +struct NoOwner {}; + +/// Handle without an owning type. +/// Analogue to std::unique_ptr +template +class Handle { +public: + /// Construct a handle and hold it's ownership. + explicit Handle(Type handle_, const Dispatch& dld_) noexcept : handle{handle_}, dld{&dld_} {} + + /// Construct an empty handle. + Handle() noexcept = default; + + /// Copying Vulkan objects is not supported and will never be. + Handle(const Handle&) = delete; + Handle& operator=(const Handle&) = delete; + + /// Construct a handle transfering ownership from another handle. + Handle(Handle&& rhs) noexcept : handle{std::exchange(rhs.handle, nullptr)}, dld{rhs.dld} {} + + /// Assign the current handle transfering the ownership from another handle. + /// Destroys any previously held object. + Handle& operator=(Handle&& rhs) noexcept { + Release(); + handle = std::exchange(rhs.handle, nullptr); + dld = rhs.dld; + return *this; + } + + /// Destroys the current handle if it existed. + ~Handle() noexcept { + Release(); + } + + /// Destroys any held object. + void reset() noexcept { + Release(); + handle = nullptr; + } + + /// Returns the address of the held object. + /// Intended for Vulkan structures that expect a pointer to an array. + const Type* address() const noexcept { + return std::addressof(handle); + } + + /// Returns the held Vulkan handle. + Type operator*() const noexcept { + return handle; + } + + /// Returns true when there's a held object. + operator bool() const noexcept { + return handle != nullptr; + } + +protected: + Type handle = nullptr; + const Dispatch* dld = nullptr; + +private: + /// Destroys the held object if it exists. + void Release() noexcept { + if (handle) { + Destroy(handle, *dld); + } + } +}; + +/// Array of a pool allocation. +/// Analogue to std::vector +template +class PoolAllocations { +public: + /// Construct an empty allocation. + PoolAllocations() = default; + + /// Construct an allocation. Errors are reported through IsOutOfPoolMemory(). + explicit PoolAllocations(std::unique_ptr allocations_, std::size_t num_, + VkDevice device_, PoolType pool_, const DeviceDispatch& dld_) noexcept + : allocations{std::move(allocations_)}, num{num_}, device{device_}, pool{pool_}, + dld{&dld_} {} + + /// Copying Vulkan allocations is not supported and will never be. + PoolAllocations(const PoolAllocations&) = delete; + PoolAllocations& operator=(const PoolAllocations&) = delete; + + /// Construct an allocation transfering ownership from another allocation. + PoolAllocations(PoolAllocations&& rhs) noexcept + : allocations{std::move(rhs.allocations)}, num{rhs.num}, device{rhs.device}, pool{rhs.pool}, + dld{rhs.dld} {} + + /// Assign an allocation transfering ownership from another allocation. + /// Releases any previously held allocation. + PoolAllocations& operator=(PoolAllocations&& rhs) noexcept { + Release(); + allocations = std::move(rhs.allocations); + num = rhs.num; + device = rhs.device; + pool = rhs.pool; + dld = rhs.dld; + return *this; + } + + /// Destroys any held allocation. + ~PoolAllocations() { + Release(); + } + + /// Returns the number of allocations. + std::size_t size() const noexcept { + return num; + } + + /// Returns a pointer to the array of allocations. + AllocationType const* data() const noexcept { + return allocations.get(); + } + + /// Returns the allocation in the specified index. + /// @pre index < size() + AllocationType operator[](std::size_t index) const noexcept { + return allocations[index]; + } + + /// True when a pool fails to construct. + bool IsOutOfPoolMemory() const noexcept { + return !device; + } + +private: + /// Destroys the held allocations if they exist. + void Release() noexcept { + if (!allocations) { + return; + } + const Span span(allocations.get(), num); + const VkResult result = Free(device, pool, span, *dld); + // There's no way to report errors from a destructor. + if (result != VK_SUCCESS) { + std::terminate(); + } + } + + std::unique_ptr allocations; + std::size_t num = 0; + VkDevice device = nullptr; + PoolType pool = nullptr; + const DeviceDispatch* dld = nullptr; +}; + +using DebugCallback = Handle; +using DescriptorSetLayout = Handle; +using DescriptorUpdateTemplateKHR = Handle; +using Pipeline = Handle; +using PipelineLayout = Handle; +using QueryPool = Handle; +using RenderPass = Handle; +using Sampler = Handle; +using SurfaceKHR = Handle; + +using DescriptorSets = PoolAllocations; +using CommandBuffers = PoolAllocations; + +/// Vulkan instance owning handle. +class Instance : public Handle { + using Handle::Handle; + +public: + /// Creates a Vulkan instance. Use "operator bool" for error handling. + static Instance Create(u32 version, Span layers, Span extensions, + InstanceDispatch& dispatch) noexcept; + + /// Enumerates physical devices. + /// @return Physical devices and an empty handle on failure. + std::optional> EnumeratePhysicalDevices(); + + /// Tries to create a debug callback messenger. Returns an empty handle on failure. + DebugCallback TryCreateDebugCallback(PFN_vkDebugUtilsMessengerCallbackEXT callback) noexcept; +}; + +class Queue { +public: + /// Construct an empty queue handle. + constexpr Queue() noexcept = default; + + /// Construct a queue handle. + constexpr Queue(VkQueue queue_, const DeviceDispatch& dld_) noexcept + : queue{queue_}, dld{&dld_} {} + + VkResult Submit(Span submit_infos, + VkFence fence = VK_NULL_HANDLE) const noexcept { + return dld->vkQueueSubmit(queue, submit_infos.size(), submit_infos.data(), fence); + } + + VkResult Present(const VkPresentInfoKHR& present_info) const noexcept { + return dld->vkQueuePresentKHR(queue, &present_info); + } + +private: + VkQueue queue = nullptr; + const DeviceDispatch* dld = nullptr; +}; + +class Buffer : public Handle { + using Handle::Handle; + +public: + /// Attaches a memory allocation. + void BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const; + + /// Set object name. + void SetObjectNameEXT(const char* name) const; +}; + +class BufferView : public Handle { + using Handle::Handle; + +public: + /// Set object name. + void SetObjectNameEXT(const char* name) const; +}; + +class Image : public Handle { + using Handle::Handle; + +public: + /// Attaches a memory allocation. + void BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const; + + /// Set object name. + void SetObjectNameEXT(const char* name) const; +}; + +class ImageView : public Handle { + using Handle::Handle; + +public: + /// Set object name. + void SetObjectNameEXT(const char* name) const; +}; + +class DeviceMemory : public Handle { + using Handle::Handle; + +public: + /// Set object name. + void SetObjectNameEXT(const char* name) const; + + u8* Map(VkDeviceSize offset, VkDeviceSize size) const { + void* data; + Check(dld->vkMapMemory(owner, handle, offset, size, 0, &data)); + return static_cast(data); + } + + void Unmap() const noexcept { + dld->vkUnmapMemory(owner, handle); + } +}; + +class Fence : public Handle { + using Handle::Handle; + +public: + /// Set object name. + void SetObjectNameEXT(const char* name) const; + + VkResult Wait(u64 timeout = std::numeric_limits::max()) const noexcept { + return dld->vkWaitForFences(owner, 1, &handle, true, timeout); + } + + VkResult GetStatus() const noexcept { + return dld->vkGetFenceStatus(owner, handle); + } + + void Reset() const { + Check(dld->vkResetFences(owner, 1, &handle)); + } +}; + +class Framebuffer : public Handle { + using Handle::Handle; + +public: + /// Set object name. + void SetObjectNameEXT(const char* name) const; +}; + +class DescriptorPool : public Handle { + using Handle::Handle; + +public: + DescriptorSets Allocate(const VkDescriptorSetAllocateInfo& ai) const; + + /// Set object name. + void SetObjectNameEXT(const char* name) const; +}; + +class CommandPool : public Handle { + using Handle::Handle; + +public: + CommandBuffers Allocate(std::size_t num_buffers, + VkCommandBufferLevel level = VK_COMMAND_BUFFER_LEVEL_PRIMARY) const; + + /// Set object name. + void SetObjectNameEXT(const char* name) const; +}; + +class SwapchainKHR : public Handle { + using Handle::Handle; + +public: + std::vector GetImages() const; +}; + +class Event : public Handle { + using Handle::Handle; + +public: + /// Set object name. + void SetObjectNameEXT(const char* name) const; + + VkResult GetStatus() const noexcept { + return dld->vkGetEventStatus(owner, handle); + } +}; + +class ShaderModule : public Handle { + using Handle::Handle; + +public: + /// Set object name. + void SetObjectNameEXT(const char* name) const; +}; + +class Semaphore : public Handle { + using Handle::Handle; + +public: + /// Set object name. + void SetObjectNameEXT(const char* name) const; + + [[nodiscard]] u64 GetCounter() const { + u64 value; + Check(dld->vkGetSemaphoreCounterValueKHR(owner, handle, &value)); + return value; + } + + /** + * Waits for a timeline semaphore on the host. + * + * @param value Value to wait + * @param timeout Time in nanoseconds to timeout + * @return True on successful wait, false on timeout + */ + bool Wait(u64 value, u64 timeout = std::numeric_limits::max()) const { + const VkSemaphoreWaitInfoKHR wait_info{ + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO_KHR, + .pNext = nullptr, + .flags = 0, + .semaphoreCount = 1, + .pSemaphores = &handle, + .pValues = &value, + }; + const VkResult result = dld->vkWaitSemaphoresKHR(owner, &wait_info, timeout); + switch (result) { + case VK_SUCCESS: + return true; + case VK_TIMEOUT: + return false; + default: + throw Exception(result); + } + } +}; + +class Device : public Handle { + using Handle::Handle; + +public: + static Device Create(VkPhysicalDevice physical_device, Span queues_ci, + Span enabled_extensions, const void* next, + DeviceDispatch& dispatch) noexcept; + + Queue GetQueue(u32 family_index) const noexcept; + + Buffer CreateBuffer(const VkBufferCreateInfo& ci) const; + + BufferView CreateBufferView(const VkBufferViewCreateInfo& ci) const; + + Image CreateImage(const VkImageCreateInfo& ci) const; + + ImageView CreateImageView(const VkImageViewCreateInfo& ci) const; + + Semaphore CreateSemaphore() const; + + Semaphore CreateSemaphore(const VkSemaphoreCreateInfo& ci) const; + + Fence CreateFence(const VkFenceCreateInfo& ci) const; + + DescriptorPool CreateDescriptorPool(const VkDescriptorPoolCreateInfo& ci) const; + + RenderPass CreateRenderPass(const VkRenderPassCreateInfo& ci) const; + + DescriptorSetLayout CreateDescriptorSetLayout(const VkDescriptorSetLayoutCreateInfo& ci) const; + + PipelineLayout CreatePipelineLayout(const VkPipelineLayoutCreateInfo& ci) const; + + Pipeline CreateGraphicsPipeline(const VkGraphicsPipelineCreateInfo& ci) const; + + Pipeline CreateComputePipeline(const VkComputePipelineCreateInfo& ci) const; + + Sampler CreateSampler(const VkSamplerCreateInfo& ci) const; + + Framebuffer CreateFramebuffer(const VkFramebufferCreateInfo& ci) const; + + CommandPool CreateCommandPool(const VkCommandPoolCreateInfo& ci) const; + + DescriptorUpdateTemplateKHR CreateDescriptorUpdateTemplateKHR( + const VkDescriptorUpdateTemplateCreateInfoKHR& ci) const; + + QueryPool CreateQueryPool(const VkQueryPoolCreateInfo& ci) const; + + ShaderModule CreateShaderModule(const VkShaderModuleCreateInfo& ci) const; + + Event CreateEvent() const; + + SwapchainKHR CreateSwapchainKHR(const VkSwapchainCreateInfoKHR& ci) const; + + DeviceMemory TryAllocateMemory(const VkMemoryAllocateInfo& ai) const noexcept; + + DeviceMemory AllocateMemory(const VkMemoryAllocateInfo& ai) const; + + VkMemoryRequirements GetBufferMemoryRequirements(VkBuffer buffer) const noexcept; + + VkMemoryRequirements GetImageMemoryRequirements(VkImage image) const noexcept; + + void UpdateDescriptorSets(Span writes, + Span copies) const noexcept; + + void UpdateDescriptorSet(VkDescriptorSet set, VkDescriptorUpdateTemplateKHR update_template, + const void* data) const noexcept { + dld->vkUpdateDescriptorSetWithTemplateKHR(handle, set, update_template, data); + } + + VkResult AcquireNextImageKHR(VkSwapchainKHR swapchain, u64 timeout, VkSemaphore semaphore, + VkFence fence, u32* image_index) const noexcept { + return dld->vkAcquireNextImageKHR(handle, swapchain, timeout, semaphore, fence, + image_index); + } + + VkResult WaitIdle() const noexcept { + return dld->vkDeviceWaitIdle(handle); + } + + void ResetQueryPoolEXT(VkQueryPool query_pool, u32 first, u32 count) const noexcept { + dld->vkResetQueryPoolEXT(handle, query_pool, first, count); + } + + VkResult GetQueryResults(VkQueryPool query_pool, u32 first, u32 count, std::size_t data_size, + void* data, VkDeviceSize stride, + VkQueryResultFlags flags) const noexcept { + return dld->vkGetQueryPoolResults(handle, query_pool, first, count, data_size, data, stride, + flags); + } +}; + +class PhysicalDevice { +public: + constexpr PhysicalDevice() noexcept = default; + + constexpr PhysicalDevice(VkPhysicalDevice physical_device_, + const InstanceDispatch& dld_) noexcept + : physical_device{physical_device_}, dld{&dld_} {} + + constexpr operator VkPhysicalDevice() const noexcept { + return physical_device; + } + + VkPhysicalDeviceProperties GetProperties() const noexcept; + + void GetProperties2KHR(VkPhysicalDeviceProperties2KHR&) const noexcept; + + VkPhysicalDeviceFeatures GetFeatures() const noexcept; + + void GetFeatures2KHR(VkPhysicalDeviceFeatures2KHR&) const noexcept; + + VkFormatProperties GetFormatProperties(VkFormat) const noexcept; + + std::vector EnumerateDeviceExtensionProperties() const; + + std::vector GetQueueFamilyProperties() const; + + bool GetSurfaceSupportKHR(u32 queue_family_index, VkSurfaceKHR) const; + + VkSurfaceCapabilitiesKHR GetSurfaceCapabilitiesKHR(VkSurfaceKHR) const; + + std::vector GetSurfaceFormatsKHR(VkSurfaceKHR) const; + + std::vector GetSurfacePresentModesKHR(VkSurfaceKHR) const; + + VkPhysicalDeviceMemoryProperties GetMemoryProperties() const noexcept; + +private: + VkPhysicalDevice physical_device = nullptr; + const InstanceDispatch* dld = nullptr; +}; + +class CommandBuffer { +public: + CommandBuffer() noexcept = default; + + explicit CommandBuffer(VkCommandBuffer handle_, const DeviceDispatch& dld_) noexcept + : handle{handle_}, dld{&dld_} {} + + const VkCommandBuffer* address() const noexcept { + return &handle; + } + + void Begin(const VkCommandBufferBeginInfo& begin_info) const { + Check(dld->vkBeginCommandBuffer(handle, &begin_info)); + } + + void End() const { + Check(dld->vkEndCommandBuffer(handle)); + } + + void BeginRenderPass(const VkRenderPassBeginInfo& renderpass_bi, + VkSubpassContents contents) const noexcept { + dld->vkCmdBeginRenderPass(handle, &renderpass_bi, contents); + } + + void EndRenderPass() const noexcept { + dld->vkCmdEndRenderPass(handle); + } + + void BeginQuery(VkQueryPool query_pool, u32 query, VkQueryControlFlags flags) const noexcept { + dld->vkCmdBeginQuery(handle, query_pool, query, flags); + } + + void EndQuery(VkQueryPool query_pool, u32 query) const noexcept { + dld->vkCmdEndQuery(handle, query_pool, query); + } + + void BindDescriptorSets(VkPipelineBindPoint bind_point, VkPipelineLayout layout, u32 first, + Span sets, Span dynamic_offsets) const noexcept { + dld->vkCmdBindDescriptorSets(handle, bind_point, layout, first, sets.size(), sets.data(), + dynamic_offsets.size(), dynamic_offsets.data()); + } + + void BindPipeline(VkPipelineBindPoint bind_point, VkPipeline pipeline) const noexcept { + dld->vkCmdBindPipeline(handle, bind_point, pipeline); + } + + void BindIndexBuffer(VkBuffer buffer, VkDeviceSize offset, + VkIndexType index_type) const noexcept { + dld->vkCmdBindIndexBuffer(handle, buffer, offset, index_type); + } + + void BindVertexBuffers(u32 first, u32 count, const VkBuffer* buffers, + const VkDeviceSize* offsets) const noexcept { + dld->vkCmdBindVertexBuffers(handle, first, count, buffers, offsets); + } + + void BindVertexBuffer(u32 binding, VkBuffer buffer, VkDeviceSize offset) const noexcept { + BindVertexBuffers(binding, 1, &buffer, &offset); + } + + void Draw(u32 vertex_count, u32 instance_count, u32 first_vertex, + u32 first_instance) const noexcept { + dld->vkCmdDraw(handle, vertex_count, instance_count, first_vertex, first_instance); + } + + void DrawIndexed(u32 index_count, u32 instance_count, u32 first_index, u32 vertex_offset, + u32 first_instance) const noexcept { + dld->vkCmdDrawIndexed(handle, index_count, instance_count, first_index, vertex_offset, + first_instance); + } + + void ClearAttachments(Span attachments, + Span rects) const noexcept { + dld->vkCmdClearAttachments(handle, attachments.size(), attachments.data(), rects.size(), + rects.data()); + } + + void BlitImage(VkImage src_image, VkImageLayout src_layout, VkImage dst_image, + VkImageLayout dst_layout, Span regions, + VkFilter filter) const noexcept { + dld->vkCmdBlitImage(handle, src_image, src_layout, dst_image, dst_layout, regions.size(), + regions.data(), filter); + } + + void ResolveImage(VkImage src_image, VkImageLayout src_layout, VkImage dst_image, + VkImageLayout dst_layout, Span regions) { + dld->vkCmdResolveImage(handle, src_image, src_layout, dst_image, dst_layout, regions.size(), + regions.data()); + } + + void Dispatch(u32 x, u32 y, u32 z) const noexcept { + dld->vkCmdDispatch(handle, x, y, z); + } + + void PipelineBarrier(VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask, + VkDependencyFlags dependency_flags, Span memory_barriers, + Span buffer_barriers, + Span image_barriers) const noexcept { + dld->vkCmdPipelineBarrier(handle, src_stage_mask, dst_stage_mask, dependency_flags, + memory_barriers.size(), memory_barriers.data(), + buffer_barriers.size(), buffer_barriers.data(), + image_barriers.size(), image_barriers.data()); + } + + void PipelineBarrier(VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask, + VkDependencyFlags dependency_flags = 0) const noexcept { + PipelineBarrier(src_stage_mask, dst_stage_mask, dependency_flags, {}, {}, {}); + } + + void PipelineBarrier(VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask, + VkDependencyFlags dependency_flags, + const VkBufferMemoryBarrier& buffer_barrier) const noexcept { + PipelineBarrier(src_stage_mask, dst_stage_mask, dependency_flags, {}, buffer_barrier, {}); + } + + void PipelineBarrier(VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask, + VkDependencyFlags dependency_flags, + const VkImageMemoryBarrier& image_barrier) const noexcept { + PipelineBarrier(src_stage_mask, dst_stage_mask, dependency_flags, {}, {}, image_barrier); + } + + void CopyBufferToImage(VkBuffer src_buffer, VkImage dst_image, VkImageLayout dst_image_layout, + Span regions) const noexcept { + dld->vkCmdCopyBufferToImage(handle, src_buffer, dst_image, dst_image_layout, regions.size(), + regions.data()); + } + + void CopyBuffer(VkBuffer src_buffer, VkBuffer dst_buffer, + Span regions) const noexcept { + dld->vkCmdCopyBuffer(handle, src_buffer, dst_buffer, regions.size(), regions.data()); + } + + void CopyImage(VkImage src_image, VkImageLayout src_layout, VkImage dst_image, + VkImageLayout dst_layout, Span regions) const noexcept { + dld->vkCmdCopyImage(handle, src_image, src_layout, dst_image, dst_layout, regions.size(), + regions.data()); + } + + void CopyImageToBuffer(VkImage src_image, VkImageLayout src_layout, VkBuffer dst_buffer, + Span regions) const noexcept { + dld->vkCmdCopyImageToBuffer(handle, src_image, src_layout, dst_buffer, regions.size(), + regions.data()); + } + + void FillBuffer(VkBuffer dst_buffer, VkDeviceSize dst_offset, VkDeviceSize size, + u32 data) const noexcept { + dld->vkCmdFillBuffer(handle, dst_buffer, dst_offset, size, data); + } + + void PushConstants(VkPipelineLayout layout, VkShaderStageFlags flags, u32 offset, u32 size, + const void* values) const noexcept { + dld->vkCmdPushConstants(handle, layout, flags, offset, size, values); + } + + template + void PushConstants(VkPipelineLayout layout, VkShaderStageFlags flags, + const T& data) const noexcept { + static_assert(std::is_trivially_copyable_v, " is not trivially copyable"); + dld->vkCmdPushConstants(handle, layout, flags, 0, static_cast(sizeof(T)), &data); + } + + void SetViewport(u32 first, Span viewports) const noexcept { + dld->vkCmdSetViewport(handle, first, viewports.size(), viewports.data()); + } + + void SetScissor(u32 first, Span scissors) const noexcept { + dld->vkCmdSetScissor(handle, first, scissors.size(), scissors.data()); + } + + void SetBlendConstants(const float blend_constants[4]) const noexcept { + dld->vkCmdSetBlendConstants(handle, blend_constants); + } + + void SetStencilCompareMask(VkStencilFaceFlags face_mask, u32 compare_mask) const noexcept { + dld->vkCmdSetStencilCompareMask(handle, face_mask, compare_mask); + } + + void SetStencilReference(VkStencilFaceFlags face_mask, u32 reference) const noexcept { + dld->vkCmdSetStencilReference(handle, face_mask, reference); + } + + void SetStencilWriteMask(VkStencilFaceFlags face_mask, u32 write_mask) const noexcept { + dld->vkCmdSetStencilWriteMask(handle, face_mask, write_mask); + } + + void SetDepthBias(float constant_factor, float clamp, float slope_factor) const noexcept { + dld->vkCmdSetDepthBias(handle, constant_factor, clamp, slope_factor); + } + + void SetDepthBounds(float min_depth_bounds, float max_depth_bounds) const noexcept { + dld->vkCmdSetDepthBounds(handle, min_depth_bounds, max_depth_bounds); + } + + void SetEvent(VkEvent event, VkPipelineStageFlags stage_flags) const noexcept { + dld->vkCmdSetEvent(handle, event, stage_flags); + } + + void WaitEvents(Span events, VkPipelineStageFlags src_stage_mask, + VkPipelineStageFlags dst_stage_mask, Span memory_barriers, + Span buffer_barriers, + Span image_barriers) const noexcept { + dld->vkCmdWaitEvents(handle, events.size(), events.data(), src_stage_mask, dst_stage_mask, + memory_barriers.size(), memory_barriers.data(), buffer_barriers.size(), + buffer_barriers.data(), image_barriers.size(), image_barriers.data()); + } + + void BindVertexBuffers2EXT(u32 first_binding, u32 binding_count, const VkBuffer* buffers, + const VkDeviceSize* offsets, const VkDeviceSize* sizes, + const VkDeviceSize* strides) const noexcept { + dld->vkCmdBindVertexBuffers2EXT(handle, first_binding, binding_count, buffers, offsets, + sizes, strides); + } + + void SetCullModeEXT(VkCullModeFlags cull_mode) const noexcept { + dld->vkCmdSetCullModeEXT(handle, cull_mode); + } + + void SetDepthBoundsTestEnableEXT(bool enable) const noexcept { + dld->vkCmdSetDepthBoundsTestEnableEXT(handle, enable ? VK_TRUE : VK_FALSE); + } + + void SetDepthCompareOpEXT(VkCompareOp compare_op) const noexcept { + dld->vkCmdSetDepthCompareOpEXT(handle, compare_op); + } + + void SetDepthTestEnableEXT(bool enable) const noexcept { + dld->vkCmdSetDepthTestEnableEXT(handle, enable ? VK_TRUE : VK_FALSE); + } + + void SetDepthWriteEnableEXT(bool enable) const noexcept { + dld->vkCmdSetDepthWriteEnableEXT(handle, enable ? VK_TRUE : VK_FALSE); + } + + void SetFrontFaceEXT(VkFrontFace front_face) const noexcept { + dld->vkCmdSetFrontFaceEXT(handle, front_face); + } + + void SetPrimitiveTopologyEXT(VkPrimitiveTopology primitive_topology) const noexcept { + dld->vkCmdSetPrimitiveTopologyEXT(handle, primitive_topology); + } + + void SetStencilOpEXT(VkStencilFaceFlags face_mask, VkStencilOp fail_op, VkStencilOp pass_op, + VkStencilOp depth_fail_op, VkCompareOp compare_op) const noexcept { + dld->vkCmdSetStencilOpEXT(handle, face_mask, fail_op, pass_op, depth_fail_op, compare_op); + } + + void SetStencilTestEnableEXT(bool enable) const noexcept { + dld->vkCmdSetStencilTestEnableEXT(handle, enable ? VK_TRUE : VK_FALSE); + } + + void BindTransformFeedbackBuffersEXT(u32 first, u32 count, const VkBuffer* buffers, + const VkDeviceSize* offsets, + const VkDeviceSize* sizes) const noexcept { + dld->vkCmdBindTransformFeedbackBuffersEXT(handle, first, count, buffers, offsets, sizes); + } + + void BeginTransformFeedbackEXT(u32 first_counter_buffer, u32 counter_buffers_count, + const VkBuffer* counter_buffers, + const VkDeviceSize* counter_buffer_offsets) const noexcept { + dld->vkCmdBeginTransformFeedbackEXT(handle, first_counter_buffer, counter_buffers_count, + counter_buffers, counter_buffer_offsets); + } + + void EndTransformFeedbackEXT(u32 first_counter_buffer, u32 counter_buffers_count, + const VkBuffer* counter_buffers, + const VkDeviceSize* counter_buffer_offsets) const noexcept { + dld->vkCmdEndTransformFeedbackEXT(handle, first_counter_buffer, counter_buffers_count, + counter_buffers, counter_buffer_offsets); + } + + void BeginDebugUtilsLabelEXT(const char* label, std::span color) const noexcept { + const VkDebugUtilsLabelEXT label_info{ + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT, + .pNext = nullptr, + .pLabelName = label, + .color{color[0], color[1], color[2], color[3]}, + }; + dld->vkCmdBeginDebugUtilsLabelEXT(handle, &label_info); + } + + void EndDebugUtilsLabelEXT() const noexcept { + dld->vkCmdEndDebugUtilsLabelEXT(handle); + } + +private: + VkCommandBuffer handle; + const DeviceDispatch* dld; +}; + +u32 AvailableVersion(const InstanceDispatch& dld) noexcept; + +std::optional> EnumerateInstanceExtensionProperties( + const InstanceDispatch& dld); + +std::optional> EnumerateInstanceLayerProperties( + const InstanceDispatch& dld); + +} // namespace Vulkan::vk -- cgit v1.2.3 From 25f88d99cead2f7f6fdbf5e36e7578472aaa65bd Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Thu, 24 Dec 2020 22:05:48 -0300 Subject: renderer_vulkan: Move instance initialization to a separate file Simplify Vulkan's backend initialization code by moving it to a separate file, allowing us to initialize a Vulkan instance from different backends. --- src/video_core/CMakeLists.txt | 2 + src/video_core/renderer_vulkan/renderer_vulkan.cpp | 112 +-------------- src/video_core/vulkan_common/vulkan_instance.cpp | 152 +++++++++++++++++++++ src/video_core/vulkan_common/vulkan_instance.h | 21 +++ 4 files changed, 176 insertions(+), 111 deletions(-) create mode 100644 src/video_core/vulkan_common/vulkan_instance.cpp create mode 100644 src/video_core/vulkan_common/vulkan_instance.h diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index e19632bb1..f8c36947a 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -258,6 +258,8 @@ add_library(video_core STATIC textures/texture.h video_core.cpp video_core.h + vulkan_common/vulkan_instance.cpp + vulkan_common/vulkan_instance.h vulkan_common/vulkan_library.cpp vulkan_common/vulkan_library.h vulkan_common/vulkan_wrapper.cpp diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 6e267f89d..82619bc61 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -29,6 +29,7 @@ #include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_state_tracker.h" #include "video_core/renderer_vulkan/vk_swapchain.h" +#include "video_core/vulkan_common/vulkan_instance.h" #include "video_core/vulkan_common/vulkan_library.h" #include "video_core/vulkan_common/vulkan_wrapper.h" @@ -46,11 +47,7 @@ #endif namespace Vulkan { - namespace { - -using Core::Frontend::WindowSystemType; - VkBool32 DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagsEXT type, const VkDebugUtilsMessengerCallbackDataEXT* data, @@ -69,109 +66,6 @@ VkBool32 DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, return VK_FALSE; } -std::pair CreateInstance( - Common::DynamicLibrary& library, vk::InstanceDispatch& dld, - WindowSystemType window_type = WindowSystemType::Headless, bool enable_debug_utils = false, - bool enable_layers = false) { - if (!library.IsOpen()) { - LOG_ERROR(Render_Vulkan, "Vulkan library not available"); - return {}; - } - if (!library.GetSymbol("vkGetInstanceProcAddr", &dld.vkGetInstanceProcAddr)) { - LOG_ERROR(Render_Vulkan, "vkGetInstanceProcAddr not present in Vulkan"); - return {}; - } - if (!vk::Load(dld)) { - LOG_ERROR(Render_Vulkan, "Failed to load Vulkan function pointers"); - return {}; - } - - std::vector extensions; - extensions.reserve(6); - switch (window_type) { - case Core::Frontend::WindowSystemType::Headless: - break; -#ifdef _WIN32 - case Core::Frontend::WindowSystemType::Windows: - extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); - break; -#endif -#if !defined(_WIN32) && !defined(__APPLE__) - case Core::Frontend::WindowSystemType::X11: - extensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); - break; - case Core::Frontend::WindowSystemType::Wayland: - extensions.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME); - break; -#endif - default: - LOG_ERROR(Render_Vulkan, "Presentation not supported on this platform"); - break; - } - if (window_type != Core::Frontend::WindowSystemType::Headless) { - extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME); - } - if (enable_debug_utils) { - extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); - } - extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); - - const std::optional properties = vk::EnumerateInstanceExtensionProperties(dld); - if (!properties) { - LOG_ERROR(Render_Vulkan, "Failed to query extension properties"); - return {}; - } - - for (const char* extension : extensions) { - const auto it = - std::find_if(properties->begin(), properties->end(), [extension](const auto& prop) { - return !std::strcmp(extension, prop.extensionName); - }); - if (it == properties->end()) { - LOG_ERROR(Render_Vulkan, "Required instance extension {} is not available", extension); - return {}; - } - } - - std::vector layers; - layers.reserve(1); - if (enable_layers) { - layers.push_back("VK_LAYER_KHRONOS_validation"); - } - - const std::optional layer_properties = vk::EnumerateInstanceLayerProperties(dld); - if (!layer_properties) { - LOG_ERROR(Render_Vulkan, "Failed to query layer properties, disabling layers"); - layers.clear(); - } - - for (auto layer_it = layers.begin(); layer_it != layers.end();) { - const char* const layer = *layer_it; - const auto it = std::find_if( - layer_properties->begin(), layer_properties->end(), - [layer](const VkLayerProperties& prop) { return !std::strcmp(layer, prop.layerName); }); - if (it == layer_properties->end()) { - LOG_ERROR(Render_Vulkan, "Layer {} not available, removing it", layer); - layer_it = layers.erase(layer_it); - } else { - ++layer_it; - } - } - - // Limit the maximum version of Vulkan to avoid using untested version. - const u32 version = std::min(vk::AvailableVersion(dld), static_cast(VK_API_VERSION_1_1)); - - vk::Instance instance = vk::Instance::Create(version, layers, extensions, dld); - if (!instance) { - LOG_ERROR(Render_Vulkan, "Failed to create Vulkan instance"); - return {}; - } - if (!vk::Load(*instance, dld)) { - LOG_ERROR(Render_Vulkan, "Failed to load Vulkan instance function pointers"); - } - return std::make_pair(std::move(instance), version); -} - std::string GetReadableVersion(u32 version) { return fmt::format("{}.{}.{}", VK_VERSION_MAJOR(version), VK_VERSION_MINOR(version), VK_VERSION_PATCH(version)); @@ -194,7 +88,6 @@ std::string GetDriverVersion(const VKDevice& device) { const u32 minor = version & 0x3fff; return fmt::format("{}.{}", major, minor); } - return GetReadableVersion(version); } @@ -233,7 +126,6 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { if (!framebuffer) { return; } - const auto& layout = render_window.GetFramebufferLayout(); if (layout.width > 0 && layout.height > 0 && render_window.IsShown()) { const VAddr framebuffer_addr = framebuffer->address + framebuffer->offset; @@ -429,12 +321,10 @@ std::vector RendererVulkan::EnumerateDevices() { if (!instance) { return {}; } - const std::optional physical_devices = instance.EnumeratePhysicalDevices(); if (!physical_devices) { return {}; } - std::vector names; names.reserve(physical_devices->size()); for (const auto& device : *physical_devices) { diff --git a/src/video_core/vulkan_common/vulkan_instance.cpp b/src/video_core/vulkan_common/vulkan_instance.cpp new file mode 100644 index 000000000..c19f93e0a --- /dev/null +++ b/src/video_core/vulkan_common/vulkan_instance.cpp @@ -0,0 +1,152 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include +#include +#include + +#include "common/common_types.h" +#include "common/dynamic_library.h" +#include "common/logging/log.h" +#include "core/frontend/emu_window.h" +#include "video_core/vulkan_common/vulkan_instance.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" + +// Include these late to avoid polluting previous headers +#ifdef _WIN32 +#include +// ensure include order +#include +#endif + +#if !defined(_WIN32) && !defined(__APPLE__) +#include +#include +#include +#endif + +namespace Vulkan { +namespace { +[[nodiscard]] std::vector RequiredExtensions( + Core::Frontend::WindowSystemType window_type, bool enable_debug_utils) { + std::vector extensions; + extensions.reserve(6); + switch (window_type) { + case Core::Frontend::WindowSystemType::Headless: + break; +#ifdef _WIN32 + case Core::Frontend::WindowSystemType::Windows: + extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); + break; +#endif +#if !defined(_WIN32) && !defined(__APPLE__) + case Core::Frontend::WindowSystemType::X11: + extensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); + break; + case Core::Frontend::WindowSystemType::Wayland: + extensions.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME); + break; +#endif + default: + LOG_ERROR(Render_Vulkan, "Presentation not supported on this platform"); + break; + } + if (window_type != Core::Frontend::WindowSystemType::Headless) { + extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME); + } + if (enable_debug_utils) { + extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + } + extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + return extensions; +} + +[[nodiscard]] bool AreExtensionsSupported(const vk::InstanceDispatch& dld, + std::span extensions) { + const std::optional properties = vk::EnumerateInstanceExtensionProperties(dld); + if (!properties) { + LOG_ERROR(Render_Vulkan, "Failed to query extension properties"); + return false; + } + for (const char* extension : extensions) { + const auto it = std::ranges::find_if(*properties, [extension](const auto& prop) { + return std::strcmp(extension, prop.extensionName) == 0; + }); + if (it == properties->end()) { + LOG_ERROR(Render_Vulkan, "Required instance extension {} is not available", extension); + return false; + } + } + return true; +} + +[[nodiscard]] std::vector Layers(bool enable_layers) { + std::vector layers; + if (enable_layers) { + layers.push_back("VK_LAYER_KHRONOS_validation"); + } + return layers; +} + +void RemoveUnavailableLayers(const vk::InstanceDispatch& dld, std::vector& layers) { + const std::optional layer_properties = vk::EnumerateInstanceLayerProperties(dld); + if (!layer_properties) { + LOG_ERROR(Render_Vulkan, "Failed to query layer properties, disabling layers"); + layers.clear(); + } + std::erase_if(layers, [&layer_properties](const char* layer) { + const auto comp = [layer](const VkLayerProperties& layer_property) { + return std::strcmp(layer, layer_property.layerName) == 0; + }; + const auto it = std::ranges::find_if(*layer_properties, comp); + if (it == layer_properties->end()) { + LOG_ERROR(Render_Vulkan, "Layer {} not available, removing it", layer); + return true; + } + return false; + }); +} +} // Anonymous namespace + +std::pair CreateInstance(Common::DynamicLibrary& library, + vk::InstanceDispatch& dld, + Core::Frontend::WindowSystemType window_type, + bool enable_debug_utils, bool enable_layers) { + if (!library.IsOpen()) { + LOG_ERROR(Render_Vulkan, "Vulkan library not available"); + return {}; + } + if (!library.GetSymbol("vkGetInstanceProcAddr", &dld.vkGetInstanceProcAddr)) { + LOG_ERROR(Render_Vulkan, "vkGetInstanceProcAddr not present in Vulkan"); + return {}; + } + if (!vk::Load(dld)) { + LOG_ERROR(Render_Vulkan, "Failed to load Vulkan function pointers"); + return {}; + } + const std::vector extensions = RequiredExtensions(window_type, enable_debug_utils); + if (!AreExtensionsSupported(dld, extensions)) { + return {}; + } + + std::vector layers = Layers(enable_layers); + RemoveUnavailableLayers(dld, layers); + + // Limit the maximum version of Vulkan to avoid using untested version. + const u32 version = std::min(vk::AvailableVersion(dld), VK_API_VERSION_1_1); + + vk::Instance instance = vk::Instance::Create(version, layers, extensions, dld); + if (!instance) { + LOG_ERROR(Render_Vulkan, "Failed to create Vulkan instance"); + return {}; + } + if (!vk::Load(*instance, dld)) { + LOG_ERROR(Render_Vulkan, "Failed to load Vulkan instance function pointers"); + } + return std::make_pair(std::move(instance), version); +} + +} // namespace Vulkan diff --git a/src/video_core/vulkan_common/vulkan_instance.h b/src/video_core/vulkan_common/vulkan_instance.h new file mode 100644 index 000000000..ff2be0a48 --- /dev/null +++ b/src/video_core/vulkan_common/vulkan_instance.h @@ -0,0 +1,21 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include + +#include "common/common_types.h" +#include "common/dynamic_library.h" +#include "core/frontend/emu_window.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" + +namespace Vulkan { + +[[nodiscard]] std::pair CreateInstance( + Common::DynamicLibrary& library, vk::InstanceDispatch& dld, + Core::Frontend::WindowSystemType window_type = Core::Frontend::WindowSystemType::Headless, + bool enable_debug_utils = false, bool enable_layers = false); + +} // namespace Vulkan -- cgit v1.2.3 From 47843b4f097ced5e99c5567b8ac3fd53b80fab0a Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Fri, 25 Dec 2020 02:01:13 -0300 Subject: renderer_vulkan: Create debug callback on separate file and throw Initialize debug callbacks (messenger) from a separate file. This allows sharing code with different backends. Change our Vulkan error handling to use exceptions instead of error codes, simplifying the initialization process. --- src/video_core/CMakeLists.txt | 2 + src/video_core/renderer_vulkan/renderer_vulkan.cpp | 37 +++--------------- src/video_core/renderer_vulkan/renderer_vulkan.h | 4 +- .../vulkan_common/vulkan_debug_callback.cpp | 45 ++++++++++++++++++++++ .../vulkan_common/vulkan_debug_callback.h | 11 ++++++ src/video_core/vulkan_common/vulkan_instance.cpp | 14 +++---- src/video_core/vulkan_common/vulkan_wrapper.cpp | 39 +++++-------------- src/video_core/vulkan_common/vulkan_wrapper.h | 15 +++++--- 8 files changed, 88 insertions(+), 79 deletions(-) create mode 100644 src/video_core/vulkan_common/vulkan_debug_callback.cpp create mode 100644 src/video_core/vulkan_common/vulkan_debug_callback.h diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index f8c36947a..9287faee1 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -258,6 +258,8 @@ add_library(video_core STATIC textures/texture.h video_core.cpp video_core.h + vulkan_common/vulkan_debug_callback.cpp + vulkan_common/vulkan_debug_callback.h vulkan_common/vulkan_instance.cpp vulkan_common/vulkan_instance.h vulkan_common/vulkan_library.cpp diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 82619bc61..8e01dc191 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -29,6 +29,7 @@ #include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_state_tracker.h" #include "video_core/renderer_vulkan/vk_swapchain.h" +#include "video_core/vulkan_common/vulkan_debug_callback.h" #include "video_core/vulkan_common/vulkan_instance.h" #include "video_core/vulkan_common/vulkan_library.h" #include "video_core/vulkan_common/vulkan_wrapper.h" @@ -48,24 +49,6 @@ namespace Vulkan { namespace { -VkBool32 DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, - VkDebugUtilsMessageTypeFlagsEXT type, - const VkDebugUtilsMessengerCallbackDataEXT* data, - [[maybe_unused]] void* user_data) { - const char* const message{data->pMessage}; - - if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) { - LOG_CRITICAL(Render_Vulkan, "{}", message); - } else if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) { - LOG_WARNING(Render_Vulkan, "{}", message); - } else if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) { - LOG_INFO(Render_Vulkan, "{}", message); - } else if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) { - LOG_DEBUG(Render_Vulkan, "{}", message); - } - return VK_FALSE; -} - std::string GetReadableVersion(u32 version) { return fmt::format("{}.{}.{}", VK_VERSION_MAJOR(version), VK_VERSION_MINOR(version), VK_VERSION_PATCH(version)); @@ -158,7 +141,11 @@ bool RendererVulkan::Init() { library = OpenLibrary(); std::tie(instance, instance_version) = CreateInstance( library, dld, render_window.GetWindowInfo().type, true, Settings::values.renderer_debug); - if (!instance || !CreateDebugCallback() || !CreateSurface() || !PickDevices()) { + if (Settings::values.renderer_debug) { + debug_callback = CreateDebugCallback(instance); + } + + if (!CreateSurface() || !PickDevices()) { return false; } @@ -201,18 +188,6 @@ void RendererVulkan::ShutDown() { device.reset(); } -bool RendererVulkan::CreateDebugCallback() { - if (!Settings::values.renderer_debug) { - return true; - } - debug_callback = instance.TryCreateDebugCallback(DebugCallback); - if (!debug_callback) { - LOG_ERROR(Render_Vulkan, "Failed to create debug callback"); - return false; - } - return true; -} - bool RendererVulkan::CreateSurface() { [[maybe_unused]] const auto& window_info = render_window.GetWindowInfo(); VkSurfaceKHR unsafe_surface = nullptr; diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index 4a0abfaad..fa7628d0e 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h @@ -56,8 +56,6 @@ public: static std::vector EnumerateDevices(); private: - bool CreateDebugCallback(); - bool CreateSurface(); bool PickDevices(); @@ -78,7 +76,7 @@ private: VKScreenInfo screen_info; - vk::DebugCallback debug_callback; + vk::DebugUtilsMessenger debug_callback; std::unique_ptr device; std::unique_ptr memory_manager; std::unique_ptr state_tracker; diff --git a/src/video_core/vulkan_common/vulkan_debug_callback.cpp b/src/video_core/vulkan_common/vulkan_debug_callback.cpp new file mode 100644 index 000000000..ea7af8ad4 --- /dev/null +++ b/src/video_core/vulkan_common/vulkan_debug_callback.cpp @@ -0,0 +1,45 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include "common/logging/log.h" +#include "video_core/vulkan_common/vulkan_debug_callback.h" + +namespace Vulkan { +namespace { +VkBool32 Callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, + VkDebugUtilsMessageTypeFlagsEXT type, + const VkDebugUtilsMessengerCallbackDataEXT* data, + [[maybe_unused]] void* user_data) { + const std::string_view message{data->pMessage}; + if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) { + LOG_CRITICAL(Render_Vulkan, "{}", message); + } else if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) { + LOG_WARNING(Render_Vulkan, "{}", message); + } else if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) { + LOG_INFO(Render_Vulkan, "{}", message); + } else if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) { + LOG_DEBUG(Render_Vulkan, "{}", message); + } + return VK_FALSE; +} +} // Anonymous namespace + +vk::DebugUtilsMessenger CreateDebugCallback(const vk::Instance& instance) { + return instance.CreateDebugUtilsMessenger(VkDebugUtilsMessengerCreateInfoEXT{ + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, + .pNext = nullptr, + .flags = 0, + .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT, + .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, + .pfnUserCallback = Callback, + }); +} + +} // namespace Vulkan diff --git a/src/video_core/vulkan_common/vulkan_debug_callback.h b/src/video_core/vulkan_common/vulkan_debug_callback.h new file mode 100644 index 000000000..2efcd244c --- /dev/null +++ b/src/video_core/vulkan_common/vulkan_debug_callback.h @@ -0,0 +1,11 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "video_core/vulkan_common/vulkan_wrapper.h" + +namespace Vulkan { + +vk::DebugUtilsMessenger CreateDebugCallback(const vk::Instance& instance); + +} // namespace Vulkan diff --git a/src/video_core/vulkan_common/vulkan_instance.cpp b/src/video_core/vulkan_common/vulkan_instance.cpp index c19f93e0a..d3d8630e5 100644 --- a/src/video_core/vulkan_common/vulkan_instance.cpp +++ b/src/video_core/vulkan_common/vulkan_instance.cpp @@ -117,21 +117,20 @@ std::pair CreateInstance(Common::DynamicLibrary& library, bool enable_debug_utils, bool enable_layers) { if (!library.IsOpen()) { LOG_ERROR(Render_Vulkan, "Vulkan library not available"); - return {}; + throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); } if (!library.GetSymbol("vkGetInstanceProcAddr", &dld.vkGetInstanceProcAddr)) { LOG_ERROR(Render_Vulkan, "vkGetInstanceProcAddr not present in Vulkan"); - return {}; + throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); } if (!vk::Load(dld)) { LOG_ERROR(Render_Vulkan, "Failed to load Vulkan function pointers"); - return {}; + throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); } const std::vector extensions = RequiredExtensions(window_type, enable_debug_utils); if (!AreExtensionsSupported(dld, extensions)) { - return {}; + throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT); } - std::vector layers = Layers(enable_layers); RemoveUnavailableLayers(dld, layers); @@ -139,12 +138,9 @@ std::pair CreateInstance(Common::DynamicLibrary& library, const u32 version = std::min(vk::AvailableVersion(dld), VK_API_VERSION_1_1); vk::Instance instance = vk::Instance::Create(version, layers, extensions, dld); - if (!instance) { - LOG_ERROR(Render_Vulkan, "Failed to create Vulkan instance"); - return {}; - } if (!vk::Load(*instance, dld)) { LOG_ERROR(Render_Vulkan, "Failed to load Vulkan instance function pointers"); + throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); } return std::make_pair(std::move(instance), version); } diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp index 478402bbd..f4177537b 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.cpp +++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp @@ -435,7 +435,7 @@ VkResult Free(VkDevice device, VkCommandPool handle, Span buffe } Instance Instance::Create(u32 version, Span layers, Span extensions, - InstanceDispatch& dispatch) noexcept { + InstanceDispatch& dispatch) { const VkApplicationInfo application_info{ .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, .pNext = nullptr, @@ -455,22 +455,17 @@ Instance Instance::Create(u32 version, Span layers, Span> Instance::EnumeratePhysicalDevices() { +std::optional> Instance::EnumeratePhysicalDevices() const { u32 num; if (dld->vkEnumeratePhysicalDevices(handle, &num, nullptr) != VK_SUCCESS) { return std::nullopt; @@ -483,27 +478,11 @@ std::optional> Instance::EnumeratePhysicalDevices( return std::make_optional(std::move(physical_devices)); } -DebugCallback Instance::TryCreateDebugCallback( - PFN_vkDebugUtilsMessengerCallbackEXT callback) noexcept { - const VkDebugUtilsMessengerCreateInfoEXT ci{ - .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, - .pNext = nullptr, - .flags = 0, - .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT, - .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT, - .pfnUserCallback = callback, - .pUserData = nullptr, - }; - - VkDebugUtilsMessengerEXT messenger; - if (dld->vkCreateDebugUtilsMessengerEXT(handle, &ci, nullptr, &messenger) != VK_SUCCESS) { - return {}; - } - return DebugCallback(messenger, handle, *dld); +DebugUtilsMessenger Instance::CreateDebugUtilsMessenger( + const VkDebugUtilsMessengerCreateInfoEXT& create_info) const { + VkDebugUtilsMessengerEXT object; + Check(dld->vkCreateDebugUtilsMessengerEXT(handle, &create_info, nullptr, &object)); + return DebugUtilsMessenger(object, handle, *dld); } void Buffer::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const { diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h index f9a184e00..03ca97ac0 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.h +++ b/src/video_core/vulkan_common/vulkan_wrapper.h @@ -555,7 +555,7 @@ private: const DeviceDispatch* dld = nullptr; }; -using DebugCallback = Handle; +using DebugUtilsMessenger = Handle; using DescriptorSetLayout = Handle; using DescriptorUpdateTemplateKHR = Handle; using Pipeline = Handle; @@ -573,16 +573,19 @@ class Instance : public Handle { using Handle::Handle; public: - /// Creates a Vulkan instance. Use "operator bool" for error handling. + /// Creates a Vulkan instance. + /// @throw Exception on initialization error. static Instance Create(u32 version, Span layers, Span extensions, - InstanceDispatch& dispatch) noexcept; + InstanceDispatch& dispatch); /// Enumerates physical devices. /// @return Physical devices and an empty handle on failure. - std::optional> EnumeratePhysicalDevices(); + std::optional> EnumeratePhysicalDevices() const; - /// Tries to create a debug callback messenger. Returns an empty handle on failure. - DebugCallback TryCreateDebugCallback(PFN_vkDebugUtilsMessengerCallbackEXT callback) noexcept; + /// Creates a debug callback messenger. + /// @throw Exception on creation failure. + DebugUtilsMessenger CreateDebugUtilsMessenger( + const VkDebugUtilsMessengerCreateInfoEXT& create_info) const; }; class Queue { -- cgit v1.2.3 From dce8720780d7fbbe4741a68ec11232d6ea304b06 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Fri, 25 Dec 2020 02:04:31 -0300 Subject: renderer_vulkan: Catch and report exceptions Move more Vulkan code to report errors with exceptions and report them through a log before notifying it with an error boolean for backwards compatibility. In the future we can replace the rasterizer two-step initialization to always use exceptions. --- src/video_core/renderer_vulkan/renderer_vulkan.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 8e01dc191..ccdc86ed7 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -137,7 +137,7 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { render_window.OnFrameDisplayed(); } -bool RendererVulkan::Init() { +bool RendererVulkan::Init() try { library = OpenLibrary(); std::tie(instance, instance_version) = CreateInstance( library, dld, render_window.GetWindowInfo().type, true, Settings::values.renderer_debug); @@ -168,8 +168,11 @@ bool RendererVulkan::Init() { blit_screen = std::make_unique(cpu_memory, render_window, *rasterizer, *device, *memory_manager, *swapchain, *scheduler, screen_info); - return true; + +} catch (const vk::Exception& exception) { + LOG_ERROR(Render_Vulkan, "Vulkan initialization failed with error: {}", exception.what()); + return false; } void RendererVulkan::ShutDown() { -- cgit v1.2.3 From 11f0f7598df993c717752030c05f7b1eca3c762c Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Fri, 25 Dec 2020 02:14:15 -0300 Subject: renderer_vulkan: Initialize surface in separate file Move surface initialization code to a separate file. It's unlikely to use this code outside of Vulkan, but keeping platform-specific code (Win32, Xlib, Wayland) in its own translation unit keeps things cleaner. --- src/video_core/CMakeLists.txt | 2 + src/video_core/renderer_vulkan/renderer_vulkan.cpp | 74 +------------------- src/video_core/renderer_vulkan/renderer_vulkan.h | 2 - src/video_core/vulkan_common/vulkan_surface.cpp | 81 ++++++++++++++++++++++ src/video_core/vulkan_common/vulkan_surface.h | 18 +++++ src/video_core/vulkan_common/vulkan_wrapper.h | 5 ++ 6 files changed, 109 insertions(+), 73 deletions(-) create mode 100644 src/video_core/vulkan_common/vulkan_surface.cpp create mode 100644 src/video_core/vulkan_common/vulkan_surface.h diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 9287faee1..f977cf12b 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -264,6 +264,8 @@ add_library(video_core STATIC vulkan_common/vulkan_instance.h vulkan_common/vulkan_library.cpp vulkan_common/vulkan_library.h + vulkan_common/vulkan_surface.cpp + vulkan_common/vulkan_surface.h vulkan_common/vulkan_wrapper.cpp vulkan_common/vulkan_wrapper.h ) diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index ccdc86ed7..831c204c2 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -32,21 +32,9 @@ #include "video_core/vulkan_common/vulkan_debug_callback.h" #include "video_core/vulkan_common/vulkan_instance.h" #include "video_core/vulkan_common/vulkan_library.h" +#include "video_core/vulkan_common/vulkan_surface.h" #include "video_core/vulkan_common/vulkan_wrapper.h" -// Include these late to avoid polluting previous headers -#ifdef _WIN32 -#include -// ensure include order -#include -#endif - -#if !defined(_WIN32) && !defined(__APPLE__) -#include -#include -#include -#endif - namespace Vulkan { namespace { std::string GetReadableVersion(u32 version) { @@ -144,8 +132,8 @@ bool RendererVulkan::Init() try { if (Settings::values.renderer_debug) { debug_callback = CreateDebugCallback(instance); } - - if (!CreateSurface() || !PickDevices()) { + surface = CreateSurface(instance, render_window); + if (!PickDevices()) { return false; } @@ -191,62 +179,6 @@ void RendererVulkan::ShutDown() { device.reset(); } -bool RendererVulkan::CreateSurface() { - [[maybe_unused]] const auto& window_info = render_window.GetWindowInfo(); - VkSurfaceKHR unsafe_surface = nullptr; - -#ifdef _WIN32 - if (window_info.type == Core::Frontend::WindowSystemType::Windows) { - const HWND hWnd = static_cast(window_info.render_surface); - const VkWin32SurfaceCreateInfoKHR win32_ci{VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, - nullptr, 0, nullptr, hWnd}; - const auto vkCreateWin32SurfaceKHR = reinterpret_cast( - dld.vkGetInstanceProcAddr(*instance, "vkCreateWin32SurfaceKHR")); - if (!vkCreateWin32SurfaceKHR || - vkCreateWin32SurfaceKHR(*instance, &win32_ci, nullptr, &unsafe_surface) != VK_SUCCESS) { - LOG_ERROR(Render_Vulkan, "Failed to initialize Win32 surface"); - return false; - } - } -#endif -#if !defined(_WIN32) && !defined(__APPLE__) - if (window_info.type == Core::Frontend::WindowSystemType::X11) { - const VkXlibSurfaceCreateInfoKHR xlib_ci{ - VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, nullptr, 0, - static_cast(window_info.display_connection), - reinterpret_cast(window_info.render_surface)}; - const auto vkCreateXlibSurfaceKHR = reinterpret_cast( - dld.vkGetInstanceProcAddr(*instance, "vkCreateXlibSurfaceKHR")); - if (!vkCreateXlibSurfaceKHR || - vkCreateXlibSurfaceKHR(*instance, &xlib_ci, nullptr, &unsafe_surface) != VK_SUCCESS) { - LOG_ERROR(Render_Vulkan, "Failed to initialize Xlib surface"); - return false; - } - } - if (window_info.type == Core::Frontend::WindowSystemType::Wayland) { - const VkWaylandSurfaceCreateInfoKHR wayland_ci{ - VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, nullptr, 0, - static_cast(window_info.display_connection), - static_cast(window_info.render_surface)}; - const auto vkCreateWaylandSurfaceKHR = reinterpret_cast( - dld.vkGetInstanceProcAddr(*instance, "vkCreateWaylandSurfaceKHR")); - if (!vkCreateWaylandSurfaceKHR || - vkCreateWaylandSurfaceKHR(*instance, &wayland_ci, nullptr, &unsafe_surface) != - VK_SUCCESS) { - LOG_ERROR(Render_Vulkan, "Failed to initialize Wayland surface"); - return false; - } - } -#endif - if (!unsafe_surface) { - LOG_ERROR(Render_Vulkan, "Presentation not supported on this platform"); - return false; - } - - surface = vk::SurfaceKHR(unsafe_surface, *instance, dld); - return true; -} - bool RendererVulkan::PickDevices() { const auto devices = instance.EnumeratePhysicalDevices(); if (!devices) { diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index fa7628d0e..7c5ce1da4 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h @@ -56,8 +56,6 @@ public: static std::vector EnumerateDevices(); private: - bool CreateSurface(); - bool PickDevices(); void Report() const; diff --git a/src/video_core/vulkan_common/vulkan_surface.cpp b/src/video_core/vulkan_common/vulkan_surface.cpp new file mode 100644 index 000000000..3c3238f96 --- /dev/null +++ b/src/video_core/vulkan_common/vulkan_surface.cpp @@ -0,0 +1,81 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" +#include "core/frontend/emu_window.h" +#include "video_core/vulkan_common/vulkan_surface.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" + +// Include these late to avoid polluting previous headers +#ifdef _WIN32 +#include +// ensure include order +#include +#endif + +#if !defined(_WIN32) && !defined(__APPLE__) +#include +#include +#include +#endif + +namespace Vulkan { + +vk::SurfaceKHR CreateSurface(const vk::Instance& instance, + const Core::Frontend::EmuWindow& emu_window) { + [[maybe_unused]] const vk::InstanceDispatch& dld = instance.Dispatch(); + [[maybe_unused]] const auto& window_info = emu_window.GetWindowInfo(); + VkSurfaceKHR unsafe_surface = nullptr; + +#ifdef _WIN32 + if (window_info.type == Core::Frontend::WindowSystemType::Windows) { + const HWND hWnd = static_cast(window_info.render_surface); + const VkWin32SurfaceCreateInfoKHR win32_ci{VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, + nullptr, 0, nullptr, hWnd}; + const auto vkCreateWin32SurfaceKHR = reinterpret_cast( + dld.vkGetInstanceProcAddr(*instance, "vkCreateWin32SurfaceKHR")); + if (!vkCreateWin32SurfaceKHR || + vkCreateWin32SurfaceKHR(*instance, &win32_ci, nullptr, &unsafe_surface) != VK_SUCCESS) { + LOG_ERROR(Render_Vulkan, "Failed to initialize Win32 surface"); + throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); + } + } +#endif +#if !defined(_WIN32) && !defined(__APPLE__) + if (window_info.type == Core::Frontend::WindowSystemType::X11) { + const VkXlibSurfaceCreateInfoKHR xlib_ci{ + VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, nullptr, 0, + static_cast(window_info.display_connection), + reinterpret_cast(window_info.render_surface)}; + const auto vkCreateXlibSurfaceKHR = reinterpret_cast( + dld.vkGetInstanceProcAddr(*instance, "vkCreateXlibSurfaceKHR")); + if (!vkCreateXlibSurfaceKHR || + vkCreateXlibSurfaceKHR(*instance, &xlib_ci, nullptr, &unsafe_surface) != VK_SUCCESS) { + LOG_ERROR(Render_Vulkan, "Failed to initialize Xlib surface"); + throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); + } + } + if (window_info.type == Core::Frontend::WindowSystemType::Wayland) { + const VkWaylandSurfaceCreateInfoKHR wayland_ci{ + VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, nullptr, 0, + static_cast(window_info.display_connection), + static_cast(window_info.render_surface)}; + const auto vkCreateWaylandSurfaceKHR = reinterpret_cast( + dld.vkGetInstanceProcAddr(*instance, "vkCreateWaylandSurfaceKHR")); + if (!vkCreateWaylandSurfaceKHR || + vkCreateWaylandSurfaceKHR(*instance, &wayland_ci, nullptr, &unsafe_surface) != + VK_SUCCESS) { + LOG_ERROR(Render_Vulkan, "Failed to initialize Wayland surface"); + throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); + } + } +#endif + if (!unsafe_surface) { + LOG_ERROR(Render_Vulkan, "Presentation not supported on this platform"); + throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); + } + return vk::SurfaceKHR(unsafe_surface, *instance, dld); +} + +} // namespace Vulkan diff --git a/src/video_core/vulkan_common/vulkan_surface.h b/src/video_core/vulkan_common/vulkan_surface.h new file mode 100644 index 000000000..05a169e32 --- /dev/null +++ b/src/video_core/vulkan_common/vulkan_surface.h @@ -0,0 +1,18 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "video_core/vulkan_common/vulkan_wrapper.h" + +namespace Core::Frontend { +class EmuWindow; +} + +namespace Vulkan { + +[[nodiscard]] vk::SurfaceKHR CreateSurface(const vk::Instance& instance, + const Core::Frontend::EmuWindow& emu_window); + +} // namespace Vulkan diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h index 03ca97ac0..012982a3f 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.h +++ b/src/video_core/vulkan_common/vulkan_wrapper.h @@ -586,6 +586,11 @@ public: /// @throw Exception on creation failure. DebugUtilsMessenger CreateDebugUtilsMessenger( const VkDebugUtilsMessengerCreateInfoEXT& create_info) const; + + /// Returns dispatch table. + const InstanceDispatch& Dispatch() const noexcept { + return *dld; + } }; class Queue { -- cgit v1.2.3 From 085adfea00a525796a3bf4b2dd345e1df656c930 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Fri, 25 Dec 2020 02:27:57 -0300 Subject: renderer_vulkan: Throw when enumerating devices fails Report device enumeration errors with exceptions to be consistent with other initialization related function calls. Reduces the amount of code to maintain. --- src/video_core/renderer_vulkan/renderer_vulkan.cpp | 35 ++++++++-------------- src/video_core/vulkan_common/vulkan_instance.cpp | 2 +- src/video_core/vulkan_common/vulkan_instance.h | 2 +- src/video_core/vulkan_common/vulkan_wrapper.cpp | 12 +++----- src/video_core/vulkan_common/vulkan_wrapper.h | 3 +- 5 files changed, 21 insertions(+), 33 deletions(-) diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 831c204c2..f64318f25 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -170,7 +170,6 @@ void RendererVulkan::ShutDown() { if (const auto& dev = device->GetLogical()) { dev.WaitIdle(); } - rasterizer.reset(); blit_screen.reset(); scheduler.reset(); @@ -180,19 +179,13 @@ void RendererVulkan::ShutDown() { } bool RendererVulkan::PickDevices() { - const auto devices = instance.EnumeratePhysicalDevices(); - if (!devices) { - LOG_ERROR(Render_Vulkan, "Failed to enumerate physical devices"); - return false; - } - + const std::vector devices = instance.EnumeratePhysicalDevices(); const s32 device_index = Settings::values.vulkan_device.GetValue(); - if (device_index < 0 || device_index >= static_cast(devices->size())) { + if (device_index < 0 || device_index >= static_cast(devices.size())) { LOG_ERROR(Render_Vulkan, "Invalid device index {}!", device_index); return false; } - const vk::PhysicalDevice physical_device((*devices)[static_cast(device_index)], - dld); + const vk::PhysicalDevice physical_device(devices[static_cast(device_index)], dld); if (!VKDevice::IsSuitable(physical_device, *surface)) { return false; } @@ -224,23 +217,21 @@ void RendererVulkan::Report() const { telemetry_session.AddField(field, "GPU_Vulkan_Extensions", extensions); } -std::vector RendererVulkan::EnumerateDevices() { +std::vector RendererVulkan::EnumerateDevices() try { vk::InstanceDispatch dld; - Common::DynamicLibrary library = OpenLibrary(); - vk::Instance instance = CreateInstance(library, dld).first; - if (!instance) { - return {}; - } - const std::optional physical_devices = instance.EnumeratePhysicalDevices(); - if (!physical_devices) { - return {}; - } + const Common::DynamicLibrary library = OpenLibrary(); + const vk::Instance instance = CreateInstance(library, dld).first; + const std::vector physical_devices = instance.EnumeratePhysicalDevices(); std::vector names; - names.reserve(physical_devices->size()); - for (const auto& device : *physical_devices) { + names.reserve(physical_devices.size()); + for (const VkPhysicalDevice device : physical_devices) { names.push_back(vk::PhysicalDevice(device, dld).GetProperties().deviceName); } return names; + +} catch (const vk::Exception& exception) { + LOG_ERROR(Render_Vulkan, "Failed to enumerate devices with error: {}", exception.what()); + return {}; } } // namespace Vulkan diff --git a/src/video_core/vulkan_common/vulkan_instance.cpp b/src/video_core/vulkan_common/vulkan_instance.cpp index d3d8630e5..ee46fc6cc 100644 --- a/src/video_core/vulkan_common/vulkan_instance.cpp +++ b/src/video_core/vulkan_common/vulkan_instance.cpp @@ -111,7 +111,7 @@ void RemoveUnavailableLayers(const vk::InstanceDispatch& dld, std::vector CreateInstance(Common::DynamicLibrary& library, +std::pair CreateInstance(const Common::DynamicLibrary& library, vk::InstanceDispatch& dld, Core::Frontend::WindowSystemType window_type, bool enable_debug_utils, bool enable_layers) { diff --git a/src/video_core/vulkan_common/vulkan_instance.h b/src/video_core/vulkan_common/vulkan_instance.h index ff2be0a48..5acca9756 100644 --- a/src/video_core/vulkan_common/vulkan_instance.h +++ b/src/video_core/vulkan_common/vulkan_instance.h @@ -14,7 +14,7 @@ namespace Vulkan { [[nodiscard]] std::pair CreateInstance( - Common::DynamicLibrary& library, vk::InstanceDispatch& dld, + const Common::DynamicLibrary& library, vk::InstanceDispatch& dld, Core::Frontend::WindowSystemType window_type = Core::Frontend::WindowSystemType::Headless, bool enable_debug_utils = false, bool enable_layers = false); diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp index f4177537b..8698c3f92 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.cpp +++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp @@ -465,17 +465,13 @@ Instance Instance::Create(u32 version, Span layers, Span> Instance::EnumeratePhysicalDevices() const { +std::vector Instance::EnumeratePhysicalDevices() const { u32 num; - if (dld->vkEnumeratePhysicalDevices(handle, &num, nullptr) != VK_SUCCESS) { - return std::nullopt; - } + Check(dld->vkEnumeratePhysicalDevices(handle, &num, nullptr)); std::vector physical_devices(num); - if (dld->vkEnumeratePhysicalDevices(handle, &num, physical_devices.data()) != VK_SUCCESS) { - return std::nullopt; - } + Check(dld->vkEnumeratePhysicalDevices(handle, &num, physical_devices.data())); SortPhysicalDevices(physical_devices, *dld); - return std::make_optional(std::move(physical_devices)); + return physical_devices; } DebugUtilsMessenger Instance::CreateDebugUtilsMessenger( diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h index 012982a3f..af3083c84 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.h +++ b/src/video_core/vulkan_common/vulkan_wrapper.h @@ -580,7 +580,8 @@ public: /// Enumerates physical devices. /// @return Physical devices and an empty handle on failure. - std::optional> EnumeratePhysicalDevices() const; + /// @throw Exception on Vulkan error. + std::vector EnumeratePhysicalDevices() const; /// Creates a debug callback messenger. /// @throw Exception on creation failure. -- cgit v1.2.3 From 53ea06dc17ccf9232aa3326a4621500058f9d253 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Fri, 25 Dec 2020 02:42:03 -0300 Subject: renderer_vulkan: Remove two step initialization on VKDevice The Vulkan device abstraction either initializes successfully on the constructor or throws a Vulkan exception. --- src/video_core/renderer_vulkan/renderer_vulkan.cpp | 15 ++++----------- src/video_core/renderer_vulkan/renderer_vulkan.h | 2 +- src/video_core/renderer_vulkan/vk_device.cpp | 12 ++---------- src/video_core/renderer_vulkan/vk_device.h | 3 --- src/video_core/vulkan_common/vulkan_wrapper.cpp | 7 ++----- src/video_core/vulkan_common/vulkan_wrapper.h | 2 +- 6 files changed, 10 insertions(+), 31 deletions(-) diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index f64318f25..fdce11b06 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -133,10 +133,8 @@ bool RendererVulkan::Init() try { debug_callback = CreateDebugCallback(instance); } surface = CreateSurface(instance, render_window); - if (!PickDevices()) { - return false; - } + InitializeDevice(); Report(); memory_manager = std::make_unique(*device); @@ -178,21 +176,16 @@ void RendererVulkan::ShutDown() { device.reset(); } -bool RendererVulkan::PickDevices() { +void RendererVulkan::InitializeDevice() { const std::vector devices = instance.EnumeratePhysicalDevices(); const s32 device_index = Settings::values.vulkan_device.GetValue(); if (device_index < 0 || device_index >= static_cast(devices.size())) { LOG_ERROR(Render_Vulkan, "Invalid device index {}!", device_index); - return false; - } - const vk::PhysicalDevice physical_device(devices[static_cast(device_index)], dld); - if (!VKDevice::IsSuitable(physical_device, *surface)) { - return false; + throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); } - + const vk::PhysicalDevice physical_device(devices[static_cast(device_index)], dld); device = std::make_unique(*instance, instance_version, physical_device, *surface, dld); - return device->Create(); } void RendererVulkan::Report() const { diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index 7c5ce1da4..a05b3bd38 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h @@ -56,7 +56,7 @@ public: static std::vector EnumerateDevices(); private: - bool PickDevices(); + void InitializeDevice(); void Report() const; diff --git a/src/video_core/renderer_vulkan/vk_device.cpp b/src/video_core/renderer_vulkan/vk_device.cpp index f3dd6eae1..831603e87 100644 --- a/src/video_core/renderer_vulkan/vk_device.cpp +++ b/src/video_core/renderer_vulkan/vk_device.cpp @@ -212,11 +212,7 @@ VKDevice::VKDevice(VkInstance instance_, u32 instance_version_, vk::PhysicalDevi instance_version{instance_version_}, format_properties{GetFormatProperties(physical, dld)} { SetupFamilies(surface); SetupFeatures(); -} - -VKDevice::~VKDevice() = default; -bool VKDevice::Create() { const auto queue_cis = GetDeviceQueueCreateInfos(); const std::vector extensions = LoadExtensions(); @@ -426,12 +422,7 @@ bool VKDevice::Create() { }; first_next = &diagnostics_nv; } - logical = vk::Device::Create(physical, queue_cis, extensions, first_next, dld); - if (!logical) { - LOG_ERROR(Render_Vulkan, "Failed to create logical device"); - return false; - } CollectTelemetryParameters(); CollectToolingInfo(); @@ -455,9 +446,10 @@ bool VKDevice::Create() { present_queue = logical.GetQueue(present_family); use_asynchronous_shaders = Settings::values.use_asynchronous_shaders.GetValue(); - return true; } +VKDevice::~VKDevice() = default; + VkFormat VKDevice::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFlags wanted_usage, FormatType format_type) const { if (IsFormatSupported(wanted_format, wanted_usage, format_type)) { diff --git a/src/video_core/renderer_vulkan/vk_device.h b/src/video_core/renderer_vulkan/vk_device.h index 9673f47c7..67617f86d 100644 --- a/src/video_core/renderer_vulkan/vk_device.h +++ b/src/video_core/renderer_vulkan/vk_device.h @@ -28,9 +28,6 @@ public: VkSurfaceKHR surface, const vk::InstanceDispatch& dld); ~VKDevice(); - /// Initializes the device. Returns true on success. - bool Create(); - /** * Returns a format supported by the device for the passed requeriments. * @param wanted_format The ideal format to be returned. It may not be the returned format. diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp index 8698c3f92..5e15ad607 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.cpp +++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp @@ -580,7 +580,7 @@ void Semaphore::SetObjectNameEXT(const char* name) const { Device Device::Create(VkPhysicalDevice physical_device, Span queues_ci, Span enabled_extensions, const void* next, - DeviceDispatch& dispatch) noexcept { + DeviceDispatch& dispatch) { const VkDeviceCreateInfo ci{ .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, .pNext = next, @@ -593,11 +593,8 @@ Device Device::Create(VkPhysicalDevice physical_device, Span { public: static Device Create(VkPhysicalDevice physical_device, Span queues_ci, Span enabled_extensions, const void* next, - DeviceDispatch& dispatch) noexcept; + DeviceDispatch& dispatch); Queue GetQueue(u32 family_index) const noexcept; -- cgit v1.2.3 From f687392e6f29d1b65cd80a18f86a55122bde417c Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Sat, 26 Dec 2020 01:50:25 -0300 Subject: vk_device: Stop initialization when device is not suitable VKDevice::IsSuitable was not being called. To address this issue, check suitability before initialization and throw an exception if it fails. By doing this, we can deduplicate some code on queue searches. Previosuly we would first search if a present and graphics queue existed, then on initialization we would search again to find the index. --- src/video_core/renderer_vulkan/vk_device.cpp | 96 +++++++++++----------------- src/video_core/renderer_vulkan/vk_device.h | 4 +- 2 files changed, 39 insertions(+), 61 deletions(-) diff --git a/src/video_core/renderer_vulkan/vk_device.cpp b/src/video_core/renderer_vulkan/vk_device.cpp index 831603e87..07edf556d 100644 --- a/src/video_core/renderer_vulkan/vk_device.cpp +++ b/src/video_core/renderer_vulkan/vk_device.cpp @@ -210,6 +210,7 @@ VKDevice::VKDevice(VkInstance instance_, u32 instance_version_, vk::PhysicalDevi VkSurfaceKHR surface, const vk::InstanceDispatch& dld_) : instance{instance_}, dld{dld_}, physical{physical_}, properties{physical.GetProperties()}, instance_version{instance_version_}, format_properties{GetFormatProperties(physical, dld)} { + CheckSuitability(); SetupFamilies(surface); SetupFeatures(); @@ -548,64 +549,41 @@ bool VKDevice::IsFormatSupported(VkFormat wanted_format, VkFormatFeatureFlags wa return (supported_usage & wanted_usage) == wanted_usage; } -bool VKDevice::IsSuitable(vk::PhysicalDevice physical, VkSurfaceKHR surface) { - bool is_suitable = true; +void VKDevice::CheckSuitability() const { std::bitset available_extensions; - - for (const auto& prop : physical.EnumerateDeviceExtensionProperties()) { + for (const VkExtensionProperties& property : physical.EnumerateDeviceExtensionProperties()) { for (std::size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) { if (available_extensions[i]) { continue; } - const std::string_view name{prop.extensionName}; + const std::string_view name{property.extensionName}; available_extensions[i] = name == REQUIRED_EXTENSIONS[i]; } } - if (!available_extensions.all()) { - for (std::size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) { - if (available_extensions[i]) { - continue; - } - LOG_ERROR(Render_Vulkan, "Missing required extension: {}", REQUIRED_EXTENSIONS[i]); - is_suitable = false; - } - } - - bool has_graphics{}, has_present{}; - const std::vector queue_family_properties = physical.GetQueueFamilyProperties(); - for (u32 i = 0; i < static_cast(queue_family_properties.size()); ++i) { - const auto& family = queue_family_properties[i]; - if (family.queueCount == 0) { + for (size_t i = 0; i < REQUIRED_EXTENSIONS.size(); ++i) { + if (available_extensions[i]) { continue; } - has_graphics |= family.queueFlags & VK_QUEUE_GRAPHICS_BIT; - has_present |= physical.GetSurfaceSupportKHR(i, surface); + LOG_ERROR(Render_Vulkan, "Missing required extension: {}", REQUIRED_EXTENSIONS[i]); + throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT); } - if (!has_graphics || !has_present) { - LOG_ERROR(Render_Vulkan, "Device lacks a graphics and present queue"); - is_suitable = false; - } - // TODO(Rodrigo): Check if the device matches all requeriments. - const auto properties{physical.GetProperties()}; - const auto& limits{properties.limits}; + const VkPhysicalDeviceLimits& limits{properties.limits}; constexpr u32 required_ubo_size = 65536; if (limits.maxUniformBufferRange < required_ubo_size) { LOG_ERROR(Render_Vulkan, "Device UBO size {} is too small, {} is required", limits.maxUniformBufferRange, required_ubo_size); - is_suitable = false; + throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT); } - constexpr u32 required_num_viewports = 16; if (limits.maxViewports < required_num_viewports) { LOG_INFO(Render_Vulkan, "Device number of viewports {} is too small, {} is required", limits.maxViewports, required_num_viewports); - is_suitable = false; + throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT); } - - const auto features{physical.GetFeatures()}; - const std::array feature_report = { + const VkPhysicalDeviceFeatures features{physical.GetFeatures()}; + const std::array feature_report{ std::make_pair(features.vertexPipelineStoresAndAtomics, "vertexPipelineStoresAndAtomics"), std::make_pair(features.imageCubeArray, "imageCubeArray"), std::make_pair(features.independentBlend, "independentBlend"), @@ -623,19 +601,13 @@ bool VKDevice::IsSuitable(vk::PhysicalDevice physical, VkSurfaceKHR surface) { std::make_pair(features.shaderStorageImageWriteWithoutFormat, "shaderStorageImageWriteWithoutFormat"), }; - for (const auto& [supported, name] : feature_report) { - if (supported) { + for (const auto& [is_supported, name] : feature_report) { + if (is_supported) { continue; } LOG_ERROR(Render_Vulkan, "Missing required feature: {}", name); - is_suitable = false; - } - - if (!is_suitable) { - LOG_ERROR(Render_Vulkan, "{} is not suitable", properties.deviceName); + throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT); } - - return is_suitable; } std::vector VKDevice::LoadExtensions() { @@ -794,28 +766,34 @@ std::vector VKDevice::LoadExtensions() { } void VKDevice::SetupFamilies(VkSurfaceKHR surface) { - std::optional graphics_family_, present_family_; - const std::vector queue_family_properties = physical.GetQueueFamilyProperties(); - for (u32 i = 0; i < static_cast(queue_family_properties.size()); ++i) { - if (graphics_family_ && present_family_) + std::optional graphics; + std::optional present; + for (u32 index = 0; index < static_cast(queue_family_properties.size()); ++index) { + if (graphics && present) { break; - - const auto& queue_family = queue_family_properties[i]; - if (queue_family.queueCount == 0) + } + const VkQueueFamilyProperties& queue_family = queue_family_properties[index]; + if (queue_family.queueCount == 0) { continue; - + } if (queue_family.queueFlags & VK_QUEUE_GRAPHICS_BIT) { - graphics_family_ = i; + graphics = index; } - if (physical.GetSurfaceSupportKHR(i, surface)) { - present_family_ = i; + if (physical.GetSurfaceSupportKHR(index, surface)) { + present = index; } } - ASSERT(graphics_family_ && present_family_); - - graphics_family = *graphics_family_; - present_family = *present_family_; + if (!graphics) { + LOG_ERROR(Render_Vulkan, "Device lacks a graphics queue"); + throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT); + } + if (!present) { + LOG_ERROR(Render_Vulkan, "Device lacks a present queue"); + throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT); + } + graphics_family = *graphics; + present_family = *present; } void VKDevice::SetupFeatures() { diff --git a/src/video_core/renderer_vulkan/vk_device.h b/src/video_core/renderer_vulkan/vk_device.h index 67617f86d..63e123d02 100644 --- a/src/video_core/renderer_vulkan/vk_device.h +++ b/src/video_core/renderer_vulkan/vk_device.h @@ -229,10 +229,10 @@ public: return use_asynchronous_shaders; } +private: /// Checks if the physical device is suitable. - static bool IsSuitable(vk::PhysicalDevice physical, VkSurfaceKHR surface); + void CheckSuitability() const; -private: /// Loads extensions into a vector and stores available ones in this object. std::vector LoadExtensions(); -- cgit v1.2.3 From 7344a7c447af2591c393e69d39892dab217196d3 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Sat, 26 Dec 2020 02:09:55 -0300 Subject: vk_device: Use an array to report lacking device limits This makes easier to add and tune the required device limits. --- src/video_core/renderer_vulkan/vk_device.cpp | 30 ++++++++++++++++------------ 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/video_core/renderer_vulkan/vk_device.cpp b/src/video_core/renderer_vulkan/vk_device.cpp index 07edf556d..024d5c2de 100644 --- a/src/video_core/renderer_vulkan/vk_device.cpp +++ b/src/video_core/renderer_vulkan/vk_device.cpp @@ -567,20 +567,24 @@ void VKDevice::CheckSuitability() const { LOG_ERROR(Render_Vulkan, "Missing required extension: {}", REQUIRED_EXTENSIONS[i]); throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT); } - // TODO(Rodrigo): Check if the device matches all requeriments. + struct LimitTuple { + u32 minimum; + u32 value; + const char* name; + }; const VkPhysicalDeviceLimits& limits{properties.limits}; - - constexpr u32 required_ubo_size = 65536; - if (limits.maxUniformBufferRange < required_ubo_size) { - LOG_ERROR(Render_Vulkan, "Device UBO size {} is too small, {} is required", - limits.maxUniformBufferRange, required_ubo_size); - throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT); - } - constexpr u32 required_num_viewports = 16; - if (limits.maxViewports < required_num_viewports) { - LOG_INFO(Render_Vulkan, "Device number of viewports {} is too small, {} is required", - limits.maxViewports, required_num_viewports); - throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT); + const std::array limits_report{ + LimitTuple{65536, limits.maxUniformBufferRange, "maxUniformBufferRange"}, + LimitTuple{16, limits.maxViewports, "maxViewports"}, + LimitTuple{8, limits.maxColorAttachments, "maxColorAttachments"}, + LimitTuple{8, limits.maxClipDistances, "maxClipDistances"}, + }; + for (const auto& tuple : limits_report) { + if (tuple.value < tuple.minimum) { + LOG_ERROR(Render_Vulkan, "{} has to be {} or greater but it is {}", tuple.name, + tuple.minimum, tuple.value); + throw vk::Exception(VK_ERROR_FEATURE_NOT_PRESENT); + } } const VkPhysicalDeviceFeatures features{physical.GetFeatures()}; const std::array feature_report{ -- cgit v1.2.3 From cdbee27692d73046cecf56fdea1c90f72ebbc0ce Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Wed, 30 Dec 2020 04:58:38 -0300 Subject: vulkan_instance: Allow different Vulkan versions and enforce 1.1 For listing the available physical devices we can use Vulkan 1.0. Now that MoltenVK supports 1.1 we can require it for running games. Add missing documentation. --- src/video_core/renderer_vulkan/renderer_vulkan.cpp | 9 ++++----- src/video_core/renderer_vulkan/renderer_vulkan.h | 1 - src/video_core/renderer_vulkan/vk_device.cpp | 10 ++++------ src/video_core/renderer_vulkan/vk_device.h | 9 ++------- .../renderer_vulkan/vk_shader_decompiler.cpp | 11 ++--------- src/video_core/vulkan_common/vulkan_instance.cpp | 21 ++++++++++++--------- src/video_core/vulkan_common/vulkan_instance.h | 19 +++++++++++++++---- 7 files changed, 39 insertions(+), 41 deletions(-) diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index fdce11b06..5b35cb407 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -127,8 +127,8 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { bool RendererVulkan::Init() try { library = OpenLibrary(); - std::tie(instance, instance_version) = CreateInstance( - library, dld, render_window.GetWindowInfo().type, true, Settings::values.renderer_debug); + instance = CreateInstance(library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type, + true, Settings::values.renderer_debug); if (Settings::values.renderer_debug) { debug_callback = CreateDebugCallback(instance); } @@ -184,8 +184,7 @@ void RendererVulkan::InitializeDevice() { throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); } const vk::PhysicalDevice physical_device(devices[static_cast(device_index)], dld); - device = - std::make_unique(*instance, instance_version, physical_device, *surface, dld); + device = std::make_unique(*instance, physical_device, *surface, dld); } void RendererVulkan::Report() const { @@ -213,7 +212,7 @@ void RendererVulkan::Report() const { std::vector RendererVulkan::EnumerateDevices() try { vk::InstanceDispatch dld; const Common::DynamicLibrary library = OpenLibrary(); - const vk::Instance instance = CreateInstance(library, dld).first; + const vk::Instance instance = CreateInstance(library, dld, VK_API_VERSION_1_0); const std::vector physical_devices = instance.EnumeratePhysicalDevices(); std::vector names; names.reserve(physical_devices.size()); diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index a05b3bd38..f22f50709 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h @@ -68,7 +68,6 @@ private: vk::InstanceDispatch dld; vk::Instance instance; - u32 instance_version{}; vk::SurfaceKHR surface; diff --git a/src/video_core/renderer_vulkan/vk_device.cpp b/src/video_core/renderer_vulkan/vk_device.cpp index 024d5c2de..fd55ca8a8 100644 --- a/src/video_core/renderer_vulkan/vk_device.cpp +++ b/src/video_core/renderer_vulkan/vk_device.cpp @@ -206,10 +206,10 @@ std::unordered_map GetFormatProperties( } // Anonymous namespace -VKDevice::VKDevice(VkInstance instance_, u32 instance_version_, vk::PhysicalDevice physical_, - VkSurfaceKHR surface, const vk::InstanceDispatch& dld_) +VKDevice::VKDevice(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR surface, + const vk::InstanceDispatch& dld_) : instance{instance_}, dld{dld_}, physical{physical_}, properties{physical.GetProperties()}, - instance_version{instance_version_}, format_properties{GetFormatProperties(physical, dld)} { + format_properties{GetFormatProperties(physical, dld)} { CheckSuitability(); SetupFamilies(surface); SetupFeatures(); @@ -653,9 +653,7 @@ std::vector VKDevice::LoadExtensions() { test(has_ext_custom_border_color, VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME, false); test(has_ext_extended_dynamic_state, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, false); test(has_ext_robustness2, VK_EXT_ROBUSTNESS_2_EXTENSION_NAME, false); - if (instance_version >= VK_API_VERSION_1_1) { - test(has_ext_subgroup_size_control, VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME, false); - } + test(has_ext_subgroup_size_control, VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME, false); if (Settings::values.renderer_debug) { test(nv_device_diagnostics_config, VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME, true); diff --git a/src/video_core/renderer_vulkan/vk_device.h b/src/video_core/renderer_vulkan/vk_device.h index 63e123d02..146acbe24 100644 --- a/src/video_core/renderer_vulkan/vk_device.h +++ b/src/video_core/renderer_vulkan/vk_device.h @@ -24,8 +24,8 @@ const u32 GuestWarpSize = 32; /// Handles data specific to a physical device. class VKDevice final { public: - explicit VKDevice(VkInstance instance, u32 instance_version, vk::PhysicalDevice physical, - VkSurfaceKHR surface, const vk::InstanceDispatch& dld); + explicit VKDevice(VkInstance instance, vk::PhysicalDevice physical, VkSurfaceKHR surface, + const vk::InstanceDispatch& dld); ~VKDevice(); /** @@ -79,11 +79,6 @@ public: return present_family; } - /// Returns the current instance Vulkan API version in Vulkan-formatted version numbers. - u32 InstanceApiVersion() const { - return instance_version; - } - /// Returns the current Vulkan API version provided in Vulkan-formatted version numbers. u32 ApiVersion() const { return properties.apiVersion; 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) { return false; } -u32 ShaderVersion(const VKDevice& device) { - if (device.InstanceApiVersion() < VK_API_VERSION_1_1) { - return 0x00010000; - } - return 0x00010300; -} - class SPIRVDecompiler final : public Sirit::Module { public: explicit SPIRVDecompiler(const VKDevice& device_, const ShaderIR& ir_, ShaderType stage_, const Registry& registry_, const Specialization& specialization_) - : Module(ShaderVersion(device_)), device{device_}, ir{ir_}, stage{stage_}, - header{ir_.GetHeader()}, registry{registry_}, specialization{specialization_} { + : Module(0x00010300), device{device_}, ir{ir_}, stage{stage_}, header{ir_.GetHeader()}, + registry{registry_}, specialization{specialization_} { if (stage_ != ShaderType::Compute) { transform_feedback = BuildTransformFeedback(registry_.GetGraphicsInfo()); } diff --git a/src/video_core/vulkan_common/vulkan_instance.cpp b/src/video_core/vulkan_common/vulkan_instance.cpp index ee46fc6cc..889ecda0c 100644 --- a/src/video_core/vulkan_common/vulkan_instance.cpp +++ b/src/video_core/vulkan_common/vulkan_instance.cpp @@ -111,10 +111,9 @@ void RemoveUnavailableLayers(const vk::InstanceDispatch& dld, std::vector CreateInstance(const Common::DynamicLibrary& library, - vk::InstanceDispatch& dld, - Core::Frontend::WindowSystemType window_type, - bool enable_debug_utils, bool enable_layers) { +vk::Instance CreateInstance(const Common::DynamicLibrary& library, vk::InstanceDispatch& dld, + u32 required_version, Core::Frontend::WindowSystemType window_type, + bool enable_debug_utils, bool enable_layers) { if (!library.IsOpen()) { LOG_ERROR(Render_Vulkan, "Vulkan library not available"); throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); @@ -134,15 +133,19 @@ std::pair CreateInstance(const Common::DynamicLibrary& librar std::vector layers = Layers(enable_layers); RemoveUnavailableLayers(dld, layers); - // Limit the maximum version of Vulkan to avoid using untested version. - const u32 version = std::min(vk::AvailableVersion(dld), VK_API_VERSION_1_1); - - vk::Instance instance = vk::Instance::Create(version, layers, extensions, dld); + const u32 available_version = vk::AvailableVersion(dld); + if (available_version < required_version) { + LOG_ERROR(Render_Vulkan, "Vulkan {}.{} is not supported, {}.{} is required", + VK_VERSION_MAJOR(available_version), VK_VERSION_MINOR(available_version), + VK_VERSION_MAJOR(required_version), VK_VERSION_MINOR(required_version)); + throw vk::Exception(VK_ERROR_INCOMPATIBLE_DRIVER); + } + vk::Instance instance = vk::Instance::Create(required_version, layers, extensions, dld); if (!vk::Load(*instance, dld)) { LOG_ERROR(Render_Vulkan, "Failed to load Vulkan instance function pointers"); throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); } - return std::make_pair(std::move(instance), version); + return instance; } } // namespace Vulkan diff --git a/src/video_core/vulkan_common/vulkan_instance.h b/src/video_core/vulkan_common/vulkan_instance.h index 5acca9756..e5e3a7144 100644 --- a/src/video_core/vulkan_common/vulkan_instance.h +++ b/src/video_core/vulkan_common/vulkan_instance.h @@ -4,8 +4,6 @@ #pragma once -#include - #include "common/common_types.h" #include "common/dynamic_library.h" #include "core/frontend/emu_window.h" @@ -13,8 +11,21 @@ namespace Vulkan { -[[nodiscard]] std::pair CreateInstance( - const Common::DynamicLibrary& library, vk::InstanceDispatch& dld, +/** + * Create a Vulkan instance + * + * @param library Dynamic library to load the Vulkan instance from + * @param dld Dispatch table to load function pointers into + * @param required_version Required Vulkan version (for example, VK_API_VERSION_1_1) + * @param window_type Window system type's enabled extension + * @param enable_debug_utils Whether to enable VK_EXT_debug_utils_extension_name or not + * @param enable_layers Whether to enable Vulkan validation layers or not + * + * @return A new Vulkan instance + * @throw vk::Exception on failure + */ +[[nodiscard]] vk::Instance CreateInstance( + const Common::DynamicLibrary& library, vk::InstanceDispatch& dld, u32 required_version, Core::Frontend::WindowSystemType window_type = Core::Frontend::WindowSystemType::Headless, bool enable_debug_utils = false, bool enable_layers = false); -- cgit v1.2.3