From ee1a3b904ebfa1115a100acebe50cd3c0ef54b19 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sat, 4 Jan 2025 15:11:38 +1000 Subject: [PATCH] VulkanDevice: Support SDL window type --- src/util/vulkan_device.cpp | 66 +++++++++++++++++++++++++------ src/util/vulkan_entry_points.inl | 2 +- src/util/vulkan_loader.cpp | 67 ++++++++++++++++++++++++++++++++ src/util/vulkan_loader.h | 6 +++ src/util/vulkan_swap_chain.cpp | 21 ++++++++-- 5 files changed, 146 insertions(+), 16 deletions(-) diff --git a/src/util/vulkan_device.cpp b/src/util/vulkan_device.cpp index 8a3eebcad..c4cc0125a 100644 --- a/src/util/vulkan_device.cpp +++ b/src/util/vulkan_device.cpp @@ -23,6 +23,11 @@ #include "fmt/format.h" #include "xxhash.h" +#ifdef ENABLE_SDL +#include +#include +#endif + #include #include #include @@ -245,29 +250,53 @@ bool VulkanDevice::SelectInstanceExtensions(ExtensionList* extension_list, const return false; }; - // Common extensions - if (wi.type != WindowInfo::Type::Surfaceless && !SupportsExtension(VK_KHR_SURFACE_EXTENSION_NAME, true)) - return false; - #if defined(VK_USE_PLATFORM_WIN32_KHR) - if (wi.type == WindowInfo::Type::Win32 && !SupportsExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME, true)) + if (wi.type == WindowInfo::Type::Win32 && (!SupportsExtension(VK_KHR_SURFACE_EXTENSION_NAME, true) || + !SupportsExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME, true))) return false; #endif #if defined(VK_USE_PLATFORM_XCB_KHR) - if (wi.type == WindowInfo::Type::XCB && !SupportsExtension(VK_KHR_XCB_SURFACE_EXTENSION_NAME, true)) + if (wi.type == WindowInfo::Type::XCB && (!SupportsExtension(VK_KHR_SURFACE_EXTENSION_NAME, true) || + !SupportsExtension(VK_KHR_XCB_SURFACE_EXTENSION_NAME, true))) return false; #endif #if defined(VK_USE_PLATFORM_WAYLAND_KHR) - if (wi.type == WindowInfo::Type::Wayland && !SupportsExtension(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, true)) + if (wi.type == WindowInfo::Type::Wayland && (!SupportsExtension(VK_KHR_SURFACE_EXTENSION_NAME, true) || + !SupportsExtension(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, true))) return false; #endif #if defined(VK_USE_PLATFORM_METAL_EXT) - if (wi.type == WindowInfo::Type::MacOS && !SupportsExtension(VK_EXT_METAL_SURFACE_EXTENSION_NAME, true)) + if (wi.type == WindowInfo::Type::MacOS && (!SupportsExtension(VK_KHR_SURFACE_EXTENSION_NAME, true) || + !SupportsExtension(VK_EXT_METAL_SURFACE_EXTENSION_NAME, true))) + { return false; + } #endif #if defined(VK_USE_PLATFORM_ANDROID_KHR) - if (wi.type == WindowInfo::Type::Android && !SupportsExtension(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME, true)) + if (wi.type == WindowInfo::Type::Android && (!SupportsExtension(VK_KHR_SURFACE_EXTENSION_NAME, true) || + !SupportsExtension(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME, true))) + { return false; + } +#endif + +#if defined(ENABLE_SDL) + if (wi.type == WindowInfo::Type::SDL) + { + Uint32 sdl_extension_count = 0; + const char* const* sdl_extensions = SDL_Vulkan_GetInstanceExtensions(&sdl_extension_count); + if (!sdl_extensions) + { + ERROR_LOG("SDL_Vulkan_GetInstanceExtensions() failed: {}", SDL_GetError()); + return false; + } + + for (unsigned int i = 0; i < sdl_extension_count; i++) + { + if (!SupportsExtension(sdl_extensions[i], true)) + return false; + } + } #endif // VK_EXT_debug_utils @@ -374,7 +403,10 @@ VulkanDevice::GPUList VulkanDevice::EnumerateGPUs() if (Vulkan::LoadVulkanInstanceFunctions(instance)) ret = EnumerateGPUs(instance); - vkDestroyInstance(instance, nullptr); + if (vkDestroyInstance) + vkDestroyInstance(instance, nullptr); + else + ERROR_LOG("Vulkan instance was leaked because vkDestroyInstance() could not be loaded."); } Vulkan::UnloadVulkanLibrary(); @@ -1894,7 +1926,13 @@ bool VulkanDevice::CreateDeviceAndMainSwapChain(std::string_view adapter, Featur bool enable_debug_utils = m_debug_device; bool enable_validation_layer = m_debug_device; - if (!Vulkan::LoadVulkanLibrary(error)) +#ifdef ENABLE_SDL + const bool library_loaded = + (wi.type == WindowInfo::Type::SDL) ? Vulkan::LoadVulkanLibraryFromSDL(error) : Vulkan::LoadVulkanLibrary(error); +#else + const bool library_loaded = Vulkan::LoadVulkanLibrary(error); +#endif + if (!library_loaded) { Error::AddPrefix(error, "Failed to load Vulkan library. Does your GPU and/or driver support Vulkan?\nThe error was:"); @@ -1924,6 +1962,12 @@ bool VulkanDevice::CreateDeviceAndMainSwapChain(std::string_view adapter, Featur { ERROR_LOG("Failed to load Vulkan instance functions"); Error::SetStringView(error, "Failed to load Vulkan instance functions"); + + if (vkDestroyInstance) + vkDestroyInstance(std::exchange(m_instance, nullptr), nullptr); + else + ERROR_LOG("Vulkan instance was leaked because vkDestroyInstance() could not be loaded."); + return false; } diff --git a/src/util/vulkan_entry_points.inl b/src/util/vulkan_entry_points.inl index 1825cfc21..0b53dc8fe 100644 --- a/src/util/vulkan_entry_points.inl +++ b/src/util/vulkan_entry_points.inl @@ -14,12 +14,12 @@ VULKAN_MODULE_ENTRY_POINT(vkGetInstanceProcAddr, true) VULKAN_MODULE_ENTRY_POINT(vkEnumerateInstanceExtensionProperties, true) VULKAN_MODULE_ENTRY_POINT(vkEnumerateInstanceLayerProperties, true) VULKAN_MODULE_ENTRY_POINT(vkEnumerateInstanceVersion, false) -VULKAN_MODULE_ENTRY_POINT(vkDestroyInstance, true) #endif // VULKAN_MODULE_ENTRY_POINT #ifdef VULKAN_INSTANCE_ENTRY_POINT +VULKAN_INSTANCE_ENTRY_POINT(vkDestroyInstance, true) VULKAN_INSTANCE_ENTRY_POINT(vkGetDeviceProcAddr, true) VULKAN_INSTANCE_ENTRY_POINT(vkEnumeratePhysicalDevices, true) VULKAN_INSTANCE_ENTRY_POINT(vkGetPhysicalDeviceFeatures, true) diff --git a/src/util/vulkan_loader.cpp b/src/util/vulkan_loader.cpp index fa5e0f223..b717fa72d 100644 --- a/src/util/vulkan_loader.cpp +++ b/src/util/vulkan_loader.cpp @@ -11,6 +11,10 @@ #include "common/error.h" #include "common/log.h" +#ifdef ENABLE_SDL +#include +#endif + #include #include #include @@ -43,9 +47,17 @@ void Vulkan::ResetVulkanLibraryFunctionPointers() static DynamicLibrary s_vulkan_library; +#ifdef ENABLE_SDL +static bool s_vulkan_library_loaded_from_sdl = false; +#endif + bool Vulkan::IsVulkanLibraryLoaded() { +#ifdef ENABLE_SDL + return (s_vulkan_library.IsOpen() || s_vulkan_library_loaded_from_sdl); +#else return s_vulkan_library.IsOpen(); +#endif } bool Vulkan::LoadVulkanLibrary(Error* error) @@ -93,10 +105,65 @@ bool Vulkan::LoadVulkanLibrary(Error* error) return true; } +#ifdef ENABLE_SDL + +bool Vulkan::LoadVulkanLibraryFromSDL(Error* error) +{ + if (!SDL_Vulkan_LoadLibrary(nullptr)) + { + Error::SetStringFmt(error, "SDL_Vulkan_LoadLibrary() failed: {}", SDL_GetError()); + return false; + } + + vkGetInstanceProcAddr = reinterpret_cast(SDL_Vulkan_GetVkGetInstanceProcAddr()); + if (!vkGetInstanceProcAddr) + { + Error::SetStringFmt(error, "SDL_Vulkan_GetVkGetInstanceProcAddr() failed: {}", SDL_GetError()); + SDL_Vulkan_UnloadLibrary(); + return false; + } + + bool required_functions_missing = false; + + // vkGetInstanceProcAddr() can't resolve itself until Vulkan 1.2. + +#define VULKAN_MODULE_ENTRY_POINT(name, required) \ + if ((reinterpret_cast(&name) != reinterpret_cast(&vkGetInstanceProcAddr)) && \ + !(name = reinterpret_cast(vkGetInstanceProcAddr(nullptr, #name))) && required) \ + { \ + ERROR_LOG("Vulkan: Failed to load required module function {}", #name); \ + required_functions_missing = true; \ + } +#include "vulkan_entry_points.inl" +#undef VULKAN_MODULE_ENTRY_POINT + + if (required_functions_missing) + { + Error::SetStringView(error, "One or more required functions are missing. The log contains more information."); + ResetVulkanLibraryFunctionPointers(); + SDL_Vulkan_UnloadLibrary(); + return false; + } + + s_vulkan_library_loaded_from_sdl = true; + return true; +} + +#endif + void Vulkan::UnloadVulkanLibrary() { ResetVulkanLibraryFunctionPointers(); + s_vulkan_library.Close(); + +#ifdef ENABLE_SDL + if (s_vulkan_library_loaded_from_sdl) + { + s_vulkan_library_loaded_from_sdl = false; + SDL_Vulkan_UnloadLibrary(); + } +#endif } bool Vulkan::LoadVulkanInstanceFunctions(VkInstance instance) diff --git a/src/util/vulkan_loader.h b/src/util/vulkan_loader.h index ef2c6f874..2497fa375 100644 --- a/src/util/vulkan_loader.h +++ b/src/util/vulkan_loader.h @@ -59,10 +59,16 @@ class Error; #endif namespace Vulkan { + bool IsVulkanLibraryLoaded(); bool LoadVulkanLibrary(Error* error); bool LoadVulkanInstanceFunctions(VkInstance instance); bool LoadVulkanDeviceFunctions(VkDevice device); void UnloadVulkanLibrary(); void ResetVulkanLibraryFunctionPointers(); + +#ifdef ENABLE_SDL +bool LoadVulkanLibraryFromSDL(Error* error); +#endif + } // namespace Vulkan diff --git a/src/util/vulkan_swap_chain.cpp b/src/util/vulkan_swap_chain.cpp index 334e74b62..55944786e 100644 --- a/src/util/vulkan_swap_chain.cpp +++ b/src/util/vulkan_swap_chain.cpp @@ -13,14 +13,14 @@ #include #include -#if defined(VK_USE_PLATFORM_XLIB_KHR) -#include -#endif - #if defined(VK_USE_PLATFORM_METAL_EXT) #include "util/metal_layer.h" #endif +#ifdef ENABLE_SDL +#include +#endif + LOG_CHANNEL(GPUDevice); static VkFormat GetLinearFormat(VkFormat format) @@ -185,6 +185,19 @@ bool VulkanSwapChain::CreateSurface(VkInstance instance, VkPhysicalDevice physic } #endif +#if defined(ENABLE_SDL) + if (m_window_info.type == WindowInfo::Type::SDL) + { + if (!SDL_Vulkan_CreateSurface(static_cast(m_window_info.window_handle), instance, nullptr, &m_surface)) + { + Error::SetStringFmt(error, "SDL_Vulkan_CreateSurface() failed: {}", SDL_GetError()); + return false; + } + + return true; + } +#endif + Error::SetStringFmt(error, "Unhandled window type: {}", static_cast(m_window_info.type)); return false; }