From 412d69d2694c3e27ac35d12f83e857f49724f2a2 Mon Sep 17 00:00:00 2001 From: Adam Sawicki Date: Wed, 9 Apr 2025 18:11:44 +0200 Subject: [PATCH 1/4] Added vmaImportVulkanFunctionsFromVolk --- Doxyfile | 3 +- include/vk_mem_alloc.h | 86 ++++++++++++++++++++++++++++++++++++++++++ src/Tests.cpp | 5 +++ src/VmaUsage.h | 3 +- src/VolkUsage.cpp | 29 ++++++++++++++ src/VulkanSample.cpp | 19 +++++++++- 6 files changed, 141 insertions(+), 4 deletions(-) create mode 100644 src/VolkUsage.cpp diff --git a/Doxyfile b/Doxyfile index 2b6bcc99..346537cf 100644 --- a/Doxyfile +++ b/Doxyfile @@ -2469,7 +2469,8 @@ PREDEFINED = VMA_CALL_PRE= \ VMA_EXTERNAL_MEMORY_WIN32=1 \ VMA_EXTERNAL_MEMORY=1 \ VMA_EXTENDS_VK_STRUCT= \ - VMA_STATS_STRING_ENABLED=1 + VMA_STATS_STRING_ENABLED=1 \ + VOLK_HEADER_VERSION=304 # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The diff --git a/include/vk_mem_alloc.h b/include/vk_mem_alloc.h index 3639f618..9004642d 100644 --- a/include/vk_mem_alloc.h +++ b/include/vk_mem_alloc.h @@ -1669,6 +1669,20 @@ typedef struct VmaVirtualAllocationInfo @{ */ +#ifdef VOLK_HEADER_VERSION +/** \brief Fully initializes `dst` structure with Vulkan functions needed by this library based on functions imported by +[volk library](https://github.com/zeux/volk). + +If you use volk, call this function after `VkInstance` and `VkDevice` is created to fill in structure #VmaVulkanFunctions +before calling vmaCreateAllocator(). + +Pointers to functions related to the entire Vulkan instance are fetched using global function definitions. +Pointers to functions related to the Vulkan device are fetched using `volkLoadDeviceTable()` for given `device`. + */ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaImportVulkanFunctionsFromVolk( + VkDevice VMA_NOT_NULL device, VmaVulkanFunctions* VMA_NOT_NULL dst); +#endif + /// Creates #VmaAllocator object. VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAllocator( const VmaAllocatorCreateInfo* VMA_NOT_NULL pCreateInfo, @@ -15082,6 +15096,78 @@ void VmaAllocator_T::PrintDetailedMap(VmaJsonWriter& json) #ifndef _VMA_PUBLIC_INTERFACE + +#ifdef VOLK_HEADER_VERSION + +VMA_CALL_PRE VkResult VMA_CALL_POST vmaImportVulkanFunctionsFromVolk( + VkDevice VMA_NOT_NULL device, VmaVulkanFunctions* VMA_NOT_NULL dst) +{ + VolkDeviceTable src = {}; + memset(&dst, 0, sizeof(dst)); + memset(&src, 0, sizeof(src)); + + volkLoadDeviceTable(&src, device); + +#define COPY_GLOBAL_TO_VMA_FUNC(volkName, vmaName) if(!dst->vmaName) dst->vmaName = volkName; +#define COPY_DEVICE_TO_VMA_FUNC(volkName, vmaName) if(!dst->vmaName) dst->vmaName = src.volkName; + + COPY_GLOBAL_TO_VMA_FUNC(vkGetInstanceProcAddr, vkGetInstanceProcAddr) + COPY_GLOBAL_TO_VMA_FUNC(vkGetDeviceProcAddr, vkGetDeviceProcAddr) + COPY_GLOBAL_TO_VMA_FUNC(vkGetPhysicalDeviceProperties, vkGetPhysicalDeviceProperties) + COPY_GLOBAL_TO_VMA_FUNC(vkGetPhysicalDeviceMemoryProperties, vkGetPhysicalDeviceMemoryProperties) + COPY_DEVICE_TO_VMA_FUNC(vkAllocateMemory, vkAllocateMemory) + COPY_DEVICE_TO_VMA_FUNC(vkFreeMemory, vkFreeMemory) + COPY_DEVICE_TO_VMA_FUNC(vkMapMemory, vkMapMemory) + COPY_DEVICE_TO_VMA_FUNC(vkUnmapMemory, vkUnmapMemory) + COPY_DEVICE_TO_VMA_FUNC(vkFlushMappedMemoryRanges, vkFlushMappedMemoryRanges) + COPY_DEVICE_TO_VMA_FUNC(vkInvalidateMappedMemoryRanges, vkInvalidateMappedMemoryRanges) + COPY_DEVICE_TO_VMA_FUNC(vkBindBufferMemory, vkBindBufferMemory) + COPY_DEVICE_TO_VMA_FUNC(vkBindImageMemory, vkBindImageMemory) + COPY_DEVICE_TO_VMA_FUNC(vkGetBufferMemoryRequirements, vkGetBufferMemoryRequirements) + COPY_DEVICE_TO_VMA_FUNC(vkGetImageMemoryRequirements, vkGetImageMemoryRequirements) + COPY_DEVICE_TO_VMA_FUNC(vkCreateBuffer, vkCreateBuffer) + COPY_DEVICE_TO_VMA_FUNC(vkDestroyBuffer, vkDestroyBuffer) + COPY_DEVICE_TO_VMA_FUNC(vkCreateImage, vkCreateImage) + COPY_DEVICE_TO_VMA_FUNC(vkDestroyImage, vkDestroyImage) + COPY_DEVICE_TO_VMA_FUNC(vkCmdCopyBuffer, vkCmdCopyBuffer) +#if VMA_VULKAN_VERSION >= 1001000 + COPY_GLOBAL_TO_VMA_FUNC(vkGetPhysicalDeviceMemoryProperties2, vkGetPhysicalDeviceMemoryProperties2KHR) + COPY_DEVICE_TO_VMA_FUNC(vkGetBufferMemoryRequirements2, vkGetBufferMemoryRequirements2KHR) + COPY_DEVICE_TO_VMA_FUNC(vkGetImageMemoryRequirements2, vkGetImageMemoryRequirements2KHR) + COPY_DEVICE_TO_VMA_FUNC(vkBindBufferMemory2, vkBindBufferMemory2KHR) + COPY_DEVICE_TO_VMA_FUNC(vkBindImageMemory2, vkBindImageMemory2KHR) +#endif +#if VMA_VULKAN_VERSION >= 1003000 + COPY_DEVICE_TO_VMA_FUNC(vkGetDeviceBufferMemoryRequirements, vkGetDeviceBufferMemoryRequirements) + COPY_DEVICE_TO_VMA_FUNC(vkGetDeviceImageMemoryRequirements, vkGetDeviceImageMemoryRequirements) +#endif +#if VMA_KHR_MAINTENANCE4 + COPY_DEVICE_TO_VMA_FUNC(vkGetDeviceBufferMemoryRequirementsKHR, vkGetDeviceBufferMemoryRequirements) + COPY_DEVICE_TO_VMA_FUNC(vkGetDeviceImageMemoryRequirementsKHR, vkGetDeviceImageMemoryRequirements) +#endif +#if VMA_DEDICATED_ALLOCATION + COPY_DEVICE_TO_VMA_FUNC(vkGetBufferMemoryRequirements2KHR, vkGetBufferMemoryRequirements2KHR) + COPY_DEVICE_TO_VMA_FUNC(vkGetImageMemoryRequirements2KHR, vkGetImageMemoryRequirements2KHR) +#endif +#if VMA_BIND_MEMORY2 + COPY_DEVICE_TO_VMA_FUNC(vkBindBufferMemory2KHR, vkBindBufferMemory2KHR) + COPY_DEVICE_TO_VMA_FUNC(vkBindImageMemory2KHR, vkBindImageMemory2KHR) +#endif +#if VMA_MEMORY_BUDGET + COPY_GLOBAL_TO_VMA_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, vkGetPhysicalDeviceMemoryProperties2KHR) +#endif +#if VMA_EXTERNAL_MEMORY_WIN32 + COPY_DEVICE_TO_VMA_FUNC(vkGetMemoryWin32HandleKHR, vkGetMemoryWin32HandleKHR) +#endif + +#undef COPY_DEVICE_TO_VMA_FUNC +#undef COPY_GLOBAL_TO_VMA_FUNC + + return VK_SUCCESS; +} + +#endif // #ifdef VOLK_HEADER_VERSION + VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAllocator( const VmaAllocatorCreateInfo* pCreateInfo, VmaAllocator* pAllocator) diff --git a/src/Tests.cpp b/src/Tests.cpp index b10ee6db..5ca56591 100644 --- a/src/Tests.cpp +++ b/src/Tests.cpp @@ -3902,6 +3902,11 @@ void TestHeapSizeLimit() allocatorCreateInfo.device = g_hDevice; allocatorCreateInfo.instance = g_hVulkanInstance; allocatorCreateInfo.pHeapSizeLimit = heapSizeLimit; +#ifdef VOLK_HEADER_VERSION + VmaVulkanFunctions vulkanFunctions = {}; + vmaImportVulkanFunctionsFromVolk(g_hDevice, &vulkanFunctions); + allocatorCreateInfo.pVulkanFunctions = &vulkanFunctions; +#endif #if VMA_DYNAMIC_VULKAN_FUNCTIONS VmaVulkanFunctions vulkanFunctions = {}; vulkanFunctions.vkGetInstanceProcAddr = vkGetInstanceProcAddr; diff --git a/src/VmaUsage.h b/src/VmaUsage.h index 906d6b93..9442487c 100644 --- a/src/VmaUsage.h +++ b/src/VmaUsage.h @@ -96,7 +96,8 @@ include all public interface declarations. Example: #pragma clang diagnostic ignored "-Wnullability-completeness" #endif -#include +//#include +#include "third_party/volk-1.4.304/volk.h" #ifdef _WIN32 #include diff --git a/src/VolkUsage.cpp b/src/VolkUsage.cpp new file mode 100644 index 00000000..e129304a --- /dev/null +++ b/src/VolkUsage.cpp @@ -0,0 +1,29 @@ +// +// Copyright (c) 2017-2025 Advanced Micro Devices, Inc. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +/* +In exactly one CPP file define macro VMA_IMPLEMENTATION and then include +vk_mem_alloc.h to include definitions of its internal implementation +*/ + +#define VOLK_IMPLEMENTATION +#include "VmaUsage.h" diff --git a/src/VulkanSample.cpp b/src/VulkanSample.cpp index a8d1f3ed..abf20e3f 100644 --- a/src/VulkanSample.cpp +++ b/src/VulkanSample.cpp @@ -426,6 +426,8 @@ void VulkanUsage::Init() g_Allocs = &g_CpuAllocationCallbacks; } + ERR_GUARD_VULKAN(volkInitialize()); + uint32_t instanceLayerPropCount = 0; ERR_GUARD_VULKAN( vkEnumerateInstanceLayerProperties(&instanceLayerPropCount, nullptr) ); std::vector instanceLayerProps(instanceLayerPropCount); @@ -513,6 +515,8 @@ void VulkanUsage::Init() ERR_GUARD_VULKAN( vkCreateInstance(&instInfo, g_Allocs, &g_hVulkanInstance) ); + volkLoadInstance(g_hVulkanInstance); + if(VK_EXT_debug_utils_enabled) { RegisterDebugCallbacks(); @@ -1511,12 +1515,22 @@ void SetAllocatorCreateInfo(VmaAllocatorCreateInfo& outInfo) outInfo.pAllocationCallbacks = &g_CpuAllocationCallbacks; } -#if VMA_DYNAMIC_VULKAN_FUNCTIONS +#ifdef VOLK_HEADER_VERSION + static VmaVulkanFunctions vulkanFunctions = {}; + vmaImportVulkanFunctionsFromVolk(g_hDevice, &vulkanFunctions); + outInfo.pVulkanFunctions = &vulkanFunctions; + +#else // #ifdef VOLK_HEADER_VERSION + +#if VMA_DYNAMIC_VULKAN_FUNCTIONS +v static VmaVulkanFunctions vulkanFunctions = {}; vulkanFunctions.vkGetInstanceProcAddr = vkGetInstanceProcAddr; vulkanFunctions.vkGetDeviceProcAddr = vkGetDeviceProcAddr; outInfo.pVulkanFunctions = &vulkanFunctions; -#endif +#endif // #if VMA_DYNAMIC_VULKAN_FUNCTIONS + +#endif // #ifdef VOLK_HEADER_VERSION // Uncomment to enable HeapSizeLimit. /* @@ -2083,6 +2097,7 @@ static void InitializeApplication() deviceCreateInfo.pQueueCreateInfos = queueCreateInfo; ERR_GUARD_VULKAN( vkCreateDevice(g_hPhysicalDevice, &deviceCreateInfo, g_Allocs, &g_hDevice) ); + volkLoadDevice(g_hDevice); SetDebugUtilsObjectName(VK_OBJECT_TYPE_DEVICE, reinterpret_cast(g_hDevice), "g_hDevice"); // Only now that SetDebugUtilsObjectName is loaded, we can assign a name to g_hVulkanInstance as well SetDebugUtilsObjectName(VK_OBJECT_TYPE_INSTANCE, reinterpret_cast(g_hVulkanInstance), "g_hVulkanInstance"); From 49322c0e4c06b476a0f3557da6df703d929d13c8 Mon Sep 17 00:00:00 2001 From: Adam Sawicki Date: Thu, 10 Apr 2025 20:05:09 +0200 Subject: [PATCH 2/4] More work on function vmaImportVulkanFunctionsFromVolk Also added Cmake option VMA_VOLK_HEADER_PATH. Also updated the documentation. --- include/vk_mem_alloc.h | 128 +++++++++++++++++++++++++++++++---------- src/CMakeLists.txt | 11 ++++ src/Tests.cpp | 2 +- src/VmaUsage.h | 9 ++- src/VolkUsage.cpp | 7 +-- src/VulkanSample.cpp | 18 +++--- 6 files changed, 129 insertions(+), 46 deletions(-) diff --git a/include/vk_mem_alloc.h b/include/vk_mem_alloc.h index 9004642d..5488c75a 100644 --- a/include/vk_mem_alloc.h +++ b/include/vk_mem_alloc.h @@ -1670,17 +1670,55 @@ typedef struct VmaVirtualAllocationInfo */ #ifdef VOLK_HEADER_VERSION -/** \brief Fully initializes `dst` structure with Vulkan functions needed by this library based on functions imported by +/** \brief Fully initializes `pDstVulkanFunctions` structure with Vulkan functions needed by this library based on functions imported by [volk library](https://github.com/zeux/volk). -If you use volk, call this function after `VkInstance` and `VkDevice` is created to fill in structure #VmaVulkanFunctions -before calling vmaCreateAllocator(). +This function is defined in VMA header only if "volk.h" was included before it. -Pointers to functions related to the entire Vulkan instance are fetched using global function definitions. -Pointers to functions related to the Vulkan device are fetched using `volkLoadDeviceTable()` for given `device`. +To use this function properly: + +-# Create `VkInstance` and `VkDevice` object. +-# Fill in structure #VmaAllocatorCreateInfo, especially members: + - VmaAllocatorCreateInfo::device + - VmaAllocatorCreateInfo::vulkanApiVersion + - VmaAllocatorCreateInfo::flags - set appropriate flags for the Vulkan extensions you enabled +-# Define structure #VmaVulkanFunctions. +-# Call this function. + Parameter `pAllocatorCreateInfo` is read to find out which functions should be fetched for + appropriate Vulkan version and extensions. + Parameter `pDstVulkanFunctions` is filled with those function pointers. + Others are set to null. +-# Attach the #VmaVulkanFunctions structure to VmaAllocatorCreateInfo::pVulkanFunctions. +-# Call vmaCreateAllocator() to create the #VmaAllocator object. + +Example: + +\code +VmaAllocatorCreateInfo allocatorCreateInfo = {}; +allocatorCreateInfo.physicalDevice = myPhysivcalDevice; +allocatorCreateInfo.device = myDevice; +allocatorCreateInfo.instance = myInstance; +allocatorCreateInfo.vulkanApiVersion = VK_API_VERSION_1_3; +allocatorCreateInfo.flags = VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT | + VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT | + VMA_ALLOCATOR_CREATE_KHR_EXTERNAL_MEMORY_WIN32_BIT; + +VmaVulkanFunctions vulkanFunctions; +VkResult res = vmaImportVulkanFunctionsFromVolk(&allocatorCreateInfo, &vulkanFunctions); +// Check res... +allocatorCreateInfo.pVulkanFunctions = &vulkanFunctions; + +VmaAllocator allocator; +res = vmaCreateAllocator(&allocatorCreateInfo, &allocator); +// Check res... +\endcode + +Internally in this function, pointers to functions related to the entire Vulkan instance are fetched using global function definitions, +while pointers to functions related to the Vulkan device are fetched using `volkLoadDeviceTable()` for given `pAllocatorCreateInfo->device`. */ VMA_CALL_PRE VkResult VMA_CALL_POST vmaImportVulkanFunctionsFromVolk( - VkDevice VMA_NOT_NULL device, VmaVulkanFunctions* VMA_NOT_NULL dst); + const VmaAllocatorCreateInfo* VMA_NOT_NULL pAllocatorCreateInfo, + VmaVulkanFunctions* VMA_NOT_NULL pDstVulkanFunctions); #endif /// Creates #VmaAllocator object. @@ -15100,16 +15138,20 @@ void VmaAllocator_T::PrintDetailedMap(VmaJsonWriter& json) #ifdef VOLK_HEADER_VERSION VMA_CALL_PRE VkResult VMA_CALL_POST vmaImportVulkanFunctionsFromVolk( - VkDevice VMA_NOT_NULL device, VmaVulkanFunctions* VMA_NOT_NULL dst) + const VmaAllocatorCreateInfo* VMA_NOT_NULL pAllocatorCreateInfo, + VmaVulkanFunctions* VMA_NOT_NULL pDstVulkanFunctions) { - VolkDeviceTable src = {}; - memset(&dst, 0, sizeof(dst)); - memset(&src, 0, sizeof(src)); + VMA_ASSERT(pAllocatorCreateInfo != VMA_NULL); + VMA_ASSERT(pAllocatorCreateInfo->instance != VK_NULL_HANDLE); + VMA_ASSERT(pAllocatorCreateInfo->device != VK_NULL_HANDLE); + + memset(pDstVulkanFunctions, 0, sizeof(*pDstVulkanFunctions)); - volkLoadDeviceTable(&src, device); + VolkDeviceTable src = {}; + volkLoadDeviceTable(&src, pAllocatorCreateInfo->device); -#define COPY_GLOBAL_TO_VMA_FUNC(volkName, vmaName) if(!dst->vmaName) dst->vmaName = volkName; -#define COPY_DEVICE_TO_VMA_FUNC(volkName, vmaName) if(!dst->vmaName) dst->vmaName = src.volkName; +#define COPY_GLOBAL_TO_VMA_FUNC(volkName, vmaName) if(!pDstVulkanFunctions->vmaName) pDstVulkanFunctions->vmaName = volkName; +#define COPY_DEVICE_TO_VMA_FUNC(volkName, vmaName) if(!pDstVulkanFunctions->vmaName) pDstVulkanFunctions->vmaName = src.volkName; COPY_GLOBAL_TO_VMA_FUNC(vkGetInstanceProcAddr, vkGetInstanceProcAddr) COPY_GLOBAL_TO_VMA_FUNC(vkGetDeviceProcAddr, vkGetDeviceProcAddr) @@ -15131,33 +15173,54 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaImportVulkanFunctionsFromVolk( COPY_DEVICE_TO_VMA_FUNC(vkDestroyImage, vkDestroyImage) COPY_DEVICE_TO_VMA_FUNC(vkCmdCopyBuffer, vkCmdCopyBuffer) #if VMA_VULKAN_VERSION >= 1001000 - COPY_GLOBAL_TO_VMA_FUNC(vkGetPhysicalDeviceMemoryProperties2, vkGetPhysicalDeviceMemoryProperties2KHR) - COPY_DEVICE_TO_VMA_FUNC(vkGetBufferMemoryRequirements2, vkGetBufferMemoryRequirements2KHR) - COPY_DEVICE_TO_VMA_FUNC(vkGetImageMemoryRequirements2, vkGetImageMemoryRequirements2KHR) - COPY_DEVICE_TO_VMA_FUNC(vkBindBufferMemory2, vkBindBufferMemory2KHR) - COPY_DEVICE_TO_VMA_FUNC(vkBindImageMemory2, vkBindImageMemory2KHR) + if (pAllocatorCreateInfo->vulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + { + COPY_GLOBAL_TO_VMA_FUNC(vkGetPhysicalDeviceMemoryProperties2, vkGetPhysicalDeviceMemoryProperties2KHR) + COPY_DEVICE_TO_VMA_FUNC(vkGetBufferMemoryRequirements2, vkGetBufferMemoryRequirements2KHR) + COPY_DEVICE_TO_VMA_FUNC(vkGetImageMemoryRequirements2, vkGetImageMemoryRequirements2KHR) + COPY_DEVICE_TO_VMA_FUNC(vkBindBufferMemory2, vkBindBufferMemory2KHR) + COPY_DEVICE_TO_VMA_FUNC(vkBindImageMemory2, vkBindImageMemory2KHR) + } #endif #if VMA_VULKAN_VERSION >= 1003000 - COPY_DEVICE_TO_VMA_FUNC(vkGetDeviceBufferMemoryRequirements, vkGetDeviceBufferMemoryRequirements) - COPY_DEVICE_TO_VMA_FUNC(vkGetDeviceImageMemoryRequirements, vkGetDeviceImageMemoryRequirements) + if (pAllocatorCreateInfo->vulkanApiVersion >= VK_MAKE_VERSION(1, 3, 0)) + { + COPY_DEVICE_TO_VMA_FUNC(vkGetDeviceBufferMemoryRequirements, vkGetDeviceBufferMemoryRequirements) + COPY_DEVICE_TO_VMA_FUNC(vkGetDeviceImageMemoryRequirements, vkGetDeviceImageMemoryRequirements) + } #endif #if VMA_KHR_MAINTENANCE4 - COPY_DEVICE_TO_VMA_FUNC(vkGetDeviceBufferMemoryRequirementsKHR, vkGetDeviceBufferMemoryRequirements) - COPY_DEVICE_TO_VMA_FUNC(vkGetDeviceImageMemoryRequirementsKHR, vkGetDeviceImageMemoryRequirements) + if((pAllocatorCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE4_BIT) != 0) + { + COPY_DEVICE_TO_VMA_FUNC(vkGetDeviceBufferMemoryRequirementsKHR, vkGetDeviceBufferMemoryRequirements) + COPY_DEVICE_TO_VMA_FUNC(vkGetDeviceImageMemoryRequirementsKHR, vkGetDeviceImageMemoryRequirements) + } #endif #if VMA_DEDICATED_ALLOCATION - COPY_DEVICE_TO_VMA_FUNC(vkGetBufferMemoryRequirements2KHR, vkGetBufferMemoryRequirements2KHR) - COPY_DEVICE_TO_VMA_FUNC(vkGetImageMemoryRequirements2KHR, vkGetImageMemoryRequirements2KHR) + if ((pAllocatorCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT) != 0) + { + COPY_DEVICE_TO_VMA_FUNC(vkGetBufferMemoryRequirements2KHR, vkGetBufferMemoryRequirements2KHR) + COPY_DEVICE_TO_VMA_FUNC(vkGetImageMemoryRequirements2KHR, vkGetImageMemoryRequirements2KHR) + } #endif #if VMA_BIND_MEMORY2 - COPY_DEVICE_TO_VMA_FUNC(vkBindBufferMemory2KHR, vkBindBufferMemory2KHR) - COPY_DEVICE_TO_VMA_FUNC(vkBindImageMemory2KHR, vkBindImageMemory2KHR) + if ((pAllocatorCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT) != 0) + { + COPY_DEVICE_TO_VMA_FUNC(vkBindBufferMemory2KHR, vkBindBufferMemory2KHR) + COPY_DEVICE_TO_VMA_FUNC(vkBindImageMemory2KHR, vkBindImageMemory2KHR) + } #endif #if VMA_MEMORY_BUDGET - COPY_GLOBAL_TO_VMA_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, vkGetPhysicalDeviceMemoryProperties2KHR) + if ((pAllocatorCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT) != 0) + { + COPY_GLOBAL_TO_VMA_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, vkGetPhysicalDeviceMemoryProperties2KHR) + } #endif #if VMA_EXTERNAL_MEMORY_WIN32 - COPY_DEVICE_TO_VMA_FUNC(vkGetMemoryWin32HandleKHR, vkGetMemoryWin32HandleKHR) + if ((pAllocatorCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_EXTERNAL_MEMORY_WIN32_BIT) != 0) + { + COPY_DEVICE_TO_VMA_FUNC(vkGetMemoryWin32HandleKHR, vkGetMemoryWin32HandleKHR) + } #endif #undef COPY_DEVICE_TO_VMA_FUNC @@ -16882,7 +16945,7 @@ See code sample below. \subsection quick_start_initialization_importing_vulkan_functions Importing Vulkan functions -You may need to configure importing Vulkan functions. There are 3 ways to do this: +You may need to configure importing Vulkan functions. There are 4 ways to do this: -# **If you link with Vulkan static library** (e.g. "vulkan-1.lib" on Windows): - You don't need to do anything. @@ -16893,10 +16956,13 @@ You may need to configure importing Vulkan functions. There are 3 ways to do thi - Provide pointers to these two functions via VmaVulkanFunctions::vkGetInstanceProcAddr, VmaVulkanFunctions::vkGetDeviceProcAddr. - The library will fetch pointers to all other functions it needs internally. --# **If you fetch pointers to all Vulkan functions in a custom way**, e.g. using some loader like - [Volk](https://github.com/zeux/volk): +-# **If you fetch pointers to all Vulkan functions in a custom way**: - Define `VMA_STATIC_VULKAN_FUNCTIONS` and `VMA_DYNAMIC_VULKAN_FUNCTIONS` to 0. - Pass these pointers via structure #VmaVulkanFunctions. +-# **If you use [volk library](https://github.com/zeux/volk)**: + - Define `VMA_STATIC_VULKAN_FUNCTIONS` and `VMA_DYNAMIC_VULKAN_FUNCTIONS` to 0. + - Use function vmaImportVulkanFunctionsFromVolk() to fill in the structure #VmaVulkanFunctions. + For more information, see the description of this function. \subsection quick_start_initialization_enabling_extensions Enabling extensions diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b0ac1043..470b9a3d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -22,6 +22,7 @@ option(VMA_STATIC_VULKAN_FUNCTIONS "Link statically with Vulkan API" ON) option(VMA_DYNAMIC_VULKAN_FUNCTIONS "Fetch pointers to Vulkan functions internally (no static linking)" OFF) +set(VMA_VOLK_HEADER_PATH "" CACHE STRING "Path to volk.h file from the volk library (optional)") option(VMA_DEBUG_ALWAYS_DEDICATED_MEMORY "Every allocation will have its own memory block" OFF) option(VMA_DEBUG_INITIALIZE_ALLOCATIONS "Automatically fill new allocations and destroyed allocations with some bit pattern" OFF) option(VMA_DEBUG_GLOBAL_MUTEX "Enable single mutex protecting all entry calls to the library" OFF) @@ -50,6 +51,7 @@ target_sources(VmaSample PRIVATE Tests.h VmaUsage.cpp VmaUsage.h + VolkUsage.cpp VulkanSample.cpp ../include/vk_mem_alloc.h ) @@ -78,6 +80,15 @@ target_sources(VmaSample PRIVATE vk_mem_alloc.natvis) add_subdirectory(Shaders) add_dependencies(VmaSample VmaSampleShaders) +if(NOT "${VMA_VOLK_HEADER_PATH}" STREQUAL "") + if(EXISTS "${VMA_VOLK_HEADER_PATH}") + message(STATUS "File volk.h found and used from path: ${VMA_VOLK_HEADER_PATH}") + target_compile_definitions(VmaSample PRIVATE VMA_VOLK_HEADER_PATH="${VMA_VOLK_HEADER_PATH}") + else() + message(FATAL_ERROR "File volk.h not found in path: ${VMA_VOLK_HEADER_PATH}") + endif() +endif() + # Use Unicode instead of multibyte set add_compile_definitions(UNICODE _UNICODE) diff --git a/src/Tests.cpp b/src/Tests.cpp index 5ca56591..71ed3af8 100644 --- a/src/Tests.cpp +++ b/src/Tests.cpp @@ -3904,7 +3904,7 @@ void TestHeapSizeLimit() allocatorCreateInfo.pHeapSizeLimit = heapSizeLimit; #ifdef VOLK_HEADER_VERSION VmaVulkanFunctions vulkanFunctions = {}; - vmaImportVulkanFunctionsFromVolk(g_hDevice, &vulkanFunctions); + vmaImportVulkanFunctionsFromVolk(&allocatorCreateInfo, &vulkanFunctions); allocatorCreateInfo.pVulkanFunctions = &vulkanFunctions; #endif #if VMA_DYNAMIC_VULKAN_FUNCTIONS diff --git a/src/VmaUsage.h b/src/VmaUsage.h index 9442487c..c018cb73 100644 --- a/src/VmaUsage.h +++ b/src/VmaUsage.h @@ -96,11 +96,14 @@ include all public interface declarations. Example: #pragma clang diagnostic ignored "-Wnullability-completeness" #endif -//#include -#include "third_party/volk-1.4.304/volk.h" +#ifdef VMA_VOLK_HEADER_PATH + #include VMA_VOLK_HEADER_PATH +#else + #include +#endif #ifdef _WIN32 -#include + #include #endif // #ifdef _WIN32 #include "vk_mem_alloc.h" diff --git a/src/VolkUsage.cpp b/src/VolkUsage.cpp index e129304a..7dfe5616 100644 --- a/src/VolkUsage.cpp +++ b/src/VolkUsage.cpp @@ -20,10 +20,9 @@ // THE SOFTWARE. // -/* -In exactly one CPP file define macro VMA_IMPLEMENTATION and then include -vk_mem_alloc.h to include definitions of its internal implementation -*/ +#ifdef VMA_VOLK_HEADER_PATH #define VOLK_IMPLEMENTATION #include "VmaUsage.h" + +#endif // #ifdef VMA_VOLK_HEADER_PATH diff --git a/src/VulkanSample.cpp b/src/VulkanSample.cpp index abf20e3f..c77e0581 100644 --- a/src/VulkanSample.cpp +++ b/src/VulkanSample.cpp @@ -426,7 +426,9 @@ void VulkanUsage::Init() g_Allocs = &g_CpuAllocationCallbacks; } +#ifdef VOLK_HEADER_VERSION ERR_GUARD_VULKAN(volkInitialize()); +#endif uint32_t instanceLayerPropCount = 0; ERR_GUARD_VULKAN( vkEnumerateInstanceLayerProperties(&instanceLayerPropCount, nullptr) ); @@ -515,7 +517,9 @@ void VulkanUsage::Init() ERR_GUARD_VULKAN( vkCreateInstance(&instInfo, g_Allocs, &g_hVulkanInstance) ); +#ifdef VOLK_HEADER_VERSION volkLoadInstance(g_hVulkanInstance); +#endif if(VK_EXT_debug_utils_enabled) { @@ -1516,22 +1520,18 @@ void SetAllocatorCreateInfo(VmaAllocatorCreateInfo& outInfo) } #ifdef VOLK_HEADER_VERSION - static VmaVulkanFunctions vulkanFunctions = {}; - vmaImportVulkanFunctionsFromVolk(g_hDevice, &vulkanFunctions); + vmaImportVulkanFunctionsFromVolk(&outInfo, &vulkanFunctions); outInfo.pVulkanFunctions = &vulkanFunctions; - -#else // #ifdef VOLK_HEADER_VERSION +#endif // #ifdef VOLK_HEADER_VERSION #if VMA_DYNAMIC_VULKAN_FUNCTIONS -v static VmaVulkanFunctions vulkanFunctions = {}; + static VmaVulkanFunctions vulkanFunctions = {}; vulkanFunctions.vkGetInstanceProcAddr = vkGetInstanceProcAddr; vulkanFunctions.vkGetDeviceProcAddr = vkGetDeviceProcAddr; outInfo.pVulkanFunctions = &vulkanFunctions; #endif // #if VMA_DYNAMIC_VULKAN_FUNCTIONS -#endif // #ifdef VOLK_HEADER_VERSION - // Uncomment to enable HeapSizeLimit. /* static std::array heapSizeLimit; @@ -2097,7 +2097,11 @@ static void InitializeApplication() deviceCreateInfo.pQueueCreateInfos = queueCreateInfo; ERR_GUARD_VULKAN( vkCreateDevice(g_hPhysicalDevice, &deviceCreateInfo, g_Allocs, &g_hDevice) ); + +#ifdef VOLK_HEADER_VERSION volkLoadDevice(g_hDevice); +#endif + SetDebugUtilsObjectName(VK_OBJECT_TYPE_DEVICE, reinterpret_cast(g_hDevice), "g_hDevice"); // Only now that SetDebugUtilsObjectName is loaded, we can assign a name to g_hVulkanInstance as well SetDebugUtilsObjectName(VK_OBJECT_TYPE_INSTANCE, reinterpret_cast(g_hVulkanInstance), "g_hVulkanInstance"); From e1c0f1ee367623900c4c41d03629e3e649ea5e64 Mon Sep 17 00:00:00 2001 From: Adam Sawicki Date: Thu, 10 Apr 2025 20:10:59 +0200 Subject: [PATCH 3/4] Fixed a typo --- include/vk_mem_alloc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/vk_mem_alloc.h b/include/vk_mem_alloc.h index 5488c75a..c3798d0b 100644 --- a/include/vk_mem_alloc.h +++ b/include/vk_mem_alloc.h @@ -1695,7 +1695,7 @@ To use this function properly: \code VmaAllocatorCreateInfo allocatorCreateInfo = {}; -allocatorCreateInfo.physicalDevice = myPhysivcalDevice; +allocatorCreateInfo.physicalDevice = myPhysicalDevice; allocatorCreateInfo.device = myDevice; allocatorCreateInfo.instance = myInstance; allocatorCreateInfo.vulkanApiVersion = VK_API_VERSION_1_3; From 071a681e3bcfe863108480e114785b3f66e59615 Mon Sep 17 00:00:00 2001 From: Adam Sawicki Date: Fri, 11 Apr 2025 17:27:57 +0200 Subject: [PATCH 4/4] Fixes in documentation --- include/vk_mem_alloc.h | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/include/vk_mem_alloc.h b/include/vk_mem_alloc.h index c3798d0b..4b785935 100644 --- a/include/vk_mem_alloc.h +++ b/include/vk_mem_alloc.h @@ -1670,24 +1670,28 @@ typedef struct VmaVirtualAllocationInfo */ #ifdef VOLK_HEADER_VERSION -/** \brief Fully initializes `pDstVulkanFunctions` structure with Vulkan functions needed by this library based on functions imported by -[volk library](https://github.com/zeux/volk). +/** \brief Fully initializes `pDstVulkanFunctions` structure with Vulkan functions needed by VMA +using [volk library](https://github.com/zeux/volk). This function is defined in VMA header only if "volk.h" was included before it. To use this function properly: --# Create `VkInstance` and `VkDevice` object. +-# Initialize volk and Vulkan: + -# Call `volkInitialize()` + -# Create `VkInstance` object + -# Call `volkLoadInstance()` + -# Create `VkDevice` object + -# Call `volkLoadDevice()` -# Fill in structure #VmaAllocatorCreateInfo, especially members: - VmaAllocatorCreateInfo::device - VmaAllocatorCreateInfo::vulkanApiVersion - VmaAllocatorCreateInfo::flags - set appropriate flags for the Vulkan extensions you enabled --# Define structure #VmaVulkanFunctions. --# Call this function. +-# Create an instance of the #VmaVulkanFunctions structure. +-# Call vmaImportVulkanFunctionsFromVolk(). Parameter `pAllocatorCreateInfo` is read to find out which functions should be fetched for appropriate Vulkan version and extensions. - Parameter `pDstVulkanFunctions` is filled with those function pointers. - Others are set to null. + Parameter `pDstVulkanFunctions` is filled with those function pointers, or null if not applicable. -# Attach the #VmaVulkanFunctions structure to VmaAllocatorCreateInfo::pVulkanFunctions. -# Call vmaCreateAllocator() to create the #VmaAllocator object.