From 3ffbf94b2a7460e250ae81e3eb6a40dcc1024e36 Mon Sep 17 00:00:00 2001 From: Robin Kertels Date: Fri, 7 Oct 2022 23:36:16 +0200 Subject: [PATCH] VideoBackends:Vulkan: Set up VMA Co-authored-by: iwubcode --- .../Core/VideoBackends/Vulkan/CMakeLists.txt | 1 + Source/Core/VideoBackends/Vulkan/VKMain.cpp | 15 +++--- .../VideoBackends/Vulkan/VulkanContext.cpp | 48 ++++++++++++++++--- .../Core/VideoBackends/Vulkan/VulkanContext.h | 8 +++- .../Vulkan/VulkanEntryPoints.inl | 5 ++ .../VideoBackends/Vulkan/VulkanLoader.cpp | 1 + .../Core/VideoBackends/Vulkan/VulkanLoader.h | 36 ++++++++++++++ 7 files changed, 100 insertions(+), 14 deletions(-) diff --git a/Source/Core/VideoBackends/Vulkan/CMakeLists.txt b/Source/Core/VideoBackends/Vulkan/CMakeLists.txt index 4489ca9e10..5fd6aa1ed7 100644 --- a/Source/Core/VideoBackends/Vulkan/CMakeLists.txt +++ b/Source/Core/VideoBackends/Vulkan/CMakeLists.txt @@ -52,6 +52,7 @@ PRIVATE target_include_directories(videovulkan PRIVATE ${CMAKE_SOURCE_DIR}/Externals/Vulkan/Include + ${CMAKE_SOURCE_DIR}/Externals/VulkanMemoryAllocator/include ) if(MSVC) diff --git a/Source/Core/VideoBackends/Vulkan/VKMain.cpp b/Source/Core/VideoBackends/Vulkan/VKMain.cpp index bc76aa5610..e81c5d066b 100644 --- a/Source/Core/VideoBackends/Vulkan/VKMain.cpp +++ b/Source/Core/VideoBackends/Vulkan/VKMain.cpp @@ -35,8 +35,9 @@ void VideoBackend::InitBackendInfo() if (LoadVulkanLibrary()) { - VkInstance temp_instance = - VulkanContext::CreateVulkanInstance(WindowSystemType::Headless, false, false); + u32 vk_api_version = 0; + VkInstance temp_instance = VulkanContext::CreateVulkanInstance(WindowSystemType::Headless, + false, false, &vk_api_version); if (temp_instance) { if (LoadVulkanInstanceFunctions(temp_instance)) @@ -114,8 +115,9 @@ bool VideoBackend::Initialize(const WindowSystemInfo& wsi) // We use this instance to fill in backend info, then re-use it for the actual device. bool enable_surface = wsi.type != WindowSystemType::Headless; bool enable_debug_reports = ShouldEnableDebugReports(enable_validation_layer); - VkInstance instance = - VulkanContext::CreateVulkanInstance(wsi.type, enable_debug_reports, enable_validation_layer); + u32 vk_api_version = 0; + VkInstance instance = VulkanContext::CreateVulkanInstance( + wsi.type, enable_debug_reports, enable_validation_layer, &vk_api_version); if (instance == VK_NULL_HANDLE) { PanicAlertFmt("Failed to create Vulkan instance."); @@ -171,8 +173,9 @@ bool VideoBackend::Initialize(const WindowSystemInfo& wsi) } // Now we can create the Vulkan device. VulkanContext takes ownership of the instance and surface. - g_vulkan_context = VulkanContext::Create(instance, gpu_list[selected_adapter_index], surface, - enable_debug_reports, enable_validation_layer); + g_vulkan_context = + VulkanContext::Create(instance, gpu_list[selected_adapter_index], surface, + enable_debug_reports, enable_validation_layer, vk_api_version); if (!g_vulkan_context) { PanicAlertFmt("Failed to create Vulkan device"); diff --git a/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp b/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp index bc9cc1169b..6df7ed3414 100644 --- a/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp +++ b/Source/Core/VideoBackends/Vulkan/VulkanContext.cpp @@ -40,6 +40,8 @@ VulkanContext::VulkanContext(VkInstance instance, VkPhysicalDevice physical_devi VulkanContext::~VulkanContext() { + if (m_allocator != VK_NULL_HANDLE) + vmaDestroyAllocator(m_allocator); if (m_device != VK_NULL_HANDLE) vkDestroyDevice(m_device, nullptr); @@ -86,7 +88,8 @@ bool VulkanContext::CheckValidationLayerAvailablility() } VkInstance VulkanContext::CreateVulkanInstance(WindowSystemType wstype, bool enable_debug_report, - bool enable_validation_layer) + bool enable_validation_layer, + u32* out_vk_api_version) { std::vector enabled_extensions; if (!SelectInstanceExtensions(&enabled_extensions, wstype, enable_debug_report)) @@ -114,6 +117,8 @@ VkInstance VulkanContext::CreateVulkanInstance(WindowSystemType wstype, bool ena } } + *out_vk_api_version = app_info.apiVersion; + VkInstanceCreateInfo instance_create_info = {}; instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; instance_create_info.pNext = nullptr; @@ -429,10 +434,9 @@ void VulkanContext::PopulateBackendInfoMultisampleModes( config->backend_info.AAModes.emplace_back(64); } -std::unique_ptr VulkanContext::Create(VkInstance instance, VkPhysicalDevice gpu, - VkSurfaceKHR surface, - bool enable_debug_reports, - bool enable_validation_layer) +std::unique_ptr +VulkanContext::Create(VkInstance instance, VkPhysicalDevice gpu, VkSurfaceKHR surface, + bool enable_debug_reports, bool enable_validation_layer, u32 vk_api_version) { std::unique_ptr context = std::make_unique(instance, gpu); @@ -445,7 +449,8 @@ std::unique_ptr VulkanContext::Create(VkInstance instance, VkPhys context->EnableDebugReports(); // Attempt to create the device. - if (!context->CreateDevice(surface, enable_validation_layer)) + if (!context->CreateDevice(surface, enable_validation_layer) || + !context->CreateAllocator(vk_api_version)) { // Since we are destroying the instance, we're also responsible for destroying the surface. if (surface != VK_NULL_HANDLE) @@ -508,6 +513,9 @@ bool VulkanContext::SelectDeviceExtensions(bool enable_surface) INFO_LOG_FMT(VIDEO, "Using VK_EXT_full_screen_exclusive for exclusive fullscreen."); #endif + AddExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, false); + AddExtension(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME, false); + return true; } @@ -695,6 +703,34 @@ bool VulkanContext::CreateDevice(VkSurfaceKHR surface, bool enable_validation_la return true; } +bool VulkanContext::CreateAllocator(u32 vk_api_version) +{ + VmaAllocatorCreateInfo allocator_info = {}; + allocator_info.flags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT; + allocator_info.physicalDevice = m_physical_device; + allocator_info.device = m_device; + allocator_info.preferredLargeHeapBlockSize = 64 << 20; + allocator_info.pAllocationCallbacks = nullptr; + allocator_info.pDeviceMemoryCallbacks = nullptr; + allocator_info.pHeapSizeLimit = nullptr; + allocator_info.pVulkanFunctions = nullptr; + allocator_info.instance = m_instance; + allocator_info.vulkanApiVersion = vk_api_version; + allocator_info.pTypeExternalMemoryHandleTypes = nullptr; + + if (SupportsDeviceExtension(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME)) + allocator_info.flags |= VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT; + + VkResult res = vmaCreateAllocator(&allocator_info, &m_allocator); + if (res != VK_SUCCESS) + { + LOG_VULKAN_ERROR(res, "vmaCreateAllocator failed: "); + return false; + } + + return true; +} + static VKAPI_ATTR VkBool32 VKAPI_CALL DebugReportCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, diff --git a/Source/Core/VideoBackends/Vulkan/VulkanContext.h b/Source/Core/VideoBackends/Vulkan/VulkanContext.h index 7f5d72a7d9..522ce69d13 100644 --- a/Source/Core/VideoBackends/Vulkan/VulkanContext.h +++ b/Source/Core/VideoBackends/Vulkan/VulkanContext.h @@ -26,7 +26,7 @@ public: // Helper method to create a Vulkan instance. static VkInstance CreateVulkanInstance(WindowSystemType wstype, bool enable_debug_report, - bool enable_validation_layer); + bool enable_validation_layer, u32* out_vk_api_version); // Returns a list of Vulkan-compatible GPUs. using GPUList = std::vector; @@ -47,7 +47,7 @@ public: // been called for the specified VideoConfig. static std::unique_ptr Create(VkInstance instance, VkPhysicalDevice gpu, VkSurfaceKHR surface, bool enable_debug_reports, - bool enable_validation_layer); + bool enable_validation_layer, u32 api_version); // Enable/disable debug message runtime. bool EnableDebugReports(); @@ -113,6 +113,8 @@ public: // Returns true if exclusive fullscreen is supported for the given surface. bool SupportsExclusiveFullscreen(const WindowSystemInfo& wsi, VkSurfaceKHR surface); + VmaAllocator GetMemoryAllocator() const { return m_allocator; } + #ifdef WIN32 // Returns the platform-specific exclusive fullscreen structure. VkSurfaceFullScreenExclusiveWin32InfoEXT @@ -127,10 +129,12 @@ private: bool CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer); void InitDriverDetails(); void PopulateShaderSubgroupSupport(); + bool CreateAllocator(u32 vk_api_version); VkInstance m_instance = VK_NULL_HANDLE; VkPhysicalDevice m_physical_device = VK_NULL_HANDLE; VkDevice m_device = VK_NULL_HANDLE; + VmaAllocator m_allocator = VK_NULL_HANDLE; VkQueue m_graphics_queue = VK_NULL_HANDLE; u32 m_graphics_queue_family_index = 0; diff --git a/Source/Core/VideoBackends/Vulkan/VulkanEntryPoints.inl b/Source/Core/VideoBackends/Vulkan/VulkanEntryPoints.inl index 8c6db283c9..3bb21c41e3 100644 --- a/Source/Core/VideoBackends/Vulkan/VulkanEntryPoints.inl +++ b/Source/Core/VideoBackends/Vulkan/VulkanEntryPoints.inl @@ -37,6 +37,7 @@ VULKAN_INSTANCE_ENTRY_POINT(vkGetPhysicalDeviceSurfaceSupportKHR, false) VULKAN_INSTANCE_ENTRY_POINT(vkGetPhysicalDeviceSurfaceCapabilitiesKHR, false) VULKAN_INSTANCE_ENTRY_POINT(vkGetPhysicalDeviceSurfaceFormatsKHR, false) VULKAN_INSTANCE_ENTRY_POINT(vkGetPhysicalDeviceSurfacePresentModesKHR, false) +VULKAN_INSTANCE_ENTRY_POINT(vkGetPhysicalDeviceMemoryProperties2, false) #if defined(VK_USE_PLATFORM_WIN32_KHR) VULKAN_INSTANCE_ENTRY_POINT(vkCreateWin32SurfaceKHR, false) @@ -192,6 +193,10 @@ VULKAN_DEVICE_ENTRY_POINT(vkDestroySwapchainKHR, false) VULKAN_DEVICE_ENTRY_POINT(vkGetSwapchainImagesKHR, false) VULKAN_DEVICE_ENTRY_POINT(vkAcquireNextImageKHR, false) VULKAN_DEVICE_ENTRY_POINT(vkQueuePresentKHR, false) +VULKAN_DEVICE_ENTRY_POINT(vkGetBufferMemoryRequirements2, false) +VULKAN_DEVICE_ENTRY_POINT(vkGetImageMemoryRequirements2, false) +VULKAN_DEVICE_ENTRY_POINT(vkBindBufferMemory2, false) +VULKAN_DEVICE_ENTRY_POINT(vkBindImageMemory2, false) #ifdef SUPPORTS_VULKAN_EXCLUSIVE_FULLSCREEN VULKAN_DEVICE_ENTRY_POINT(vkAcquireFullScreenExclusiveModeEXT, false) diff --git a/Source/Core/VideoBackends/Vulkan/VulkanLoader.cpp b/Source/Core/VideoBackends/Vulkan/VulkanLoader.cpp index c554f07314..9b62244dfd 100644 --- a/Source/Core/VideoBackends/Vulkan/VulkanLoader.cpp +++ b/Source/Core/VideoBackends/Vulkan/VulkanLoader.cpp @@ -1,6 +1,7 @@ // Copyright 2016 Dolphin Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#define VMA_IMPLEMENTATION #include "VideoBackends/Vulkan/VulkanLoader.h" #include diff --git a/Source/Core/VideoBackends/Vulkan/VulkanLoader.h b/Source/Core/VideoBackends/Vulkan/VulkanLoader.h index 2d6843953b..c9b92f5ac8 100644 --- a/Source/Core/VideoBackends/Vulkan/VulkanLoader.h +++ b/Source/Core/VideoBackends/Vulkan/VulkanLoader.h @@ -37,6 +37,42 @@ #undef VULKAN_INSTANCE_ENTRY_POINT #undef VULKAN_MODULE_ENTRY_POINT +// Include vma allocator globally since including it before the vulkan headers causes +// errors +#ifdef _MSVC_LANG +#pragma warning(push, 4) +#pragma warning(disable : 4189) // local variable is initialized but not referenced + +#endif // #ifdef _MSVC_LANG + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-variable" +#endif // #ifdef __clang__ + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-variable" +#endif // #ifdef __GNUC__ + +#define VMA_VULKAN_VERSION 1001000 +#define VMA_STATIC_VULKAN_FUNCTIONS 1 +#define VMA_DYNAMIC_VULKAN_FUNCTIONS 0 +#undef VK_NO_PROTOTYPES +#include "vk_mem_alloc.h" + +#ifdef _MSVC_LANG +#pragma warning(pop) +#endif // #ifdef _MSVC_LANG + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif // #ifdef __clang__ + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif // #ifdef __GNUC__ + #include "Common/Logging/Log.h" namespace Vulkan