From 746c651391d8018b2f0c7de17d422cf0305a00e6 Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Mon, 26 Aug 2024 00:25:32 +0200 Subject: [PATCH 01/10] basic outline of the Win32 handle extension --- include/vk_mem_alloc.h | 121 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 119 insertions(+), 2 deletions(-) diff --git a/include/vk_mem_alloc.h b/include/vk_mem_alloc.h index ef2e147..0278f5c 100644 --- a/include/vk_mem_alloc.h +++ b/include/vk_mem_alloc.h @@ -6069,6 +6069,54 @@ private: #endif // _VMA_MAPPING_HYSTERESIS +#if defined(VK_USE_PLATFORM_WIN32_KHR) +class VmaWin32Handle +{ +public: + VmaWin32Handle() noexcept : m_hHandle(VMA_NULL) { } + VmaWin32Handle(HANDLE hHandle) noexcept : m_hHandle(hHandle) { } + ~VmaWin32Handle() noexcept { if (m_hHandle != VMA_NULL) { ::CloseHandle(m_hHandle); } } + VMA_CLASS_NO_COPY_NO_MOVE(VmaWin32Handle) +public: + VkResult Init(VkDevice device, VkDeviceMemory memory, decltype(&vkGetMemoryWin32HandleKHR) vkGetMemoryWin32HandleKHR) noexcept + { + VkResult res = VK_ERROR_FEATURE_NOT_PRESENT; + if (vkGetMemoryWin32HandleKHR != VMA_NULL) + { + VkMemoryGetWin32HandleInfoKHR handleInfo{ }; + handleInfo.sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR; + handleInfo.memory = memory; + handleInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR; + res = vkGetMemoryWin32HandleKHR(device, &handleInfo, &m_hHandle); + } + return res; + } + HANDLE Duplicate(HANDLE hTargetProcess = VMA_NULL) const noexcept + { + if (!m_hHandle) + return m_hHandle; + + HANDLE hCurrentProcess = ::GetCurrentProcess(); + HANDLE hDupHandle = VMA_NULL; + if (!::DuplicateHandle(hCurrentProcess, m_hHandle, hTargetProcess ? hTargetProcess : hCurrentProcess, &hDupHandle, 0, FALSE, DUPLICATE_SAME_ACCESS)) + { + VMA_ASSERT(0 && "Failed to duplicate handle."); + } + return hDupHandle; + } + operator bool() const noexcept { return m_hHandle != VMA_NULL; } + +private: + HANDLE m_hHandle; +}; +#else +class VmaWin32Handle +{ + void* placeholder = VMA_NULL; +}; +#endif // VK_USE_PLATFORM_WIN32_KHR + + #ifndef _VMA_DEVICE_MEMORY_BLOCK /* Represents a single block of device memory (`VkDeviceMemory`) with all the @@ -6135,7 +6183,12 @@ public: VkDeviceSize allocationLocalOffset, VkImage hImage, const void* pNext); - +#ifdef VK_USE_PLATFORM_WIN32_KHR + VkResult CreateWin32Handle( + const VmaAllocator hAllocator, + HANDLE hTargetProcess, + HANDLE* pHandle)noexcept; +#endif // VK_USE_PLATFORM_WIN32_KHR private: VmaPool m_hParentPool; // VK_NULL_HANDLE if not belongs to custom pool. uint32_t m_MemoryTypeIndex; @@ -6151,6 +6204,8 @@ private: VmaMappingHysteresis m_MappingHysteresis; uint32_t m_MapCount; void* m_pMappedData; + + VmaWin32Handle m_Handle; // Win32 handle }; #endif // _VMA_DEVICE_MEMORY_BLOCK @@ -6236,6 +6291,10 @@ public: void PrintParameters(class VmaJsonWriter& json) const; #endif +#ifdef VK_USE_PLATFORM_WIN32_KHR + VkResult GetWin32Handle(VmaAllocator hAllocator, HANDLE hTargetProcess, HANDLE* hHandle) const noexcept; +#endif // VK_USE_PLATFORM_WIN32_KHR + private: // Allocation out of VmaDeviceMemoryBlock. struct BlockAllocation @@ -6251,6 +6310,7 @@ private: void* m_pMappedData; // Not null means memory is mapped. VmaAllocation_T* m_Prev; VmaAllocation_T* m_Next; + VmaWin32Handle m_Handle; // Win32 handle }; union { @@ -10434,7 +10494,8 @@ VmaDeviceMemoryBlock::VmaDeviceMemoryBlock(VmaAllocator hAllocator) m_Id(0), m_hMemory(VK_NULL_HANDLE), m_MapCount(0), - m_pMappedData(VMA_NULL) {} + m_pMappedData(VMA_NULL), + m_Handle(VMA_NULL) {} VmaDeviceMemoryBlock::~VmaDeviceMemoryBlock() { @@ -10677,6 +10738,38 @@ VkResult VmaDeviceMemoryBlock::BindImageMemory( VmaMutexLock lock(m_MapAndBindMutex, hAllocator->m_UseMutex); return hAllocator->BindVulkanImage(m_hMemory, memoryOffset, hImage, pNext); } + +#ifdef VK_USE_PLATFORM_WIN32_KHR +VkResult VmaDeviceMemoryBlock::CreateWin32Handle(const VmaAllocator hAllocator, HANDLE hTargetProcess, HANDLE* pHandle) noexcept +{ + VMA_ASSERT(pHandle); + *pHandle = VMA_NULL; + + // relieves the mutex + if (m_Handle) + { + *pHandle = m_Handle.Duplicate(hTargetProcess); + return VK_SUCCESS; + } + + VmaMutexLock lock(m_MapAndBindMutex, hAllocator->m_UseMutex); + if (m_Handle) + { + *pHandle = m_Handle.Duplicate(hTargetProcess); + return VK_SUCCESS; + } + + // Do we pass the function manually or use the one from the allocator? + VkResult res = m_Handle.Init(hAllocator->m_hDevice, m_hMemory, &vkGetMemoryWin32HandleKHR); + if (res != VK_SUCCESS) + { + return res; + } + + *pHandle = m_Handle.Duplicate(hTargetProcess); + return VK_SUCCESS; +} +#endif // VK_USE_PLATFORM_WIN32_KHR #endif // _VMA_DEVICE_MEMORY_BLOCK_FUNCTIONS #ifndef _VMA_ALLOCATION_T_FUNCTIONS @@ -10977,6 +11070,21 @@ void VmaAllocation_T::PrintParameters(class VmaJsonWriter& json) const json.WriteString(m_pName); } } +#ifdef VK_USE_PLATFORM_WIN32_KHR +inline VkResult VmaAllocation_T::GetWin32Handle(VmaAllocator hAllocator, HANDLE hTargetProcess, HANDLE* pHandle) const noexcept +{ + switch (m_Type) + { + case ALLOCATION_TYPE_BLOCK: + return m_BlockAllocation.m_Block->CreateWin32Handle(hAllocator, hTargetProcess, pHandle); + case ALLOCATION_TYPE_DEDICATED: + // return m_DedicatedAllocation.m_hMemory; + default: + VMA_ASSERT(0); + return VK_ERROR_FEATURE_NOT_PRESENT; + } +} +#endif // VK_USE_PLATFORM_WIN32_KHR #endif // VMA_STATS_STRING_ENABLED void VmaAllocation_T::FreeName(VmaAllocator hAllocator) @@ -16429,6 +16537,15 @@ VMA_CALL_PRE void VMA_CALL_POST vmaFreeVirtualBlockStatsString(VmaVirtualBlock V VmaFreeString(virtualBlock->GetAllocationCallbacks(), pStatsString); } } +#ifdef VK_USE_PLATFORM_WIN32_KHR +VMA_CALL_PRE VkResult VMA_CALL_POST vmaGetMemoryWin32HandleKHR(VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, HANDLE hTargetProcess, HANDLE* pHandle) +{ + VMA_ASSERT(allocator && allocation); + VMA_DEBUG_GLOBAL_MUTEX_LOCK; + return allocation->GetWin32Handle(allocator, hTargetProcess, pHandle); +} +#endif // VK_USE_PLATFORM_WIN32_KHR #endif // VMA_STATS_STRING_ENABLED #endif // _VMA_PUBLIC_INTERFACE #endif // VMA_IMPLEMENTATION From 33bd6c6032055a174050372ac12d6611c9ebfd59 Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Mon, 26 Aug 2024 12:41:13 +0200 Subject: [PATCH 02/10] made handle atomic --- include/vk_mem_alloc.h | 101 +++++++++++++++++++++++++---------------- 1 file changed, 62 insertions(+), 39 deletions(-) diff --git a/include/vk_mem_alloc.h b/include/vk_mem_alloc.h index 0278f5c..60dcea6 100644 --- a/include/vk_mem_alloc.h +++ b/include/vk_mem_alloc.h @@ -6077,41 +6077,85 @@ public: VmaWin32Handle(HANDLE hHandle) noexcept : m_hHandle(hHandle) { } ~VmaWin32Handle() noexcept { if (m_hHandle != VMA_NULL) { ::CloseHandle(m_hHandle); } } VMA_CLASS_NO_COPY_NO_MOVE(VmaWin32Handle) + public: - VkResult Init(VkDevice device, VkDeviceMemory memory, decltype(&vkGetMemoryWin32HandleKHR) vkGetMemoryWin32HandleKHR) noexcept + // Strengthened + VkResult GetHandle(VkDevice device, VkDeviceMemory memory, decltype(&vkGetMemoryWin32HandleKHR) pvkGetMemoryWin32HandleKHR, HANDLE hTargetProcess, HANDLE* pHandle) noexcept + { + *pHandle = VMA_NULL; + // We only care about atomicity of handle retrieval, not about memory order. + HANDLE handle = m_hHandle.load(std::memory_order_relaxed); + + // Try to get handle first. + if (handle != VMA_NULL) + { + *pHandle = Duplicate(hTargetProcess); + return VK_SUCCESS; + } + + HANDLE hCreatedHandle = VMA_NULL; + + // If failed, try to create it. + VkResult res = Create(device, memory, pvkGetMemoryWin32HandleKHR, &hCreatedHandle); + if (res == VK_SUCCESS) + { + // Successfully created handle, try to set it. + if (!m_hHandle.compare_exchange_strong(handle, hCreatedHandle, std::memory_order_relaxed)) + { + // AMD workaround + if (hCreatedHandle != m_hHandle.load(std::memory_order_relaxed)) + { + ::CloseHandle(hCreatedHandle); + } + } + } + + // If somehow it was set in the meantime, return it. + if (m_hHandle.load(std::memory_order_relaxed)) + { + *pHandle = Duplicate(hTargetProcess); + return VK_SUCCESS; + } + return res; +} + + operator bool() const noexcept { return m_hHandle != VMA_NULL; } +private: + // Not atomic + static VkResult Create(VkDevice device, VkDeviceMemory memory, decltype(&vkGetMemoryWin32HandleKHR) pvkGetMemoryWin32HandleKHR, HANDLE* pHandle) noexcept { VkResult res = VK_ERROR_FEATURE_NOT_PRESENT; - if (vkGetMemoryWin32HandleKHR != VMA_NULL) + if (pvkGetMemoryWin32HandleKHR != VMA_NULL) { VkMemoryGetWin32HandleInfoKHR handleInfo{ }; handleInfo.sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR; handleInfo.memory = memory; handleInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR; - res = vkGetMemoryWin32HandleKHR(device, &handleInfo, &m_hHandle); + res = pvkGetMemoryWin32HandleKHR(device, &handleInfo, pHandle); } return res; } HANDLE Duplicate(HANDLE hTargetProcess = VMA_NULL) const noexcept { - if (!m_hHandle) - return m_hHandle; + HANDLE handle = m_hHandle.load(std::memory_order_relaxed); + if (!handle) + return handle; HANDLE hCurrentProcess = ::GetCurrentProcess(); HANDLE hDupHandle = VMA_NULL; - if (!::DuplicateHandle(hCurrentProcess, m_hHandle, hTargetProcess ? hTargetProcess : hCurrentProcess, &hDupHandle, 0, FALSE, DUPLICATE_SAME_ACCESS)) + if (!::DuplicateHandle(hCurrentProcess, handle, hTargetProcess ? hTargetProcess : hCurrentProcess, &hDupHandle, 0, FALSE, DUPLICATE_SAME_ACCESS)) { VMA_ASSERT(0 && "Failed to duplicate handle."); } return hDupHandle; } - operator bool() const noexcept { return m_hHandle != VMA_NULL; } - private: - HANDLE m_hHandle; + std::atomic m_hHandle; }; #else class VmaWin32Handle { + // ABI compatibility void* placeholder = VMA_NULL; }; #endif // VK_USE_PLATFORM_WIN32_KHR @@ -6186,6 +6230,7 @@ public: #ifdef VK_USE_PLATFORM_WIN32_KHR VkResult CreateWin32Handle( const VmaAllocator hAllocator, + decltype(&vkGetMemoryWin32HandleKHR) pvkGetMemoryWin32HandleKHR, HANDLE hTargetProcess, HANDLE* pHandle)noexcept; #endif // VK_USE_PLATFORM_WIN32_KHR @@ -6310,7 +6355,7 @@ private: void* m_pMappedData; // Not null means memory is mapped. VmaAllocation_T* m_Prev; VmaAllocation_T* m_Next; - VmaWin32Handle m_Handle; // Win32 handle + mutable VmaWin32Handle m_Handle; // Win32 handle }; union { @@ -10740,34 +10785,10 @@ VkResult VmaDeviceMemoryBlock::BindImageMemory( } #ifdef VK_USE_PLATFORM_WIN32_KHR -VkResult VmaDeviceMemoryBlock::CreateWin32Handle(const VmaAllocator hAllocator, HANDLE hTargetProcess, HANDLE* pHandle) noexcept +VkResult VmaDeviceMemoryBlock::CreateWin32Handle(const VmaAllocator hAllocator, decltype(&vkGetMemoryWin32HandleKHR) pvkGetMemoryWin32HandleKHR, HANDLE hTargetProcess, HANDLE* pHandle) noexcept { VMA_ASSERT(pHandle); - *pHandle = VMA_NULL; - - // relieves the mutex - if (m_Handle) - { - *pHandle = m_Handle.Duplicate(hTargetProcess); - return VK_SUCCESS; - } - - VmaMutexLock lock(m_MapAndBindMutex, hAllocator->m_UseMutex); - if (m_Handle) - { - *pHandle = m_Handle.Duplicate(hTargetProcess); - return VK_SUCCESS; - } - - // Do we pass the function manually or use the one from the allocator? - VkResult res = m_Handle.Init(hAllocator->m_hDevice, m_hMemory, &vkGetMemoryWin32HandleKHR); - if (res != VK_SUCCESS) - { - return res; - } - - *pHandle = m_Handle.Duplicate(hTargetProcess); - return VK_SUCCESS; + return m_Handle.GetHandle(hAllocator->m_hDevice, m_hMemory, &vkGetMemoryWin32HandleKHR, hTargetProcess, pHandle); } #endif // VK_USE_PLATFORM_WIN32_KHR #endif // _VMA_DEVICE_MEMORY_BLOCK_FUNCTIONS @@ -11071,14 +11092,16 @@ void VmaAllocation_T::PrintParameters(class VmaJsonWriter& json) const } } #ifdef VK_USE_PLATFORM_WIN32_KHR -inline VkResult VmaAllocation_T::GetWin32Handle(VmaAllocator hAllocator, HANDLE hTargetProcess, HANDLE* pHandle) const noexcept +VkResult VmaAllocation_T::GetWin32Handle(VmaAllocator hAllocator, HANDLE hTargetProcess, HANDLE* pHandle) const noexcept { + // Where do we get this function from? + auto pvkGetMemoryWin32HandleKHR = &vkGetMemoryWin32HandleKHR; switch (m_Type) { case ALLOCATION_TYPE_BLOCK: - return m_BlockAllocation.m_Block->CreateWin32Handle(hAllocator, hTargetProcess, pHandle); + return m_BlockAllocation.m_Block->CreateWin32Handle(hAllocator, pvkGetMemoryWin32HandleKHR, hTargetProcess, pHandle); case ALLOCATION_TYPE_DEDICATED: - // return m_DedicatedAllocation.m_hMemory; + return m_DedicatedAllocation.m_Handle.GetHandle(hAllocator->m_hDevice, m_DedicatedAllocation.m_hMemory, pvkGetMemoryWin32HandleKHR, hTargetProcess, pHandle); default: VMA_ASSERT(0); return VK_ERROR_FEATURE_NOT_PRESENT; From 8c665c4c950a043ec1ae232b1f69eebe3943f46b Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Mon, 26 Aug 2024 13:29:42 +0200 Subject: [PATCH 03/10] added vkGetMemoryWin32HandleKHR to functions --- include/vk_mem_alloc.h | 52 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/include/vk_mem_alloc.h b/include/vk_mem_alloc.h index 60dcea6..a0c3bdd 100644 --- a/include/vk_mem_alloc.h +++ b/include/vk_mem_alloc.h @@ -461,6 +461,14 @@ typedef enum VmaAllocatorCreateFlagBits */ VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT = 0x00000100, + /** + Enables usage of VK_KHR_external_memory_win32 extension in the library. + + You should set this flag if you found available and enabled this device extension, + while creating Vulkan device passed as VmaAllocatorCreateInfo::device. + */ + VMA_ALLOCATOR_CREATE_KHR_EXTERNAL_MEMORY_WIN32 = 0x00000200, + VMA_ALLOCATOR_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VmaAllocatorCreateFlagBits; /// See #VmaAllocatorCreateFlagBits. @@ -1035,6 +1043,11 @@ typedef struct VmaVulkanFunctions /// Fetch from "vkGetDeviceImageMemoryRequirements" on Vulkan >= 1.3, but you can also fetch it from "vkGetDeviceImageMemoryRequirementsKHR" if you enabled extension VK_KHR_maintenance4. PFN_vkGetDeviceImageMemoryRequirementsKHR VMA_NULLABLE vkGetDeviceImageMemoryRequirements; #endif +#ifdef VK_USE_PLATFORM_WIN32_KHR + PFN_vkGetMemoryWin32HandleKHR VMA_NULLABLE vkGetMemoryWin32HandleKHR; +#else + void* VMA_NULLABLE vkGetMemoryWin32HandleKHR; +#endif } VmaVulkanFunctions; /// Description of a Allocator to be created. @@ -10176,6 +10189,7 @@ public: bool m_UseExtMemoryPriority; bool m_UseKhrMaintenance4; bool m_UseKhrMaintenance5; + bool m_UseKhrExternalMemoryWin32; const VkDevice m_hDevice; const VkInstance m_hInstance; const bool m_AllocationCallbacksSpecified; @@ -11095,7 +11109,7 @@ void VmaAllocation_T::PrintParameters(class VmaJsonWriter& json) const VkResult VmaAllocation_T::GetWin32Handle(VmaAllocator hAllocator, HANDLE hTargetProcess, HANDLE* pHandle) const noexcept { // Where do we get this function from? - auto pvkGetMemoryWin32HandleKHR = &vkGetMemoryWin32HandleKHR; + auto pvkGetMemoryWin32HandleKHR = hAllocator->GetVulkanFunctions().vkGetMemoryWin32HandleKHR; switch (m_Type) { case ALLOCATION_TYPE_BLOCK: @@ -12838,6 +12852,7 @@ VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) : m_UseExtMemoryPriority((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT) != 0), m_UseKhrMaintenance4((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE4_BIT) != 0), m_UseKhrMaintenance5((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT) != 0), + m_UseKhrExternalMemoryWin32((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_EXTERNAL_MEMORY_WIN32) != 0), m_hDevice(pCreateInfo->device), m_hInstance(pCreateInfo->instance), m_AllocationCallbacksSpecified(pCreateInfo->pAllocationCallbacks != VMA_NULL), @@ -12929,6 +12944,19 @@ VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) : VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT is set but required extension is not available in your Vulkan header or its support in VMA has been disabled by a preprocessor macro."); } #endif +#if !(VMA_KHR_MAINTENANCE5) + if(m_UseKhrMaintenance5) + { + VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT is set but required extension is not available in your Vulkan header or its support in VMA has been disabled by a preprocessor macro."); + } +#endif + +#if !defined(VK_USE_PLATFORM_WIN32_KHR) + if(m_UseKhrExternalMemoryWin32) + { + VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT is set but required extension is not available in your Vulkan header or its support in VMA has been disabled by a preprocessor macro."); + } +#endif memset(&m_DeviceMemoryCallbacks, 0 ,sizeof(m_DeviceMemoryCallbacks)); memset(&m_PhysicalDeviceProperties, 0, sizeof(m_PhysicalDeviceProperties)); @@ -13104,6 +13132,11 @@ void VmaAllocator_T::ImportVulkanFunctions_Static() m_VulkanFunctions.vkGetDeviceImageMemoryRequirements = (PFN_vkGetDeviceImageMemoryRequirements)vkGetDeviceImageMemoryRequirements; } #endif +#ifdef VK_USE_PLATFORM_WIN32_KHR + m_VulkanFunctions.vkGetMemoryWin32HandleKHR = (PFN_vkGetMemoryWin32HandleKHR)vkGetMemoryWin32HandleKHR; +#else + m_VulkanFunctions.vkGetMemoryWin32HandleKHR = VMA_NULL; +#endif } #endif // VMA_STATIC_VULKAN_FUNCTIONS == 1 @@ -13153,7 +13186,9 @@ void VmaAllocator_T::ImportVulkanFunctions_Custom(const VmaVulkanFunctions* pVul VMA_COPY_IF_NOT_NULL(vkGetDeviceBufferMemoryRequirements); VMA_COPY_IF_NOT_NULL(vkGetDeviceImageMemoryRequirements); #endif - +#ifdef VK_USE_PLATFORM_WIN32_KHR + VMA_COPY_IF_NOT_NULL(vkGetMemoryWin32HandleKHR); +#endif #undef VMA_COPY_IF_NOT_NULL } @@ -13255,7 +13290,12 @@ void VmaAllocator_T::ImportVulkanFunctions_Dynamic() VMA_FETCH_DEVICE_FUNC(vkGetDeviceImageMemoryRequirements, PFN_vkGetDeviceImageMemoryRequirementsKHR, "vkGetDeviceImageMemoryRequirementsKHR"); } #endif - +#ifdef VK_USE_PLATFORM_WIN32_KHR + if (m_UseKhrExternalMemoryWin32) + { + VMA_FETCH_DEVICE_FUNC(vkGetMemoryWin32HandleKHR, PFN_vkGetMemoryWin32HandleKHR, "vkGetMemoryWin32HandleKHR"); + } +#endif #undef VMA_FETCH_DEVICE_FUNC #undef VMA_FETCH_INSTANCE_FUNC } @@ -13304,6 +13344,12 @@ void VmaAllocator_T::ValidateVulkanFunctions() VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties2KHR != VMA_NULL); } #endif +#ifdef VK_USE_PLATFORM_WIN32_KHR + if (m_UseKhrExternalMemoryWin32) + { + VMA_ASSERT(m_VulkanFunctions.vkGetMemoryWin32HandleKHR != VMA_NULL); + } +#endif // Not validating these due to suspected driver bugs with these function // pointers being null despite correct extension or Vulkan version is enabled. From c41e3fb5a69fcbc4feb7a0678cf3e7a403febdc5 Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Mon, 26 Aug 2024 14:11:41 +0200 Subject: [PATCH 04/10] extra safety --- include/vk_mem_alloc.h | 5849 ++++++++++++++++++++-------------------- 1 file changed, 2920 insertions(+), 2929 deletions(-) diff --git a/include/vk_mem_alloc.h b/include/vk_mem_alloc.h index a0c3bdd..fed962c 100644 --- a/include/vk_mem_alloc.h +++ b/include/vk_mem_alloc.h @@ -132,15 +132,15 @@ extern "C" { #endif #if !defined(VMA_VULKAN_VERSION) - #if defined(VK_VERSION_1_3) - #define VMA_VULKAN_VERSION 1003000 - #elif defined(VK_VERSION_1_2) - #define VMA_VULKAN_VERSION 1002000 - #elif defined(VK_VERSION_1_1) - #define VMA_VULKAN_VERSION 1001000 - #else - #define VMA_VULKAN_VERSION 1000000 - #endif +#if defined(VK_VERSION_1_3) +#define VMA_VULKAN_VERSION 1003000 +#elif defined(VK_VERSION_1_2) +#define VMA_VULKAN_VERSION 1002000 +#elif defined(VK_VERSION_1_1) +#define VMA_VULKAN_VERSION 1001000 +#else +#define VMA_VULKAN_VERSION 1000000 +#endif #endif #if defined(__ANDROID__) && defined(VK_NO_PROTOTYPES) && VMA_STATIC_VULKAN_FUNCTIONS @@ -163,83 +163,83 @@ extern "C" { extern PFN_vkCreateImage vkCreateImage; extern PFN_vkDestroyImage vkDestroyImage; extern PFN_vkCmdCopyBuffer vkCmdCopyBuffer; - #if VMA_VULKAN_VERSION >= 1001000 - extern PFN_vkGetBufferMemoryRequirements2 vkGetBufferMemoryRequirements2; - extern PFN_vkGetImageMemoryRequirements2 vkGetImageMemoryRequirements2; - extern PFN_vkBindBufferMemory2 vkBindBufferMemory2; - extern PFN_vkBindImageMemory2 vkBindImageMemory2; - extern PFN_vkGetPhysicalDeviceMemoryProperties2 vkGetPhysicalDeviceMemoryProperties2; - #endif // #if VMA_VULKAN_VERSION >= 1001000 +#if VMA_VULKAN_VERSION >= 1001000 + extern PFN_vkGetBufferMemoryRequirements2 vkGetBufferMemoryRequirements2; + extern PFN_vkGetImageMemoryRequirements2 vkGetImageMemoryRequirements2; + extern PFN_vkBindBufferMemory2 vkBindBufferMemory2; + extern PFN_vkBindImageMemory2 vkBindImageMemory2; + extern PFN_vkGetPhysicalDeviceMemoryProperties2 vkGetPhysicalDeviceMemoryProperties2; +#endif // #if VMA_VULKAN_VERSION >= 1001000 #endif // #if defined(__ANDROID__) && VMA_STATIC_VULKAN_FUNCTIONS && VK_NO_PROTOTYPES #if !defined(VMA_DEDICATED_ALLOCATION) - #if VK_KHR_get_memory_requirements2 && VK_KHR_dedicated_allocation - #define VMA_DEDICATED_ALLOCATION 1 - #else - #define VMA_DEDICATED_ALLOCATION 0 - #endif +#if VK_KHR_get_memory_requirements2 && VK_KHR_dedicated_allocation +#define VMA_DEDICATED_ALLOCATION 1 +#else +#define VMA_DEDICATED_ALLOCATION 0 +#endif #endif #if !defined(VMA_BIND_MEMORY2) - #if VK_KHR_bind_memory2 - #define VMA_BIND_MEMORY2 1 - #else - #define VMA_BIND_MEMORY2 0 - #endif +#if VK_KHR_bind_memory2 +#define VMA_BIND_MEMORY2 1 +#else +#define VMA_BIND_MEMORY2 0 +#endif #endif #if !defined(VMA_MEMORY_BUDGET) - #if VK_EXT_memory_budget && (VK_KHR_get_physical_device_properties2 || VMA_VULKAN_VERSION >= 1001000) - #define VMA_MEMORY_BUDGET 1 - #else - #define VMA_MEMORY_BUDGET 0 - #endif +#if VK_EXT_memory_budget && (VK_KHR_get_physical_device_properties2 || VMA_VULKAN_VERSION >= 1001000) +#define VMA_MEMORY_BUDGET 1 +#else +#define VMA_MEMORY_BUDGET 0 +#endif #endif -// Defined to 1 when VK_KHR_buffer_device_address device extension or equivalent core Vulkan 1.2 feature is defined in its headers. + // Defined to 1 when VK_KHR_buffer_device_address device extension or equivalent core Vulkan 1.2 feature is defined in its headers. #if !defined(VMA_BUFFER_DEVICE_ADDRESS) - #if VK_KHR_buffer_device_address || VMA_VULKAN_VERSION >= 1002000 - #define VMA_BUFFER_DEVICE_ADDRESS 1 - #else - #define VMA_BUFFER_DEVICE_ADDRESS 0 - #endif +#if VK_KHR_buffer_device_address || VMA_VULKAN_VERSION >= 1002000 +#define VMA_BUFFER_DEVICE_ADDRESS 1 +#else +#define VMA_BUFFER_DEVICE_ADDRESS 0 +#endif #endif // Defined to 1 when VK_EXT_memory_priority device extension is defined in Vulkan headers. #if !defined(VMA_MEMORY_PRIORITY) - #if VK_EXT_memory_priority - #define VMA_MEMORY_PRIORITY 1 - #else - #define VMA_MEMORY_PRIORITY 0 - #endif +#if VK_EXT_memory_priority +#define VMA_MEMORY_PRIORITY 1 +#else +#define VMA_MEMORY_PRIORITY 0 +#endif #endif // Defined to 1 when VK_KHR_maintenance4 device extension is defined in Vulkan headers. #if !defined(VMA_KHR_MAINTENANCE4) - #if VK_KHR_maintenance4 - #define VMA_KHR_MAINTENANCE4 1 - #else - #define VMA_KHR_MAINTENANCE4 0 - #endif +#if VK_KHR_maintenance4 +#define VMA_KHR_MAINTENANCE4 1 +#else +#define VMA_KHR_MAINTENANCE4 0 +#endif #endif // Defined to 1 when VK_KHR_maintenance5 device extension is defined in Vulkan headers. #if !defined(VMA_KHR_MAINTENANCE5) - #if VK_KHR_maintenance5 - #define VMA_KHR_MAINTENANCE5 1 - #else - #define VMA_KHR_MAINTENANCE5 0 - #endif +#if VK_KHR_maintenance5 +#define VMA_KHR_MAINTENANCE5 1 +#else +#define VMA_KHR_MAINTENANCE5 0 +#endif #endif // Defined to 1 when VK_KHR_external_memory device extension is defined in Vulkan headers. #if !defined(VMA_EXTERNAL_MEMORY) - #if VK_KHR_external_memory - #define VMA_EXTERNAL_MEMORY 1 - #else - #define VMA_EXTERNAL_MEMORY 0 - #endif +#if VK_KHR_external_memory +#define VMA_EXTERNAL_MEMORY 1 +#else +#define VMA_EXTERNAL_MEMORY 0 +#endif #endif // Define these macros to decorate all public functions with additional code, @@ -248,16 +248,16 @@ extern "C" { // #define VMA_CALL_PRE __declspec(dllexport) // #define VMA_CALL_POST __cdecl #ifndef VMA_CALL_PRE - #define VMA_CALL_PRE +#define VMA_CALL_PRE #endif #ifndef VMA_CALL_POST - #define VMA_CALL_POST +#define VMA_CALL_POST #endif // Define this macro to decorate pNext pointers with an attribute specifying the Vulkan // structure that will be extended via the pNext chain. #ifndef VMA_EXTENDS_VK_STRUCT - #define VMA_EXTENDS_VK_STRUCT(vkStruct) +#define VMA_EXTENDS_VK_STRUCT(vkStruct) #endif // Define this macro to decorate pointers with an attribute specifying the @@ -272,49 +272,49 @@ extern "C" { // this means the number of memory heaps available in the device associated // with the VmaAllocator being dealt with. #ifndef VMA_LEN_IF_NOT_NULL - #define VMA_LEN_IF_NOT_NULL(len) +#define VMA_LEN_IF_NOT_NULL(len) #endif // The VMA_NULLABLE macro is defined to be _Nullable when compiling with Clang. // see: https://clang.llvm.org/docs/AttributeReference.html#nullable #ifndef VMA_NULLABLE - #ifdef __clang__ - #define VMA_NULLABLE _Nullable - #else - #define VMA_NULLABLE - #endif +#ifdef __clang__ +#define VMA_NULLABLE _Nullable +#else +#define VMA_NULLABLE +#endif #endif // The VMA_NOT_NULL macro is defined to be _Nonnull when compiling with Clang. // see: https://clang.llvm.org/docs/AttributeReference.html#nonnull #ifndef VMA_NOT_NULL - #ifdef __clang__ - #define VMA_NOT_NULL _Nonnull - #else - #define VMA_NOT_NULL - #endif +#ifdef __clang__ +#define VMA_NOT_NULL _Nonnull +#else +#define VMA_NOT_NULL +#endif #endif // If non-dispatchable handles are represented as pointers then we can give // then nullability annotations #ifndef VMA_NOT_NULL_NON_DISPATCHABLE - #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) - #define VMA_NOT_NULL_NON_DISPATCHABLE VMA_NOT_NULL - #else - #define VMA_NOT_NULL_NON_DISPATCHABLE - #endif +#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) +#define VMA_NOT_NULL_NON_DISPATCHABLE VMA_NOT_NULL +#else +#define VMA_NOT_NULL_NON_DISPATCHABLE +#endif #endif #ifndef VMA_NULLABLE_NON_DISPATCHABLE - #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) - #define VMA_NULLABLE_NON_DISPATCHABLE VMA_NULLABLE - #else - #define VMA_NULLABLE_NON_DISPATCHABLE - #endif +#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) +#define VMA_NULLABLE_NON_DISPATCHABLE VMA_NULLABLE +#else +#define VMA_NULLABLE_NON_DISPATCHABLE +#endif #endif #ifndef VMA_STATS_STRING_ENABLED - #define VMA_STATS_STRING_ENABLED 1 +#define VMA_STATS_STRING_ENABLED 1 #endif //////////////////////////////////////////////////////////////////////////////// @@ -334,525 +334,525 @@ extern "C" { */ /// Flags for created #VmaAllocator. -typedef enum VmaAllocatorCreateFlagBits -{ - /** \brief Allocator and all objects created from it will not be synchronized internally, so you must guarantee they are used from only one thread at a time or synchronized externally by you. + typedef enum VmaAllocatorCreateFlagBits + { + /** \brief Allocator and all objects created from it will not be synchronized internally, so you must guarantee they are used from only one thread at a time or synchronized externally by you. - Using this flag may increase performance because internal mutexes are not used. - */ - VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT = 0x00000001, - /** \brief Enables usage of VK_KHR_dedicated_allocation extension. + Using this flag may increase performance because internal mutexes are not used. + */ + VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT = 0x00000001, + /** \brief Enables usage of VK_KHR_dedicated_allocation extension. - The flag works only if VmaAllocatorCreateInfo::vulkanApiVersion `== VK_API_VERSION_1_0`. - When it is `VK_API_VERSION_1_1`, the flag is ignored because the extension has been promoted to Vulkan 1.1. + The flag works only if VmaAllocatorCreateInfo::vulkanApiVersion `== VK_API_VERSION_1_0`. + When it is `VK_API_VERSION_1_1`, the flag is ignored because the extension has been promoted to Vulkan 1.1. - Using this extension will automatically allocate dedicated blocks of memory for - some buffers and images instead of suballocating place for them out of bigger - memory blocks (as if you explicitly used #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT - flag) when it is recommended by the driver. It may improve performance on some - GPUs. + Using this extension will automatically allocate dedicated blocks of memory for + some buffers and images instead of suballocating place for them out of bigger + memory blocks (as if you explicitly used #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT + flag) when it is recommended by the driver. It may improve performance on some + GPUs. - You may set this flag only if you found out that following device extensions are - supported, you enabled them while creating Vulkan device passed as - VmaAllocatorCreateInfo::device, and you want them to be used internally by this - library: + You may set this flag only if you found out that following device extensions are + supported, you enabled them while creating Vulkan device passed as + VmaAllocatorCreateInfo::device, and you want them to be used internally by this + library: - - VK_KHR_get_memory_requirements2 (device extension) - - VK_KHR_dedicated_allocation (device extension) + - VK_KHR_get_memory_requirements2 (device extension) + - VK_KHR_dedicated_allocation (device extension) - When this flag is set, you can experience following warnings reported by Vulkan - validation layer. You can ignore them. + When this flag is set, you can experience following warnings reported by Vulkan + validation layer. You can ignore them. - > vkBindBufferMemory(): Binding memory to buffer 0x2d but vkGetBufferMemoryRequirements() has not been called on that buffer. - */ - VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT = 0x00000002, - /** - Enables usage of VK_KHR_bind_memory2 extension. + > vkBindBufferMemory(): Binding memory to buffer 0x2d but vkGetBufferMemoryRequirements() has not been called on that buffer. + */ + VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT = 0x00000002, + /** + Enables usage of VK_KHR_bind_memory2 extension. - The flag works only if VmaAllocatorCreateInfo::vulkanApiVersion `== VK_API_VERSION_1_0`. - When it is `VK_API_VERSION_1_1`, the flag is ignored because the extension has been promoted to Vulkan 1.1. + The flag works only if VmaAllocatorCreateInfo::vulkanApiVersion `== VK_API_VERSION_1_0`. + When it is `VK_API_VERSION_1_1`, the flag is ignored because the extension has been promoted to Vulkan 1.1. - You may set this flag only if you found out that this device extension is supported, - you enabled it while creating Vulkan device passed as VmaAllocatorCreateInfo::device, - and you want it to be used internally by this library. + You may set this flag only if you found out that this device extension is supported, + you enabled it while creating Vulkan device passed as VmaAllocatorCreateInfo::device, + and you want it to be used internally by this library. - The extension provides functions `vkBindBufferMemory2KHR` and `vkBindImageMemory2KHR`, - which allow to pass a chain of `pNext` structures while binding. - This flag is required if you use `pNext` parameter in vmaBindBufferMemory2() or vmaBindImageMemory2(). - */ - VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT = 0x00000004, - /** - Enables usage of VK_EXT_memory_budget extension. + The extension provides functions `vkBindBufferMemory2KHR` and `vkBindImageMemory2KHR`, + which allow to pass a chain of `pNext` structures while binding. + This flag is required if you use `pNext` parameter in vmaBindBufferMemory2() or vmaBindImageMemory2(). + */ + VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT = 0x00000004, + /** + Enables usage of VK_EXT_memory_budget extension. - You may set this flag only if you found out that this device extension is supported, - you enabled it while creating Vulkan device passed as VmaAllocatorCreateInfo::device, - and you want it to be used internally by this library, along with another instance extension - VK_KHR_get_physical_device_properties2, which is required by it (or Vulkan 1.1, where this extension is promoted). + You may set this flag only if you found out that this device extension is supported, + you enabled it while creating Vulkan device passed as VmaAllocatorCreateInfo::device, + and you want it to be used internally by this library, along with another instance extension + VK_KHR_get_physical_device_properties2, which is required by it (or Vulkan 1.1, where this extension is promoted). - The extension provides query for current memory usage and budget, which will probably - be more accurate than an estimation used by the library otherwise. - */ - VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT = 0x00000008, - /** - Enables usage of VK_AMD_device_coherent_memory extension. + The extension provides query for current memory usage and budget, which will probably + be more accurate than an estimation used by the library otherwise. + */ + VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT = 0x00000008, + /** + Enables usage of VK_AMD_device_coherent_memory extension. - You may set this flag only if you: + You may set this flag only if you: - - found out that this device extension is supported and enabled it while creating Vulkan device passed as VmaAllocatorCreateInfo::device, - - checked that `VkPhysicalDeviceCoherentMemoryFeaturesAMD::deviceCoherentMemory` is true and set it while creating the Vulkan device, - - want it to be used internally by this library. + - found out that this device extension is supported and enabled it while creating Vulkan device passed as VmaAllocatorCreateInfo::device, + - checked that `VkPhysicalDeviceCoherentMemoryFeaturesAMD::deviceCoherentMemory` is true and set it while creating the Vulkan device, + - want it to be used internally by this library. - The extension and accompanying device feature provide access to memory types with - `VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD` and `VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD` flags. - They are useful mostly for writing breadcrumb markers - a common method for debugging GPU crash/hang/TDR. + The extension and accompanying device feature provide access to memory types with + `VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD` and `VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD` flags. + They are useful mostly for writing breadcrumb markers - a common method for debugging GPU crash/hang/TDR. - When the extension is not enabled, such memory types are still enumerated, but their usage is illegal. - To protect from this error, if you don't create the allocator with this flag, it will refuse to allocate any memory or create a custom pool in such memory type, - returning `VK_ERROR_FEATURE_NOT_PRESENT`. - */ - VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT = 0x00000010, - /** - Enables usage of "buffer device address" feature, which allows you to use function - `vkGetBufferDeviceAddress*` to get raw GPU pointer to a buffer and pass it for usage inside a shader. + When the extension is not enabled, such memory types are still enumerated, but their usage is illegal. + To protect from this error, if you don't create the allocator with this flag, it will refuse to allocate any memory or create a custom pool in such memory type, + returning `VK_ERROR_FEATURE_NOT_PRESENT`. + */ + VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT = 0x00000010, + /** + Enables usage of "buffer device address" feature, which allows you to use function + `vkGetBufferDeviceAddress*` to get raw GPU pointer to a buffer and pass it for usage inside a shader. - You may set this flag only if you: + You may set this flag only if you: - 1. (For Vulkan version < 1.2) Found as available and enabled device extension - VK_KHR_buffer_device_address. - This extension is promoted to core Vulkan 1.2. - 2. Found as available and enabled device feature `VkPhysicalDeviceBufferDeviceAddressFeatures::bufferDeviceAddress`. + 1. (For Vulkan version < 1.2) Found as available and enabled device extension + VK_KHR_buffer_device_address. + This extension is promoted to core Vulkan 1.2. + 2. Found as available and enabled device feature `VkPhysicalDeviceBufferDeviceAddressFeatures::bufferDeviceAddress`. - When this flag is set, you can create buffers with `VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT` using VMA. - The library automatically adds `VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT` to - allocated memory blocks wherever it might be needed. + When this flag is set, you can create buffers with `VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT` using VMA. + The library automatically adds `VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT` to + allocated memory blocks wherever it might be needed. - For more information, see documentation chapter \ref enabling_buffer_device_address. - */ - VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT = 0x00000020, - /** - Enables usage of VK_EXT_memory_priority extension in the library. + For more information, see documentation chapter \ref enabling_buffer_device_address. + */ + VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT = 0x00000020, + /** + Enables usage of VK_EXT_memory_priority extension in the library. - You may set this flag only if you found available and enabled this device extension, - along with `VkPhysicalDeviceMemoryPriorityFeaturesEXT::memoryPriority == VK_TRUE`, - while creating Vulkan device passed as VmaAllocatorCreateInfo::device. + You may set this flag only if you found available and enabled this device extension, + along with `VkPhysicalDeviceMemoryPriorityFeaturesEXT::memoryPriority == VK_TRUE`, + while creating Vulkan device passed as VmaAllocatorCreateInfo::device. - When this flag is used, VmaAllocationCreateInfo::priority and VmaPoolCreateInfo::priority - are used to set priorities of allocated Vulkan memory. Without it, these variables are ignored. + When this flag is used, VmaAllocationCreateInfo::priority and VmaPoolCreateInfo::priority + are used to set priorities of allocated Vulkan memory. Without it, these variables are ignored. - A priority must be a floating-point value between 0 and 1, indicating the priority of the allocation relative to other memory allocations. - Larger values are higher priority. The granularity of the priorities is implementation-dependent. - It is automatically passed to every call to `vkAllocateMemory` done by the library using structure `VkMemoryPriorityAllocateInfoEXT`. - The value to be used for default priority is 0.5. - For more details, see the documentation of the VK_EXT_memory_priority extension. - */ - VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT = 0x00000040, - /** - Enables usage of VK_KHR_maintenance4 extension in the library. + A priority must be a floating-point value between 0 and 1, indicating the priority of the allocation relative to other memory allocations. + Larger values are higher priority. The granularity of the priorities is implementation-dependent. + It is automatically passed to every call to `vkAllocateMemory` done by the library using structure `VkMemoryPriorityAllocateInfoEXT`. + The value to be used for default priority is 0.5. + For more details, see the documentation of the VK_EXT_memory_priority extension. + */ + VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT = 0x00000040, + /** + Enables usage of VK_KHR_maintenance4 extension in the library. - You may set this flag only if you found available and enabled this device extension, - while creating Vulkan device passed as VmaAllocatorCreateInfo::device. - */ - VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE4_BIT = 0x00000080, - /** - Enables usage of VK_KHR_maintenance5 extension in the library. + You may set this flag only if you found available and enabled this device extension, + while creating Vulkan device passed as VmaAllocatorCreateInfo::device. + */ + VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE4_BIT = 0x00000080, + /** + Enables usage of VK_KHR_maintenance5 extension in the library. - You should set this flag if you found available and enabled this device extension, - while creating Vulkan device passed as VmaAllocatorCreateInfo::device. - */ - VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT = 0x00000100, + You should set this flag if you found available and enabled this device extension, + while creating Vulkan device passed as VmaAllocatorCreateInfo::device. + */ + VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT = 0x00000100, + + /** + Enables usage of VK_KHR_external_memory_win32 extension in the library. + + You should set this flag if you found available and enabled this device extension, + while creating Vulkan device passed as VmaAllocatorCreateInfo::device. + */ + VMA_ALLOCATOR_CREATE_KHR_EXTERNAL_MEMORY_WIN32 = 0x00000200, + + VMA_ALLOCATOR_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF + } VmaAllocatorCreateFlagBits; + /// See #VmaAllocatorCreateFlagBits. + typedef VkFlags VmaAllocatorCreateFlags; + + /** @} */ /** - Enables usage of VK_KHR_external_memory_win32 extension in the library. - - You should set this flag if you found available and enabled this device extension, - while creating Vulkan device passed as VmaAllocatorCreateInfo::device. + \addtogroup group_alloc + @{ */ - VMA_ALLOCATOR_CREATE_KHR_EXTERNAL_MEMORY_WIN32 = 0x00000200, - VMA_ALLOCATOR_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VmaAllocatorCreateFlagBits; -/// See #VmaAllocatorCreateFlagBits. -typedef VkFlags VmaAllocatorCreateFlags; + /// \brief Intended usage of the allocated memory. + typedef enum VmaMemoryUsage + { + /** No intended memory usage specified. + Use other members of VmaAllocationCreateInfo to specify your requirements. + */ + VMA_MEMORY_USAGE_UNKNOWN = 0, + /** + \deprecated Obsolete, preserved for backward compatibility. + Prefers `VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT`. + */ + VMA_MEMORY_USAGE_GPU_ONLY = 1, + /** + \deprecated Obsolete, preserved for backward compatibility. + Guarantees `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT` and `VK_MEMORY_PROPERTY_HOST_COHERENT_BIT`. + */ + VMA_MEMORY_USAGE_CPU_ONLY = 2, + /** + \deprecated Obsolete, preserved for backward compatibility. + Guarantees `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT`, prefers `VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT`. + */ + VMA_MEMORY_USAGE_CPU_TO_GPU = 3, + /** + \deprecated Obsolete, preserved for backward compatibility. + Guarantees `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT`, prefers `VK_MEMORY_PROPERTY_HOST_CACHED_BIT`. + */ + VMA_MEMORY_USAGE_GPU_TO_CPU = 4, + /** + \deprecated Obsolete, preserved for backward compatibility. + Prefers not `VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT`. + */ + VMA_MEMORY_USAGE_CPU_COPY = 5, + /** + Lazily allocated GPU memory having `VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT`. + Exists mostly on mobile platforms. Using it on desktop PC or other GPUs with no such memory type present will fail the allocation. -/** @} */ + Usage: Memory for transient attachment images (color attachments, depth attachments etc.), created with `VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT`. -/** -\addtogroup group_alloc -@{ -*/ + Allocations with this usage are always created as dedicated - it implies #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT. + */ + VMA_MEMORY_USAGE_GPU_LAZILY_ALLOCATED = 6, + /** + Selects best memory type automatically. + This flag is recommended for most common use cases. -/// \brief Intended usage of the allocated memory. -typedef enum VmaMemoryUsage -{ - /** No intended memory usage specified. - Use other members of VmaAllocationCreateInfo to specify your requirements. - */ - VMA_MEMORY_USAGE_UNKNOWN = 0, - /** - \deprecated Obsolete, preserved for backward compatibility. - Prefers `VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT`. - */ - VMA_MEMORY_USAGE_GPU_ONLY = 1, - /** - \deprecated Obsolete, preserved for backward compatibility. - Guarantees `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT` and `VK_MEMORY_PROPERTY_HOST_COHERENT_BIT`. - */ - VMA_MEMORY_USAGE_CPU_ONLY = 2, - /** - \deprecated Obsolete, preserved for backward compatibility. - Guarantees `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT`, prefers `VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT`. - */ - VMA_MEMORY_USAGE_CPU_TO_GPU = 3, - /** - \deprecated Obsolete, preserved for backward compatibility. - Guarantees `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT`, prefers `VK_MEMORY_PROPERTY_HOST_CACHED_BIT`. - */ - VMA_MEMORY_USAGE_GPU_TO_CPU = 4, - /** - \deprecated Obsolete, preserved for backward compatibility. - Prefers not `VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT`. - */ - VMA_MEMORY_USAGE_CPU_COPY = 5, - /** - Lazily allocated GPU memory having `VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT`. - Exists mostly on mobile platforms. Using it on desktop PC or other GPUs with no such memory type present will fail the allocation. + When using this flag, if you want to map the allocation (using vmaMapMemory() or #VMA_ALLOCATION_CREATE_MAPPED_BIT), + you must pass one of the flags: #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT + in VmaAllocationCreateInfo::flags. - Usage: Memory for transient attachment images (color attachments, depth attachments etc.), created with `VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT`. + It can be used only with functions that let the library know `VkBufferCreateInfo` or `VkImageCreateInfo`, e.g. + vmaCreateBuffer(), vmaCreateImage(), vmaFindMemoryTypeIndexForBufferInfo(), vmaFindMemoryTypeIndexForImageInfo() + and not with generic memory allocation functions. + */ + VMA_MEMORY_USAGE_AUTO = 7, + /** + Selects best memory type automatically with preference for GPU (device) memory. - Allocations with this usage are always created as dedicated - it implies #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT. - */ - VMA_MEMORY_USAGE_GPU_LAZILY_ALLOCATED = 6, - /** - Selects best memory type automatically. - This flag is recommended for most common use cases. + When using this flag, if you want to map the allocation (using vmaMapMemory() or #VMA_ALLOCATION_CREATE_MAPPED_BIT), + you must pass one of the flags: #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT + in VmaAllocationCreateInfo::flags. - When using this flag, if you want to map the allocation (using vmaMapMemory() or #VMA_ALLOCATION_CREATE_MAPPED_BIT), - you must pass one of the flags: #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT - in VmaAllocationCreateInfo::flags. + It can be used only with functions that let the library know `VkBufferCreateInfo` or `VkImageCreateInfo`, e.g. + vmaCreateBuffer(), vmaCreateImage(), vmaFindMemoryTypeIndexForBufferInfo(), vmaFindMemoryTypeIndexForImageInfo() + and not with generic memory allocation functions. + */ + VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE = 8, + /** + Selects best memory type automatically with preference for CPU (host) memory. - It can be used only with functions that let the library know `VkBufferCreateInfo` or `VkImageCreateInfo`, e.g. - vmaCreateBuffer(), vmaCreateImage(), vmaFindMemoryTypeIndexForBufferInfo(), vmaFindMemoryTypeIndexForImageInfo() - and not with generic memory allocation functions. - */ - VMA_MEMORY_USAGE_AUTO = 7, - /** - Selects best memory type automatically with preference for GPU (device) memory. + When using this flag, if you want to map the allocation (using vmaMapMemory() or #VMA_ALLOCATION_CREATE_MAPPED_BIT), + you must pass one of the flags: #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT + in VmaAllocationCreateInfo::flags. - When using this flag, if you want to map the allocation (using vmaMapMemory() or #VMA_ALLOCATION_CREATE_MAPPED_BIT), - you must pass one of the flags: #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT - in VmaAllocationCreateInfo::flags. + It can be used only with functions that let the library know `VkBufferCreateInfo` or `VkImageCreateInfo`, e.g. + vmaCreateBuffer(), vmaCreateImage(), vmaFindMemoryTypeIndexForBufferInfo(), vmaFindMemoryTypeIndexForImageInfo() + and not with generic memory allocation functions. + */ + VMA_MEMORY_USAGE_AUTO_PREFER_HOST = 9, - It can be used only with functions that let the library know `VkBufferCreateInfo` or `VkImageCreateInfo`, e.g. - vmaCreateBuffer(), vmaCreateImage(), vmaFindMemoryTypeIndexForBufferInfo(), vmaFindMemoryTypeIndexForImageInfo() - and not with generic memory allocation functions. - */ - VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE = 8, - /** - Selects best memory type automatically with preference for CPU (host) memory. + VMA_MEMORY_USAGE_MAX_ENUM = 0x7FFFFFFF + } VmaMemoryUsage; - When using this flag, if you want to map the allocation (using vmaMapMemory() or #VMA_ALLOCATION_CREATE_MAPPED_BIT), - you must pass one of the flags: #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT - in VmaAllocationCreateInfo::flags. + /// Flags to be passed as VmaAllocationCreateInfo::flags. + typedef enum VmaAllocationCreateFlagBits + { + /** \brief Set this flag if the allocation should have its own memory block. - It can be used only with functions that let the library know `VkBufferCreateInfo` or `VkImageCreateInfo`, e.g. - vmaCreateBuffer(), vmaCreateImage(), vmaFindMemoryTypeIndexForBufferInfo(), vmaFindMemoryTypeIndexForImageInfo() - and not with generic memory allocation functions. - */ - VMA_MEMORY_USAGE_AUTO_PREFER_HOST = 9, + Use it for special, big resources, like fullscreen images used as attachments. - VMA_MEMORY_USAGE_MAX_ENUM = 0x7FFFFFFF -} VmaMemoryUsage; + If you use this flag while creating a buffer or an image, `VkMemoryDedicatedAllocateInfo` + structure is applied if possible. + */ + VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT = 0x00000001, -/// Flags to be passed as VmaAllocationCreateInfo::flags. -typedef enum VmaAllocationCreateFlagBits -{ - /** \brief Set this flag if the allocation should have its own memory block. + /** \brief Set this flag to only try to allocate from existing `VkDeviceMemory` blocks and never create new such block. - Use it for special, big resources, like fullscreen images used as attachments. + If new allocation cannot be placed in any of the existing blocks, allocation + fails with `VK_ERROR_OUT_OF_DEVICE_MEMORY` error. - If you use this flag while creating a buffer or an image, `VkMemoryDedicatedAllocateInfo` - structure is applied if possible. - */ - VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT = 0x00000001, + You should not use #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT and + #VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT at the same time. It makes no sense. + */ + VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT = 0x00000002, + /** \brief Set this flag to use a memory that will be persistently mapped and retrieve pointer to it. - /** \brief Set this flag to only try to allocate from existing `VkDeviceMemory` blocks and never create new such block. + Pointer to mapped memory will be returned through VmaAllocationInfo::pMappedData. - If new allocation cannot be placed in any of the existing blocks, allocation - fails with `VK_ERROR_OUT_OF_DEVICE_MEMORY` error. + It is valid to use this flag for allocation made from memory type that is not + `HOST_VISIBLE`. This flag is then ignored and memory is not mapped. This is + useful if you need an allocation that is efficient to use on GPU + (`DEVICE_LOCAL`) and still want to map it directly if possible on platforms that + support it (e.g. Intel GPU). + */ + VMA_ALLOCATION_CREATE_MAPPED_BIT = 0x00000004, + /** \deprecated Preserved for backward compatibility. Consider using vmaSetAllocationName() instead. - You should not use #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT and - #VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT at the same time. It makes no sense. - */ - VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT = 0x00000002, - /** \brief Set this flag to use a memory that will be persistently mapped and retrieve pointer to it. + Set this flag to treat VmaAllocationCreateInfo::pUserData as pointer to a + null-terminated string. Instead of copying pointer value, a local copy of the + string is made and stored in allocation's `pName`. The string is automatically + freed together with the allocation. It is also used in vmaBuildStatsString(). + */ + VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT = 0x00000020, + /** Allocation will be created from upper stack in a double stack pool. - Pointer to mapped memory will be returned through VmaAllocationInfo::pMappedData. + This flag is only allowed for custom pools created with #VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT flag. + */ + VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT = 0x00000040, + /** Create both buffer/image and allocation, but don't bind them together. + It is useful when you want to bind yourself to do some more advanced binding, e.g. using some extensions. + The flag is meaningful only with functions that bind by default: vmaCreateBuffer(), vmaCreateImage(). + Otherwise it is ignored. - It is valid to use this flag for allocation made from memory type that is not - `HOST_VISIBLE`. This flag is then ignored and memory is not mapped. This is - useful if you need an allocation that is efficient to use on GPU - (`DEVICE_LOCAL`) and still want to map it directly if possible on platforms that - support it (e.g. Intel GPU). - */ - VMA_ALLOCATION_CREATE_MAPPED_BIT = 0x00000004, - /** \deprecated Preserved for backward compatibility. Consider using vmaSetAllocationName() instead. + If you want to make sure the new buffer/image is not tied to the new memory allocation + through `VkMemoryDedicatedAllocateInfoKHR` structure in case the allocation ends up in its own memory block, + use also flag #VMA_ALLOCATION_CREATE_CAN_ALIAS_BIT. + */ + VMA_ALLOCATION_CREATE_DONT_BIND_BIT = 0x00000080, + /** Create allocation only if additional device memory required for it, if any, won't exceed + memory budget. Otherwise return `VK_ERROR_OUT_OF_DEVICE_MEMORY`. + */ + VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT = 0x00000100, + /** \brief Set this flag if the allocated memory will have aliasing resources. - Set this flag to treat VmaAllocationCreateInfo::pUserData as pointer to a - null-terminated string. Instead of copying pointer value, a local copy of the - string is made and stored in allocation's `pName`. The string is automatically - freed together with the allocation. It is also used in vmaBuildStatsString(). - */ - VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT = 0x00000020, - /** Allocation will be created from upper stack in a double stack pool. + Usage of this flag prevents supplying `VkMemoryDedicatedAllocateInfoKHR` when #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT is specified. + Otherwise created dedicated memory will not be suitable for aliasing resources, resulting in Vulkan Validation Layer errors. + */ + VMA_ALLOCATION_CREATE_CAN_ALIAS_BIT = 0x00000200, + /** + Requests possibility to map the allocation (using vmaMapMemory() or #VMA_ALLOCATION_CREATE_MAPPED_BIT). - This flag is only allowed for custom pools created with #VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT flag. - */ - VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT = 0x00000040, - /** Create both buffer/image and allocation, but don't bind them together. - It is useful when you want to bind yourself to do some more advanced binding, e.g. using some extensions. - The flag is meaningful only with functions that bind by default: vmaCreateBuffer(), vmaCreateImage(). - Otherwise it is ignored. + - If you use #VMA_MEMORY_USAGE_AUTO or other `VMA_MEMORY_USAGE_AUTO*` value, + you must use this flag to be able to map the allocation. Otherwise, mapping is incorrect. + - If you use other value of #VmaMemoryUsage, this flag is ignored and mapping is always possible in memory types that are `HOST_VISIBLE`. + This includes allocations created in \ref custom_memory_pools. - If you want to make sure the new buffer/image is not tied to the new memory allocation - through `VkMemoryDedicatedAllocateInfoKHR` structure in case the allocation ends up in its own memory block, - use also flag #VMA_ALLOCATION_CREATE_CAN_ALIAS_BIT. - */ - VMA_ALLOCATION_CREATE_DONT_BIND_BIT = 0x00000080, - /** Create allocation only if additional device memory required for it, if any, won't exceed - memory budget. Otherwise return `VK_ERROR_OUT_OF_DEVICE_MEMORY`. - */ - VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT = 0x00000100, - /** \brief Set this flag if the allocated memory will have aliasing resources. + Declares that mapped memory will only be written sequentially, e.g. using `memcpy()` or a loop writing number-by-number, + never read or accessed randomly, so a memory type can be selected that is uncached and write-combined. - Usage of this flag prevents supplying `VkMemoryDedicatedAllocateInfoKHR` when #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT is specified. - Otherwise created dedicated memory will not be suitable for aliasing resources, resulting in Vulkan Validation Layer errors. - */ - VMA_ALLOCATION_CREATE_CAN_ALIAS_BIT = 0x00000200, - /** - Requests possibility to map the allocation (using vmaMapMemory() or #VMA_ALLOCATION_CREATE_MAPPED_BIT). + \warning Violating this declaration may work correctly, but will likely be very slow. + Watch out for implicit reads introduced by doing e.g. `pMappedData[i] += x;` + Better prepare your data in a local variable and `memcpy()` it to the mapped pointer all at once. + */ + VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT = 0x00000400, + /** + Requests possibility to map the allocation (using vmaMapMemory() or #VMA_ALLOCATION_CREATE_MAPPED_BIT). - - If you use #VMA_MEMORY_USAGE_AUTO or other `VMA_MEMORY_USAGE_AUTO*` value, - you must use this flag to be able to map the allocation. Otherwise, mapping is incorrect. - - If you use other value of #VmaMemoryUsage, this flag is ignored and mapping is always possible in memory types that are `HOST_VISIBLE`. - This includes allocations created in \ref custom_memory_pools. + - If you use #VMA_MEMORY_USAGE_AUTO or other `VMA_MEMORY_USAGE_AUTO*` value, + you must use this flag to be able to map the allocation. Otherwise, mapping is incorrect. + - If you use other value of #VmaMemoryUsage, this flag is ignored and mapping is always possible in memory types that are `HOST_VISIBLE`. + This includes allocations created in \ref custom_memory_pools. - Declares that mapped memory will only be written sequentially, e.g. using `memcpy()` or a loop writing number-by-number, - never read or accessed randomly, so a memory type can be selected that is uncached and write-combined. + Declares that mapped memory can be read, written, and accessed in random order, + so a `HOST_CACHED` memory type is preferred. + */ + VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT = 0x00000800, + /** + Together with #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT, + it says that despite request for host access, a not-`HOST_VISIBLE` memory type can be selected + if it may improve performance. - \warning Violating this declaration may work correctly, but will likely be very slow. - Watch out for implicit reads introduced by doing e.g. `pMappedData[i] += x;` - Better prepare your data in a local variable and `memcpy()` it to the mapped pointer all at once. - */ - VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT = 0x00000400, - /** - Requests possibility to map the allocation (using vmaMapMemory() or #VMA_ALLOCATION_CREATE_MAPPED_BIT). - - - If you use #VMA_MEMORY_USAGE_AUTO or other `VMA_MEMORY_USAGE_AUTO*` value, - you must use this flag to be able to map the allocation. Otherwise, mapping is incorrect. - - If you use other value of #VmaMemoryUsage, this flag is ignored and mapping is always possible in memory types that are `HOST_VISIBLE`. - This includes allocations created in \ref custom_memory_pools. - - Declares that mapped memory can be read, written, and accessed in random order, - so a `HOST_CACHED` memory type is preferred. - */ - VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT = 0x00000800, - /** - Together with #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT, - it says that despite request for host access, a not-`HOST_VISIBLE` memory type can be selected - if it may improve performance. - - By using this flag, you declare that you will check if the allocation ended up in a `HOST_VISIBLE` memory type - (e.g. using vmaGetAllocationMemoryProperties()) and if not, you will create some "staging" buffer and - issue an explicit transfer to write/read your data. - To prepare for this possibility, don't forget to add appropriate flags like - `VK_BUFFER_USAGE_TRANSFER_DST_BIT`, `VK_BUFFER_USAGE_TRANSFER_SRC_BIT` to the parameters of created buffer or image. - */ - VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT = 0x00001000, - /** Allocation strategy that chooses smallest possible free range for the allocation - to minimize memory usage and fragmentation, possibly at the expense of allocation time. - */ - VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT = 0x00010000, - /** Allocation strategy that chooses first suitable free range for the allocation - - not necessarily in terms of the smallest offset but the one that is easiest and fastest to find - to minimize allocation time, possibly at the expense of allocation quality. - */ - VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT = 0x00020000, - /** Allocation strategy that chooses always the lowest offset in available space. - This is not the most efficient strategy but achieves highly packed data. - Used internally by defragmentation, not recommended in typical usage. - */ - VMA_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT = 0x00040000, - /** Alias to #VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT. - */ - VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT = VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT, - /** Alias to #VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT. - */ - VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT = VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT, - /** A bit mask to extract only `STRATEGY` bits from entire set of flags. - */ - VMA_ALLOCATION_CREATE_STRATEGY_MASK = + By using this flag, you declare that you will check if the allocation ended up in a `HOST_VISIBLE` memory type + (e.g. using vmaGetAllocationMemoryProperties()) and if not, you will create some "staging" buffer and + issue an explicit transfer to write/read your data. + To prepare for this possibility, don't forget to add appropriate flags like + `VK_BUFFER_USAGE_TRANSFER_DST_BIT`, `VK_BUFFER_USAGE_TRANSFER_SRC_BIT` to the parameters of created buffer or image. + */ + VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT = 0x00001000, + /** Allocation strategy that chooses smallest possible free range for the allocation + to minimize memory usage and fragmentation, possibly at the expense of allocation time. + */ + VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT = 0x00010000, + /** Allocation strategy that chooses first suitable free range for the allocation - + not necessarily in terms of the smallest offset but the one that is easiest and fastest to find + to minimize allocation time, possibly at the expense of allocation quality. + */ + VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT = 0x00020000, + /** Allocation strategy that chooses always the lowest offset in available space. + This is not the most efficient strategy but achieves highly packed data. + Used internally by defragmentation, not recommended in typical usage. + */ + VMA_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT = 0x00040000, + /** Alias to #VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT. + */ + VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT = VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT, + /** Alias to #VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT. + */ + VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT = VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT, + /** A bit mask to extract only `STRATEGY` bits from entire set of flags. + */ + VMA_ALLOCATION_CREATE_STRATEGY_MASK = VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT | VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT | VMA_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT, - VMA_ALLOCATION_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VmaAllocationCreateFlagBits; -/// See #VmaAllocationCreateFlagBits. -typedef VkFlags VmaAllocationCreateFlags; + VMA_ALLOCATION_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF + } VmaAllocationCreateFlagBits; + /// See #VmaAllocationCreateFlagBits. + typedef VkFlags VmaAllocationCreateFlags; -/// Flags to be passed as VmaPoolCreateInfo::flags. -typedef enum VmaPoolCreateFlagBits -{ - /** \brief Use this flag if you always allocate only buffers and linear images or only optimal images out of this pool and so Buffer-Image Granularity can be ignored. + /// Flags to be passed as VmaPoolCreateInfo::flags. + typedef enum VmaPoolCreateFlagBits + { + /** \brief Use this flag if you always allocate only buffers and linear images or only optimal images out of this pool and so Buffer-Image Granularity can be ignored. - This is an optional optimization flag. + This is an optional optimization flag. - If you always allocate using vmaCreateBuffer(), vmaCreateImage(), - vmaAllocateMemoryForBuffer(), then you don't need to use it because allocator - knows exact type of your allocations so it can handle Buffer-Image Granularity - in the optimal way. + If you always allocate using vmaCreateBuffer(), vmaCreateImage(), + vmaAllocateMemoryForBuffer(), then you don't need to use it because allocator + knows exact type of your allocations so it can handle Buffer-Image Granularity + in the optimal way. - If you also allocate using vmaAllocateMemoryForImage() or vmaAllocateMemory(), - exact type of such allocations is not known, so allocator must be conservative - in handling Buffer-Image Granularity, which can lead to suboptimal allocation - (wasted memory). In that case, if you can make sure you always allocate only - buffers and linear images or only optimal images out of this pool, use this flag - to make allocator disregard Buffer-Image Granularity and so make allocations - faster and more optimal. - */ - VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT = 0x00000002, + If you also allocate using vmaAllocateMemoryForImage() or vmaAllocateMemory(), + exact type of such allocations is not known, so allocator must be conservative + in handling Buffer-Image Granularity, which can lead to suboptimal allocation + (wasted memory). In that case, if you can make sure you always allocate only + buffers and linear images or only optimal images out of this pool, use this flag + to make allocator disregard Buffer-Image Granularity and so make allocations + faster and more optimal. + */ + VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT = 0x00000002, - /** \brief Enables alternative, linear allocation algorithm in this pool. + /** \brief Enables alternative, linear allocation algorithm in this pool. - Specify this flag to enable linear allocation algorithm, which always creates - new allocations after last one and doesn't reuse space from allocations freed in - between. It trades memory consumption for simplified algorithm and data - structure, which has better performance and uses less memory for metadata. + Specify this flag to enable linear allocation algorithm, which always creates + new allocations after last one and doesn't reuse space from allocations freed in + between. It trades memory consumption for simplified algorithm and data + structure, which has better performance and uses less memory for metadata. - By using this flag, you can achieve behavior of free-at-once, stack, - ring buffer, and double stack. - For details, see documentation chapter \ref linear_algorithm. - */ - VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT = 0x00000004, + By using this flag, you can achieve behavior of free-at-once, stack, + ring buffer, and double stack. + For details, see documentation chapter \ref linear_algorithm. + */ + VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT = 0x00000004, - /** Bit mask to extract only `ALGORITHM` bits from entire set of flags. - */ - VMA_POOL_CREATE_ALGORITHM_MASK = + /** Bit mask to extract only `ALGORITHM` bits from entire set of flags. + */ + VMA_POOL_CREATE_ALGORITHM_MASK = VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT, - VMA_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VmaPoolCreateFlagBits; -/// Flags to be passed as VmaPoolCreateInfo::flags. See #VmaPoolCreateFlagBits. -typedef VkFlags VmaPoolCreateFlags; + VMA_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF + } VmaPoolCreateFlagBits; + /// Flags to be passed as VmaPoolCreateInfo::flags. See #VmaPoolCreateFlagBits. + typedef VkFlags VmaPoolCreateFlags; -/// Flags to be passed as VmaDefragmentationInfo::flags. -typedef enum VmaDefragmentationFlagBits -{ - /* \brief Use simple but fast algorithm for defragmentation. - May not achieve best results but will require least time to compute and least allocations to copy. - */ - VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FAST_BIT = 0x1, - /* \brief Default defragmentation algorithm, applied also when no `ALGORITHM` flag is specified. - Offers a balance between defragmentation quality and the amount of allocations and bytes that need to be moved. - */ - VMA_DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED_BIT = 0x2, - /* \brief Perform full defragmentation of memory. - Can result in notably more time to compute and allocations to copy, but will achieve best memory packing. - */ - VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FULL_BIT = 0x4, - /** \brief Use the most roboust algorithm at the cost of time to compute and number of copies to make. - Only available when bufferImageGranularity is greater than 1, since it aims to reduce - alignment issues between different types of resources. - Otherwise falls back to same behavior as #VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FULL_BIT. - */ - VMA_DEFRAGMENTATION_FLAG_ALGORITHM_EXTENSIVE_BIT = 0x8, + /// Flags to be passed as VmaDefragmentationInfo::flags. + typedef enum VmaDefragmentationFlagBits + { + /* \brief Use simple but fast algorithm for defragmentation. + May not achieve best results but will require least time to compute and least allocations to copy. + */ + VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FAST_BIT = 0x1, + /* \brief Default defragmentation algorithm, applied also when no `ALGORITHM` flag is specified. + Offers a balance between defragmentation quality and the amount of allocations and bytes that need to be moved. + */ + VMA_DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED_BIT = 0x2, + /* \brief Perform full defragmentation of memory. + Can result in notably more time to compute and allocations to copy, but will achieve best memory packing. + */ + VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FULL_BIT = 0x4, + /** \brief Use the most roboust algorithm at the cost of time to compute and number of copies to make. + Only available when bufferImageGranularity is greater than 1, since it aims to reduce + alignment issues between different types of resources. + Otherwise falls back to same behavior as #VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FULL_BIT. + */ + VMA_DEFRAGMENTATION_FLAG_ALGORITHM_EXTENSIVE_BIT = 0x8, - /// A bit mask to extract only `ALGORITHM` bits from entire set of flags. - VMA_DEFRAGMENTATION_FLAG_ALGORITHM_MASK = + /// A bit mask to extract only `ALGORITHM` bits from entire set of flags. + VMA_DEFRAGMENTATION_FLAG_ALGORITHM_MASK = VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FAST_BIT | VMA_DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED_BIT | VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FULL_BIT | VMA_DEFRAGMENTATION_FLAG_ALGORITHM_EXTENSIVE_BIT, - VMA_DEFRAGMENTATION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VmaDefragmentationFlagBits; -/// See #VmaDefragmentationFlagBits. -typedef VkFlags VmaDefragmentationFlags; + VMA_DEFRAGMENTATION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF + } VmaDefragmentationFlagBits; + /// See #VmaDefragmentationFlagBits. + typedef VkFlags VmaDefragmentationFlags; -/// Operation performed on single defragmentation move. See structure #VmaDefragmentationMove. -typedef enum VmaDefragmentationMoveOperation -{ - /// Buffer/image has been recreated at `dstTmpAllocation`, data has been copied, old buffer/image has been destroyed. `srcAllocation` should be changed to point to the new place. This is the default value set by vmaBeginDefragmentationPass(). - VMA_DEFRAGMENTATION_MOVE_OPERATION_COPY = 0, - /// Set this value if you cannot move the allocation. New place reserved at `dstTmpAllocation` will be freed. `srcAllocation` will remain unchanged. - VMA_DEFRAGMENTATION_MOVE_OPERATION_IGNORE = 1, - /// Set this value if you decide to abandon the allocation and you destroyed the buffer/image. New place reserved at `dstTmpAllocation` will be freed, along with `srcAllocation`, which will be destroyed. - VMA_DEFRAGMENTATION_MOVE_OPERATION_DESTROY = 2, -} VmaDefragmentationMoveOperation; + /// Operation performed on single defragmentation move. See structure #VmaDefragmentationMove. + typedef enum VmaDefragmentationMoveOperation + { + /// Buffer/image has been recreated at `dstTmpAllocation`, data has been copied, old buffer/image has been destroyed. `srcAllocation` should be changed to point to the new place. This is the default value set by vmaBeginDefragmentationPass(). + VMA_DEFRAGMENTATION_MOVE_OPERATION_COPY = 0, + /// Set this value if you cannot move the allocation. New place reserved at `dstTmpAllocation` will be freed. `srcAllocation` will remain unchanged. + VMA_DEFRAGMENTATION_MOVE_OPERATION_IGNORE = 1, + /// Set this value if you decide to abandon the allocation and you destroyed the buffer/image. New place reserved at `dstTmpAllocation` will be freed, along with `srcAllocation`, which will be destroyed. + VMA_DEFRAGMENTATION_MOVE_OPERATION_DESTROY = 2, + } VmaDefragmentationMoveOperation; -/** @} */ + /** @} */ -/** -\addtogroup group_virtual -@{ -*/ - -/// Flags to be passed as VmaVirtualBlockCreateInfo::flags. -typedef enum VmaVirtualBlockCreateFlagBits -{ - /** \brief Enables alternative, linear allocation algorithm in this virtual block. - - Specify this flag to enable linear allocation algorithm, which always creates - new allocations after last one and doesn't reuse space from allocations freed in - between. It trades memory consumption for simplified algorithm and data - structure, which has better performance and uses less memory for metadata. - - By using this flag, you can achieve behavior of free-at-once, stack, - ring buffer, and double stack. - For details, see documentation chapter \ref linear_algorithm. + /** + \addtogroup group_virtual + @{ */ - VMA_VIRTUAL_BLOCK_CREATE_LINEAR_ALGORITHM_BIT = 0x00000001, - /** \brief Bit mask to extract only `ALGORITHM` bits from entire set of flags. - */ - VMA_VIRTUAL_BLOCK_CREATE_ALGORITHM_MASK = + /// Flags to be passed as VmaVirtualBlockCreateInfo::flags. + typedef enum VmaVirtualBlockCreateFlagBits + { + /** \brief Enables alternative, linear allocation algorithm in this virtual block. + + Specify this flag to enable linear allocation algorithm, which always creates + new allocations after last one and doesn't reuse space from allocations freed in + between. It trades memory consumption for simplified algorithm and data + structure, which has better performance and uses less memory for metadata. + + By using this flag, you can achieve behavior of free-at-once, stack, + ring buffer, and double stack. + For details, see documentation chapter \ref linear_algorithm. + */ + VMA_VIRTUAL_BLOCK_CREATE_LINEAR_ALGORITHM_BIT = 0x00000001, + + /** \brief Bit mask to extract only `ALGORITHM` bits from entire set of flags. + */ + VMA_VIRTUAL_BLOCK_CREATE_ALGORITHM_MASK = VMA_VIRTUAL_BLOCK_CREATE_LINEAR_ALGORITHM_BIT, - VMA_VIRTUAL_BLOCK_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VmaVirtualBlockCreateFlagBits; -/// Flags to be passed as VmaVirtualBlockCreateInfo::flags. See #VmaVirtualBlockCreateFlagBits. -typedef VkFlags VmaVirtualBlockCreateFlags; + VMA_VIRTUAL_BLOCK_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF + } VmaVirtualBlockCreateFlagBits; + /// Flags to be passed as VmaVirtualBlockCreateInfo::flags. See #VmaVirtualBlockCreateFlagBits. + typedef VkFlags VmaVirtualBlockCreateFlags; -/// Flags to be passed as VmaVirtualAllocationCreateInfo::flags. -typedef enum VmaVirtualAllocationCreateFlagBits -{ - /** \brief Allocation will be created from upper stack in a double stack pool. + /// Flags to be passed as VmaVirtualAllocationCreateInfo::flags. + typedef enum VmaVirtualAllocationCreateFlagBits + { + /** \brief Allocation will be created from upper stack in a double stack pool. - This flag is only allowed for virtual blocks created with #VMA_VIRTUAL_BLOCK_CREATE_LINEAR_ALGORITHM_BIT flag. - */ - VMA_VIRTUAL_ALLOCATION_CREATE_UPPER_ADDRESS_BIT = VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT, - /** \brief Allocation strategy that tries to minimize memory usage. - */ - VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT = VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT, - /** \brief Allocation strategy that tries to minimize allocation time. - */ - VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT = VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT, - /** Allocation strategy that chooses always the lowest offset in available space. - This is not the most efficient strategy but achieves highly packed data. - */ - VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT = VMA_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT, - /** \brief A bit mask to extract only `STRATEGY` bits from entire set of flags. + This flag is only allowed for virtual blocks created with #VMA_VIRTUAL_BLOCK_CREATE_LINEAR_ALGORITHM_BIT flag. + */ + VMA_VIRTUAL_ALLOCATION_CREATE_UPPER_ADDRESS_BIT = VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT, + /** \brief Allocation strategy that tries to minimize memory usage. + */ + VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT = VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT, + /** \brief Allocation strategy that tries to minimize allocation time. + */ + VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT = VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT, + /** Allocation strategy that chooses always the lowest offset in available space. + This is not the most efficient strategy but achieves highly packed data. + */ + VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT = VMA_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT, + /** \brief A bit mask to extract only `STRATEGY` bits from entire set of flags. - These strategy flags are binary compatible with equivalent flags in #VmaAllocationCreateFlagBits. - */ - VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MASK = VMA_ALLOCATION_CREATE_STRATEGY_MASK, + These strategy flags are binary compatible with equivalent flags in #VmaAllocationCreateFlagBits. + */ + VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MASK = VMA_ALLOCATION_CREATE_STRATEGY_MASK, - VMA_VIRTUAL_ALLOCATION_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF -} VmaVirtualAllocationCreateFlagBits; -/// Flags to be passed as VmaVirtualAllocationCreateInfo::flags. See #VmaVirtualAllocationCreateFlagBits. -typedef VkFlags VmaVirtualAllocationCreateFlags; + VMA_VIRTUAL_ALLOCATION_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF + } VmaVirtualAllocationCreateFlagBits; + /// Flags to be passed as VmaVirtualAllocationCreateInfo::flags. See #VmaVirtualAllocationCreateFlagBits. + typedef VkFlags VmaVirtualAllocationCreateFlags; -/** @} */ + /** @} */ #endif // _VMA_ENUM_DECLARATIONS @@ -871,781 +871,781 @@ Call function vmaDestroyAllocator() to destroy it. It is recommended to create just one object of this type per `VkDevice` object, right after Vulkan is initialized and keep it alive until before Vulkan device is destroyed. */ -VK_DEFINE_HANDLE(VmaAllocator) + VK_DEFINE_HANDLE(VmaAllocator) -/** @} */ + /** @} */ -/** -\addtogroup group_alloc -@{ -*/ + /** + \addtogroup group_alloc + @{ + */ -/** \struct VmaPool -\brief Represents custom memory pool + /** \struct VmaPool + \brief Represents custom memory pool -Fill structure VmaPoolCreateInfo and call function vmaCreatePool() to create it. -Call function vmaDestroyPool() to destroy it. + Fill structure VmaPoolCreateInfo and call function vmaCreatePool() to create it. + Call function vmaDestroyPool() to destroy it. -For more information see [Custom memory pools](@ref choosing_memory_type_custom_memory_pools). -*/ -VK_DEFINE_HANDLE(VmaPool) + For more information see [Custom memory pools](@ref choosing_memory_type_custom_memory_pools). + */ + VK_DEFINE_HANDLE(VmaPool) -/** \struct VmaAllocation -\brief Represents single memory allocation. + /** \struct VmaAllocation + \brief Represents single memory allocation. -It may be either dedicated block of `VkDeviceMemory` or a specific region of a bigger block of this type -plus unique offset. + It may be either dedicated block of `VkDeviceMemory` or a specific region of a bigger block of this type + plus unique offset. -There are multiple ways to create such object. -You need to fill structure VmaAllocationCreateInfo. -For more information see [Choosing memory type](@ref choosing_memory_type). + There are multiple ways to create such object. + You need to fill structure VmaAllocationCreateInfo. + For more information see [Choosing memory type](@ref choosing_memory_type). -Although the library provides convenience functions that create Vulkan buffer or image, -allocate memory for it and bind them together, -binding of the allocation to a buffer or an image is out of scope of the allocation itself. -Allocation object can exist without buffer/image bound, -binding can be done manually by the user, and destruction of it can be done -independently of destruction of the allocation. + Although the library provides convenience functions that create Vulkan buffer or image, + allocate memory for it and bind them together, + binding of the allocation to a buffer or an image is out of scope of the allocation itself. + Allocation object can exist without buffer/image bound, + binding can be done manually by the user, and destruction of it can be done + independently of destruction of the allocation. -The object also remembers its size and some other information. -To retrieve this information, use function vmaGetAllocationInfo() and inspect -returned structure VmaAllocationInfo. -*/ -VK_DEFINE_HANDLE(VmaAllocation) + The object also remembers its size and some other information. + To retrieve this information, use function vmaGetAllocationInfo() and inspect + returned structure VmaAllocationInfo. + */ + VK_DEFINE_HANDLE(VmaAllocation) -/** \struct VmaDefragmentationContext -\brief An opaque object that represents started defragmentation process. + /** \struct VmaDefragmentationContext + \brief An opaque object that represents started defragmentation process. -Fill structure #VmaDefragmentationInfo and call function vmaBeginDefragmentation() to create it. -Call function vmaEndDefragmentation() to destroy it. -*/ -VK_DEFINE_HANDLE(VmaDefragmentationContext) + Fill structure #VmaDefragmentationInfo and call function vmaBeginDefragmentation() to create it. + Call function vmaEndDefragmentation() to destroy it. + */ + VK_DEFINE_HANDLE(VmaDefragmentationContext) -/** @} */ + /** @} */ -/** -\addtogroup group_virtual -@{ -*/ + /** + \addtogroup group_virtual + @{ + */ -/** \struct VmaVirtualAllocation -\brief Represents single memory allocation done inside VmaVirtualBlock. + /** \struct VmaVirtualAllocation + \brief Represents single memory allocation done inside VmaVirtualBlock. -Use it as a unique identifier to virtual allocation within the single block. + Use it as a unique identifier to virtual allocation within the single block. -Use value `VK_NULL_HANDLE` to represent a null/invalid allocation. -*/ -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VmaVirtualAllocation) + Use value `VK_NULL_HANDLE` to represent a null/invalid allocation. + */ + VK_DEFINE_NON_DISPATCHABLE_HANDLE(VmaVirtualAllocation) -/** @} */ + /** @} */ -/** -\addtogroup group_virtual -@{ -*/ + /** + \addtogroup group_virtual + @{ + */ -/** \struct VmaVirtualBlock -\brief Handle to a virtual block object that allows to use core allocation algorithm without allocating any real GPU memory. + /** \struct VmaVirtualBlock + \brief Handle to a virtual block object that allows to use core allocation algorithm without allocating any real GPU memory. -Fill in #VmaVirtualBlockCreateInfo structure and use vmaCreateVirtualBlock() to create it. Use vmaDestroyVirtualBlock() to destroy it. -For more information, see documentation chapter \ref virtual_allocator. + Fill in #VmaVirtualBlockCreateInfo structure and use vmaCreateVirtualBlock() to create it. Use vmaDestroyVirtualBlock() to destroy it. + For more information, see documentation chapter \ref virtual_allocator. -This object is not thread-safe - should not be used from multiple threads simultaneously, must be synchronized externally. -*/ -VK_DEFINE_HANDLE(VmaVirtualBlock) + This object is not thread-safe - should not be used from multiple threads simultaneously, must be synchronized externally. + */ + VK_DEFINE_HANDLE(VmaVirtualBlock) -/** @} */ + /** @} */ -/** -\addtogroup group_init -@{ -*/ + /** + \addtogroup group_init + @{ + */ -/// Callback function called after successful vkAllocateMemory. -typedef void (VKAPI_PTR* PFN_vmaAllocateDeviceMemoryFunction)( - VmaAllocator VMA_NOT_NULL allocator, - uint32_t memoryType, - VkDeviceMemory VMA_NOT_NULL_NON_DISPATCHABLE memory, - VkDeviceSize size, - void* VMA_NULLABLE pUserData); + /// Callback function called after successful vkAllocateMemory. + typedef void (VKAPI_PTR* PFN_vmaAllocateDeviceMemoryFunction)( + VmaAllocator VMA_NOT_NULL allocator, + uint32_t memoryType, + VkDeviceMemory VMA_NOT_NULL_NON_DISPATCHABLE memory, + VkDeviceSize size, + void* VMA_NULLABLE pUserData); -/// Callback function called before vkFreeMemory. -typedef void (VKAPI_PTR* PFN_vmaFreeDeviceMemoryFunction)( - VmaAllocator VMA_NOT_NULL allocator, - uint32_t memoryType, - VkDeviceMemory VMA_NOT_NULL_NON_DISPATCHABLE memory, - VkDeviceSize size, - void* VMA_NULLABLE pUserData); + /// Callback function called before vkFreeMemory. + typedef void (VKAPI_PTR* PFN_vmaFreeDeviceMemoryFunction)( + VmaAllocator VMA_NOT_NULL allocator, + uint32_t memoryType, + VkDeviceMemory VMA_NOT_NULL_NON_DISPATCHABLE memory, + VkDeviceSize size, + void* VMA_NULLABLE pUserData); -/** \brief Set of callbacks that the library will call for `vkAllocateMemory` and `vkFreeMemory`. + /** \brief Set of callbacks that the library will call for `vkAllocateMemory` and `vkFreeMemory`. -Provided for informative purpose, e.g. to gather statistics about number of -allocations or total amount of memory allocated in Vulkan. + Provided for informative purpose, e.g. to gather statistics about number of + allocations or total amount of memory allocated in Vulkan. -Used in VmaAllocatorCreateInfo::pDeviceMemoryCallbacks. -*/ -typedef struct VmaDeviceMemoryCallbacks -{ - /// Optional, can be null. - PFN_vmaAllocateDeviceMemoryFunction VMA_NULLABLE pfnAllocate; - /// Optional, can be null. - PFN_vmaFreeDeviceMemoryFunction VMA_NULLABLE pfnFree; - /// Optional, can be null. - void* VMA_NULLABLE pUserData; -} VmaDeviceMemoryCallbacks; + Used in VmaAllocatorCreateInfo::pDeviceMemoryCallbacks. + */ + typedef struct VmaDeviceMemoryCallbacks + { + /// Optional, can be null. + PFN_vmaAllocateDeviceMemoryFunction VMA_NULLABLE pfnAllocate; + /// Optional, can be null. + PFN_vmaFreeDeviceMemoryFunction VMA_NULLABLE pfnFree; + /// Optional, can be null. + void* VMA_NULLABLE pUserData; + } VmaDeviceMemoryCallbacks; -/** \brief Pointers to some Vulkan functions - a subset used by the library. + /** \brief Pointers to some Vulkan functions - a subset used by the library. -Used in VmaAllocatorCreateInfo::pVulkanFunctions. -*/ -typedef struct VmaVulkanFunctions -{ - /// Required when using VMA_DYNAMIC_VULKAN_FUNCTIONS. - PFN_vkGetInstanceProcAddr VMA_NULLABLE vkGetInstanceProcAddr; - /// Required when using VMA_DYNAMIC_VULKAN_FUNCTIONS. - PFN_vkGetDeviceProcAddr VMA_NULLABLE vkGetDeviceProcAddr; - PFN_vkGetPhysicalDeviceProperties VMA_NULLABLE vkGetPhysicalDeviceProperties; - PFN_vkGetPhysicalDeviceMemoryProperties VMA_NULLABLE vkGetPhysicalDeviceMemoryProperties; - PFN_vkAllocateMemory VMA_NULLABLE vkAllocateMemory; - PFN_vkFreeMemory VMA_NULLABLE vkFreeMemory; - PFN_vkMapMemory VMA_NULLABLE vkMapMemory; - PFN_vkUnmapMemory VMA_NULLABLE vkUnmapMemory; - PFN_vkFlushMappedMemoryRanges VMA_NULLABLE vkFlushMappedMemoryRanges; - PFN_vkInvalidateMappedMemoryRanges VMA_NULLABLE vkInvalidateMappedMemoryRanges; - PFN_vkBindBufferMemory VMA_NULLABLE vkBindBufferMemory; - PFN_vkBindImageMemory VMA_NULLABLE vkBindImageMemory; - PFN_vkGetBufferMemoryRequirements VMA_NULLABLE vkGetBufferMemoryRequirements; - PFN_vkGetImageMemoryRequirements VMA_NULLABLE vkGetImageMemoryRequirements; - PFN_vkCreateBuffer VMA_NULLABLE vkCreateBuffer; - PFN_vkDestroyBuffer VMA_NULLABLE vkDestroyBuffer; - PFN_vkCreateImage VMA_NULLABLE vkCreateImage; - PFN_vkDestroyImage VMA_NULLABLE vkDestroyImage; - PFN_vkCmdCopyBuffer VMA_NULLABLE vkCmdCopyBuffer; + Used in VmaAllocatorCreateInfo::pVulkanFunctions. + */ + typedef struct VmaVulkanFunctions + { + /// Required when using VMA_DYNAMIC_VULKAN_FUNCTIONS. + PFN_vkGetInstanceProcAddr VMA_NULLABLE vkGetInstanceProcAddr; + /// Required when using VMA_DYNAMIC_VULKAN_FUNCTIONS. + PFN_vkGetDeviceProcAddr VMA_NULLABLE vkGetDeviceProcAddr; + PFN_vkGetPhysicalDeviceProperties VMA_NULLABLE vkGetPhysicalDeviceProperties; + PFN_vkGetPhysicalDeviceMemoryProperties VMA_NULLABLE vkGetPhysicalDeviceMemoryProperties; + PFN_vkAllocateMemory VMA_NULLABLE vkAllocateMemory; + PFN_vkFreeMemory VMA_NULLABLE vkFreeMemory; + PFN_vkMapMemory VMA_NULLABLE vkMapMemory; + PFN_vkUnmapMemory VMA_NULLABLE vkUnmapMemory; + PFN_vkFlushMappedMemoryRanges VMA_NULLABLE vkFlushMappedMemoryRanges; + PFN_vkInvalidateMappedMemoryRanges VMA_NULLABLE vkInvalidateMappedMemoryRanges; + PFN_vkBindBufferMemory VMA_NULLABLE vkBindBufferMemory; + PFN_vkBindImageMemory VMA_NULLABLE vkBindImageMemory; + PFN_vkGetBufferMemoryRequirements VMA_NULLABLE vkGetBufferMemoryRequirements; + PFN_vkGetImageMemoryRequirements VMA_NULLABLE vkGetImageMemoryRequirements; + PFN_vkCreateBuffer VMA_NULLABLE vkCreateBuffer; + PFN_vkDestroyBuffer VMA_NULLABLE vkDestroyBuffer; + PFN_vkCreateImage VMA_NULLABLE vkCreateImage; + PFN_vkDestroyImage VMA_NULLABLE vkDestroyImage; + PFN_vkCmdCopyBuffer VMA_NULLABLE vkCmdCopyBuffer; #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 - /// Fetch "vkGetBufferMemoryRequirements2" on Vulkan >= 1.1, fetch "vkGetBufferMemoryRequirements2KHR" when using VK_KHR_dedicated_allocation extension. - PFN_vkGetBufferMemoryRequirements2KHR VMA_NULLABLE vkGetBufferMemoryRequirements2KHR; - /// Fetch "vkGetImageMemoryRequirements2" on Vulkan >= 1.1, fetch "vkGetImageMemoryRequirements2KHR" when using VK_KHR_dedicated_allocation extension. - PFN_vkGetImageMemoryRequirements2KHR VMA_NULLABLE vkGetImageMemoryRequirements2KHR; + /// Fetch "vkGetBufferMemoryRequirements2" on Vulkan >= 1.1, fetch "vkGetBufferMemoryRequirements2KHR" when using VK_KHR_dedicated_allocation extension. + PFN_vkGetBufferMemoryRequirements2KHR VMA_NULLABLE vkGetBufferMemoryRequirements2KHR; + /// Fetch "vkGetImageMemoryRequirements2" on Vulkan >= 1.1, fetch "vkGetImageMemoryRequirements2KHR" when using VK_KHR_dedicated_allocation extension. + PFN_vkGetImageMemoryRequirements2KHR VMA_NULLABLE vkGetImageMemoryRequirements2KHR; #endif #if VMA_BIND_MEMORY2 || VMA_VULKAN_VERSION >= 1001000 - /// Fetch "vkBindBufferMemory2" on Vulkan >= 1.1, fetch "vkBindBufferMemory2KHR" when using VK_KHR_bind_memory2 extension. - PFN_vkBindBufferMemory2KHR VMA_NULLABLE vkBindBufferMemory2KHR; - /// Fetch "vkBindImageMemory2" on Vulkan >= 1.1, fetch "vkBindImageMemory2KHR" when using VK_KHR_bind_memory2 extension. - PFN_vkBindImageMemory2KHR VMA_NULLABLE vkBindImageMemory2KHR; + /// Fetch "vkBindBufferMemory2" on Vulkan >= 1.1, fetch "vkBindBufferMemory2KHR" when using VK_KHR_bind_memory2 extension. + PFN_vkBindBufferMemory2KHR VMA_NULLABLE vkBindBufferMemory2KHR; + /// Fetch "vkBindImageMemory2" on Vulkan >= 1.1, fetch "vkBindImageMemory2KHR" when using VK_KHR_bind_memory2 extension. + PFN_vkBindImageMemory2KHR VMA_NULLABLE vkBindImageMemory2KHR; #endif #if VMA_MEMORY_BUDGET || VMA_VULKAN_VERSION >= 1001000 - /// Fetch from "vkGetPhysicalDeviceMemoryProperties2" on Vulkan >= 1.1, but you can also fetch it from "vkGetPhysicalDeviceMemoryProperties2KHR" if you enabled extension VK_KHR_get_physical_device_properties2. - PFN_vkGetPhysicalDeviceMemoryProperties2KHR VMA_NULLABLE vkGetPhysicalDeviceMemoryProperties2KHR; + /// Fetch from "vkGetPhysicalDeviceMemoryProperties2" on Vulkan >= 1.1, but you can also fetch it from "vkGetPhysicalDeviceMemoryProperties2KHR" if you enabled extension VK_KHR_get_physical_device_properties2. + PFN_vkGetPhysicalDeviceMemoryProperties2KHR VMA_NULLABLE vkGetPhysicalDeviceMemoryProperties2KHR; #endif #if VMA_KHR_MAINTENANCE4 || VMA_VULKAN_VERSION >= 1003000 - /// Fetch from "vkGetDeviceBufferMemoryRequirements" on Vulkan >= 1.3, but you can also fetch it from "vkGetDeviceBufferMemoryRequirementsKHR" if you enabled extension VK_KHR_maintenance4. - PFN_vkGetDeviceBufferMemoryRequirementsKHR VMA_NULLABLE vkGetDeviceBufferMemoryRequirements; - /// Fetch from "vkGetDeviceImageMemoryRequirements" on Vulkan >= 1.3, but you can also fetch it from "vkGetDeviceImageMemoryRequirementsKHR" if you enabled extension VK_KHR_maintenance4. - PFN_vkGetDeviceImageMemoryRequirementsKHR VMA_NULLABLE vkGetDeviceImageMemoryRequirements; + /// Fetch from "vkGetDeviceBufferMemoryRequirements" on Vulkan >= 1.3, but you can also fetch it from "vkGetDeviceBufferMemoryRequirementsKHR" if you enabled extension VK_KHR_maintenance4. + PFN_vkGetDeviceBufferMemoryRequirementsKHR VMA_NULLABLE vkGetDeviceBufferMemoryRequirements; + /// Fetch from "vkGetDeviceImageMemoryRequirements" on Vulkan >= 1.3, but you can also fetch it from "vkGetDeviceImageMemoryRequirementsKHR" if you enabled extension VK_KHR_maintenance4. + PFN_vkGetDeviceImageMemoryRequirementsKHR VMA_NULLABLE vkGetDeviceImageMemoryRequirements; #endif #ifdef VK_USE_PLATFORM_WIN32_KHR - PFN_vkGetMemoryWin32HandleKHR VMA_NULLABLE vkGetMemoryWin32HandleKHR; + PFN_vkGetMemoryWin32HandleKHR VMA_NULLABLE vkGetMemoryWin32HandleKHR; #else - void* VMA_NULLABLE vkGetMemoryWin32HandleKHR; + void* VMA_NULLABLE vkGetMemoryWin32HandleKHR; #endif -} VmaVulkanFunctions; + } VmaVulkanFunctions; -/// Description of a Allocator to be created. -typedef struct VmaAllocatorCreateInfo -{ - /// Flags for created allocator. Use #VmaAllocatorCreateFlagBits enum. - VmaAllocatorCreateFlags flags; - /// Vulkan physical device. - /** It must be valid throughout whole lifetime of created allocator. */ - VkPhysicalDevice VMA_NOT_NULL physicalDevice; - /// Vulkan device. - /** It must be valid throughout whole lifetime of created allocator. */ - VkDevice VMA_NOT_NULL device; - /// Preferred size of a single `VkDeviceMemory` block to be allocated from large heaps > 1 GiB. Optional. - /** Set to 0 to use default, which is currently 256 MiB. */ - VkDeviceSize preferredLargeHeapBlockSize; - /// Custom CPU memory allocation callbacks. Optional. - /** Optional, can be null. When specified, will also be used for all CPU-side memory allocations. */ - const VkAllocationCallbacks* VMA_NULLABLE pAllocationCallbacks; - /// Informative callbacks for `vkAllocateMemory`, `vkFreeMemory`. Optional. - /** Optional, can be null. */ - const VmaDeviceMemoryCallbacks* VMA_NULLABLE pDeviceMemoryCallbacks; - /** \brief Either null or a pointer to an array of limits on maximum number of bytes that can be allocated out of particular Vulkan memory heap. + /// Description of a Allocator to be created. + typedef struct VmaAllocatorCreateInfo + { + /// Flags for created allocator. Use #VmaAllocatorCreateFlagBits enum. + VmaAllocatorCreateFlags flags; + /// Vulkan physical device. + /** It must be valid throughout whole lifetime of created allocator. */ + VkPhysicalDevice VMA_NOT_NULL physicalDevice; + /// Vulkan device. + /** It must be valid throughout whole lifetime of created allocator. */ + VkDevice VMA_NOT_NULL device; + /// Preferred size of a single `VkDeviceMemory` block to be allocated from large heaps > 1 GiB. Optional. + /** Set to 0 to use default, which is currently 256 MiB. */ + VkDeviceSize preferredLargeHeapBlockSize; + /// Custom CPU memory allocation callbacks. Optional. + /** Optional, can be null. When specified, will also be used for all CPU-side memory allocations. */ + const VkAllocationCallbacks* VMA_NULLABLE pAllocationCallbacks; + /// Informative callbacks for `vkAllocateMemory`, `vkFreeMemory`. Optional. + /** Optional, can be null. */ + const VmaDeviceMemoryCallbacks* VMA_NULLABLE pDeviceMemoryCallbacks; + /** \brief Either null or a pointer to an array of limits on maximum number of bytes that can be allocated out of particular Vulkan memory heap. - If not NULL, it must be a pointer to an array of - `VkPhysicalDeviceMemoryProperties::memoryHeapCount` elements, defining limit on - maximum number of bytes that can be allocated out of particular Vulkan memory - heap. + If not NULL, it must be a pointer to an array of + `VkPhysicalDeviceMemoryProperties::memoryHeapCount` elements, defining limit on + maximum number of bytes that can be allocated out of particular Vulkan memory + heap. - Any of the elements may be equal to `VK_WHOLE_SIZE`, which means no limit on that - heap. This is also the default in case of `pHeapSizeLimit` = NULL. + Any of the elements may be equal to `VK_WHOLE_SIZE`, which means no limit on that + heap. This is also the default in case of `pHeapSizeLimit` = NULL. - If there is a limit defined for a heap: + If there is a limit defined for a heap: - - If user tries to allocate more memory from that heap using this allocator, - the allocation fails with `VK_ERROR_OUT_OF_DEVICE_MEMORY`. - - If the limit is smaller than heap size reported in `VkMemoryHeap::size`, the - value of this limit will be reported instead when using vmaGetMemoryProperties(). + - If user tries to allocate more memory from that heap using this allocator, + the allocation fails with `VK_ERROR_OUT_OF_DEVICE_MEMORY`. + - If the limit is smaller than heap size reported in `VkMemoryHeap::size`, the + value of this limit will be reported instead when using vmaGetMemoryProperties(). - Warning! Using this feature may not be equivalent to installing a GPU with - smaller amount of memory, because graphics driver doesn't necessary fail new - allocations with `VK_ERROR_OUT_OF_DEVICE_MEMORY` result when memory capacity is - exceeded. It may return success and just silently migrate some device memory - blocks to system RAM. This driver behavior can also be controlled using - VK_AMD_memory_overallocation_behavior extension. - */ - const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL("VkPhysicalDeviceMemoryProperties::memoryHeapCount") pHeapSizeLimit; + Warning! Using this feature may not be equivalent to installing a GPU with + smaller amount of memory, because graphics driver doesn't necessary fail new + allocations with `VK_ERROR_OUT_OF_DEVICE_MEMORY` result when memory capacity is + exceeded. It may return success and just silently migrate some device memory + blocks to system RAM. This driver behavior can also be controlled using + VK_AMD_memory_overallocation_behavior extension. + */ + const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL("VkPhysicalDeviceMemoryProperties::memoryHeapCount") pHeapSizeLimit; - /** \brief Pointers to Vulkan functions. Can be null. + /** \brief Pointers to Vulkan functions. Can be null. - For details see [Pointers to Vulkan functions](@ref config_Vulkan_functions). - */ - const VmaVulkanFunctions* VMA_NULLABLE pVulkanFunctions; - /** \brief Handle to Vulkan instance object. + For details see [Pointers to Vulkan functions](@ref config_Vulkan_functions). + */ + const VmaVulkanFunctions* VMA_NULLABLE pVulkanFunctions; + /** \brief Handle to Vulkan instance object. - Starting from version 3.0.0 this member is no longer optional, it must be set! - */ - VkInstance VMA_NOT_NULL instance; - /** \brief Optional. Vulkan version that the application uses. + Starting from version 3.0.0 this member is no longer optional, it must be set! + */ + VkInstance VMA_NOT_NULL instance; + /** \brief Optional. Vulkan version that the application uses. - It must be a value in the format as created by macro `VK_MAKE_VERSION` or a constant like: `VK_API_VERSION_1_1`, `VK_API_VERSION_1_0`. - The patch version number specified is ignored. Only the major and minor versions are considered. - Only versions 1.0, 1.1, 1.2, 1.3 are supported by the current implementation. - Leaving it initialized to zero is equivalent to `VK_API_VERSION_1_0`. - It must match the Vulkan version used by the application and supported on the selected physical device, - so it must be no higher than `VkApplicationInfo::apiVersion` passed to `vkCreateInstance` - and no higher than `VkPhysicalDeviceProperties::apiVersion` found on the physical device used. - */ - uint32_t vulkanApiVersion; + It must be a value in the format as created by macro `VK_MAKE_VERSION` or a constant like: `VK_API_VERSION_1_1`, `VK_API_VERSION_1_0`. + The patch version number specified is ignored. Only the major and minor versions are considered. + Only versions 1.0, 1.1, 1.2, 1.3 are supported by the current implementation. + Leaving it initialized to zero is equivalent to `VK_API_VERSION_1_0`. + It must match the Vulkan version used by the application and supported on the selected physical device, + so it must be no higher than `VkApplicationInfo::apiVersion` passed to `vkCreateInstance` + and no higher than `VkPhysicalDeviceProperties::apiVersion` found on the physical device used. + */ + uint32_t vulkanApiVersion; #if VMA_EXTERNAL_MEMORY - /** \brief Either null or a pointer to an array of external memory handle types for each Vulkan memory type. + /** \brief Either null or a pointer to an array of external memory handle types for each Vulkan memory type. - If not NULL, it must be a pointer to an array of `VkPhysicalDeviceMemoryProperties::memoryTypeCount` - elements, defining external memory handle types of particular Vulkan memory type, - to be passed using `VkExportMemoryAllocateInfoKHR`. + If not NULL, it must be a pointer to an array of `VkPhysicalDeviceMemoryProperties::memoryTypeCount` + elements, defining external memory handle types of particular Vulkan memory type, + to be passed using `VkExportMemoryAllocateInfoKHR`. - Any of the elements may be equal to 0, which means not to use `VkExportMemoryAllocateInfoKHR` on this memory type. - This is also the default in case of `pTypeExternalMemoryHandleTypes` = NULL. - */ - const VkExternalMemoryHandleTypeFlagsKHR* VMA_NULLABLE VMA_LEN_IF_NOT_NULL("VkPhysicalDeviceMemoryProperties::memoryTypeCount") pTypeExternalMemoryHandleTypes; + Any of the elements may be equal to 0, which means not to use `VkExportMemoryAllocateInfoKHR` on this memory type. + This is also the default in case of `pTypeExternalMemoryHandleTypes` = NULL. + */ + const VkExternalMemoryHandleTypeFlagsKHR* VMA_NULLABLE VMA_LEN_IF_NOT_NULL("VkPhysicalDeviceMemoryProperties::memoryTypeCount") pTypeExternalMemoryHandleTypes; #endif // #if VMA_EXTERNAL_MEMORY -} VmaAllocatorCreateInfo; + } VmaAllocatorCreateInfo; -/// Information about existing #VmaAllocator object. -typedef struct VmaAllocatorInfo -{ - /** \brief Handle to Vulkan instance object. + /// Information about existing #VmaAllocator object. + typedef struct VmaAllocatorInfo + { + /** \brief Handle to Vulkan instance object. - This is the same value as has been passed through VmaAllocatorCreateInfo::instance. + This is the same value as has been passed through VmaAllocatorCreateInfo::instance. + */ + VkInstance VMA_NOT_NULL instance; + /** \brief Handle to Vulkan physical device object. + + This is the same value as has been passed through VmaAllocatorCreateInfo::physicalDevice. + */ + VkPhysicalDevice VMA_NOT_NULL physicalDevice; + /** \brief Handle to Vulkan device object. + + This is the same value as has been passed through VmaAllocatorCreateInfo::device. + */ + VkDevice VMA_NOT_NULL device; + } VmaAllocatorInfo; + + /** @} */ + + /** + \addtogroup group_stats + @{ */ - VkInstance VMA_NOT_NULL instance; - /** \brief Handle to Vulkan physical device object. - This is the same value as has been passed through VmaAllocatorCreateInfo::physicalDevice. + /** \brief Calculated statistics of memory usage e.g. in a specific memory type, heap, custom pool, or total. + + These are fast to calculate. + See functions: vmaGetHeapBudgets(), vmaGetPoolStatistics(). */ - VkPhysicalDevice VMA_NOT_NULL physicalDevice; - /** \brief Handle to Vulkan device object. + typedef struct VmaStatistics + { + /** \brief Number of `VkDeviceMemory` objects - Vulkan memory blocks allocated. + */ + uint32_t blockCount; + /** \brief Number of #VmaAllocation objects allocated. - This is the same value as has been passed through VmaAllocatorCreateInfo::device. + Dedicated allocations have their own blocks, so each one adds 1 to `allocationCount` as well as `blockCount`. + */ + uint32_t allocationCount; + /** \brief Number of bytes allocated in `VkDeviceMemory` blocks. + + \note To avoid confusion, please be aware that what Vulkan calls an "allocation" - a whole `VkDeviceMemory` object + (e.g. as in `VkPhysicalDeviceLimits::maxMemoryAllocationCount`) is called a "block" in VMA, while VMA calls + "allocation" a #VmaAllocation object that represents a memory region sub-allocated from such block, usually for a single buffer or image. + */ + VkDeviceSize blockBytes; + /** \brief Total number of bytes occupied by all #VmaAllocation objects. + + Always less or equal than `blockBytes`. + Difference `(blockBytes - allocationBytes)` is the amount of memory allocated from Vulkan + but unused by any #VmaAllocation. + */ + VkDeviceSize allocationBytes; + } VmaStatistics; + + /** \brief More detailed statistics than #VmaStatistics. + + These are slower to calculate. Use for debugging purposes. + See functions: vmaCalculateStatistics(), vmaCalculatePoolStatistics(). + + Previous version of the statistics API provided averages, but they have been removed + because they can be easily calculated as: + + \code + VkDeviceSize allocationSizeAvg = detailedStats.statistics.allocationBytes / detailedStats.statistics.allocationCount; + VkDeviceSize unusedBytes = detailedStats.statistics.blockBytes - detailedStats.statistics.allocationBytes; + VkDeviceSize unusedRangeSizeAvg = unusedBytes / detailedStats.unusedRangeCount; + \endcode */ - VkDevice VMA_NOT_NULL device; -} VmaAllocatorInfo; + typedef struct VmaDetailedStatistics + { + /// Basic statistics. + VmaStatistics statistics; + /// Number of free ranges of memory between allocations. + uint32_t unusedRangeCount; + /// Smallest allocation size. `VK_WHOLE_SIZE` if there are 0 allocations. + VkDeviceSize allocationSizeMin; + /// Largest allocation size. 0 if there are 0 allocations. + VkDeviceSize allocationSizeMax; + /// Smallest empty range size. `VK_WHOLE_SIZE` if there are 0 empty ranges. + VkDeviceSize unusedRangeSizeMin; + /// Largest empty range size. 0 if there are 0 empty ranges. + VkDeviceSize unusedRangeSizeMax; + } VmaDetailedStatistics; -/** @} */ + /** \brief General statistics from current state of the Allocator - + total memory usage across all memory heaps and types. -/** -\addtogroup group_stats -@{ -*/ - -/** \brief Calculated statistics of memory usage e.g. in a specific memory type, heap, custom pool, or total. - -These are fast to calculate. -See functions: vmaGetHeapBudgets(), vmaGetPoolStatistics(). -*/ -typedef struct VmaStatistics -{ - /** \brief Number of `VkDeviceMemory` objects - Vulkan memory blocks allocated. + These are slower to calculate. Use for debugging purposes. + See function vmaCalculateStatistics(). */ - uint32_t blockCount; - /** \brief Number of #VmaAllocation objects allocated. + typedef struct VmaTotalStatistics + { + VmaDetailedStatistics memoryType[VK_MAX_MEMORY_TYPES]; + VmaDetailedStatistics memoryHeap[VK_MAX_MEMORY_HEAPS]; + VmaDetailedStatistics total; + } VmaTotalStatistics; - Dedicated allocations have their own blocks, so each one adds 1 to `allocationCount` as well as `blockCount`. + /** \brief Statistics of current memory usage and available budget for a specific memory heap. + + These are fast to calculate. + See function vmaGetHeapBudgets(). */ - uint32_t allocationCount; - /** \brief Number of bytes allocated in `VkDeviceMemory` blocks. + typedef struct VmaBudget + { + /** \brief Statistics fetched from the library. + */ + VmaStatistics statistics; + /** \brief Estimated current memory usage of the program, in bytes. - \note To avoid confusion, please be aware that what Vulkan calls an "allocation" - a whole `VkDeviceMemory` object - (e.g. as in `VkPhysicalDeviceLimits::maxMemoryAllocationCount`) is called a "block" in VMA, while VMA calls - "allocation" a #VmaAllocation object that represents a memory region sub-allocated from such block, usually for a single buffer or image. + Fetched from system using VK_EXT_memory_budget extension if enabled. + + It might be different than `statistics.blockBytes` (usually higher) due to additional implicit objects + also occupying the memory, like swapchain, pipelines, descriptor heaps, command buffers, or + `VkDeviceMemory` blocks allocated outside of this library, if any. + */ + VkDeviceSize usage; + /** \brief Estimated amount of memory available to the program, in bytes. + + Fetched from system using VK_EXT_memory_budget extension if enabled. + + It might be different (most probably smaller) than `VkMemoryHeap::size[heapIndex]` due to factors + external to the program, decided by the operating system. + Difference `budget - usage` is the amount of additional memory that can probably + be allocated without problems. Exceeding the budget may result in various problems. + */ + VkDeviceSize budget; + } VmaBudget; + + /** @} */ + + /** + \addtogroup group_alloc + @{ */ - VkDeviceSize blockBytes; - /** \brief Total number of bytes occupied by all #VmaAllocation objects. - Always less or equal than `blockBytes`. - Difference `(blockBytes - allocationBytes)` is the amount of memory allocated from Vulkan - but unused by any #VmaAllocation. + /** \brief Parameters of new #VmaAllocation. + + To be used with functions like vmaCreateBuffer(), vmaCreateImage(), and many others. */ - VkDeviceSize allocationBytes; -} VmaStatistics; + typedef struct VmaAllocationCreateInfo + { + /// Use #VmaAllocationCreateFlagBits enum. + VmaAllocationCreateFlags flags; + /** \brief Intended usage of memory. -/** \brief More detailed statistics than #VmaStatistics. + You can leave #VMA_MEMORY_USAGE_UNKNOWN if you specify memory requirements in other way. \n + If `pool` is not null, this member is ignored. + */ + VmaMemoryUsage usage; + /** \brief Flags that must be set in a Memory Type chosen for an allocation. -These are slower to calculate. Use for debugging purposes. -See functions: vmaCalculateStatistics(), vmaCalculatePoolStatistics(). + Leave 0 if you specify memory requirements in other way. \n + If `pool` is not null, this member is ignored.*/ + VkMemoryPropertyFlags requiredFlags; + /** \brief Flags that preferably should be set in a memory type chosen for an allocation. -Previous version of the statistics API provided averages, but they have been removed -because they can be easily calculated as: + Set to 0 if no additional flags are preferred. \n + If `pool` is not null, this member is ignored. */ + VkMemoryPropertyFlags preferredFlags; + /** \brief Bitmask containing one bit set for every memory type acceptable for this allocation. -\code -VkDeviceSize allocationSizeAvg = detailedStats.statistics.allocationBytes / detailedStats.statistics.allocationCount; -VkDeviceSize unusedBytes = detailedStats.statistics.blockBytes - detailedStats.statistics.allocationBytes; -VkDeviceSize unusedRangeSizeAvg = unusedBytes / detailedStats.unusedRangeCount; -\endcode -*/ -typedef struct VmaDetailedStatistics -{ - /// Basic statistics. - VmaStatistics statistics; - /// Number of free ranges of memory between allocations. - uint32_t unusedRangeCount; - /// Smallest allocation size. `VK_WHOLE_SIZE` if there are 0 allocations. - VkDeviceSize allocationSizeMin; - /// Largest allocation size. 0 if there are 0 allocations. - VkDeviceSize allocationSizeMax; - /// Smallest empty range size. `VK_WHOLE_SIZE` if there are 0 empty ranges. - VkDeviceSize unusedRangeSizeMin; - /// Largest empty range size. 0 if there are 0 empty ranges. - VkDeviceSize unusedRangeSizeMax; -} VmaDetailedStatistics; + Value 0 is equivalent to `UINT32_MAX` - it means any memory type is accepted if + it meets other requirements specified by this structure, with no further + restrictions on memory type index. \n + If `pool` is not null, this member is ignored. + */ + uint32_t memoryTypeBits; + /** \brief Pool that this allocation should be created in. -/** \brief General statistics from current state of the Allocator - -total memory usage across all memory heaps and types. + Leave `VK_NULL_HANDLE` to allocate from default pool. If not null, members: + `usage`, `requiredFlags`, `preferredFlags`, `memoryTypeBits` are ignored. + */ + VmaPool VMA_NULLABLE pool; + /** \brief Custom general-purpose pointer that will be stored in #VmaAllocation, can be read as VmaAllocationInfo::pUserData and changed using vmaSetAllocationUserData(). -These are slower to calculate. Use for debugging purposes. -See function vmaCalculateStatistics(). -*/ -typedef struct VmaTotalStatistics -{ - VmaDetailedStatistics memoryType[VK_MAX_MEMORY_TYPES]; - VmaDetailedStatistics memoryHeap[VK_MAX_MEMORY_HEAPS]; - VmaDetailedStatistics total; -} VmaTotalStatistics; + If #VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT is used, it must be either + null or pointer to a null-terminated string. The string will be then copied to + internal buffer, so it doesn't need to be valid after allocation call. + */ + void* VMA_NULLABLE pUserData; + /** \brief A floating-point value between 0 and 1, indicating the priority of the allocation relative to other memory allocations. -/** \brief Statistics of current memory usage and available budget for a specific memory heap. + It is used only when #VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT flag was used during creation of the #VmaAllocator object + and this allocation ends up as dedicated or is explicitly forced as dedicated using #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT. + Otherwise, it has the priority of a memory block where it is placed and this variable is ignored. + */ + float priority; + } VmaAllocationCreateInfo; -These are fast to calculate. -See function vmaGetHeapBudgets(). -*/ -typedef struct VmaBudget -{ - /** \brief Statistics fetched from the library. + /// Describes parameter of created #VmaPool. + typedef struct VmaPoolCreateInfo + { + /** \brief Vulkan memory type index to allocate this pool from. + */ + uint32_t memoryTypeIndex; + /** \brief Use combination of #VmaPoolCreateFlagBits. + */ + VmaPoolCreateFlags flags; + /** \brief Size of a single `VkDeviceMemory` block to be allocated as part of this pool, in bytes. Optional. + + Specify nonzero to set explicit, constant size of memory blocks used by this + pool. + + Leave 0 to use default and let the library manage block sizes automatically. + Sizes of particular blocks may vary. + In this case, the pool will also support dedicated allocations. + */ + VkDeviceSize blockSize; + /** \brief Minimum number of blocks to be always allocated in this pool, even if they stay empty. + + Set to 0 to have no preallocated blocks and allow the pool be completely empty. + */ + size_t minBlockCount; + /** \brief Maximum number of blocks that can be allocated in this pool. Optional. + + Set to 0 to use default, which is `SIZE_MAX`, which means no limit. + + Set to same value as VmaPoolCreateInfo::minBlockCount to have fixed amount of memory allocated + throughout whole lifetime of this pool. + */ + size_t maxBlockCount; + /** \brief A floating-point value between 0 and 1, indicating the priority of the allocations in this pool relative to other memory allocations. + + It is used only when #VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT flag was used during creation of the #VmaAllocator object. + Otherwise, this variable is ignored. + */ + float priority; + /** \brief Additional minimum alignment to be used for all allocations created from this pool. Can be 0. + + Leave 0 (default) not to impose any additional alignment. If not 0, it must be a power of two. + It can be useful in cases where alignment returned by Vulkan by functions like `vkGetBufferMemoryRequirements` is not enough, + e.g. when doing interop with OpenGL. + */ + VkDeviceSize minAllocationAlignment; + /** \brief Additional `pNext` chain to be attached to `VkMemoryAllocateInfo` used for every allocation made by this pool. Optional. + + Optional, can be null. If not null, it must point to a `pNext` chain of structures that can be attached to `VkMemoryAllocateInfo`. + It can be useful for special needs such as adding `VkExportMemoryAllocateInfoKHR`. + Structures pointed by this member must remain alive and unchanged for the whole lifetime of the custom pool. + + Please note that some structures, e.g. `VkMemoryPriorityAllocateInfoEXT`, `VkMemoryDedicatedAllocateInfoKHR`, + can be attached automatically by this library when using other, more convenient of its features. + */ + void* VMA_NULLABLE VMA_EXTENDS_VK_STRUCT(VkMemoryAllocateInfo) pMemoryAllocateNext; + } VmaPoolCreateInfo; + + /** @} */ + + /** + \addtogroup group_alloc + @{ */ - VmaStatistics statistics; - /** \brief Estimated current memory usage of the program, in bytes. - Fetched from system using VK_EXT_memory_budget extension if enabled. + /** + Parameters of #VmaAllocation objects, that can be retrieved using function vmaGetAllocationInfo(). - It might be different than `statistics.blockBytes` (usually higher) due to additional implicit objects - also occupying the memory, like swapchain, pipelines, descriptor heaps, command buffers, or - `VkDeviceMemory` blocks allocated outside of this library, if any. + There is also an extended version of this structure that carries additional parameters: #VmaAllocationInfo2. */ - VkDeviceSize usage; - /** \brief Estimated amount of memory available to the program, in bytes. + typedef struct VmaAllocationInfo + { + /** \brief Memory type index that this allocation was allocated from. - Fetched from system using VK_EXT_memory_budget extension if enabled. + It never changes. + */ + uint32_t memoryType; + /** \brief Handle to Vulkan memory object. - It might be different (most probably smaller) than `VkMemoryHeap::size[heapIndex]` due to factors - external to the program, decided by the operating system. - Difference `budget - usage` is the amount of additional memory that can probably - be allocated without problems. Exceeding the budget may result in various problems. + Same memory object can be shared by multiple allocations. + + It can change after the allocation is moved during \ref defragmentation. + */ + VkDeviceMemory VMA_NULLABLE_NON_DISPATCHABLE deviceMemory; + /** \brief Offset in `VkDeviceMemory` object to the beginning of this allocation, in bytes. `(deviceMemory, offset)` pair is unique to this allocation. + + You usually don't need to use this offset. If you create a buffer or an image together with the allocation using e.g. function + vmaCreateBuffer(), vmaCreateImage(), functions that operate on these resources refer to the beginning of the buffer or image, + not entire device memory block. Functions like vmaMapMemory(), vmaBindBufferMemory() also refer to the beginning of the allocation + and apply this offset automatically. + + It can change after the allocation is moved during \ref defragmentation. + */ + VkDeviceSize offset; + /** \brief Size of this allocation, in bytes. + + It never changes. + + \note Allocation size returned in this variable may be greater than the size + requested for the resource e.g. as `VkBufferCreateInfo::size`. Whole size of the + allocation is accessible for operations on memory e.g. using a pointer after + mapping with vmaMapMemory(), but operations on the resource e.g. using + `vkCmdCopyBuffer` must be limited to the size of the resource. + */ + VkDeviceSize size; + /** \brief Pointer to the beginning of this allocation as mapped data. + + If the allocation hasn't been mapped using vmaMapMemory() and hasn't been + created with #VMA_ALLOCATION_CREATE_MAPPED_BIT flag, this value is null. + + It can change after call to vmaMapMemory(), vmaUnmapMemory(). + It can also change after the allocation is moved during \ref defragmentation. + */ + void* VMA_NULLABLE pMappedData; + /** \brief Custom general-purpose pointer that was passed as VmaAllocationCreateInfo::pUserData or set using vmaSetAllocationUserData(). + + It can change after call to vmaSetAllocationUserData() for this allocation. + */ + void* VMA_NULLABLE pUserData; + /** \brief Custom allocation name that was set with vmaSetAllocationName(). + + It can change after call to vmaSetAllocationName() for this allocation. + + Another way to set custom name is to pass it in VmaAllocationCreateInfo::pUserData with + additional flag #VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT set [DEPRECATED]. + */ + const char* VMA_NULLABLE pName; + } VmaAllocationInfo; + + /// Extended parameters of a #VmaAllocation object that can be retrieved using function vmaGetAllocationInfo2(). + typedef struct VmaAllocationInfo2 + { + /** \brief Basic parameters of the allocation. + + If you need only these, you can use function vmaGetAllocationInfo() and structure #VmaAllocationInfo instead. + */ + VmaAllocationInfo allocationInfo; + /** \brief Size of the `VkDeviceMemory` block that the allocation belongs to. + + In case of an allocation with dedicated memory, it will be equal to `allocationInfo.size`. + */ + VkDeviceSize blockSize; + /** \brief `VK_TRUE` if the allocation has dedicated memory, `VK_FALSE` if it was placed as part of a larger memory block. + + When `VK_TRUE`, it also means `VkMemoryDedicatedAllocateInfo` was used when creating the allocation + (if VK_KHR_dedicated_allocation extension or Vulkan version >= 1.1 is enabled). + */ + VkBool32 dedicatedMemory; + } VmaAllocationInfo2; + + /** Callback function called during vmaBeginDefragmentation() to check custom criterion about ending current defragmentation pass. + + Should return true if the defragmentation needs to stop current pass. */ - VkDeviceSize budget; -} VmaBudget; + typedef VkBool32(VKAPI_PTR* PFN_vmaCheckDefragmentationBreakFunction)(void* VMA_NULLABLE pUserData); -/** @} */ + /** \brief Parameters for defragmentation. -/** -\addtogroup group_alloc -@{ -*/ - -/** \brief Parameters of new #VmaAllocation. - -To be used with functions like vmaCreateBuffer(), vmaCreateImage(), and many others. -*/ -typedef struct VmaAllocationCreateInfo -{ - /// Use #VmaAllocationCreateFlagBits enum. - VmaAllocationCreateFlags flags; - /** \brief Intended usage of memory. - - You can leave #VMA_MEMORY_USAGE_UNKNOWN if you specify memory requirements in other way. \n - If `pool` is not null, this member is ignored. + To be used with function vmaBeginDefragmentation(). */ - VmaMemoryUsage usage; - /** \brief Flags that must be set in a Memory Type chosen for an allocation. + typedef struct VmaDefragmentationInfo + { + /// \brief Use combination of #VmaDefragmentationFlagBits. + VmaDefragmentationFlags flags; + /** \brief Custom pool to be defragmented. - Leave 0 if you specify memory requirements in other way. \n - If `pool` is not null, this member is ignored.*/ - VkMemoryPropertyFlags requiredFlags; - /** \brief Flags that preferably should be set in a memory type chosen for an allocation. + If null then default pools will undergo defragmentation process. + */ + VmaPool VMA_NULLABLE pool; + /** \brief Maximum numbers of bytes that can be copied during single pass, while moving allocations to different places. - Set to 0 if no additional flags are preferred. \n - If `pool` is not null, this member is ignored. */ - VkMemoryPropertyFlags preferredFlags; - /** \brief Bitmask containing one bit set for every memory type acceptable for this allocation. + `0` means no limit. + */ + VkDeviceSize maxBytesPerPass; + /** \brief Maximum number of allocations that can be moved during single pass to a different place. - Value 0 is equivalent to `UINT32_MAX` - it means any memory type is accepted if - it meets other requirements specified by this structure, with no further - restrictions on memory type index. \n - If `pool` is not null, this member is ignored. + `0` means no limit. + */ + uint32_t maxAllocationsPerPass; + /** \brief Optional custom callback for stopping vmaBeginDefragmentation(). + + Have to return true for breaking current defragmentation pass. + */ + PFN_vmaCheckDefragmentationBreakFunction VMA_NULLABLE pfnBreakCallback; + /// \brief Optional data to pass to custom callback for stopping pass of defragmentation. + void* VMA_NULLABLE pBreakCallbackUserData; + } VmaDefragmentationInfo; + + /// Single move of an allocation to be done for defragmentation. + typedef struct VmaDefragmentationMove + { + /// Operation to be performed on the allocation by vmaEndDefragmentationPass(). Default value is #VMA_DEFRAGMENTATION_MOVE_OPERATION_COPY. You can modify it. + VmaDefragmentationMoveOperation operation; + /// Allocation that should be moved. + VmaAllocation VMA_NOT_NULL srcAllocation; + /** \brief Temporary allocation pointing to destination memory that will replace `srcAllocation`. + + \warning Do not store this allocation in your data structures! It exists only temporarily, for the duration of the defragmentation pass, + to be used for binding new buffer/image to the destination memory using e.g. vmaBindBufferMemory(). + vmaEndDefragmentationPass() will destroy it and make `srcAllocation` point to this memory. + */ + VmaAllocation VMA_NOT_NULL dstTmpAllocation; + } VmaDefragmentationMove; + + /** \brief Parameters for incremental defragmentation steps. + + To be used with function vmaBeginDefragmentationPass(). */ - uint32_t memoryTypeBits; - /** \brief Pool that this allocation should be created in. + typedef struct VmaDefragmentationPassMoveInfo + { + /// Number of elements in the `pMoves` array. + uint32_t moveCount; + /** \brief Array of moves to be performed by the user in the current defragmentation pass. - Leave `VK_NULL_HANDLE` to allocate from default pool. If not null, members: - `usage`, `requiredFlags`, `preferredFlags`, `memoryTypeBits` are ignored. + Pointer to an array of `moveCount` elements, owned by VMA, created in vmaBeginDefragmentationPass(), destroyed in vmaEndDefragmentationPass(). + + For each element, you should: + + 1. Create a new buffer/image in the place pointed by VmaDefragmentationMove::dstMemory + VmaDefragmentationMove::dstOffset. + 2. Copy data from the VmaDefragmentationMove::srcAllocation e.g. using `vkCmdCopyBuffer`, `vkCmdCopyImage`. + 3. Make sure these commands finished executing on the GPU. + 4. Destroy the old buffer/image. + + Only then you can finish defragmentation pass by calling vmaEndDefragmentationPass(). + After this call, the allocation will point to the new place in memory. + + Alternatively, if you cannot move specific allocation, you can set VmaDefragmentationMove::operation to #VMA_DEFRAGMENTATION_MOVE_OPERATION_IGNORE. + + Alternatively, if you decide you want to completely remove the allocation: + + 1. Destroy its buffer/image. + 2. Set VmaDefragmentationMove::operation to #VMA_DEFRAGMENTATION_MOVE_OPERATION_DESTROY. + + Then, after vmaEndDefragmentationPass() the allocation will be freed. + */ + VmaDefragmentationMove* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(moveCount) pMoves; + } VmaDefragmentationPassMoveInfo; + + /// Statistics returned for defragmentation process in function vmaEndDefragmentation(). + typedef struct VmaDefragmentationStats + { + /// Total number of bytes that have been copied while moving allocations to different places. + VkDeviceSize bytesMoved; + /// Total number of bytes that have been released to the system by freeing empty `VkDeviceMemory` objects. + VkDeviceSize bytesFreed; + /// Number of allocations that have been moved to different places. + uint32_t allocationsMoved; + /// Number of empty `VkDeviceMemory` objects that have been released to the system. + uint32_t deviceMemoryBlocksFreed; + } VmaDefragmentationStats; + + /** @} */ + + /** + \addtogroup group_virtual + @{ */ - VmaPool VMA_NULLABLE pool; - /** \brief Custom general-purpose pointer that will be stored in #VmaAllocation, can be read as VmaAllocationInfo::pUserData and changed using vmaSetAllocationUserData(). - If #VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT is used, it must be either - null or pointer to a null-terminated string. The string will be then copied to - internal buffer, so it doesn't need to be valid after allocation call. - */ - void* VMA_NULLABLE pUserData; - /** \brief A floating-point value between 0 and 1, indicating the priority of the allocation relative to other memory allocations. - - It is used only when #VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT flag was used during creation of the #VmaAllocator object - and this allocation ends up as dedicated or is explicitly forced as dedicated using #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT. - Otherwise, it has the priority of a memory block where it is placed and this variable is ignored. - */ - float priority; -} VmaAllocationCreateInfo; - -/// Describes parameter of created #VmaPool. -typedef struct VmaPoolCreateInfo -{ - /** \brief Vulkan memory type index to allocate this pool from. - */ - uint32_t memoryTypeIndex; - /** \brief Use combination of #VmaPoolCreateFlagBits. - */ - VmaPoolCreateFlags flags; - /** \brief Size of a single `VkDeviceMemory` block to be allocated as part of this pool, in bytes. Optional. - - Specify nonzero to set explicit, constant size of memory blocks used by this - pool. - - Leave 0 to use default and let the library manage block sizes automatically. - Sizes of particular blocks may vary. - In this case, the pool will also support dedicated allocations. - */ - VkDeviceSize blockSize; - /** \brief Minimum number of blocks to be always allocated in this pool, even if they stay empty. - - Set to 0 to have no preallocated blocks and allow the pool be completely empty. - */ - size_t minBlockCount; - /** \brief Maximum number of blocks that can be allocated in this pool. Optional. - - Set to 0 to use default, which is `SIZE_MAX`, which means no limit. - - Set to same value as VmaPoolCreateInfo::minBlockCount to have fixed amount of memory allocated - throughout whole lifetime of this pool. - */ - size_t maxBlockCount; - /** \brief A floating-point value between 0 and 1, indicating the priority of the allocations in this pool relative to other memory allocations. - - It is used only when #VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT flag was used during creation of the #VmaAllocator object. - Otherwise, this variable is ignored. - */ - float priority; - /** \brief Additional minimum alignment to be used for all allocations created from this pool. Can be 0. - - Leave 0 (default) not to impose any additional alignment. If not 0, it must be a power of two. - It can be useful in cases where alignment returned by Vulkan by functions like `vkGetBufferMemoryRequirements` is not enough, - e.g. when doing interop with OpenGL. - */ - VkDeviceSize minAllocationAlignment; - /** \brief Additional `pNext` chain to be attached to `VkMemoryAllocateInfo` used for every allocation made by this pool. Optional. - - Optional, can be null. If not null, it must point to a `pNext` chain of structures that can be attached to `VkMemoryAllocateInfo`. - It can be useful for special needs such as adding `VkExportMemoryAllocateInfoKHR`. - Structures pointed by this member must remain alive and unchanged for the whole lifetime of the custom pool. - - Please note that some structures, e.g. `VkMemoryPriorityAllocateInfoEXT`, `VkMemoryDedicatedAllocateInfoKHR`, - can be attached automatically by this library when using other, more convenient of its features. - */ - void* VMA_NULLABLE VMA_EXTENDS_VK_STRUCT(VkMemoryAllocateInfo) pMemoryAllocateNext; -} VmaPoolCreateInfo; - -/** @} */ - -/** -\addtogroup group_alloc -@{ -*/ - -/** -Parameters of #VmaAllocation objects, that can be retrieved using function vmaGetAllocationInfo(). - -There is also an extended version of this structure that carries additional parameters: #VmaAllocationInfo2. -*/ -typedef struct VmaAllocationInfo -{ - /** \brief Memory type index that this allocation was allocated from. - - It never changes. - */ - uint32_t memoryType; - /** \brief Handle to Vulkan memory object. - - Same memory object can be shared by multiple allocations. - - It can change after the allocation is moved during \ref defragmentation. - */ - VkDeviceMemory VMA_NULLABLE_NON_DISPATCHABLE deviceMemory; - /** \brief Offset in `VkDeviceMemory` object to the beginning of this allocation, in bytes. `(deviceMemory, offset)` pair is unique to this allocation. - - You usually don't need to use this offset. If you create a buffer or an image together with the allocation using e.g. function - vmaCreateBuffer(), vmaCreateImage(), functions that operate on these resources refer to the beginning of the buffer or image, - not entire device memory block. Functions like vmaMapMemory(), vmaBindBufferMemory() also refer to the beginning of the allocation - and apply this offset automatically. - - It can change after the allocation is moved during \ref defragmentation. - */ - VkDeviceSize offset; - /** \brief Size of this allocation, in bytes. - - It never changes. - - \note Allocation size returned in this variable may be greater than the size - requested for the resource e.g. as `VkBufferCreateInfo::size`. Whole size of the - allocation is accessible for operations on memory e.g. using a pointer after - mapping with vmaMapMemory(), but operations on the resource e.g. using - `vkCmdCopyBuffer` must be limited to the size of the resource. - */ - VkDeviceSize size; - /** \brief Pointer to the beginning of this allocation as mapped data. - - If the allocation hasn't been mapped using vmaMapMemory() and hasn't been - created with #VMA_ALLOCATION_CREATE_MAPPED_BIT flag, this value is null. - - It can change after call to vmaMapMemory(), vmaUnmapMemory(). - It can also change after the allocation is moved during \ref defragmentation. - */ - void* VMA_NULLABLE pMappedData; - /** \brief Custom general-purpose pointer that was passed as VmaAllocationCreateInfo::pUserData or set using vmaSetAllocationUserData(). - - It can change after call to vmaSetAllocationUserData() for this allocation. - */ - void* VMA_NULLABLE pUserData; - /** \brief Custom allocation name that was set with vmaSetAllocationName(). - - It can change after call to vmaSetAllocationName() for this allocation. - - Another way to set custom name is to pass it in VmaAllocationCreateInfo::pUserData with - additional flag #VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT set [DEPRECATED]. - */ - const char* VMA_NULLABLE pName; -} VmaAllocationInfo; - -/// Extended parameters of a #VmaAllocation object that can be retrieved using function vmaGetAllocationInfo2(). -typedef struct VmaAllocationInfo2 -{ - /** \brief Basic parameters of the allocation. - - If you need only these, you can use function vmaGetAllocationInfo() and structure #VmaAllocationInfo instead. - */ - VmaAllocationInfo allocationInfo; - /** \brief Size of the `VkDeviceMemory` block that the allocation belongs to. - - In case of an allocation with dedicated memory, it will be equal to `allocationInfo.size`. - */ - VkDeviceSize blockSize; - /** \brief `VK_TRUE` if the allocation has dedicated memory, `VK_FALSE` if it was placed as part of a larger memory block. - - When `VK_TRUE`, it also means `VkMemoryDedicatedAllocateInfo` was used when creating the allocation - (if VK_KHR_dedicated_allocation extension or Vulkan version >= 1.1 is enabled). - */ - VkBool32 dedicatedMemory; -} VmaAllocationInfo2; - -/** Callback function called during vmaBeginDefragmentation() to check custom criterion about ending current defragmentation pass. - -Should return true if the defragmentation needs to stop current pass. -*/ -typedef VkBool32 (VKAPI_PTR* PFN_vmaCheckDefragmentationBreakFunction)(void* VMA_NULLABLE pUserData); - -/** \brief Parameters for defragmentation. - -To be used with function vmaBeginDefragmentation(). -*/ -typedef struct VmaDefragmentationInfo -{ - /// \brief Use combination of #VmaDefragmentationFlagBits. - VmaDefragmentationFlags flags; - /** \brief Custom pool to be defragmented. - - If null then default pools will undergo defragmentation process. - */ - VmaPool VMA_NULLABLE pool; - /** \brief Maximum numbers of bytes that can be copied during single pass, while moving allocations to different places. - - `0` means no limit. - */ - VkDeviceSize maxBytesPerPass; - /** \brief Maximum number of allocations that can be moved during single pass to a different place. - - `0` means no limit. - */ - uint32_t maxAllocationsPerPass; - /** \brief Optional custom callback for stopping vmaBeginDefragmentation(). - - Have to return true for breaking current defragmentation pass. - */ - PFN_vmaCheckDefragmentationBreakFunction VMA_NULLABLE pfnBreakCallback; - /// \brief Optional data to pass to custom callback for stopping pass of defragmentation. - void* VMA_NULLABLE pBreakCallbackUserData; -} VmaDefragmentationInfo; - -/// Single move of an allocation to be done for defragmentation. -typedef struct VmaDefragmentationMove -{ - /// Operation to be performed on the allocation by vmaEndDefragmentationPass(). Default value is #VMA_DEFRAGMENTATION_MOVE_OPERATION_COPY. You can modify it. - VmaDefragmentationMoveOperation operation; - /// Allocation that should be moved. - VmaAllocation VMA_NOT_NULL srcAllocation; - /** \brief Temporary allocation pointing to destination memory that will replace `srcAllocation`. - - \warning Do not store this allocation in your data structures! It exists only temporarily, for the duration of the defragmentation pass, - to be used for binding new buffer/image to the destination memory using e.g. vmaBindBufferMemory(). - vmaEndDefragmentationPass() will destroy it and make `srcAllocation` point to this memory. - */ - VmaAllocation VMA_NOT_NULL dstTmpAllocation; -} VmaDefragmentationMove; - -/** \brief Parameters for incremental defragmentation steps. - -To be used with function vmaBeginDefragmentationPass(). -*/ -typedef struct VmaDefragmentationPassMoveInfo -{ - /// Number of elements in the `pMoves` array. - uint32_t moveCount; - /** \brief Array of moves to be performed by the user in the current defragmentation pass. - - Pointer to an array of `moveCount` elements, owned by VMA, created in vmaBeginDefragmentationPass(), destroyed in vmaEndDefragmentationPass(). - - For each element, you should: - - 1. Create a new buffer/image in the place pointed by VmaDefragmentationMove::dstMemory + VmaDefragmentationMove::dstOffset. - 2. Copy data from the VmaDefragmentationMove::srcAllocation e.g. using `vkCmdCopyBuffer`, `vkCmdCopyImage`. - 3. Make sure these commands finished executing on the GPU. - 4. Destroy the old buffer/image. - - Only then you can finish defragmentation pass by calling vmaEndDefragmentationPass(). - After this call, the allocation will point to the new place in memory. - - Alternatively, if you cannot move specific allocation, you can set VmaDefragmentationMove::operation to #VMA_DEFRAGMENTATION_MOVE_OPERATION_IGNORE. - - Alternatively, if you decide you want to completely remove the allocation: - - 1. Destroy its buffer/image. - 2. Set VmaDefragmentationMove::operation to #VMA_DEFRAGMENTATION_MOVE_OPERATION_DESTROY. - - Then, after vmaEndDefragmentationPass() the allocation will be freed. - */ - VmaDefragmentationMove* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(moveCount) pMoves; -} VmaDefragmentationPassMoveInfo; - -/// Statistics returned for defragmentation process in function vmaEndDefragmentation(). -typedef struct VmaDefragmentationStats -{ - /// Total number of bytes that have been copied while moving allocations to different places. - VkDeviceSize bytesMoved; - /// Total number of bytes that have been released to the system by freeing empty `VkDeviceMemory` objects. - VkDeviceSize bytesFreed; - /// Number of allocations that have been moved to different places. - uint32_t allocationsMoved; - /// Number of empty `VkDeviceMemory` objects that have been released to the system. - uint32_t deviceMemoryBlocksFreed; -} VmaDefragmentationStats; - -/** @} */ - -/** -\addtogroup group_virtual -@{ -*/ - -/// Parameters of created #VmaVirtualBlock object to be passed to vmaCreateVirtualBlock(). -typedef struct VmaVirtualBlockCreateInfo -{ - /** \brief Total size of the virtual block. - - Sizes can be expressed in bytes or any units you want as long as you are consistent in using them. - For example, if you allocate from some array of structures, 1 can mean single instance of entire structure. - */ - VkDeviceSize size; - - /** \brief Use combination of #VmaVirtualBlockCreateFlagBits. - */ - VmaVirtualBlockCreateFlags flags; - - /** \brief Custom CPU memory allocation callbacks. Optional. - - Optional, can be null. When specified, they will be used for all CPU-side memory allocations. - */ - const VkAllocationCallbacks* VMA_NULLABLE pAllocationCallbacks; -} VmaVirtualBlockCreateInfo; - -/// Parameters of created virtual allocation to be passed to vmaVirtualAllocate(). -typedef struct VmaVirtualAllocationCreateInfo -{ - /** \brief Size of the allocation. - - Cannot be zero. - */ - VkDeviceSize size; - /** \brief Required alignment of the allocation. Optional. - - Must be power of two. Special value 0 has the same meaning as 1 - means no special alignment is required, so allocation can start at any offset. - */ - VkDeviceSize alignment; - /** \brief Use combination of #VmaVirtualAllocationCreateFlagBits. - */ - VmaVirtualAllocationCreateFlags flags; - /** \brief Custom pointer to be associated with the allocation. Optional. - - It can be any value and can be used for user-defined purposes. It can be fetched or changed later. - */ - void* VMA_NULLABLE pUserData; -} VmaVirtualAllocationCreateInfo; - -/// Parameters of an existing virtual allocation, returned by vmaGetVirtualAllocationInfo(). -typedef struct VmaVirtualAllocationInfo -{ - /** \brief Offset of the allocation. - - Offset at which the allocation was made. - */ - VkDeviceSize offset; - /** \brief Size of the allocation. - - Same value as passed in VmaVirtualAllocationCreateInfo::size. - */ - VkDeviceSize size; - /** \brief Custom pointer associated with the allocation. - - Same value as passed in VmaVirtualAllocationCreateInfo::pUserData or to vmaSetVirtualAllocationUserData(). - */ - void* VMA_NULLABLE pUserData; -} VmaVirtualAllocationInfo; - -/** @} */ + /// Parameters of created #VmaVirtualBlock object to be passed to vmaCreateVirtualBlock(). + typedef struct VmaVirtualBlockCreateInfo + { + /** \brief Total size of the virtual block. + + Sizes can be expressed in bytes or any units you want as long as you are consistent in using them. + For example, if you allocate from some array of structures, 1 can mean single instance of entire structure. + */ + VkDeviceSize size; + + /** \brief Use combination of #VmaVirtualBlockCreateFlagBits. + */ + VmaVirtualBlockCreateFlags flags; + + /** \brief Custom CPU memory allocation callbacks. Optional. + + Optional, can be null. When specified, they will be used for all CPU-side memory allocations. + */ + const VkAllocationCallbacks* VMA_NULLABLE pAllocationCallbacks; + } VmaVirtualBlockCreateInfo; + + /// Parameters of created virtual allocation to be passed to vmaVirtualAllocate(). + typedef struct VmaVirtualAllocationCreateInfo + { + /** \brief Size of the allocation. + + Cannot be zero. + */ + VkDeviceSize size; + /** \brief Required alignment of the allocation. Optional. + + Must be power of two. Special value 0 has the same meaning as 1 - means no special alignment is required, so allocation can start at any offset. + */ + VkDeviceSize alignment; + /** \brief Use combination of #VmaVirtualAllocationCreateFlagBits. + */ + VmaVirtualAllocationCreateFlags flags; + /** \brief Custom pointer to be associated with the allocation. Optional. + + It can be any value and can be used for user-defined purposes. It can be fetched or changed later. + */ + void* VMA_NULLABLE pUserData; + } VmaVirtualAllocationCreateInfo; + + /// Parameters of an existing virtual allocation, returned by vmaGetVirtualAllocationInfo(). + typedef struct VmaVirtualAllocationInfo + { + /** \brief Offset of the allocation. + + Offset at which the allocation was made. + */ + VkDeviceSize offset; + /** \brief Size of the allocation. + + Same value as passed in VmaVirtualAllocationCreateInfo::size. + */ + VkDeviceSize size; + /** \brief Custom pointer associated with the allocation. + + Same value as passed in VmaVirtualAllocationCreateInfo::pUserData or to vmaSetVirtualAllocationUserData(). + */ + void* VMA_NULLABLE pUserData; + } VmaVirtualAllocationInfo; + + /** @} */ #endif // _VMA_DATA_TYPES_DECLARATIONS @@ -1657,1051 +1657,1051 @@ typedef struct VmaVirtualAllocationInfo */ /// Creates #VmaAllocator object. -VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAllocator( - const VmaAllocatorCreateInfo* VMA_NOT_NULL pCreateInfo, - VmaAllocator VMA_NULLABLE* VMA_NOT_NULL pAllocator); - -/// Destroys allocator object. -VMA_CALL_PRE void VMA_CALL_POST vmaDestroyAllocator( - VmaAllocator VMA_NULLABLE allocator); - -/** \brief Returns information about existing #VmaAllocator object - handle to Vulkan device etc. - -It might be useful if you want to keep just the #VmaAllocator handle and fetch other required handles to -`VkPhysicalDevice`, `VkDevice` etc. every time using this function. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocatorInfo( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocatorInfo* VMA_NOT_NULL pAllocatorInfo); - -/** -PhysicalDeviceProperties are fetched from physicalDevice by the allocator. -You can access it here, without fetching it again on your own. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaGetPhysicalDeviceProperties( - VmaAllocator VMA_NOT_NULL allocator, - const VkPhysicalDeviceProperties* VMA_NULLABLE* VMA_NOT_NULL ppPhysicalDeviceProperties); - -/** -PhysicalDeviceMemoryProperties are fetched from physicalDevice by the allocator. -You can access it here, without fetching it again on your own. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaGetMemoryProperties( - VmaAllocator VMA_NOT_NULL allocator, - const VkPhysicalDeviceMemoryProperties* VMA_NULLABLE* VMA_NOT_NULL ppPhysicalDeviceMemoryProperties); - -/** -\brief Given Memory Type Index, returns Property Flags of this memory type. - -This is just a convenience function. Same information can be obtained using -vmaGetMemoryProperties(). -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaGetMemoryTypeProperties( - VmaAllocator VMA_NOT_NULL allocator, - uint32_t memoryTypeIndex, - VkMemoryPropertyFlags* VMA_NOT_NULL pFlags); - -/** \brief Sets index of the current frame. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaSetCurrentFrameIndex( - VmaAllocator VMA_NOT_NULL allocator, - uint32_t frameIndex); - -/** @} */ - -/** -\addtogroup group_stats -@{ -*/ - -/** \brief Retrieves statistics from current state of the Allocator. - -This function is called "calculate" not "get" because it has to traverse all -internal data structures, so it may be quite slow. Use it for debugging purposes. -For faster but more brief statistics suitable to be called every frame or every allocation, -use vmaGetHeapBudgets(). - -Note that when using allocator from multiple threads, returned information may immediately -become outdated. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaCalculateStatistics( - VmaAllocator VMA_NOT_NULL allocator, - VmaTotalStatistics* VMA_NOT_NULL pStats); - -/** \brief Retrieves information about current memory usage and budget for all memory heaps. - -\param allocator -\param[out] pBudgets Must point to array with number of elements at least equal to number of memory heaps in physical device used. - -This function is called "get" not "calculate" because it is very fast, suitable to be called -every frame or every allocation. For more detailed statistics use vmaCalculateStatistics(). - -Note that when using allocator from multiple threads, returned information may immediately -become outdated. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaGetHeapBudgets( - VmaAllocator VMA_NOT_NULL allocator, - VmaBudget* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL("VkPhysicalDeviceMemoryProperties::memoryHeapCount") pBudgets); - -/** @} */ - -/** -\addtogroup group_alloc -@{ -*/ - -/** -\brief Helps to find memoryTypeIndex, given memoryTypeBits and VmaAllocationCreateInfo. - -This algorithm tries to find a memory type that: - -- Is allowed by memoryTypeBits. -- Contains all the flags from pAllocationCreateInfo->requiredFlags. -- Matches intended usage. -- Has as many flags from pAllocationCreateInfo->preferredFlags as possible. - -\return Returns VK_ERROR_FEATURE_NOT_PRESENT if not found. Receiving such result -from this function or any other allocating function probably means that your -device doesn't support any memory type with requested features for the specific -type of resource you want to use it for. Please check parameters of your -resource, like image layout (OPTIMAL versus LINEAR) or mip level count. -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndex( - VmaAllocator VMA_NOT_NULL allocator, - uint32_t memoryTypeBits, - const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, - uint32_t* VMA_NOT_NULL pMemoryTypeIndex); - -/** -\brief Helps to find memoryTypeIndex, given VkBufferCreateInfo and VmaAllocationCreateInfo. - -It can be useful e.g. to determine value to be used as VmaPoolCreateInfo::memoryTypeIndex. -It internally creates a temporary, dummy buffer that never has memory bound. -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForBufferInfo( - VmaAllocator VMA_NOT_NULL allocator, - const VkBufferCreateInfo* VMA_NOT_NULL pBufferCreateInfo, - const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, - uint32_t* VMA_NOT_NULL pMemoryTypeIndex); - -/** -\brief Helps to find memoryTypeIndex, given VkImageCreateInfo and VmaAllocationCreateInfo. - -It can be useful e.g. to determine value to be used as VmaPoolCreateInfo::memoryTypeIndex. -It internally creates a temporary, dummy image that never has memory bound. -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForImageInfo( - VmaAllocator VMA_NOT_NULL allocator, - const VkImageCreateInfo* VMA_NOT_NULL pImageCreateInfo, - const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, - uint32_t* VMA_NOT_NULL pMemoryTypeIndex); - -/** \brief Allocates Vulkan device memory and creates #VmaPool object. - -\param allocator Allocator object. -\param pCreateInfo Parameters of pool to create. -\param[out] pPool Handle to created pool. -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreatePool( - VmaAllocator VMA_NOT_NULL allocator, - const VmaPoolCreateInfo* VMA_NOT_NULL pCreateInfo, - VmaPool VMA_NULLABLE* VMA_NOT_NULL pPool); - -/** \brief Destroys #VmaPool object and frees Vulkan device memory. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaDestroyPool( - VmaAllocator VMA_NOT_NULL allocator, - VmaPool VMA_NULLABLE pool); - -/** @} */ - -/** -\addtogroup group_stats -@{ -*/ - -/** \brief Retrieves statistics of existing #VmaPool object. - -\param allocator Allocator object. -\param pool Pool object. -\param[out] pPoolStats Statistics of specified pool. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaGetPoolStatistics( - VmaAllocator VMA_NOT_NULL allocator, - VmaPool VMA_NOT_NULL pool, - VmaStatistics* VMA_NOT_NULL pPoolStats); - -/** \brief Retrieves detailed statistics of existing #VmaPool object. - -\param allocator Allocator object. -\param pool Pool object. -\param[out] pPoolStats Statistics of specified pool. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaCalculatePoolStatistics( - VmaAllocator VMA_NOT_NULL allocator, - VmaPool VMA_NOT_NULL pool, - VmaDetailedStatistics* VMA_NOT_NULL pPoolStats); - -/** @} */ - -/** -\addtogroup group_alloc -@{ -*/ - -/** \brief Checks magic number in margins around all allocations in given memory pool in search for corruptions. - -Corruption detection is enabled only when `VMA_DEBUG_DETECT_CORRUPTION` macro is defined to nonzero, -`VMA_DEBUG_MARGIN` is defined to nonzero and the pool is created in memory type that is -`HOST_VISIBLE` and `HOST_COHERENT`. For more information, see [Corruption detection](@ref debugging_memory_usage_corruption_detection). - -Possible return values: - -- `VK_ERROR_FEATURE_NOT_PRESENT` - corruption detection is not enabled for specified pool. -- `VK_SUCCESS` - corruption detection has been performed and succeeded. -- `VK_ERROR_UNKNOWN` - corruption detection has been performed and found memory corruptions around one of the allocations. - `VMA_ASSERT` is also fired in that case. -- Other value: Error returned by Vulkan, e.g. memory mapping failure. -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckPoolCorruption( - VmaAllocator VMA_NOT_NULL allocator, - VmaPool VMA_NOT_NULL pool); - -/** \brief Retrieves name of a custom pool. - -After the call `ppName` is either null or points to an internally-owned null-terminated string -containing name of the pool that was previously set. The pointer becomes invalid when the pool is -destroyed or its name is changed using vmaSetPoolName(). -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaGetPoolName( - VmaAllocator VMA_NOT_NULL allocator, - VmaPool VMA_NOT_NULL pool, - const char* VMA_NULLABLE* VMA_NOT_NULL ppName); - -/** \brief Sets name of a custom pool. - -`pName` can be either null or pointer to a null-terminated string with new name for the pool. -Function makes internal copy of the string, so it can be changed or freed immediately after this call. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaSetPoolName( - VmaAllocator VMA_NOT_NULL allocator, - VmaPool VMA_NOT_NULL pool, - const char* VMA_NULLABLE pName); - -/** \brief General purpose memory allocation. - -\param allocator -\param pVkMemoryRequirements -\param pCreateInfo -\param[out] pAllocation Handle to allocated memory. -\param[out] pAllocationInfo Optional. Information about allocated memory. It can be later fetched using function vmaGetAllocationInfo(). - -You should free the memory using vmaFreeMemory() or vmaFreeMemoryPages(). - -It is recommended to use vmaAllocateMemoryForBuffer(), vmaAllocateMemoryForImage(), -vmaCreateBuffer(), vmaCreateImage() instead whenever possible. -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemory( - VmaAllocator VMA_NOT_NULL allocator, - const VkMemoryRequirements* VMA_NOT_NULL pVkMemoryRequirements, - const VmaAllocationCreateInfo* VMA_NOT_NULL pCreateInfo, - VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation, - VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); - -/** \brief General purpose memory allocation for multiple allocation objects at once. - -\param allocator Allocator object. -\param pVkMemoryRequirements Memory requirements for each allocation. -\param pCreateInfo Creation parameters for each allocation. -\param allocationCount Number of allocations to make. -\param[out] pAllocations Pointer to array that will be filled with handles to created allocations. -\param[out] pAllocationInfo Optional. Pointer to array that will be filled with parameters of created allocations. - -You should free the memory using vmaFreeMemory() or vmaFreeMemoryPages(). - -Word "pages" is just a suggestion to use this function to allocate pieces of memory needed for sparse binding. -It is just a general purpose allocation function able to make multiple allocations at once. -It may be internally optimized to be more efficient than calling vmaAllocateMemory() `allocationCount` times. - -All allocations are made using same parameters. All of them are created out of the same memory pool and type. -If any allocation fails, all allocations already made within this function call are also freed, so that when -returned result is not `VK_SUCCESS`, `pAllocation` array is always entirely filled with `VK_NULL_HANDLE`. -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryPages( - VmaAllocator VMA_NOT_NULL allocator, - const VkMemoryRequirements* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(allocationCount) pVkMemoryRequirements, - const VmaAllocationCreateInfo* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(allocationCount) pCreateInfo, - size_t allocationCount, - VmaAllocation VMA_NULLABLE* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(allocationCount) pAllocations, - VmaAllocationInfo* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) pAllocationInfo); - -/** \brief Allocates memory suitable for given `VkBuffer`. - -\param allocator -\param buffer -\param pCreateInfo -\param[out] pAllocation Handle to allocated memory. -\param[out] pAllocationInfo Optional. Information about allocated memory. It can be later fetched using function vmaGetAllocationInfo(). - -It only creates #VmaAllocation. To bind the memory to the buffer, use vmaBindBufferMemory(). - -This is a special-purpose function. In most cases you should use vmaCreateBuffer(). - -You must free the allocation using vmaFreeMemory() when no longer needed. -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForBuffer( - VmaAllocator VMA_NOT_NULL allocator, - VkBuffer VMA_NOT_NULL_NON_DISPATCHABLE buffer, - const VmaAllocationCreateInfo* VMA_NOT_NULL pCreateInfo, - VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation, - VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); - -/** \brief Allocates memory suitable for given `VkImage`. - -\param allocator -\param image -\param pCreateInfo -\param[out] pAllocation Handle to allocated memory. -\param[out] pAllocationInfo Optional. Information about allocated memory. It can be later fetched using function vmaGetAllocationInfo(). - -It only creates #VmaAllocation. To bind the memory to the buffer, use vmaBindImageMemory(). - -This is a special-purpose function. In most cases you should use vmaCreateImage(). - -You must free the allocation using vmaFreeMemory() when no longer needed. -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForImage( - VmaAllocator VMA_NOT_NULL allocator, - VkImage VMA_NOT_NULL_NON_DISPATCHABLE image, - const VmaAllocationCreateInfo* VMA_NOT_NULL pCreateInfo, - VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation, - VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); - -/** \brief Frees memory previously allocated using vmaAllocateMemory(), vmaAllocateMemoryForBuffer(), or vmaAllocateMemoryForImage(). - -Passing `VK_NULL_HANDLE` as `allocation` is valid. Such function call is just skipped. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemory( - VmaAllocator VMA_NOT_NULL allocator, - const VmaAllocation VMA_NULLABLE allocation); - -/** \brief Frees memory and destroys multiple allocations. - -Word "pages" is just a suggestion to use this function to free pieces of memory used for sparse binding. -It is just a general purpose function to free memory and destroy allocations made using e.g. vmaAllocateMemory(), -vmaAllocateMemoryPages() and other functions. -It may be internally optimized to be more efficient than calling vmaFreeMemory() `allocationCount` times. - -Allocations in `pAllocations` array can come from any memory pools and types. -Passing `VK_NULL_HANDLE` as elements of `pAllocations` array is valid. Such entries are just skipped. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemoryPages( - VmaAllocator VMA_NOT_NULL allocator, - size_t allocationCount, - const VmaAllocation VMA_NULLABLE* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(allocationCount) pAllocations); - -/** \brief Returns current information about specified allocation. - -Current parameters of given allocation are returned in `pAllocationInfo`. - -Although this function doesn't lock any mutex, so it should be quite efficient, -you should avoid calling it too often. -You can retrieve same VmaAllocationInfo structure while creating your resource, from function -vmaCreateBuffer(), vmaCreateImage(). You can remember it if you are sure parameters don't change -(e.g. due to defragmentation). - -There is also a new function vmaGetAllocationInfo2() that offers extended information -about the allocation, returned using new structure #VmaAllocationInfo2. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationInfo( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocation VMA_NOT_NULL allocation, - VmaAllocationInfo* VMA_NOT_NULL pAllocationInfo); - -/** \brief Returns extended information about specified allocation. - -Current parameters of given allocation are returned in `pAllocationInfo`. -Extended parameters in structure #VmaAllocationInfo2 include memory block size -and a flag telling whether the allocation has dedicated memory. -It can be useful e.g. for interop with OpenGL. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationInfo2( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocation VMA_NOT_NULL allocation, - VmaAllocationInfo2* VMA_NOT_NULL pAllocationInfo); - -/** \brief Sets pUserData in given allocation to new value. - -The value of pointer `pUserData` is copied to allocation's `pUserData`. -It is opaque, so you can use it however you want - e.g. -as a pointer, ordinal number or some handle to you own data. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaSetAllocationUserData( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocation VMA_NOT_NULL allocation, - void* VMA_NULLABLE pUserData); - -/** \brief Sets pName in given allocation to new value. - -`pName` must be either null, or pointer to a null-terminated string. The function -makes local copy of the string and sets it as allocation's `pName`. String -passed as pName doesn't need to be valid for whole lifetime of the allocation - -you can free it after this call. String previously pointed by allocation's -`pName` is freed from memory. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaSetAllocationName( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocation VMA_NOT_NULL allocation, - const char* VMA_NULLABLE pName); - -/** -\brief Given an allocation, returns Property Flags of its memory type. - -This is just a convenience function. Same information can be obtained using -vmaGetAllocationInfo() + vmaGetMemoryProperties(). -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationMemoryProperties( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocation VMA_NOT_NULL allocation, - VkMemoryPropertyFlags* VMA_NOT_NULL pFlags); - -/** \brief Maps memory represented by given allocation and returns pointer to it. - -Maps memory represented by given allocation to make it accessible to CPU code. -When succeeded, `*ppData` contains pointer to first byte of this memory. - -\warning -If the allocation is part of a bigger `VkDeviceMemory` block, returned pointer is -correctly offsetted to the beginning of region assigned to this particular allocation. -Unlike the result of `vkMapMemory`, it points to the allocation, not to the beginning of the whole block. -You should not add VmaAllocationInfo::offset to it! - -Mapping is internally reference-counted and synchronized, so despite raw Vulkan -function `vkMapMemory()` cannot be used to map same block of `VkDeviceMemory` -multiple times simultaneously, it is safe to call this function on allocations -assigned to the same memory block. Actual Vulkan memory will be mapped on first -mapping and unmapped on last unmapping. - -If the function succeeded, you must call vmaUnmapMemory() to unmap the -allocation when mapping is no longer needed or before freeing the allocation, at -the latest. - -It also safe to call this function multiple times on the same allocation. You -must call vmaUnmapMemory() same number of times as you called vmaMapMemory(). - -It is also safe to call this function on allocation created with -#VMA_ALLOCATION_CREATE_MAPPED_BIT flag. Its memory stays mapped all the time. -You must still call vmaUnmapMemory() same number of times as you called -vmaMapMemory(). You must not call vmaUnmapMemory() additional time to free the -"0-th" mapping made automatically due to #VMA_ALLOCATION_CREATE_MAPPED_BIT flag. - -This function fails when used on allocation made in memory type that is not -`HOST_VISIBLE`. - -This function doesn't automatically flush or invalidate caches. -If the allocation is made from a memory types that is not `HOST_COHERENT`, -you also need to use vmaInvalidateAllocation() / vmaFlushAllocation(), as required by Vulkan specification. -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaMapMemory( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocation VMA_NOT_NULL allocation, - void* VMA_NULLABLE* VMA_NOT_NULL ppData); - -/** \brief Unmaps memory represented by given allocation, mapped previously using vmaMapMemory(). - -For details, see description of vmaMapMemory(). - -This function doesn't automatically flush or invalidate caches. -If the allocation is made from a memory types that is not `HOST_COHERENT`, -you also need to use vmaInvalidateAllocation() / vmaFlushAllocation(), as required by Vulkan specification. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaUnmapMemory( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocation VMA_NOT_NULL allocation); - -/** \brief Flushes memory of given allocation. - -Calls `vkFlushMappedMemoryRanges()` for memory associated with given range of given allocation. -It needs to be called after writing to a mapped memory for memory types that are not `HOST_COHERENT`. -Unmap operation doesn't do that automatically. - -- `offset` must be relative to the beginning of allocation. -- `size` can be `VK_WHOLE_SIZE`. It means all memory from `offset` the the end of given allocation. -- `offset` and `size` don't have to be aligned. - They are internally rounded down/up to multiply of `nonCoherentAtomSize`. -- If `size` is 0, this call is ignored. -- If memory type that the `allocation` belongs to is not `HOST_VISIBLE` or it is `HOST_COHERENT`, - this call is ignored. - -Warning! `offset` and `size` are relative to the contents of given `allocation`. -If you mean whole allocation, you can pass 0 and `VK_WHOLE_SIZE`, respectively. -Do not pass allocation's offset as `offset`!!! - -This function returns the `VkResult` from `vkFlushMappedMemoryRanges` if it is -called, otherwise `VK_SUCCESS`. -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocation( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocation VMA_NOT_NULL allocation, - VkDeviceSize offset, - VkDeviceSize size); - -/** \brief Invalidates memory of given allocation. - -Calls `vkInvalidateMappedMemoryRanges()` for memory associated with given range of given allocation. -It needs to be called before reading from a mapped memory for memory types that are not `HOST_COHERENT`. -Map operation doesn't do that automatically. - -- `offset` must be relative to the beginning of allocation. -- `size` can be `VK_WHOLE_SIZE`. It means all memory from `offset` the the end of given allocation. -- `offset` and `size` don't have to be aligned. - They are internally rounded down/up to multiply of `nonCoherentAtomSize`. -- If `size` is 0, this call is ignored. -- If memory type that the `allocation` belongs to is not `HOST_VISIBLE` or it is `HOST_COHERENT`, - this call is ignored. - -Warning! `offset` and `size` are relative to the contents of given `allocation`. -If you mean whole allocation, you can pass 0 and `VK_WHOLE_SIZE`, respectively. -Do not pass allocation's offset as `offset`!!! - -This function returns the `VkResult` from `vkInvalidateMappedMemoryRanges` if -it is called, otherwise `VK_SUCCESS`. -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocation( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocation VMA_NOT_NULL allocation, - VkDeviceSize offset, - VkDeviceSize size); - -/** \brief Flushes memory of given set of allocations. - -Calls `vkFlushMappedMemoryRanges()` for memory associated with given ranges of given allocations. -For more information, see documentation of vmaFlushAllocation(). - -\param allocator -\param allocationCount -\param allocations -\param offsets If not null, it must point to an array of offsets of regions to flush, relative to the beginning of respective allocations. Null means all offsets are zero. -\param sizes If not null, it must point to an array of sizes of regions to flush in respective allocations. Null means `VK_WHOLE_SIZE` for all allocations. - -This function returns the `VkResult` from `vkFlushMappedMemoryRanges` if it is -called, otherwise `VK_SUCCESS`. -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocations( - VmaAllocator VMA_NOT_NULL allocator, - uint32_t allocationCount, - const VmaAllocation VMA_NOT_NULL* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) allocations, - const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) offsets, - const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) sizes); - -/** \brief Invalidates memory of given set of allocations. - -Calls `vkInvalidateMappedMemoryRanges()` for memory associated with given ranges of given allocations. -For more information, see documentation of vmaInvalidateAllocation(). - -\param allocator -\param allocationCount -\param allocations -\param offsets If not null, it must point to an array of offsets of regions to flush, relative to the beginning of respective allocations. Null means all offsets are zero. -\param sizes If not null, it must point to an array of sizes of regions to flush in respective allocations. Null means `VK_WHOLE_SIZE` for all allocations. - -This function returns the `VkResult` from `vkInvalidateMappedMemoryRanges` if it is -called, otherwise `VK_SUCCESS`. -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocations( - VmaAllocator VMA_NOT_NULL allocator, - uint32_t allocationCount, - const VmaAllocation VMA_NOT_NULL* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) allocations, - const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) offsets, - const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) sizes); - -/** \brief Maps the allocation temporarily if needed, copies data from specified host pointer to it, and flushes the memory from the host caches if needed. - -\param allocator -\param pSrcHostPointer Pointer to the host data that become source of the copy. -\param dstAllocation Handle to the allocation that becomes destination of the copy. -\param dstAllocationLocalOffset Offset within `dstAllocation` where to write copied data, in bytes. -\param size Number of bytes to copy. - -This is a convenience function that allows to copy data from a host pointer to an allocation easily. -Same behavior can be achieved by calling vmaMapMemory(), `memcpy()`, vmaUnmapMemory(), vmaFlushAllocation(). - -This function can be called only for allocations created in a memory type that has `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT` flag. -It can be ensured e.g. by using #VMA_MEMORY_USAGE_AUTO and #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or -#VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT. -Otherwise, the function will fail and generate a Validation Layers error. - -`dstAllocationLocalOffset` is relative to the contents of given `dstAllocation`. -If you mean whole allocation, you should pass 0. -Do not pass allocation's offset within device memory block this parameter! -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaCopyMemoryToAllocation( - VmaAllocator VMA_NOT_NULL allocator, - const void* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(size) pSrcHostPointer, - VmaAllocation VMA_NOT_NULL dstAllocation, - VkDeviceSize dstAllocationLocalOffset, - VkDeviceSize size); - -/** \brief Invalidates memory in the host caches if needed, maps the allocation temporarily if needed, and copies data from it to a specified host pointer. - -\param allocator -\param srcAllocation Handle to the allocation that becomes source of the copy. -\param srcAllocationLocalOffset Offset within `srcAllocation` where to read copied data, in bytes. -\param pDstHostPointer Pointer to the host memory that become destination of the copy. -\param size Number of bytes to copy. - -This is a convenience function that allows to copy data from an allocation to a host pointer easily. -Same behavior can be achieved by calling vmaInvalidateAllocation(), vmaMapMemory(), `memcpy()`, vmaUnmapMemory(). - -This function should be called only for allocations created in a memory type that has `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT` -and `VK_MEMORY_PROPERTY_HOST_CACHED_BIT` flag. -It can be ensured e.g. by using #VMA_MEMORY_USAGE_AUTO and #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT. -Otherwise, the function may fail and generate a Validation Layers error. -It may also work very slowly when reading from an uncached memory. - -`srcAllocationLocalOffset` is relative to the contents of given `srcAllocation`. -If you mean whole allocation, you should pass 0. -Do not pass allocation's offset within device memory block as this parameter! -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaCopyAllocationToMemory( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocation VMA_NOT_NULL srcAllocation, - VkDeviceSize srcAllocationLocalOffset, - void* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(size) pDstHostPointer, - VkDeviceSize size); - -/** \brief Checks magic number in margins around all allocations in given memory types (in both default and custom pools) in search for corruptions. - -\param allocator -\param memoryTypeBits Bit mask, where each bit set means that a memory type with that index should be checked. - -Corruption detection is enabled only when `VMA_DEBUG_DETECT_CORRUPTION` macro is defined to nonzero, -`VMA_DEBUG_MARGIN` is defined to nonzero and only for memory types that are -`HOST_VISIBLE` and `HOST_COHERENT`. For more information, see [Corruption detection](@ref debugging_memory_usage_corruption_detection). - -Possible return values: - -- `VK_ERROR_FEATURE_NOT_PRESENT` - corruption detection is not enabled for any of specified memory types. -- `VK_SUCCESS` - corruption detection has been performed and succeeded. -- `VK_ERROR_UNKNOWN` - corruption detection has been performed and found memory corruptions around one of the allocations. - `VMA_ASSERT` is also fired in that case. -- Other value: Error returned by Vulkan, e.g. memory mapping failure. -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckCorruption( - VmaAllocator VMA_NOT_NULL allocator, - uint32_t memoryTypeBits); - -/** \brief Begins defragmentation process. - -\param allocator Allocator object. -\param pInfo Structure filled with parameters of defragmentation. -\param[out] pContext Context object that must be passed to vmaEndDefragmentation() to finish defragmentation. -\returns -- `VK_SUCCESS` if defragmentation can begin. -- `VK_ERROR_FEATURE_NOT_PRESENT` if defragmentation is not supported. - -For more information about defragmentation, see documentation chapter: -[Defragmentation](@ref defragmentation). -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaBeginDefragmentation( - VmaAllocator VMA_NOT_NULL allocator, - const VmaDefragmentationInfo* VMA_NOT_NULL pInfo, - VmaDefragmentationContext VMA_NULLABLE* VMA_NOT_NULL pContext); - -/** \brief Ends defragmentation process. - -\param allocator Allocator object. -\param context Context object that has been created by vmaBeginDefragmentation(). -\param[out] pStats Optional stats for the defragmentation. Can be null. - -Use this function to finish defragmentation started by vmaBeginDefragmentation(). -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaEndDefragmentation( - VmaAllocator VMA_NOT_NULL allocator, - VmaDefragmentationContext VMA_NOT_NULL context, - VmaDefragmentationStats* VMA_NULLABLE pStats); - -/** \brief Starts single defragmentation pass. - -\param allocator Allocator object. -\param context Context object that has been created by vmaBeginDefragmentation(). -\param[out] pPassInfo Computed information for current pass. -\returns -- `VK_SUCCESS` if no more moves are possible. Then you can omit call to vmaEndDefragmentationPass() and simply end whole defragmentation. -- `VK_INCOMPLETE` if there are pending moves returned in `pPassInfo`. You need to perform them, call vmaEndDefragmentationPass(), - and then preferably try another pass with vmaBeginDefragmentationPass(). -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaBeginDefragmentationPass( - VmaAllocator VMA_NOT_NULL allocator, - VmaDefragmentationContext VMA_NOT_NULL context, - VmaDefragmentationPassMoveInfo* VMA_NOT_NULL pPassInfo); - -/** \brief Ends single defragmentation pass. - -\param allocator Allocator object. -\param context Context object that has been created by vmaBeginDefragmentation(). -\param pPassInfo Computed information for current pass filled by vmaBeginDefragmentationPass() and possibly modified by you. - -Returns `VK_SUCCESS` if no more moves are possible or `VK_INCOMPLETE` if more defragmentations are possible. - -Ends incremental defragmentation pass and commits all defragmentation moves from `pPassInfo`. -After this call: - -- Allocations at `pPassInfo[i].srcAllocation` that had `pPassInfo[i].operation ==` #VMA_DEFRAGMENTATION_MOVE_OPERATION_COPY - (which is the default) will be pointing to the new destination place. -- Allocation at `pPassInfo[i].srcAllocation` that had `pPassInfo[i].operation ==` #VMA_DEFRAGMENTATION_MOVE_OPERATION_DESTROY - will be freed. - -If no more moves are possible you can end whole defragmentation. -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaEndDefragmentationPass( - VmaAllocator VMA_NOT_NULL allocator, - VmaDefragmentationContext VMA_NOT_NULL context, - VmaDefragmentationPassMoveInfo* VMA_NOT_NULL pPassInfo); - -/** \brief Binds buffer to allocation. - -Binds specified buffer to region of memory represented by specified allocation. -Gets `VkDeviceMemory` handle and offset from the allocation. -If you want to create a buffer, allocate memory for it and bind them together separately, -you should use this function for binding instead of standard `vkBindBufferMemory()`, -because it ensures proper synchronization so that when a `VkDeviceMemory` object is used by multiple -allocations, calls to `vkBind*Memory()` or `vkMapMemory()` won't happen from multiple threads simultaneously -(which is illegal in Vulkan). - -It is recommended to use function vmaCreateBuffer() instead of this one. -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocation VMA_NOT_NULL allocation, - VkBuffer VMA_NOT_NULL_NON_DISPATCHABLE buffer); - -/** \brief Binds buffer to allocation with additional parameters. - -\param allocator -\param allocation -\param allocationLocalOffset Additional offset to be added while binding, relative to the beginning of the `allocation`. Normally it should be 0. -\param buffer -\param pNext A chain of structures to be attached to `VkBindBufferMemoryInfoKHR` structure used internally. Normally it should be null. - -This function is similar to vmaBindBufferMemory(), but it provides additional parameters. - -If `pNext` is not null, #VmaAllocator object must have been created with #VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT flag -or with VmaAllocatorCreateInfo::vulkanApiVersion `>= VK_API_VERSION_1_1`. Otherwise the call fails. -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory2( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocation VMA_NOT_NULL allocation, - VkDeviceSize allocationLocalOffset, - VkBuffer VMA_NOT_NULL_NON_DISPATCHABLE buffer, - const void* VMA_NULLABLE VMA_EXTENDS_VK_STRUCT(VkBindBufferMemoryInfoKHR) pNext); - -/** \brief Binds image to allocation. - -Binds specified image to region of memory represented by specified allocation. -Gets `VkDeviceMemory` handle and offset from the allocation. -If you want to create an image, allocate memory for it and bind them together separately, -you should use this function for binding instead of standard `vkBindImageMemory()`, -because it ensures proper synchronization so that when a `VkDeviceMemory` object is used by multiple -allocations, calls to `vkBind*Memory()` or `vkMapMemory()` won't happen from multiple threads simultaneously -(which is illegal in Vulkan). - -It is recommended to use function vmaCreateImage() instead of this one. -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocation VMA_NOT_NULL allocation, - VkImage VMA_NOT_NULL_NON_DISPATCHABLE image); - -/** \brief Binds image to allocation with additional parameters. - -\param allocator -\param allocation -\param allocationLocalOffset Additional offset to be added while binding, relative to the beginning of the `allocation`. Normally it should be 0. -\param image -\param pNext A chain of structures to be attached to `VkBindImageMemoryInfoKHR` structure used internally. Normally it should be null. - -This function is similar to vmaBindImageMemory(), but it provides additional parameters. - -If `pNext` is not null, #VmaAllocator object must have been created with #VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT flag -or with VmaAllocatorCreateInfo::vulkanApiVersion `>= VK_API_VERSION_1_1`. Otherwise the call fails. -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory2( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocation VMA_NOT_NULL allocation, - VkDeviceSize allocationLocalOffset, - VkImage VMA_NOT_NULL_NON_DISPATCHABLE image, - const void* VMA_NULLABLE VMA_EXTENDS_VK_STRUCT(VkBindImageMemoryInfoKHR) pNext); - -/** \brief Creates a new `VkBuffer`, allocates and binds memory for it. - -\param allocator -\param pBufferCreateInfo -\param pAllocationCreateInfo -\param[out] pBuffer Buffer that was created. -\param[out] pAllocation Allocation that was created. -\param[out] pAllocationInfo Optional. Information about allocated memory. It can be later fetched using function vmaGetAllocationInfo(). - -This function automatically: - --# Creates buffer. --# Allocates appropriate memory for it. --# Binds the buffer with the memory. - -If any of these operations fail, buffer and allocation are not created, -returned value is negative error code, `*pBuffer` and `*pAllocation` are null. - -If the function succeeded, you must destroy both buffer and allocation when you -no longer need them using either convenience function vmaDestroyBuffer() or -separately, using `vkDestroyBuffer()` and vmaFreeMemory(). - -If #VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT flag was used, -VK_KHR_dedicated_allocation extension is used internally to query driver whether -it requires or prefers the new buffer to have dedicated allocation. If yes, -and if dedicated allocation is possible -(#VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT is not used), it creates dedicated -allocation for this buffer, just like when using -#VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT. - -\note This function creates a new `VkBuffer`. Sub-allocation of parts of one large buffer, -although recommended as a good practice, is out of scope of this library and could be implemented -by the user as a higher-level logic on top of VMA. -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBuffer( - VmaAllocator VMA_NOT_NULL allocator, - const VkBufferCreateInfo* VMA_NOT_NULL pBufferCreateInfo, - const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, - VkBuffer VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pBuffer, - VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation, - VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); - -/** \brief Creates a buffer with additional minimum alignment. - -Similar to vmaCreateBuffer() but provides additional parameter `minAlignment` which allows to specify custom, -minimum alignment to be used when placing the buffer inside a larger memory block, which may be needed e.g. -for interop with OpenGL. -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBufferWithAlignment( - VmaAllocator VMA_NOT_NULL allocator, - const VkBufferCreateInfo* VMA_NOT_NULL pBufferCreateInfo, - const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, - VkDeviceSize minAlignment, - VkBuffer VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pBuffer, - VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation, - VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); - -/** \brief Creates a new `VkBuffer`, binds already created memory for it. - -\param allocator -\param allocation Allocation that provides memory to be used for binding new buffer to it. -\param pBufferCreateInfo -\param[out] pBuffer Buffer that was created. - -This function automatically: - --# Creates buffer. --# Binds the buffer with the supplied memory. - -If any of these operations fail, buffer is not created, -returned value is negative error code and `*pBuffer` is null. - -If the function succeeded, you must destroy the buffer when you -no longer need it using `vkDestroyBuffer()`. If you want to also destroy the corresponding -allocation you can use convenience function vmaDestroyBuffer(). - -\note There is a new version of this function augmented with parameter `allocationLocalOffset` - see vmaCreateAliasingBuffer2(). -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAliasingBuffer( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocation VMA_NOT_NULL allocation, - const VkBufferCreateInfo* VMA_NOT_NULL pBufferCreateInfo, - VkBuffer VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pBuffer); - -/** \brief Creates a new `VkBuffer`, binds already created memory for it. - -\param allocator -\param allocation Allocation that provides memory to be used for binding new buffer to it. -\param allocationLocalOffset Additional offset to be added while binding, relative to the beginning of the allocation. Normally it should be 0. -\param pBufferCreateInfo -\param[out] pBuffer Buffer that was created. - -This function automatically: - --# Creates buffer. --# Binds the buffer with the supplied memory. - -If any of these operations fail, buffer is not created, -returned value is negative error code and `*pBuffer` is null. - -If the function succeeded, you must destroy the buffer when you -no longer need it using `vkDestroyBuffer()`. If you want to also destroy the corresponding -allocation you can use convenience function vmaDestroyBuffer(). - -\note This is a new version of the function augmented with parameter `allocationLocalOffset`. -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAliasingBuffer2( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocation VMA_NOT_NULL allocation, - VkDeviceSize allocationLocalOffset, - const VkBufferCreateInfo* VMA_NOT_NULL pBufferCreateInfo, - VkBuffer VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pBuffer); - -/** \brief Destroys Vulkan buffer and frees allocated memory. - -This is just a convenience function equivalent to: - -\code -vkDestroyBuffer(device, buffer, allocationCallbacks); -vmaFreeMemory(allocator, allocation); -\endcode - -It is safe to pass null as buffer and/or allocation. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaDestroyBuffer( - VmaAllocator VMA_NOT_NULL allocator, - VkBuffer VMA_NULLABLE_NON_DISPATCHABLE buffer, - VmaAllocation VMA_NULLABLE allocation); - -/// Function similar to vmaCreateBuffer(). -VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateImage( - VmaAllocator VMA_NOT_NULL allocator, - const VkImageCreateInfo* VMA_NOT_NULL pImageCreateInfo, - const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, - VkImage VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pImage, - VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation, - VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); - -/// Function similar to vmaCreateAliasingBuffer() but for images. -VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAliasingImage( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocation VMA_NOT_NULL allocation, - const VkImageCreateInfo* VMA_NOT_NULL pImageCreateInfo, - VkImage VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pImage); - -/// Function similar to vmaCreateAliasingBuffer2() but for images. -VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAliasingImage2( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocation VMA_NOT_NULL allocation, - VkDeviceSize allocationLocalOffset, - const VkImageCreateInfo* VMA_NOT_NULL pImageCreateInfo, - VkImage VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pImage); - -/** \brief Destroys Vulkan image and frees allocated memory. - -This is just a convenience function equivalent to: - -\code -vkDestroyImage(device, image, allocationCallbacks); -vmaFreeMemory(allocator, allocation); -\endcode - -It is safe to pass null as image and/or allocation. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaDestroyImage( - VmaAllocator VMA_NOT_NULL allocator, - VkImage VMA_NULLABLE_NON_DISPATCHABLE image, - VmaAllocation VMA_NULLABLE allocation); - -/** @} */ - -/** -\addtogroup group_virtual -@{ -*/ - -/** \brief Creates new #VmaVirtualBlock object. - -\param pCreateInfo Parameters for creation. -\param[out] pVirtualBlock Returned virtual block object or `VMA_NULL` if creation failed. -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateVirtualBlock( - const VmaVirtualBlockCreateInfo* VMA_NOT_NULL pCreateInfo, - VmaVirtualBlock VMA_NULLABLE* VMA_NOT_NULL pVirtualBlock); - -/** \brief Destroys #VmaVirtualBlock object. - -Please note that you should consciously handle virtual allocations that could remain unfreed in the block. -You should either free them individually using vmaVirtualFree() or call vmaClearVirtualBlock() -if you are sure this is what you want. If you do neither, an assert is called. - -If you keep pointers to some additional metadata associated with your virtual allocations in their `pUserData`, -don't forget to free them. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaDestroyVirtualBlock( - VmaVirtualBlock VMA_NULLABLE virtualBlock); - -/** \brief Returns true of the #VmaVirtualBlock is empty - contains 0 virtual allocations and has all its space available for new allocations. -*/ -VMA_CALL_PRE VkBool32 VMA_CALL_POST vmaIsVirtualBlockEmpty( - VmaVirtualBlock VMA_NOT_NULL virtualBlock); - -/** \brief Returns information about a specific virtual allocation within a virtual block, like its size and `pUserData` pointer. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaGetVirtualAllocationInfo( - VmaVirtualBlock VMA_NOT_NULL virtualBlock, - VmaVirtualAllocation VMA_NOT_NULL_NON_DISPATCHABLE allocation, VmaVirtualAllocationInfo* VMA_NOT_NULL pVirtualAllocInfo); - -/** \brief Allocates new virtual allocation inside given #VmaVirtualBlock. - -If the allocation fails due to not enough free space available, `VK_ERROR_OUT_OF_DEVICE_MEMORY` is returned -(despite the function doesn't ever allocate actual GPU memory). -`pAllocation` is then set to `VK_NULL_HANDLE` and `pOffset`, if not null, it set to `UINT64_MAX`. - -\param virtualBlock Virtual block -\param pCreateInfo Parameters for the allocation -\param[out] pAllocation Returned handle of the new allocation -\param[out] pOffset Returned offset of the new allocation. Optional, can be null. -*/ -VMA_CALL_PRE VkResult VMA_CALL_POST vmaVirtualAllocate( - VmaVirtualBlock VMA_NOT_NULL virtualBlock, - const VmaVirtualAllocationCreateInfo* VMA_NOT_NULL pCreateInfo, - VmaVirtualAllocation VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pAllocation, - VkDeviceSize* VMA_NULLABLE pOffset); - -/** \brief Frees virtual allocation inside given #VmaVirtualBlock. - -It is correct to call this function with `allocation == VK_NULL_HANDLE` - it does nothing. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaVirtualFree( - VmaVirtualBlock VMA_NOT_NULL virtualBlock, - VmaVirtualAllocation VMA_NULLABLE_NON_DISPATCHABLE allocation); - -/** \brief Frees all virtual allocations inside given #VmaVirtualBlock. - -You must either call this function or free each virtual allocation individually with vmaVirtualFree() -before destroying a virtual block. Otherwise, an assert is called. - -If you keep pointer to some additional metadata associated with your virtual allocation in its `pUserData`, -don't forget to free it as well. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaClearVirtualBlock( - VmaVirtualBlock VMA_NOT_NULL virtualBlock); - -/** \brief Changes custom pointer associated with given virtual allocation. -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaSetVirtualAllocationUserData( - VmaVirtualBlock VMA_NOT_NULL virtualBlock, - VmaVirtualAllocation VMA_NOT_NULL_NON_DISPATCHABLE allocation, - void* VMA_NULLABLE pUserData); - -/** \brief Calculates and returns statistics about virtual allocations and memory usage in given #VmaVirtualBlock. - -This function is fast to call. For more detailed statistics, see vmaCalculateVirtualBlockStatistics(). -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaGetVirtualBlockStatistics( - VmaVirtualBlock VMA_NOT_NULL virtualBlock, - VmaStatistics* VMA_NOT_NULL pStats); - -/** \brief Calculates and returns detailed statistics about virtual allocations and memory usage in given #VmaVirtualBlock. - -This function is slow to call. Use for debugging purposes. -For less detailed statistics, see vmaGetVirtualBlockStatistics(). -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaCalculateVirtualBlockStatistics( - VmaVirtualBlock VMA_NOT_NULL virtualBlock, - VmaDetailedStatistics* VMA_NOT_NULL pStats); - -/** @} */ + VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAllocator( + const VmaAllocatorCreateInfo* VMA_NOT_NULL pCreateInfo, + VmaAllocator VMA_NULLABLE* VMA_NOT_NULL pAllocator); + + /// Destroys allocator object. + VMA_CALL_PRE void VMA_CALL_POST vmaDestroyAllocator( + VmaAllocator VMA_NULLABLE allocator); + + /** \brief Returns information about existing #VmaAllocator object - handle to Vulkan device etc. + + It might be useful if you want to keep just the #VmaAllocator handle and fetch other required handles to + `VkPhysicalDevice`, `VkDevice` etc. every time using this function. + */ + VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocatorInfo( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocatorInfo* VMA_NOT_NULL pAllocatorInfo); + + /** + PhysicalDeviceProperties are fetched from physicalDevice by the allocator. + You can access it here, without fetching it again on your own. + */ + VMA_CALL_PRE void VMA_CALL_POST vmaGetPhysicalDeviceProperties( + VmaAllocator VMA_NOT_NULL allocator, + const VkPhysicalDeviceProperties* VMA_NULLABLE* VMA_NOT_NULL ppPhysicalDeviceProperties); + + /** + PhysicalDeviceMemoryProperties are fetched from physicalDevice by the allocator. + You can access it here, without fetching it again on your own. + */ + VMA_CALL_PRE void VMA_CALL_POST vmaGetMemoryProperties( + VmaAllocator VMA_NOT_NULL allocator, + const VkPhysicalDeviceMemoryProperties* VMA_NULLABLE* VMA_NOT_NULL ppPhysicalDeviceMemoryProperties); + + /** + \brief Given Memory Type Index, returns Property Flags of this memory type. + + This is just a convenience function. Same information can be obtained using + vmaGetMemoryProperties(). + */ + VMA_CALL_PRE void VMA_CALL_POST vmaGetMemoryTypeProperties( + VmaAllocator VMA_NOT_NULL allocator, + uint32_t memoryTypeIndex, + VkMemoryPropertyFlags* VMA_NOT_NULL pFlags); + + /** \brief Sets index of the current frame. + */ + VMA_CALL_PRE void VMA_CALL_POST vmaSetCurrentFrameIndex( + VmaAllocator VMA_NOT_NULL allocator, + uint32_t frameIndex); + + /** @} */ + + /** + \addtogroup group_stats + @{ + */ + + /** \brief Retrieves statistics from current state of the Allocator. + + This function is called "calculate" not "get" because it has to traverse all + internal data structures, so it may be quite slow. Use it for debugging purposes. + For faster but more brief statistics suitable to be called every frame or every allocation, + use vmaGetHeapBudgets(). + + Note that when using allocator from multiple threads, returned information may immediately + become outdated. + */ + VMA_CALL_PRE void VMA_CALL_POST vmaCalculateStatistics( + VmaAllocator VMA_NOT_NULL allocator, + VmaTotalStatistics* VMA_NOT_NULL pStats); + + /** \brief Retrieves information about current memory usage and budget for all memory heaps. + + \param allocator + \param[out] pBudgets Must point to array with number of elements at least equal to number of memory heaps in physical device used. + + This function is called "get" not "calculate" because it is very fast, suitable to be called + every frame or every allocation. For more detailed statistics use vmaCalculateStatistics(). + + Note that when using allocator from multiple threads, returned information may immediately + become outdated. + */ + VMA_CALL_PRE void VMA_CALL_POST vmaGetHeapBudgets( + VmaAllocator VMA_NOT_NULL allocator, + VmaBudget* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL("VkPhysicalDeviceMemoryProperties::memoryHeapCount") pBudgets); + + /** @} */ + + /** + \addtogroup group_alloc + @{ + */ + + /** + \brief Helps to find memoryTypeIndex, given memoryTypeBits and VmaAllocationCreateInfo. + + This algorithm tries to find a memory type that: + + - Is allowed by memoryTypeBits. + - Contains all the flags from pAllocationCreateInfo->requiredFlags. + - Matches intended usage. + - Has as many flags from pAllocationCreateInfo->preferredFlags as possible. + + \return Returns VK_ERROR_FEATURE_NOT_PRESENT if not found. Receiving such result + from this function or any other allocating function probably means that your + device doesn't support any memory type with requested features for the specific + type of resource you want to use it for. Please check parameters of your + resource, like image layout (OPTIMAL versus LINEAR) or mip level count. + */ + VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndex( + VmaAllocator VMA_NOT_NULL allocator, + uint32_t memoryTypeBits, + const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, + uint32_t* VMA_NOT_NULL pMemoryTypeIndex); + + /** + \brief Helps to find memoryTypeIndex, given VkBufferCreateInfo and VmaAllocationCreateInfo. + + It can be useful e.g. to determine value to be used as VmaPoolCreateInfo::memoryTypeIndex. + It internally creates a temporary, dummy buffer that never has memory bound. + */ + VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForBufferInfo( + VmaAllocator VMA_NOT_NULL allocator, + const VkBufferCreateInfo* VMA_NOT_NULL pBufferCreateInfo, + const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, + uint32_t* VMA_NOT_NULL pMemoryTypeIndex); + + /** + \brief Helps to find memoryTypeIndex, given VkImageCreateInfo and VmaAllocationCreateInfo. + + It can be useful e.g. to determine value to be used as VmaPoolCreateInfo::memoryTypeIndex. + It internally creates a temporary, dummy image that never has memory bound. + */ + VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForImageInfo( + VmaAllocator VMA_NOT_NULL allocator, + const VkImageCreateInfo* VMA_NOT_NULL pImageCreateInfo, + const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, + uint32_t* VMA_NOT_NULL pMemoryTypeIndex); + + /** \brief Allocates Vulkan device memory and creates #VmaPool object. + + \param allocator Allocator object. + \param pCreateInfo Parameters of pool to create. + \param[out] pPool Handle to created pool. + */ + VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreatePool( + VmaAllocator VMA_NOT_NULL allocator, + const VmaPoolCreateInfo* VMA_NOT_NULL pCreateInfo, + VmaPool VMA_NULLABLE* VMA_NOT_NULL pPool); + + /** \brief Destroys #VmaPool object and frees Vulkan device memory. + */ + VMA_CALL_PRE void VMA_CALL_POST vmaDestroyPool( + VmaAllocator VMA_NOT_NULL allocator, + VmaPool VMA_NULLABLE pool); + + /** @} */ + + /** + \addtogroup group_stats + @{ + */ + + /** \brief Retrieves statistics of existing #VmaPool object. + + \param allocator Allocator object. + \param pool Pool object. + \param[out] pPoolStats Statistics of specified pool. + */ + VMA_CALL_PRE void VMA_CALL_POST vmaGetPoolStatistics( + VmaAllocator VMA_NOT_NULL allocator, + VmaPool VMA_NOT_NULL pool, + VmaStatistics* VMA_NOT_NULL pPoolStats); + + /** \brief Retrieves detailed statistics of existing #VmaPool object. + + \param allocator Allocator object. + \param pool Pool object. + \param[out] pPoolStats Statistics of specified pool. + */ + VMA_CALL_PRE void VMA_CALL_POST vmaCalculatePoolStatistics( + VmaAllocator VMA_NOT_NULL allocator, + VmaPool VMA_NOT_NULL pool, + VmaDetailedStatistics* VMA_NOT_NULL pPoolStats); + + /** @} */ + + /** + \addtogroup group_alloc + @{ + */ + + /** \brief Checks magic number in margins around all allocations in given memory pool in search for corruptions. + + Corruption detection is enabled only when `VMA_DEBUG_DETECT_CORRUPTION` macro is defined to nonzero, + `VMA_DEBUG_MARGIN` is defined to nonzero and the pool is created in memory type that is + `HOST_VISIBLE` and `HOST_COHERENT`. For more information, see [Corruption detection](@ref debugging_memory_usage_corruption_detection). + + Possible return values: + + - `VK_ERROR_FEATURE_NOT_PRESENT` - corruption detection is not enabled for specified pool. + - `VK_SUCCESS` - corruption detection has been performed and succeeded. + - `VK_ERROR_UNKNOWN` - corruption detection has been performed and found memory corruptions around one of the allocations. + `VMA_ASSERT` is also fired in that case. + - Other value: Error returned by Vulkan, e.g. memory mapping failure. + */ + VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckPoolCorruption( + VmaAllocator VMA_NOT_NULL allocator, + VmaPool VMA_NOT_NULL pool); + + /** \brief Retrieves name of a custom pool. + + After the call `ppName` is either null or points to an internally-owned null-terminated string + containing name of the pool that was previously set. The pointer becomes invalid when the pool is + destroyed or its name is changed using vmaSetPoolName(). + */ + VMA_CALL_PRE void VMA_CALL_POST vmaGetPoolName( + VmaAllocator VMA_NOT_NULL allocator, + VmaPool VMA_NOT_NULL pool, + const char* VMA_NULLABLE* VMA_NOT_NULL ppName); + + /** \brief Sets name of a custom pool. + + `pName` can be either null or pointer to a null-terminated string with new name for the pool. + Function makes internal copy of the string, so it can be changed or freed immediately after this call. + */ + VMA_CALL_PRE void VMA_CALL_POST vmaSetPoolName( + VmaAllocator VMA_NOT_NULL allocator, + VmaPool VMA_NOT_NULL pool, + const char* VMA_NULLABLE pName); + + /** \brief General purpose memory allocation. + + \param allocator + \param pVkMemoryRequirements + \param pCreateInfo + \param[out] pAllocation Handle to allocated memory. + \param[out] pAllocationInfo Optional. Information about allocated memory. It can be later fetched using function vmaGetAllocationInfo(). + + You should free the memory using vmaFreeMemory() or vmaFreeMemoryPages(). + + It is recommended to use vmaAllocateMemoryForBuffer(), vmaAllocateMemoryForImage(), + vmaCreateBuffer(), vmaCreateImage() instead whenever possible. + */ + VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemory( + VmaAllocator VMA_NOT_NULL allocator, + const VkMemoryRequirements* VMA_NOT_NULL pVkMemoryRequirements, + const VmaAllocationCreateInfo* VMA_NOT_NULL pCreateInfo, + VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation, + VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); + + /** \brief General purpose memory allocation for multiple allocation objects at once. + + \param allocator Allocator object. + \param pVkMemoryRequirements Memory requirements for each allocation. + \param pCreateInfo Creation parameters for each allocation. + \param allocationCount Number of allocations to make. + \param[out] pAllocations Pointer to array that will be filled with handles to created allocations. + \param[out] pAllocationInfo Optional. Pointer to array that will be filled with parameters of created allocations. + + You should free the memory using vmaFreeMemory() or vmaFreeMemoryPages(). + + Word "pages" is just a suggestion to use this function to allocate pieces of memory needed for sparse binding. + It is just a general purpose allocation function able to make multiple allocations at once. + It may be internally optimized to be more efficient than calling vmaAllocateMemory() `allocationCount` times. + + All allocations are made using same parameters. All of them are created out of the same memory pool and type. + If any allocation fails, all allocations already made within this function call are also freed, so that when + returned result is not `VK_SUCCESS`, `pAllocation` array is always entirely filled with `VK_NULL_HANDLE`. + */ + VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryPages( + VmaAllocator VMA_NOT_NULL allocator, + const VkMemoryRequirements* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(allocationCount) pVkMemoryRequirements, + const VmaAllocationCreateInfo* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(allocationCount) pCreateInfo, + size_t allocationCount, + VmaAllocation VMA_NULLABLE* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(allocationCount) pAllocations, + VmaAllocationInfo* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) pAllocationInfo); + + /** \brief Allocates memory suitable for given `VkBuffer`. + + \param allocator + \param buffer + \param pCreateInfo + \param[out] pAllocation Handle to allocated memory. + \param[out] pAllocationInfo Optional. Information about allocated memory. It can be later fetched using function vmaGetAllocationInfo(). + + It only creates #VmaAllocation. To bind the memory to the buffer, use vmaBindBufferMemory(). + + This is a special-purpose function. In most cases you should use vmaCreateBuffer(). + + You must free the allocation using vmaFreeMemory() when no longer needed. + */ + VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForBuffer( + VmaAllocator VMA_NOT_NULL allocator, + VkBuffer VMA_NOT_NULL_NON_DISPATCHABLE buffer, + const VmaAllocationCreateInfo* VMA_NOT_NULL pCreateInfo, + VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation, + VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); + + /** \brief Allocates memory suitable for given `VkImage`. + + \param allocator + \param image + \param pCreateInfo + \param[out] pAllocation Handle to allocated memory. + \param[out] pAllocationInfo Optional. Information about allocated memory. It can be later fetched using function vmaGetAllocationInfo(). + + It only creates #VmaAllocation. To bind the memory to the buffer, use vmaBindImageMemory(). + + This is a special-purpose function. In most cases you should use vmaCreateImage(). + + You must free the allocation using vmaFreeMemory() when no longer needed. + */ + VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForImage( + VmaAllocator VMA_NOT_NULL allocator, + VkImage VMA_NOT_NULL_NON_DISPATCHABLE image, + const VmaAllocationCreateInfo* VMA_NOT_NULL pCreateInfo, + VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation, + VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); + + /** \brief Frees memory previously allocated using vmaAllocateMemory(), vmaAllocateMemoryForBuffer(), or vmaAllocateMemoryForImage(). + + Passing `VK_NULL_HANDLE` as `allocation` is valid. Such function call is just skipped. + */ + VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemory( + VmaAllocator VMA_NOT_NULL allocator, + const VmaAllocation VMA_NULLABLE allocation); + + /** \brief Frees memory and destroys multiple allocations. + + Word "pages" is just a suggestion to use this function to free pieces of memory used for sparse binding. + It is just a general purpose function to free memory and destroy allocations made using e.g. vmaAllocateMemory(), + vmaAllocateMemoryPages() and other functions. + It may be internally optimized to be more efficient than calling vmaFreeMemory() `allocationCount` times. + + Allocations in `pAllocations` array can come from any memory pools and types. + Passing `VK_NULL_HANDLE` as elements of `pAllocations` array is valid. Such entries are just skipped. + */ + VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemoryPages( + VmaAllocator VMA_NOT_NULL allocator, + size_t allocationCount, + const VmaAllocation VMA_NULLABLE* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(allocationCount) pAllocations); + + /** \brief Returns current information about specified allocation. + + Current parameters of given allocation are returned in `pAllocationInfo`. + + Although this function doesn't lock any mutex, so it should be quite efficient, + you should avoid calling it too often. + You can retrieve same VmaAllocationInfo structure while creating your resource, from function + vmaCreateBuffer(), vmaCreateImage(). You can remember it if you are sure parameters don't change + (e.g. due to defragmentation). + + There is also a new function vmaGetAllocationInfo2() that offers extended information + about the allocation, returned using new structure #VmaAllocationInfo2. + */ + VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationInfo( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VmaAllocationInfo* VMA_NOT_NULL pAllocationInfo); + + /** \brief Returns extended information about specified allocation. + + Current parameters of given allocation are returned in `pAllocationInfo`. + Extended parameters in structure #VmaAllocationInfo2 include memory block size + and a flag telling whether the allocation has dedicated memory. + It can be useful e.g. for interop with OpenGL. + */ + VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationInfo2( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VmaAllocationInfo2* VMA_NOT_NULL pAllocationInfo); + + /** \brief Sets pUserData in given allocation to new value. + + The value of pointer `pUserData` is copied to allocation's `pUserData`. + It is opaque, so you can use it however you want - e.g. + as a pointer, ordinal number or some handle to you own data. + */ + VMA_CALL_PRE void VMA_CALL_POST vmaSetAllocationUserData( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + void* VMA_NULLABLE pUserData); + + /** \brief Sets pName in given allocation to new value. + + `pName` must be either null, or pointer to a null-terminated string. The function + makes local copy of the string and sets it as allocation's `pName`. String + passed as pName doesn't need to be valid for whole lifetime of the allocation - + you can free it after this call. String previously pointed by allocation's + `pName` is freed from memory. + */ + VMA_CALL_PRE void VMA_CALL_POST vmaSetAllocationName( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + const char* VMA_NULLABLE pName); + + /** + \brief Given an allocation, returns Property Flags of its memory type. + + This is just a convenience function. Same information can be obtained using + vmaGetAllocationInfo() + vmaGetMemoryProperties(). + */ + VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationMemoryProperties( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkMemoryPropertyFlags* VMA_NOT_NULL pFlags); + + /** \brief Maps memory represented by given allocation and returns pointer to it. + + Maps memory represented by given allocation to make it accessible to CPU code. + When succeeded, `*ppData` contains pointer to first byte of this memory. + + \warning + If the allocation is part of a bigger `VkDeviceMemory` block, returned pointer is + correctly offsetted to the beginning of region assigned to this particular allocation. + Unlike the result of `vkMapMemory`, it points to the allocation, not to the beginning of the whole block. + You should not add VmaAllocationInfo::offset to it! + + Mapping is internally reference-counted and synchronized, so despite raw Vulkan + function `vkMapMemory()` cannot be used to map same block of `VkDeviceMemory` + multiple times simultaneously, it is safe to call this function on allocations + assigned to the same memory block. Actual Vulkan memory will be mapped on first + mapping and unmapped on last unmapping. + + If the function succeeded, you must call vmaUnmapMemory() to unmap the + allocation when mapping is no longer needed or before freeing the allocation, at + the latest. + + It also safe to call this function multiple times on the same allocation. You + must call vmaUnmapMemory() same number of times as you called vmaMapMemory(). + + It is also safe to call this function on allocation created with + #VMA_ALLOCATION_CREATE_MAPPED_BIT flag. Its memory stays mapped all the time. + You must still call vmaUnmapMemory() same number of times as you called + vmaMapMemory(). You must not call vmaUnmapMemory() additional time to free the + "0-th" mapping made automatically due to #VMA_ALLOCATION_CREATE_MAPPED_BIT flag. + + This function fails when used on allocation made in memory type that is not + `HOST_VISIBLE`. + + This function doesn't automatically flush or invalidate caches. + If the allocation is made from a memory types that is not `HOST_COHERENT`, + you also need to use vmaInvalidateAllocation() / vmaFlushAllocation(), as required by Vulkan specification. + */ + VMA_CALL_PRE VkResult VMA_CALL_POST vmaMapMemory( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + void* VMA_NULLABLE* VMA_NOT_NULL ppData); + + /** \brief Unmaps memory represented by given allocation, mapped previously using vmaMapMemory(). + + For details, see description of vmaMapMemory(). + + This function doesn't automatically flush or invalidate caches. + If the allocation is made from a memory types that is not `HOST_COHERENT`, + you also need to use vmaInvalidateAllocation() / vmaFlushAllocation(), as required by Vulkan specification. + */ + VMA_CALL_PRE void VMA_CALL_POST vmaUnmapMemory( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation); + + /** \brief Flushes memory of given allocation. + + Calls `vkFlushMappedMemoryRanges()` for memory associated with given range of given allocation. + It needs to be called after writing to a mapped memory for memory types that are not `HOST_COHERENT`. + Unmap operation doesn't do that automatically. + + - `offset` must be relative to the beginning of allocation. + - `size` can be `VK_WHOLE_SIZE`. It means all memory from `offset` the the end of given allocation. + - `offset` and `size` don't have to be aligned. + They are internally rounded down/up to multiply of `nonCoherentAtomSize`. + - If `size` is 0, this call is ignored. + - If memory type that the `allocation` belongs to is not `HOST_VISIBLE` or it is `HOST_COHERENT`, + this call is ignored. + + Warning! `offset` and `size` are relative to the contents of given `allocation`. + If you mean whole allocation, you can pass 0 and `VK_WHOLE_SIZE`, respectively. + Do not pass allocation's offset as `offset`!!! + + This function returns the `VkResult` from `vkFlushMappedMemoryRanges` if it is + called, otherwise `VK_SUCCESS`. + */ + VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocation( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkDeviceSize offset, + VkDeviceSize size); + + /** \brief Invalidates memory of given allocation. + + Calls `vkInvalidateMappedMemoryRanges()` for memory associated with given range of given allocation. + It needs to be called before reading from a mapped memory for memory types that are not `HOST_COHERENT`. + Map operation doesn't do that automatically. + + - `offset` must be relative to the beginning of allocation. + - `size` can be `VK_WHOLE_SIZE`. It means all memory from `offset` the the end of given allocation. + - `offset` and `size` don't have to be aligned. + They are internally rounded down/up to multiply of `nonCoherentAtomSize`. + - If `size` is 0, this call is ignored. + - If memory type that the `allocation` belongs to is not `HOST_VISIBLE` or it is `HOST_COHERENT`, + this call is ignored. + + Warning! `offset` and `size` are relative to the contents of given `allocation`. + If you mean whole allocation, you can pass 0 and `VK_WHOLE_SIZE`, respectively. + Do not pass allocation's offset as `offset`!!! + + This function returns the `VkResult` from `vkInvalidateMappedMemoryRanges` if + it is called, otherwise `VK_SUCCESS`. + */ + VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocation( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkDeviceSize offset, + VkDeviceSize size); + + /** \brief Flushes memory of given set of allocations. + + Calls `vkFlushMappedMemoryRanges()` for memory associated with given ranges of given allocations. + For more information, see documentation of vmaFlushAllocation(). + + \param allocator + \param allocationCount + \param allocations + \param offsets If not null, it must point to an array of offsets of regions to flush, relative to the beginning of respective allocations. Null means all offsets are zero. + \param sizes If not null, it must point to an array of sizes of regions to flush in respective allocations. Null means `VK_WHOLE_SIZE` for all allocations. + + This function returns the `VkResult` from `vkFlushMappedMemoryRanges` if it is + called, otherwise `VK_SUCCESS`. + */ + VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocations( + VmaAllocator VMA_NOT_NULL allocator, + uint32_t allocationCount, + const VmaAllocation VMA_NOT_NULL* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) allocations, + const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) offsets, + const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) sizes); + + /** \brief Invalidates memory of given set of allocations. + + Calls `vkInvalidateMappedMemoryRanges()` for memory associated with given ranges of given allocations. + For more information, see documentation of vmaInvalidateAllocation(). + + \param allocator + \param allocationCount + \param allocations + \param offsets If not null, it must point to an array of offsets of regions to flush, relative to the beginning of respective allocations. Null means all offsets are zero. + \param sizes If not null, it must point to an array of sizes of regions to flush in respective allocations. Null means `VK_WHOLE_SIZE` for all allocations. + + This function returns the `VkResult` from `vkInvalidateMappedMemoryRanges` if it is + called, otherwise `VK_SUCCESS`. + */ + VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocations( + VmaAllocator VMA_NOT_NULL allocator, + uint32_t allocationCount, + const VmaAllocation VMA_NOT_NULL* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) allocations, + const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) offsets, + const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) sizes); + + /** \brief Maps the allocation temporarily if needed, copies data from specified host pointer to it, and flushes the memory from the host caches if needed. + + \param allocator + \param pSrcHostPointer Pointer to the host data that become source of the copy. + \param dstAllocation Handle to the allocation that becomes destination of the copy. + \param dstAllocationLocalOffset Offset within `dstAllocation` where to write copied data, in bytes. + \param size Number of bytes to copy. + + This is a convenience function that allows to copy data from a host pointer to an allocation easily. + Same behavior can be achieved by calling vmaMapMemory(), `memcpy()`, vmaUnmapMemory(), vmaFlushAllocation(). + + This function can be called only for allocations created in a memory type that has `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT` flag. + It can be ensured e.g. by using #VMA_MEMORY_USAGE_AUTO and #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or + #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT. + Otherwise, the function will fail and generate a Validation Layers error. + + `dstAllocationLocalOffset` is relative to the contents of given `dstAllocation`. + If you mean whole allocation, you should pass 0. + Do not pass allocation's offset within device memory block this parameter! + */ + VMA_CALL_PRE VkResult VMA_CALL_POST vmaCopyMemoryToAllocation( + VmaAllocator VMA_NOT_NULL allocator, + const void* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(size) pSrcHostPointer, + VmaAllocation VMA_NOT_NULL dstAllocation, + VkDeviceSize dstAllocationLocalOffset, + VkDeviceSize size); + + /** \brief Invalidates memory in the host caches if needed, maps the allocation temporarily if needed, and copies data from it to a specified host pointer. + + \param allocator + \param srcAllocation Handle to the allocation that becomes source of the copy. + \param srcAllocationLocalOffset Offset within `srcAllocation` where to read copied data, in bytes. + \param pDstHostPointer Pointer to the host memory that become destination of the copy. + \param size Number of bytes to copy. + + This is a convenience function that allows to copy data from an allocation to a host pointer easily. + Same behavior can be achieved by calling vmaInvalidateAllocation(), vmaMapMemory(), `memcpy()`, vmaUnmapMemory(). + + This function should be called only for allocations created in a memory type that has `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT` + and `VK_MEMORY_PROPERTY_HOST_CACHED_BIT` flag. + It can be ensured e.g. by using #VMA_MEMORY_USAGE_AUTO and #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT. + Otherwise, the function may fail and generate a Validation Layers error. + It may also work very slowly when reading from an uncached memory. + + `srcAllocationLocalOffset` is relative to the contents of given `srcAllocation`. + If you mean whole allocation, you should pass 0. + Do not pass allocation's offset within device memory block as this parameter! + */ + VMA_CALL_PRE VkResult VMA_CALL_POST vmaCopyAllocationToMemory( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL srcAllocation, + VkDeviceSize srcAllocationLocalOffset, + void* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(size) pDstHostPointer, + VkDeviceSize size); + + /** \brief Checks magic number in margins around all allocations in given memory types (in both default and custom pools) in search for corruptions. + + \param allocator + \param memoryTypeBits Bit mask, where each bit set means that a memory type with that index should be checked. + + Corruption detection is enabled only when `VMA_DEBUG_DETECT_CORRUPTION` macro is defined to nonzero, + `VMA_DEBUG_MARGIN` is defined to nonzero and only for memory types that are + `HOST_VISIBLE` and `HOST_COHERENT`. For more information, see [Corruption detection](@ref debugging_memory_usage_corruption_detection). + + Possible return values: + + - `VK_ERROR_FEATURE_NOT_PRESENT` - corruption detection is not enabled for any of specified memory types. + - `VK_SUCCESS` - corruption detection has been performed and succeeded. + - `VK_ERROR_UNKNOWN` - corruption detection has been performed and found memory corruptions around one of the allocations. + `VMA_ASSERT` is also fired in that case. + - Other value: Error returned by Vulkan, e.g. memory mapping failure. + */ + VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckCorruption( + VmaAllocator VMA_NOT_NULL allocator, + uint32_t memoryTypeBits); + + /** \brief Begins defragmentation process. + + \param allocator Allocator object. + \param pInfo Structure filled with parameters of defragmentation. + \param[out] pContext Context object that must be passed to vmaEndDefragmentation() to finish defragmentation. + \returns + - `VK_SUCCESS` if defragmentation can begin. + - `VK_ERROR_FEATURE_NOT_PRESENT` if defragmentation is not supported. + + For more information about defragmentation, see documentation chapter: + [Defragmentation](@ref defragmentation). + */ + VMA_CALL_PRE VkResult VMA_CALL_POST vmaBeginDefragmentation( + VmaAllocator VMA_NOT_NULL allocator, + const VmaDefragmentationInfo* VMA_NOT_NULL pInfo, + VmaDefragmentationContext VMA_NULLABLE* VMA_NOT_NULL pContext); + + /** \brief Ends defragmentation process. + + \param allocator Allocator object. + \param context Context object that has been created by vmaBeginDefragmentation(). + \param[out] pStats Optional stats for the defragmentation. Can be null. + + Use this function to finish defragmentation started by vmaBeginDefragmentation(). + */ + VMA_CALL_PRE void VMA_CALL_POST vmaEndDefragmentation( + VmaAllocator VMA_NOT_NULL allocator, + VmaDefragmentationContext VMA_NOT_NULL context, + VmaDefragmentationStats* VMA_NULLABLE pStats); + + /** \brief Starts single defragmentation pass. + + \param allocator Allocator object. + \param context Context object that has been created by vmaBeginDefragmentation(). + \param[out] pPassInfo Computed information for current pass. + \returns + - `VK_SUCCESS` if no more moves are possible. Then you can omit call to vmaEndDefragmentationPass() and simply end whole defragmentation. + - `VK_INCOMPLETE` if there are pending moves returned in `pPassInfo`. You need to perform them, call vmaEndDefragmentationPass(), + and then preferably try another pass with vmaBeginDefragmentationPass(). + */ + VMA_CALL_PRE VkResult VMA_CALL_POST vmaBeginDefragmentationPass( + VmaAllocator VMA_NOT_NULL allocator, + VmaDefragmentationContext VMA_NOT_NULL context, + VmaDefragmentationPassMoveInfo* VMA_NOT_NULL pPassInfo); + + /** \brief Ends single defragmentation pass. + + \param allocator Allocator object. + \param context Context object that has been created by vmaBeginDefragmentation(). + \param pPassInfo Computed information for current pass filled by vmaBeginDefragmentationPass() and possibly modified by you. + + Returns `VK_SUCCESS` if no more moves are possible or `VK_INCOMPLETE` if more defragmentations are possible. + + Ends incremental defragmentation pass and commits all defragmentation moves from `pPassInfo`. + After this call: + + - Allocations at `pPassInfo[i].srcAllocation` that had `pPassInfo[i].operation ==` #VMA_DEFRAGMENTATION_MOVE_OPERATION_COPY + (which is the default) will be pointing to the new destination place. + - Allocation at `pPassInfo[i].srcAllocation` that had `pPassInfo[i].operation ==` #VMA_DEFRAGMENTATION_MOVE_OPERATION_DESTROY + will be freed. + + If no more moves are possible you can end whole defragmentation. + */ + VMA_CALL_PRE VkResult VMA_CALL_POST vmaEndDefragmentationPass( + VmaAllocator VMA_NOT_NULL allocator, + VmaDefragmentationContext VMA_NOT_NULL context, + VmaDefragmentationPassMoveInfo* VMA_NOT_NULL pPassInfo); + + /** \brief Binds buffer to allocation. + + Binds specified buffer to region of memory represented by specified allocation. + Gets `VkDeviceMemory` handle and offset from the allocation. + If you want to create a buffer, allocate memory for it and bind them together separately, + you should use this function for binding instead of standard `vkBindBufferMemory()`, + because it ensures proper synchronization so that when a `VkDeviceMemory` object is used by multiple + allocations, calls to `vkBind*Memory()` or `vkMapMemory()` won't happen from multiple threads simultaneously + (which is illegal in Vulkan). + + It is recommended to use function vmaCreateBuffer() instead of this one. + */ + VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkBuffer VMA_NOT_NULL_NON_DISPATCHABLE buffer); + + /** \brief Binds buffer to allocation with additional parameters. + + \param allocator + \param allocation + \param allocationLocalOffset Additional offset to be added while binding, relative to the beginning of the `allocation`. Normally it should be 0. + \param buffer + \param pNext A chain of structures to be attached to `VkBindBufferMemoryInfoKHR` structure used internally. Normally it should be null. + + This function is similar to vmaBindBufferMemory(), but it provides additional parameters. + + If `pNext` is not null, #VmaAllocator object must have been created with #VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT flag + or with VmaAllocatorCreateInfo::vulkanApiVersion `>= VK_API_VERSION_1_1`. Otherwise the call fails. + */ + VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory2( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkDeviceSize allocationLocalOffset, + VkBuffer VMA_NOT_NULL_NON_DISPATCHABLE buffer, + const void* VMA_NULLABLE VMA_EXTENDS_VK_STRUCT(VkBindBufferMemoryInfoKHR) pNext); + + /** \brief Binds image to allocation. + + Binds specified image to region of memory represented by specified allocation. + Gets `VkDeviceMemory` handle and offset from the allocation. + If you want to create an image, allocate memory for it and bind them together separately, + you should use this function for binding instead of standard `vkBindImageMemory()`, + because it ensures proper synchronization so that when a `VkDeviceMemory` object is used by multiple + allocations, calls to `vkBind*Memory()` or `vkMapMemory()` won't happen from multiple threads simultaneously + (which is illegal in Vulkan). + + It is recommended to use function vmaCreateImage() instead of this one. + */ + VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkImage VMA_NOT_NULL_NON_DISPATCHABLE image); + + /** \brief Binds image to allocation with additional parameters. + + \param allocator + \param allocation + \param allocationLocalOffset Additional offset to be added while binding, relative to the beginning of the `allocation`. Normally it should be 0. + \param image + \param pNext A chain of structures to be attached to `VkBindImageMemoryInfoKHR` structure used internally. Normally it should be null. + + This function is similar to vmaBindImageMemory(), but it provides additional parameters. + + If `pNext` is not null, #VmaAllocator object must have been created with #VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT flag + or with VmaAllocatorCreateInfo::vulkanApiVersion `>= VK_API_VERSION_1_1`. Otherwise the call fails. + */ + VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory2( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkDeviceSize allocationLocalOffset, + VkImage VMA_NOT_NULL_NON_DISPATCHABLE image, + const void* VMA_NULLABLE VMA_EXTENDS_VK_STRUCT(VkBindImageMemoryInfoKHR) pNext); + + /** \brief Creates a new `VkBuffer`, allocates and binds memory for it. + + \param allocator + \param pBufferCreateInfo + \param pAllocationCreateInfo + \param[out] pBuffer Buffer that was created. + \param[out] pAllocation Allocation that was created. + \param[out] pAllocationInfo Optional. Information about allocated memory. It can be later fetched using function vmaGetAllocationInfo(). + + This function automatically: + + -# Creates buffer. + -# Allocates appropriate memory for it. + -# Binds the buffer with the memory. + + If any of these operations fail, buffer and allocation are not created, + returned value is negative error code, `*pBuffer` and `*pAllocation` are null. + + If the function succeeded, you must destroy both buffer and allocation when you + no longer need them using either convenience function vmaDestroyBuffer() or + separately, using `vkDestroyBuffer()` and vmaFreeMemory(). + + If #VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT flag was used, + VK_KHR_dedicated_allocation extension is used internally to query driver whether + it requires or prefers the new buffer to have dedicated allocation. If yes, + and if dedicated allocation is possible + (#VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT is not used), it creates dedicated + allocation for this buffer, just like when using + #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT. + + \note This function creates a new `VkBuffer`. Sub-allocation of parts of one large buffer, + although recommended as a good practice, is out of scope of this library and could be implemented + by the user as a higher-level logic on top of VMA. + */ + VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBuffer( + VmaAllocator VMA_NOT_NULL allocator, + const VkBufferCreateInfo* VMA_NOT_NULL pBufferCreateInfo, + const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, + VkBuffer VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pBuffer, + VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation, + VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); + + /** \brief Creates a buffer with additional minimum alignment. + + Similar to vmaCreateBuffer() but provides additional parameter `minAlignment` which allows to specify custom, + minimum alignment to be used when placing the buffer inside a larger memory block, which may be needed e.g. + for interop with OpenGL. + */ + VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBufferWithAlignment( + VmaAllocator VMA_NOT_NULL allocator, + const VkBufferCreateInfo* VMA_NOT_NULL pBufferCreateInfo, + const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, + VkDeviceSize minAlignment, + VkBuffer VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pBuffer, + VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation, + VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); + + /** \brief Creates a new `VkBuffer`, binds already created memory for it. + + \param allocator + \param allocation Allocation that provides memory to be used for binding new buffer to it. + \param pBufferCreateInfo + \param[out] pBuffer Buffer that was created. + + This function automatically: + + -# Creates buffer. + -# Binds the buffer with the supplied memory. + + If any of these operations fail, buffer is not created, + returned value is negative error code and `*pBuffer` is null. + + If the function succeeded, you must destroy the buffer when you + no longer need it using `vkDestroyBuffer()`. If you want to also destroy the corresponding + allocation you can use convenience function vmaDestroyBuffer(). + + \note There is a new version of this function augmented with parameter `allocationLocalOffset` - see vmaCreateAliasingBuffer2(). + */ + VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAliasingBuffer( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + const VkBufferCreateInfo* VMA_NOT_NULL pBufferCreateInfo, + VkBuffer VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pBuffer); + + /** \brief Creates a new `VkBuffer`, binds already created memory for it. + + \param allocator + \param allocation Allocation that provides memory to be used for binding new buffer to it. + \param allocationLocalOffset Additional offset to be added while binding, relative to the beginning of the allocation. Normally it should be 0. + \param pBufferCreateInfo + \param[out] pBuffer Buffer that was created. + + This function automatically: + + -# Creates buffer. + -# Binds the buffer with the supplied memory. + + If any of these operations fail, buffer is not created, + returned value is negative error code and `*pBuffer` is null. + + If the function succeeded, you must destroy the buffer when you + no longer need it using `vkDestroyBuffer()`. If you want to also destroy the corresponding + allocation you can use convenience function vmaDestroyBuffer(). + + \note This is a new version of the function augmented with parameter `allocationLocalOffset`. + */ + VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAliasingBuffer2( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkDeviceSize allocationLocalOffset, + const VkBufferCreateInfo* VMA_NOT_NULL pBufferCreateInfo, + VkBuffer VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pBuffer); + + /** \brief Destroys Vulkan buffer and frees allocated memory. + + This is just a convenience function equivalent to: + + \code + vkDestroyBuffer(device, buffer, allocationCallbacks); + vmaFreeMemory(allocator, allocation); + \endcode + + It is safe to pass null as buffer and/or allocation. + */ + VMA_CALL_PRE void VMA_CALL_POST vmaDestroyBuffer( + VmaAllocator VMA_NOT_NULL allocator, + VkBuffer VMA_NULLABLE_NON_DISPATCHABLE buffer, + VmaAllocation VMA_NULLABLE allocation); + + /// Function similar to vmaCreateBuffer(). + VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateImage( + VmaAllocator VMA_NOT_NULL allocator, + const VkImageCreateInfo* VMA_NOT_NULL pImageCreateInfo, + const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, + VkImage VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pImage, + VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation, + VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); + + /// Function similar to vmaCreateAliasingBuffer() but for images. + VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAliasingImage( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + const VkImageCreateInfo* VMA_NOT_NULL pImageCreateInfo, + VkImage VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pImage); + + /// Function similar to vmaCreateAliasingBuffer2() but for images. + VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAliasingImage2( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkDeviceSize allocationLocalOffset, + const VkImageCreateInfo* VMA_NOT_NULL pImageCreateInfo, + VkImage VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pImage); + + /** \brief Destroys Vulkan image and frees allocated memory. + + This is just a convenience function equivalent to: + + \code + vkDestroyImage(device, image, allocationCallbacks); + vmaFreeMemory(allocator, allocation); + \endcode + + It is safe to pass null as image and/or allocation. + */ + VMA_CALL_PRE void VMA_CALL_POST vmaDestroyImage( + VmaAllocator VMA_NOT_NULL allocator, + VkImage VMA_NULLABLE_NON_DISPATCHABLE image, + VmaAllocation VMA_NULLABLE allocation); + + /** @} */ + + /** + \addtogroup group_virtual + @{ + */ + + /** \brief Creates new #VmaVirtualBlock object. + + \param pCreateInfo Parameters for creation. + \param[out] pVirtualBlock Returned virtual block object or `VMA_NULL` if creation failed. + */ + VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateVirtualBlock( + const VmaVirtualBlockCreateInfo* VMA_NOT_NULL pCreateInfo, + VmaVirtualBlock VMA_NULLABLE* VMA_NOT_NULL pVirtualBlock); + + /** \brief Destroys #VmaVirtualBlock object. + + Please note that you should consciously handle virtual allocations that could remain unfreed in the block. + You should either free them individually using vmaVirtualFree() or call vmaClearVirtualBlock() + if you are sure this is what you want. If you do neither, an assert is called. + + If you keep pointers to some additional metadata associated with your virtual allocations in their `pUserData`, + don't forget to free them. + */ + VMA_CALL_PRE void VMA_CALL_POST vmaDestroyVirtualBlock( + VmaVirtualBlock VMA_NULLABLE virtualBlock); + + /** \brief Returns true of the #VmaVirtualBlock is empty - contains 0 virtual allocations and has all its space available for new allocations. + */ + VMA_CALL_PRE VkBool32 VMA_CALL_POST vmaIsVirtualBlockEmpty( + VmaVirtualBlock VMA_NOT_NULL virtualBlock); + + /** \brief Returns information about a specific virtual allocation within a virtual block, like its size and `pUserData` pointer. + */ + VMA_CALL_PRE void VMA_CALL_POST vmaGetVirtualAllocationInfo( + VmaVirtualBlock VMA_NOT_NULL virtualBlock, + VmaVirtualAllocation VMA_NOT_NULL_NON_DISPATCHABLE allocation, VmaVirtualAllocationInfo* VMA_NOT_NULL pVirtualAllocInfo); + + /** \brief Allocates new virtual allocation inside given #VmaVirtualBlock. + + If the allocation fails due to not enough free space available, `VK_ERROR_OUT_OF_DEVICE_MEMORY` is returned + (despite the function doesn't ever allocate actual GPU memory). + `pAllocation` is then set to `VK_NULL_HANDLE` and `pOffset`, if not null, it set to `UINT64_MAX`. + + \param virtualBlock Virtual block + \param pCreateInfo Parameters for the allocation + \param[out] pAllocation Returned handle of the new allocation + \param[out] pOffset Returned offset of the new allocation. Optional, can be null. + */ + VMA_CALL_PRE VkResult VMA_CALL_POST vmaVirtualAllocate( + VmaVirtualBlock VMA_NOT_NULL virtualBlock, + const VmaVirtualAllocationCreateInfo* VMA_NOT_NULL pCreateInfo, + VmaVirtualAllocation VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pAllocation, + VkDeviceSize* VMA_NULLABLE pOffset); + + /** \brief Frees virtual allocation inside given #VmaVirtualBlock. + + It is correct to call this function with `allocation == VK_NULL_HANDLE` - it does nothing. + */ + VMA_CALL_PRE void VMA_CALL_POST vmaVirtualFree( + VmaVirtualBlock VMA_NOT_NULL virtualBlock, + VmaVirtualAllocation VMA_NULLABLE_NON_DISPATCHABLE allocation); + + /** \brief Frees all virtual allocations inside given #VmaVirtualBlock. + + You must either call this function or free each virtual allocation individually with vmaVirtualFree() + before destroying a virtual block. Otherwise, an assert is called. + + If you keep pointer to some additional metadata associated with your virtual allocation in its `pUserData`, + don't forget to free it as well. + */ + VMA_CALL_PRE void VMA_CALL_POST vmaClearVirtualBlock( + VmaVirtualBlock VMA_NOT_NULL virtualBlock); + + /** \brief Changes custom pointer associated with given virtual allocation. + */ + VMA_CALL_PRE void VMA_CALL_POST vmaSetVirtualAllocationUserData( + VmaVirtualBlock VMA_NOT_NULL virtualBlock, + VmaVirtualAllocation VMA_NOT_NULL_NON_DISPATCHABLE allocation, + void* VMA_NULLABLE pUserData); + + /** \brief Calculates and returns statistics about virtual allocations and memory usage in given #VmaVirtualBlock. + + This function is fast to call. For more detailed statistics, see vmaCalculateVirtualBlockStatistics(). + */ + VMA_CALL_PRE void VMA_CALL_POST vmaGetVirtualBlockStatistics( + VmaVirtualBlock VMA_NOT_NULL virtualBlock, + VmaStatistics* VMA_NOT_NULL pStats); + + /** \brief Calculates and returns detailed statistics about virtual allocations and memory usage in given #VmaVirtualBlock. + + This function is slow to call. Use for debugging purposes. + For less detailed statistics, see vmaGetVirtualBlockStatistics(). + */ + VMA_CALL_PRE void VMA_CALL_POST vmaCalculateVirtualBlockStatistics( + VmaVirtualBlock VMA_NOT_NULL virtualBlock, + VmaDetailedStatistics* VMA_NOT_NULL pStats); + + /** @} */ #if VMA_STATS_STRING_ENABLED /** @@ -2716,31 +2716,31 @@ VMA_CALL_PRE void VMA_CALL_POST vmaCalculateVirtualBlockStatistics( Returned string must be freed using vmaFreeVirtualBlockStatsString(). */ -VMA_CALL_PRE void VMA_CALL_POST vmaBuildVirtualBlockStatsString( - VmaVirtualBlock VMA_NOT_NULL virtualBlock, - char* VMA_NULLABLE* VMA_NOT_NULL ppStatsString, - VkBool32 detailedMap); + VMA_CALL_PRE void VMA_CALL_POST vmaBuildVirtualBlockStatsString( + VmaVirtualBlock VMA_NOT_NULL virtualBlock, + char* VMA_NULLABLE* VMA_NOT_NULL ppStatsString, + VkBool32 detailedMap); -/// Frees a string returned by vmaBuildVirtualBlockStatsString(). -VMA_CALL_PRE void VMA_CALL_POST vmaFreeVirtualBlockStatsString( - VmaVirtualBlock VMA_NOT_NULL virtualBlock, - char* VMA_NULLABLE pStatsString); + /// Frees a string returned by vmaBuildVirtualBlockStatsString(). + VMA_CALL_PRE void VMA_CALL_POST vmaFreeVirtualBlockStatsString( + VmaVirtualBlock VMA_NOT_NULL virtualBlock, + char* VMA_NULLABLE pStatsString); -/** \brief Builds and returns statistics as a null-terminated string in JSON format. -\param allocator -\param[out] ppStatsString Must be freed using vmaFreeStatsString() function. -\param detailedMap -*/ -VMA_CALL_PRE void VMA_CALL_POST vmaBuildStatsString( - VmaAllocator VMA_NOT_NULL allocator, - char* VMA_NULLABLE* VMA_NOT_NULL ppStatsString, - VkBool32 detailedMap); + /** \brief Builds and returns statistics as a null-terminated string in JSON format. + \param allocator + \param[out] ppStatsString Must be freed using vmaFreeStatsString() function. + \param detailedMap + */ + VMA_CALL_PRE void VMA_CALL_POST vmaBuildStatsString( + VmaAllocator VMA_NOT_NULL allocator, + char* VMA_NULLABLE* VMA_NOT_NULL ppStatsString, + VkBool32 detailedMap); -VMA_CALL_PRE void VMA_CALL_POST vmaFreeStatsString( - VmaAllocator VMA_NOT_NULL allocator, - char* VMA_NULLABLE pStatsString); + VMA_CALL_PRE void VMA_CALL_POST vmaFreeStatsString( + VmaAllocator VMA_NOT_NULL allocator, + char* VMA_NULLABLE pStatsString); -/** @} */ + /** @} */ #endif // VMA_STATS_STRING_ENABLED @@ -2776,22 +2776,22 @@ VMA_CALL_PRE void VMA_CALL_POST vmaFreeStatsString( #include #if !defined(VMA_CPP20) - #if __cplusplus >= 202002L || _MSVC_LANG >= 202002L // C++20 - #define VMA_CPP20 1 - #else - #define VMA_CPP20 0 - #endif +#if __cplusplus >= 202002L || _MSVC_LANG >= 202002L // C++20 +#define VMA_CPP20 1 +#else +#define VMA_CPP20 0 +#endif #endif #ifdef _MSC_VER - #include // For functions like __popcnt, _BitScanForward etc. +#include // For functions like __popcnt, _BitScanForward etc. #endif #if VMA_CPP20 - #include +#include #endif #if VMA_STATS_STRING_ENABLED - #include // For snprintf +#include // For snprintf #endif /******************************************************************************* @@ -2809,7 +2809,7 @@ internally, like: vulkanFunctions.vkAllocateMemory = &vkAllocateMemory; */ #if !defined(VMA_STATIC_VULKAN_FUNCTIONS) && !defined(VK_NO_PROTOTYPES) - #define VMA_STATIC_VULKAN_FUNCTIONS 1 +#define VMA_STATIC_VULKAN_FUNCTIONS 1 #endif /* @@ -2823,19 +2823,19 @@ VmaVulkanFunctions::vkGetInstanceProcAddr and vkGetDeviceProcAddr as VmaAllocatorCreateInfo::pVulkanFunctions. Other members can be null. */ #if !defined(VMA_DYNAMIC_VULKAN_FUNCTIONS) - #define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 +#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 #endif #ifndef VMA_USE_STL_SHARED_MUTEX - #if __cplusplus >= 201703L || _MSVC_LANG >= 201703L // C++17 - #define VMA_USE_STL_SHARED_MUTEX 1 - // Visual studio defines __cplusplus properly only when passed additional parameter: /Zc:__cplusplus - // Otherwise it is always 199711L, despite shared_mutex works since Visual Studio 2015 Update 2. - #elif defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023918 && __cplusplus == 199711L && _MSVC_LANG >= 201703L - #define VMA_USE_STL_SHARED_MUTEX 1 - #else - #define VMA_USE_STL_SHARED_MUTEX 0 - #endif +#if __cplusplus >= 201703L || _MSVC_LANG >= 201703L // C++17 +#define VMA_USE_STL_SHARED_MUTEX 1 +// Visual studio defines __cplusplus properly only when passed additional parameter: /Zc:__cplusplus +// Otherwise it is always 199711L, despite shared_mutex works since Visual Studio 2015 Update 2. +#elif defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023918 && __cplusplus == 199711L && _MSVC_LANG >= 201703L +#define VMA_USE_STL_SHARED_MUTEX 1 +#else +#define VMA_USE_STL_SHARED_MUTEX 0 +#endif #endif /* @@ -2860,48 +2860,48 @@ The following headers are used in this CONFIGURATION section only, so feel free remove them if not needed. */ #if !defined(VMA_CONFIGURATION_USER_INCLUDES_H) - #include // for assert - #include // for min, max, swap - #include +#include // for assert +#include // for min, max, swap +#include #else - #include VMA_CONFIGURATION_USER_INCLUDES_H +#include VMA_CONFIGURATION_USER_INCLUDES_H #endif #ifndef VMA_NULL - // Value used as null pointer. Define it to e.g.: nullptr, NULL, 0, (void*)0. - #define VMA_NULL nullptr +// Value used as null pointer. Define it to e.g.: nullptr, NULL, 0, (void*)0. +#define VMA_NULL nullptr #endif #ifndef VMA_FALLTHROUGH - #if __cplusplus >= 201703L || _MSVC_LANG >= 201703L // C++17 - #define VMA_FALLTHROUGH [[fallthrough]] - #else - #define VMA_FALLTHROUGH - #endif +#if __cplusplus >= 201703L || _MSVC_LANG >= 201703L // C++17 +#define VMA_FALLTHROUGH [[fallthrough]] +#else +#define VMA_FALLTHROUGH +#endif #endif // Normal assert to check for programmer's errors, especially in Debug configuration. #ifndef VMA_ASSERT - #ifdef NDEBUG - #define VMA_ASSERT(expr) - #else - #define VMA_ASSERT(expr) assert(expr) - #endif +#ifdef NDEBUG +#define VMA_ASSERT(expr) +#else +#define VMA_ASSERT(expr) assert(expr) +#endif #endif // Assert that will be called very often, like inside data structures e.g. operator[]. // Making it non-empty can make program slow. #ifndef VMA_HEAVY_ASSERT - #ifdef NDEBUG - #define VMA_HEAVY_ASSERT(expr) - #else - #define VMA_HEAVY_ASSERT(expr) //VMA_ASSERT(expr) - #endif +#ifdef NDEBUG +#define VMA_HEAVY_ASSERT(expr) +#else +#define VMA_HEAVY_ASSERT(expr) //VMA_ASSERT(expr) +#endif #endif // Assert used for reporting memory leaks - unfreed allocations. #ifndef VMA_ASSERT_LEAK - #define VMA_ASSERT_LEAK(expr) VMA_ASSERT(expr) +#define VMA_ASSERT_LEAK(expr) VMA_ASSERT(expr) #endif // If your compiler is not compatible with C++17 and definition of @@ -2914,7 +2914,7 @@ remove them if not needed. static void* vma_aligned_alloc(size_t alignment, size_t size) { // alignment must be >= sizeof(void*) - if(alignment < sizeof(void*)) + if (alignment < sizeof(void*)) { alignment = sizeof(void*); } @@ -2946,13 +2946,13 @@ static void* vma_aligned_alloc(size_t alignment, size_t size) //#endif // alignment must be >= sizeof(void*) - if(alignment < sizeof(void*)) + if (alignment < sizeof(void*)) { alignment = sizeof(void*); } - void *pointer; - if(posix_memalign(&pointer, alignment, size) == 0) + void* pointer; + if (posix_memalign(&pointer, alignment, size) == 0) return pointer; return VMA_NULL; } @@ -2987,75 +2987,75 @@ static void vma_aligned_free(void* VMA_NULLABLE ptr) #endif #ifndef VMA_ALIGN_OF - #define VMA_ALIGN_OF(type) (alignof(type)) +#define VMA_ALIGN_OF(type) (alignof(type)) #endif #ifndef VMA_SYSTEM_ALIGNED_MALLOC - #define VMA_SYSTEM_ALIGNED_MALLOC(size, alignment) vma_aligned_alloc((alignment), (size)) +#define VMA_SYSTEM_ALIGNED_MALLOC(size, alignment) vma_aligned_alloc((alignment), (size)) #endif #ifndef VMA_SYSTEM_ALIGNED_FREE - // VMA_SYSTEM_FREE is the old name, but might have been defined by the user - #if defined(VMA_SYSTEM_FREE) - #define VMA_SYSTEM_ALIGNED_FREE(ptr) VMA_SYSTEM_FREE(ptr) - #else - #define VMA_SYSTEM_ALIGNED_FREE(ptr) vma_aligned_free(ptr) - #endif +// VMA_SYSTEM_FREE is the old name, but might have been defined by the user +#if defined(VMA_SYSTEM_FREE) +#define VMA_SYSTEM_ALIGNED_FREE(ptr) VMA_SYSTEM_FREE(ptr) +#else +#define VMA_SYSTEM_ALIGNED_FREE(ptr) vma_aligned_free(ptr) +#endif #endif #ifndef VMA_COUNT_BITS_SET // Returns number of bits set to 1 in (v) - #define VMA_COUNT_BITS_SET(v) VmaCountBitsSet(v) +#define VMA_COUNT_BITS_SET(v) VmaCountBitsSet(v) #endif #ifndef VMA_BITSCAN_LSB // Scans integer for index of first nonzero value from the Least Significant Bit (LSB). If mask is 0 then returns UINT8_MAX - #define VMA_BITSCAN_LSB(mask) VmaBitScanLSB(mask) +#define VMA_BITSCAN_LSB(mask) VmaBitScanLSB(mask) #endif #ifndef VMA_BITSCAN_MSB // Scans integer for index of first nonzero value from the Most Significant Bit (MSB). If mask is 0 then returns UINT8_MAX - #define VMA_BITSCAN_MSB(mask) VmaBitScanMSB(mask) +#define VMA_BITSCAN_MSB(mask) VmaBitScanMSB(mask) #endif #ifndef VMA_MIN - #define VMA_MIN(v1, v2) ((std::min)((v1), (v2))) +#define VMA_MIN(v1, v2) ((std::min)((v1), (v2))) #endif #ifndef VMA_MAX - #define VMA_MAX(v1, v2) ((std::max)((v1), (v2))) +#define VMA_MAX(v1, v2) ((std::max)((v1), (v2))) #endif #ifndef VMA_SORT - #define VMA_SORT(beg, end, cmp) std::sort(beg, end, cmp) +#define VMA_SORT(beg, end, cmp) std::sort(beg, end, cmp) #endif #ifndef VMA_DEBUG_LOG_FORMAT - #define VMA_DEBUG_LOG_FORMAT(format, ...) - /* - #define VMA_DEBUG_LOG_FORMAT(format, ...) do { \ - printf((format), __VA_ARGS__); \ - printf("\n"); \ - } while(false) - */ +#define VMA_DEBUG_LOG_FORMAT(format, ...) +/* +#define VMA_DEBUG_LOG_FORMAT(format, ...) do { \ + printf((format), __VA_ARGS__); \ + printf("\n"); \ +} while(false) +*/ #endif #ifndef VMA_DEBUG_LOG - #define VMA_DEBUG_LOG(str) VMA_DEBUG_LOG_FORMAT("%s", (str)) +#define VMA_DEBUG_LOG(str) VMA_DEBUG_LOG_FORMAT("%s", (str)) #endif #ifndef VMA_LEAK_LOG_FORMAT - #define VMA_LEAK_LOG_FORMAT(format, ...) VMA_DEBUG_LOG_FORMAT(format, __VA_ARGS__) +#define VMA_LEAK_LOG_FORMAT(format, ...) VMA_DEBUG_LOG_FORMAT(format, __VA_ARGS__) #endif #ifndef VMA_CLASS_NO_COPY - #define VMA_CLASS_NO_COPY(className) \ +#define VMA_CLASS_NO_COPY(className) \ private: \ className(const className&) = delete; \ className& operator=(const className&) = delete; #endif #ifndef VMA_CLASS_NO_COPY_NO_MOVE - #define VMA_CLASS_NO_COPY_NO_MOVE(className) \ +#define VMA_CLASS_NO_COPY_NO_MOVE(className) \ private: \ className(const className&) = delete; \ className(className&&) = delete; \ @@ -3065,178 +3065,178 @@ static void vma_aligned_free(void* VMA_NULLABLE ptr) // Define this macro to 1 to enable functions: vmaBuildStatsString, vmaFreeStatsString. #if VMA_STATS_STRING_ENABLED - static inline void VmaUint32ToStr(char* VMA_NOT_NULL outStr, size_t strLen, uint32_t num) - { - snprintf(outStr, strLen, "%" PRIu32, num); - } - static inline void VmaUint64ToStr(char* VMA_NOT_NULL outStr, size_t strLen, uint64_t num) - { - snprintf(outStr, strLen, "%" PRIu64, num); - } - static inline void VmaPtrToStr(char* VMA_NOT_NULL outStr, size_t strLen, const void* ptr) - { - snprintf(outStr, strLen, "%p", ptr); - } +static inline void VmaUint32ToStr(char* VMA_NOT_NULL outStr, size_t strLen, uint32_t num) +{ + snprintf(outStr, strLen, "%" PRIu32, num); +} +static inline void VmaUint64ToStr(char* VMA_NOT_NULL outStr, size_t strLen, uint64_t num) +{ + snprintf(outStr, strLen, "%" PRIu64, num); +} +static inline void VmaPtrToStr(char* VMA_NOT_NULL outStr, size_t strLen, const void* ptr) +{ + snprintf(outStr, strLen, "%p", ptr); +} #endif #ifndef VMA_MUTEX - class VmaMutex - { +class VmaMutex +{ VMA_CLASS_NO_COPY_NO_MOVE(VmaMutex) - public: - VmaMutex() { } - void Lock() { m_Mutex.lock(); } - void Unlock() { m_Mutex.unlock(); } - bool TryLock() { return m_Mutex.try_lock(); } - private: - std::mutex m_Mutex; - }; - #define VMA_MUTEX VmaMutex +public: + VmaMutex() { } + void Lock() { m_Mutex.lock(); } + void Unlock() { m_Mutex.unlock(); } + bool TryLock() { return m_Mutex.try_lock(); } +private: + std::mutex m_Mutex; +}; +#define VMA_MUTEX VmaMutex #endif // Read-write mutex, where "read" is shared access, "write" is exclusive access. #ifndef VMA_RW_MUTEX - #if VMA_USE_STL_SHARED_MUTEX - // Use std::shared_mutex from C++17. - #include - class VmaRWMutex - { - public: - void LockRead() { m_Mutex.lock_shared(); } - void UnlockRead() { m_Mutex.unlock_shared(); } - bool TryLockRead() { return m_Mutex.try_lock_shared(); } - void LockWrite() { m_Mutex.lock(); } - void UnlockWrite() { m_Mutex.unlock(); } - bool TryLockWrite() { return m_Mutex.try_lock(); } - private: - std::shared_mutex m_Mutex; - }; - #define VMA_RW_MUTEX VmaRWMutex - #elif defined(_WIN32) && defined(WINVER) && WINVER >= 0x0600 - // Use SRWLOCK from WinAPI. - // Minimum supported client = Windows Vista, server = Windows Server 2008. - class VmaRWMutex - { - public: - VmaRWMutex() { InitializeSRWLock(&m_Lock); } - void LockRead() { AcquireSRWLockShared(&m_Lock); } - void UnlockRead() { ReleaseSRWLockShared(&m_Lock); } - bool TryLockRead() { return TryAcquireSRWLockShared(&m_Lock) != FALSE; } - void LockWrite() { AcquireSRWLockExclusive(&m_Lock); } - void UnlockWrite() { ReleaseSRWLockExclusive(&m_Lock); } - bool TryLockWrite() { return TryAcquireSRWLockExclusive(&m_Lock) != FALSE; } - private: - SRWLOCK m_Lock; - }; - #define VMA_RW_MUTEX VmaRWMutex - #else - // Less efficient fallback: Use normal mutex. - class VmaRWMutex - { - public: - void LockRead() { m_Mutex.Lock(); } - void UnlockRead() { m_Mutex.Unlock(); } - bool TryLockRead() { return m_Mutex.TryLock(); } - void LockWrite() { m_Mutex.Lock(); } - void UnlockWrite() { m_Mutex.Unlock(); } - bool TryLockWrite() { return m_Mutex.TryLock(); } - private: - VMA_MUTEX m_Mutex; - }; - #define VMA_RW_MUTEX VmaRWMutex - #endif // #if VMA_USE_STL_SHARED_MUTEX +#if VMA_USE_STL_SHARED_MUTEX + // Use std::shared_mutex from C++17. +#include +class VmaRWMutex +{ +public: + void LockRead() { m_Mutex.lock_shared(); } + void UnlockRead() { m_Mutex.unlock_shared(); } + bool TryLockRead() { return m_Mutex.try_lock_shared(); } + void LockWrite() { m_Mutex.lock(); } + void UnlockWrite() { m_Mutex.unlock(); } + bool TryLockWrite() { return m_Mutex.try_lock(); } +private: + std::shared_mutex m_Mutex; +}; +#define VMA_RW_MUTEX VmaRWMutex +#elif defined(_WIN32) && defined(WINVER) && WINVER >= 0x0600 + // Use SRWLOCK from WinAPI. + // Minimum supported client = Windows Vista, server = Windows Server 2008. +class VmaRWMutex +{ +public: + VmaRWMutex() { InitializeSRWLock(&m_Lock); } + void LockRead() { AcquireSRWLockShared(&m_Lock); } + void UnlockRead() { ReleaseSRWLockShared(&m_Lock); } + bool TryLockRead() { return TryAcquireSRWLockShared(&m_Lock) != FALSE; } + void LockWrite() { AcquireSRWLockExclusive(&m_Lock); } + void UnlockWrite() { ReleaseSRWLockExclusive(&m_Lock); } + bool TryLockWrite() { return TryAcquireSRWLockExclusive(&m_Lock) != FALSE; } +private: + SRWLOCK m_Lock; +}; +#define VMA_RW_MUTEX VmaRWMutex +#else + // Less efficient fallback: Use normal mutex. +class VmaRWMutex +{ +public: + void LockRead() { m_Mutex.Lock(); } + void UnlockRead() { m_Mutex.Unlock(); } + bool TryLockRead() { return m_Mutex.TryLock(); } + void LockWrite() { m_Mutex.Lock(); } + void UnlockWrite() { m_Mutex.Unlock(); } + bool TryLockWrite() { return m_Mutex.TryLock(); } +private: + VMA_MUTEX m_Mutex; +}; +#define VMA_RW_MUTEX VmaRWMutex +#endif // #if VMA_USE_STL_SHARED_MUTEX #endif // #ifndef VMA_RW_MUTEX /* If providing your own implementation, you need to implement a subset of std::atomic. */ #ifndef VMA_ATOMIC_UINT32 - #include - #define VMA_ATOMIC_UINT32 std::atomic +#include +#define VMA_ATOMIC_UINT32 std::atomic #endif #ifndef VMA_ATOMIC_UINT64 - #include - #define VMA_ATOMIC_UINT64 std::atomic +#include +#define VMA_ATOMIC_UINT64 std::atomic #endif #ifndef VMA_DEBUG_ALWAYS_DEDICATED_MEMORY - /** - Every allocation will have its own memory block. - Define to 1 for debugging purposes only. - */ - #define VMA_DEBUG_ALWAYS_DEDICATED_MEMORY (0) +/** +Every allocation will have its own memory block. +Define to 1 for debugging purposes only. +*/ +#define VMA_DEBUG_ALWAYS_DEDICATED_MEMORY (0) #endif #ifndef VMA_MIN_ALIGNMENT - /** - Minimum alignment of all allocations, in bytes. - Set to more than 1 for debugging purposes. Must be power of two. - */ - #ifdef VMA_DEBUG_ALIGNMENT // Old name - #define VMA_MIN_ALIGNMENT VMA_DEBUG_ALIGNMENT - #else - #define VMA_MIN_ALIGNMENT (1) - #endif +/** +Minimum alignment of all allocations, in bytes. +Set to more than 1 for debugging purposes. Must be power of two. +*/ +#ifdef VMA_DEBUG_ALIGNMENT // Old name +#define VMA_MIN_ALIGNMENT VMA_DEBUG_ALIGNMENT +#else +#define VMA_MIN_ALIGNMENT (1) +#endif #endif #ifndef VMA_DEBUG_MARGIN - /** - Minimum margin after every allocation, in bytes. - Set nonzero for debugging purposes only. - */ - #define VMA_DEBUG_MARGIN (0) +/** +Minimum margin after every allocation, in bytes. +Set nonzero for debugging purposes only. +*/ +#define VMA_DEBUG_MARGIN (0) #endif #ifndef VMA_DEBUG_INITIALIZE_ALLOCATIONS - /** - Define this macro to 1 to automatically fill new allocations and destroyed - allocations with some bit pattern. - */ - #define VMA_DEBUG_INITIALIZE_ALLOCATIONS (0) +/** +Define this macro to 1 to automatically fill new allocations and destroyed +allocations with some bit pattern. +*/ +#define VMA_DEBUG_INITIALIZE_ALLOCATIONS (0) #endif #ifndef VMA_DEBUG_DETECT_CORRUPTION - /** - Define this macro to 1 together with non-zero value of VMA_DEBUG_MARGIN to - enable writing magic value to the margin after every allocation and - validating it, so that memory corruptions (out-of-bounds writes) are detected. - */ - #define VMA_DEBUG_DETECT_CORRUPTION (0) +/** +Define this macro to 1 together with non-zero value of VMA_DEBUG_MARGIN to +enable writing magic value to the margin after every allocation and +validating it, so that memory corruptions (out-of-bounds writes) are detected. +*/ +#define VMA_DEBUG_DETECT_CORRUPTION (0) #endif #ifndef VMA_DEBUG_GLOBAL_MUTEX - /** - Set this to 1 for debugging purposes only, to enable single mutex protecting all - entry calls to the library. Can be useful for debugging multithreading issues. - */ - #define VMA_DEBUG_GLOBAL_MUTEX (0) +/** +Set this to 1 for debugging purposes only, to enable single mutex protecting all +entry calls to the library. Can be useful for debugging multithreading issues. +*/ +#define VMA_DEBUG_GLOBAL_MUTEX (0) #endif #ifndef VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY - /** - Minimum value for VkPhysicalDeviceLimits::bufferImageGranularity. - Set to more than 1 for debugging purposes only. Must be power of two. - */ - #define VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY (1) +/** +Minimum value for VkPhysicalDeviceLimits::bufferImageGranularity. +Set to more than 1 for debugging purposes only. Must be power of two. +*/ +#define VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY (1) #endif #ifndef VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT - /* - Set this to 1 to make VMA never exceed VkPhysicalDeviceLimits::maxMemoryAllocationCount - and return error instead of leaving up to Vulkan implementation what to do in such cases. - */ - #define VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT (0) +/* +Set this to 1 to make VMA never exceed VkPhysicalDeviceLimits::maxMemoryAllocationCount +and return error instead of leaving up to Vulkan implementation what to do in such cases. +*/ +#define VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT (0) #endif #ifndef VMA_SMALL_HEAP_MAX_SIZE - /// Maximum size of a memory heap in Vulkan to consider it "small". - #define VMA_SMALL_HEAP_MAX_SIZE (1024ull * 1024 * 1024) +/// Maximum size of a memory heap in Vulkan to consider it "small". +#define VMA_SMALL_HEAP_MAX_SIZE (1024ull * 1024 * 1024) #endif #ifndef VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE /// Default size of a block allocated as single VkDeviceMemory from a "large" heap. - #define VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE (256ull * 1024 * 1024) +#define VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE (256ull * 1024 * 1024) #endif /* @@ -3247,7 +3247,7 @@ vkMapMemory/vkUnmapMemory too many times, which may improve performance and help tools like RenderDoc. */ #ifndef VMA_MAPPING_HYSTERESIS_ENABLED - #define VMA_MAPPING_HYSTERESIS_ENABLED 1 +#define VMA_MAPPING_HYSTERESIS_ENABLED 1 #endif #define VMA_VALIDATE(cond) do { if(!(cond)) { \ @@ -3296,7 +3296,7 @@ static const char* VMA_SUBALLOCATION_TYPE_NAMES[] = #endif static VkAllocationCallbacks VmaEmptyAllocationCallbacks = - { VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL }; +{ VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL }; #ifndef _VMA_ENUM_DECLARATIONS @@ -3436,7 +3436,7 @@ static inline uint8_t VmaBitScanLSB(uint64_t mask) return static_cast(pos); return UINT8_MAX; #elif VMA_CPP20 - if(mask) + if (mask) return static_cast(std::countr_zero(mask)); return UINT8_MAX; #elif defined __GNUC__ || defined __clang__ @@ -3462,7 +3462,7 @@ static inline uint8_t VmaBitScanLSB(uint32_t mask) return static_cast(pos); return UINT8_MAX; #elif VMA_CPP20 - if(mask) + if (mask) return static_cast(std::countr_zero(mask)); return UINT8_MAX; #elif defined __GNUC__ || defined __clang__ @@ -3487,7 +3487,7 @@ static inline uint8_t VmaBitScanMSB(uint64_t mask) if (_BitScanReverse64(&pos, mask)) return static_cast(pos); #elif VMA_CPP20 - if(mask) + if (mask) return 63 - static_cast(std::countl_zero(mask)); #elif defined __GNUC__ || defined __clang__ if (mask) @@ -3512,7 +3512,7 @@ static inline uint8_t VmaBitScanMSB(uint32_t mask) if (_BitScanReverse(&pos, mask)) return static_cast(pos); #elif VMA_CPP20 - if(mask) + if (mask) return 31 - static_cast(std::countl_zero(mask)); #elif defined __GNUC__ || defined __clang__ if (mask) @@ -3811,10 +3811,10 @@ static inline void VmaPnextChainPushFront(MainT* mainStruct, NewT* newStruct) template static inline const FindT* VmaPnextChainFind(const MainT* mainStruct, VkStructureType sType) { - for(const VkBaseInStructure* s = (const VkBaseInStructure*)mainStruct->pNext; + for (const VkBaseInStructure* s = (const VkBaseInStructure*)mainStruct->pNext; s != VMA_NULL; s = s->pNext) { - if(s->sType == sType) + if (s->sType == sType) { return (const FindT*)s; } @@ -3837,8 +3837,8 @@ struct VmaBufferImageUsage VmaBufferImageUsage() { *this = UNKNOWN; } explicit VmaBufferImageUsage(BaseType usage) : Value(usage) { } - VmaBufferImageUsage(const VkBufferCreateInfo &createInfo, bool useKhrMaintenance5); - explicit VmaBufferImageUsage(const VkImageCreateInfo &createInfo); + VmaBufferImageUsage(const VkBufferCreateInfo& createInfo, bool useKhrMaintenance5); + explicit VmaBufferImageUsage(const VkImageCreateInfo& createInfo); bool operator==(const VmaBufferImageUsage& rhs) const { return Value == rhs.Value; } bool operator!=(const VmaBufferImageUsage& rhs) const { return Value != rhs.Value; } @@ -3853,18 +3853,18 @@ struct VmaBufferImageUsage const VmaBufferImageUsage VmaBufferImageUsage::UNKNOWN = VmaBufferImageUsage(0); -VmaBufferImageUsage::VmaBufferImageUsage(const VkBufferCreateInfo &createInfo, +VmaBufferImageUsage::VmaBufferImageUsage(const VkBufferCreateInfo& createInfo, bool useKhrMaintenance5) { #if VMA_KHR_MAINTENANCE5 - if(useKhrMaintenance5) + if (useKhrMaintenance5) { // If VkBufferCreateInfo::pNext chain contains VkBufferUsageFlags2CreateInfoKHR, // take usage from it and ignore VkBufferCreateInfo::usage, per specification // of the VK_KHR_maintenance5 extension. const VkBufferUsageFlags2CreateInfoKHR* const usageFlags2 = VmaPnextChainFind(&createInfo, VK_STRUCTURE_TYPE_BUFFER_USAGE_FLAGS_2_CREATE_INFO_KHR); - if(usageFlags2) + if (usageFlags2) { this->Value = usageFlags2->usage; return; @@ -3875,7 +3875,7 @@ VmaBufferImageUsage::VmaBufferImageUsage(const VkBufferCreateInfo &createInfo, this->Value = (BaseType)createInfo.usage; } -VmaBufferImageUsage::VmaBufferImageUsage(const VkImageCreateInfo &createInfo) +VmaBufferImageUsage::VmaBufferImageUsage(const VkImageCreateInfo& createInfo) { // Maybe in the future there will be VK_KHR_maintenanceN extension with structure // VkImageUsageFlags2CreateInfoKHR, like the one for buffers... @@ -3897,12 +3897,12 @@ static bool FindMemoryPreferences( outPreferredFlags = allocCreateInfo.preferredFlags; outNotPreferredFlags = 0; - switch(allocCreateInfo.usage) + switch (allocCreateInfo.usage) { case VMA_MEMORY_USAGE_UNKNOWN: break; case VMA_MEMORY_USAGE_GPU_ONLY: - if(!isIntegratedGPU || (outPreferredFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) + if (!isIntegratedGPU || (outPreferredFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) { outPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; } @@ -3912,7 +3912,7 @@ static bool FindMemoryPreferences( break; case VMA_MEMORY_USAGE_CPU_TO_GPU: outRequiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; - if(!isIntegratedGPU || (outPreferredFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) + if (!isIntegratedGPU || (outPreferredFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) { outPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; } @@ -3931,10 +3931,10 @@ static bool FindMemoryPreferences( case VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE: case VMA_MEMORY_USAGE_AUTO_PREFER_HOST: { - if(bufImgUsage == VmaBufferImageUsage::UNKNOWN) + if (bufImgUsage == VmaBufferImageUsage::UNKNOWN) { VMA_ASSERT(0 && "VMA_MEMORY_USAGE_AUTO* values can only be used with functions like vmaCreateBuffer, vmaCreateImage so that the details of the created resource are known." - " Maybe you use VkBufferUsageFlags2CreateInfoKHR but forgot to use VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT?" ); + " Maybe you use VkBufferUsageFlags2CreateInfoKHR but forgot to use VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT?"); return false; } @@ -3946,7 +3946,7 @@ static bool FindMemoryPreferences( const bool preferHost = allocCreateInfo.usage == VMA_MEMORY_USAGE_AUTO_PREFER_HOST; // CPU random access - e.g. a buffer written to or transferred from GPU to read back on CPU. - if(hostAccessRandom) + if (hostAccessRandom) { // Prefer cached. Cannot require it, because some platforms don't have it (e.g. Raspberry Pi - see #362)! outPreferredFlags |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT; @@ -3966,12 +3966,12 @@ static bool FindMemoryPreferences( } } // CPU sequential write - may be CPU or host-visible GPU memory, uncached and write-combined. - else if(hostAccessSequentialWrite) + else if (hostAccessSequentialWrite) { // Want uncached and write-combined. outNotPreferredFlags |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT; - if(!isIntegratedGPU && deviceAccess && hostAccessAllowTransferInstead && !preferHost) + if (!isIntegratedGPU && deviceAccess && hostAccessAllowTransferInstead && !preferHost) { outPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; } @@ -3979,10 +3979,10 @@ static bool FindMemoryPreferences( { outRequiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; // Direct GPU access, CPU sequential write (e.g. a dynamic uniform buffer updated every frame) - if(deviceAccess) + if (deviceAccess) { // Could go to CPU memory or GPU BAR/unified. Up to the user to decide. If no preference, choose GPU memory. - if(preferHost) + if (preferHost) outNotPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; else outPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; @@ -3991,7 +3991,7 @@ static bool FindMemoryPreferences( else { // Could go to CPU memory or GPU BAR/unified. Up to the user to decide. If no preference, choose CPU memory. - if(preferDevice) + if (preferDevice) outPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; else outNotPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; @@ -4013,7 +4013,7 @@ static bool FindMemoryPreferences( // a "swap file" copy to free some GPU memory (then better CPU memory). // Up to the user to decide. If no preferece, assume the former and choose GPU memory. - if(preferHost) + if (preferHost) outNotPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; else outPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; @@ -4025,7 +4025,7 @@ static bool FindMemoryPreferences( } // Avoid DEVICE_COHERENT unless explicitly requested. - if(((allocCreateInfo.requiredFlags | allocCreateInfo.preferredFlags) & + if (((allocCreateInfo.requiredFlags | allocCreateInfo.preferredFlags) & (VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY | VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD_COPY)) == 0) { outNotPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD_COPY; @@ -4238,7 +4238,7 @@ public: { if (m_pMutex) { m_pMutex->Lock(); } } - ~VmaMutexLock() { if (m_pMutex) { m_pMutex->Unlock(); } } + ~VmaMutexLock() { if (m_pMutex) { m_pMutex->Unlock(); } } private: VMA_MUTEX* m_pMutex; @@ -4277,10 +4277,10 @@ private: }; #if VMA_DEBUG_GLOBAL_MUTEX - static VMA_MUTEX gDebugGlobalMutex; - #define VMA_DEBUG_GLOBAL_MUTEX_LOCK VmaMutexLock debugGlobalMutexLock(gDebugGlobalMutex, true); +static VMA_MUTEX gDebugGlobalMutex; +#define VMA_DEBUG_GLOBAL_MUTEX_LOCK VmaMutexLock debugGlobalMutexLock(gDebugGlobalMutex, true); #else - #define VMA_DEBUG_GLOBAL_MUTEX_LOCK +#define VMA_DEBUG_GLOBAL_MUTEX_LOCK #endif #endif // _VMA_MUTEX_LOCK @@ -4294,7 +4294,7 @@ public: ~AtomicTransactionalIncrement() { - if(m_Atomic) + if (m_Atomic) --(*m_Atomic); } @@ -4929,7 +4929,7 @@ VmaListItem* VmaRawList::PushBack() { ItemType* const pNewItem = m_ItemAllocator.Alloc(); pNewItem->pNext = VMA_NULL; - if(IsEmpty()) + if (IsEmpty()) { pNewItem->pPrev = VMA_NULL; m_pFront = pNewItem; @@ -4983,7 +4983,7 @@ void VmaRawList::PopBack() VMA_HEAVY_ASSERT(m_Count > 0); ItemType* const pBackItem = m_pBack; ItemType* const pPrevItem = pBackItem->pPrev; - if(pPrevItem != VMA_NULL) + if (pPrevItem != VMA_NULL) { pPrevItem->pNext = VMA_NULL; } @@ -5016,7 +5016,7 @@ void VmaRawList::Remove(ItemType* pItem) VMA_HEAVY_ASSERT(pItem != VMA_NULL); VMA_HEAVY_ASSERT(m_Count > 0); - if(pItem->pPrev != VMA_NULL) + if (pItem->pPrev != VMA_NULL) { pItem->pPrev->pNext = pItem->pNext; } @@ -5026,7 +5026,7 @@ void VmaRawList::Remove(ItemType* pItem) m_pFront = pItem->pNext; } - if(pItem->pNext != VMA_NULL) + if (pItem->pNext != VMA_NULL) { pItem->pNext->pPrev = pItem->pPrev; } @@ -5043,14 +5043,14 @@ void VmaRawList::Remove(ItemType* pItem) template VmaListItem* VmaRawList::InsertBefore(ItemType* pItem) { - if(pItem != VMA_NULL) + if (pItem != VMA_NULL) { ItemType* const prevItem = pItem->pPrev; ItemType* const newItem = m_ItemAllocator.Alloc(); newItem->pPrev = prevItem; newItem->pNext = pItem; pItem->pPrev = newItem; - if(prevItem != VMA_NULL) + if (prevItem != VMA_NULL) { prevItem->pNext = newItem; } @@ -5069,14 +5069,14 @@ VmaListItem* VmaRawList::InsertBefore(ItemType* pItem) template VmaListItem* VmaRawList::InsertAfter(ItemType* pItem) { - if(pItem != VMA_NULL) + if (pItem != VMA_NULL) { ItemType* const nextItem = pItem->pNext; ItemType* const newItem = m_ItemAllocator.Alloc(); newItem->pNext = nextItem; newItem->pPrev = pItem; pItem->pNext = newItem; - if(nextItem != VMA_NULL) + if (nextItem != VMA_NULL) { nextItem->pPrev = newItem; } @@ -5125,7 +5125,7 @@ public: friend class const_iterator; friend class VmaList; public: - iterator() : m_pList(VMA_NULL), m_pItem(VMA_NULL) {} + iterator() : m_pList(VMA_NULL), m_pItem(VMA_NULL) {} iterator(const reverse_iterator& src) : m_pList(src.m_pList), m_pItem(src.m_pItem) {} T& operator*() const { VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); return m_pItem->Value; } @@ -5144,7 +5144,7 @@ public: VmaRawList* m_pList; VmaListItem* m_pItem; - iterator(VmaRawList* pList, VmaListItem* pItem) : m_pList(pList), m_pItem(pItem) {} + iterator(VmaRawList* pList, VmaListItem* pItem) : m_pList(pList), m_pItem(pItem) {} }; class reverse_iterator { @@ -5160,8 +5160,8 @@ public: bool operator==(const reverse_iterator& rhs) const { VMA_HEAVY_ASSERT(m_pList == rhs.m_pList); return m_pItem == rhs.m_pItem; } bool operator!=(const reverse_iterator& rhs) const { VMA_HEAVY_ASSERT(m_pList == rhs.m_pList); return m_pItem != rhs.m_pItem; } - reverse_iterator operator++(int) { reverse_iterator result = *this; ++* this; return result; } - reverse_iterator operator--(int) { reverse_iterator result = *this; --* this; return result; } + reverse_iterator operator++(int) { reverse_iterator result = *this; ++*this; return result; } + reverse_iterator operator--(int) { reverse_iterator result = *this; --*this; return result; } reverse_iterator& operator++() { VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); m_pItem = m_pItem->pPrev; return *this; } reverse_iterator& operator--(); @@ -5170,7 +5170,7 @@ public: VmaRawList* m_pList; VmaListItem* m_pItem; - reverse_iterator(VmaRawList* pList, VmaListItem* pItem) : m_pList(pList), m_pItem(pItem) {} + reverse_iterator(VmaRawList* pList, VmaListItem* pItem) : m_pList(pList), m_pItem(pItem) {} }; class const_iterator { @@ -5188,8 +5188,8 @@ public: bool operator==(const const_iterator& rhs) const { VMA_HEAVY_ASSERT(m_pList == rhs.m_pList); return m_pItem == rhs.m_pItem; } bool operator!=(const const_iterator& rhs) const { VMA_HEAVY_ASSERT(m_pList == rhs.m_pList); return m_pItem != rhs.m_pItem; } - const_iterator operator++(int) { const_iterator result = *this; ++* this; return result; } - const_iterator operator--(int) { const_iterator result = *this; --* this; return result; } + const_iterator operator++(int) { const_iterator result = *this; ++*this; return result; } + const_iterator operator--(int) { const_iterator result = *this; --*this; return result; } const_iterator& operator++() { VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); m_pItem = m_pItem->pNext; return *this; } const_iterator& operator--(); @@ -5216,8 +5216,8 @@ public: bool operator==(const const_reverse_iterator& rhs) const { VMA_HEAVY_ASSERT(m_pList == rhs.m_pList); return m_pItem == rhs.m_pItem; } bool operator!=(const const_reverse_iterator& rhs) const { VMA_HEAVY_ASSERT(m_pList == rhs.m_pList); return m_pItem != rhs.m_pItem; } - const_reverse_iterator operator++(int) { const_reverse_iterator result = *this; ++* this; return result; } - const_reverse_iterator operator--(int) { const_reverse_iterator result = *this; --* this; return result; } + const_reverse_iterator operator++(int) { const_reverse_iterator result = *this; ++*this; return result; } + const_reverse_iterator operator--(int) { const_reverse_iterator result = *this; --*this; return result; } const_reverse_iterator& operator++() { VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); m_pItem = m_pItem->pPrev; return *this; } const_reverse_iterator& operator--(); @@ -5347,7 +5347,7 @@ public: // Movable, not copyable. VmaIntrusiveLinkedList() = default; - VmaIntrusiveLinkedList(VmaIntrusiveLinkedList && src); + VmaIntrusiveLinkedList(VmaIntrusiveLinkedList&& src); VmaIntrusiveLinkedList(const VmaIntrusiveLinkedList&) = delete; VmaIntrusiveLinkedList& operator=(VmaIntrusiveLinkedList&& src); VmaIntrusiveLinkedList& operator=(const VmaIntrusiveLinkedList&) = delete; @@ -5997,10 +5997,10 @@ public: bool PostMap() { #if VMA_MAPPING_HYSTERESIS_ENABLED - if(m_ExtraMapping == 0) + if (m_ExtraMapping == 0) { ++m_MajorCounter; - if(m_MajorCounter >= COUNTER_MIN_EXTRA_MAPPING) + if (m_MajorCounter >= COUNTER_MIN_EXTRA_MAPPING) { m_ExtraMapping = 1; m_MajorCounter = 0; @@ -6018,7 +6018,7 @@ public: void PostUnmap() { #if VMA_MAPPING_HYSTERESIS_ENABLED - if(m_ExtraMapping == 0) + if (m_ExtraMapping == 0) ++m_MajorCounter; else // m_ExtraMapping == 1 PostMinorCounter(); @@ -6029,7 +6029,7 @@ public: void PostAlloc() { #if VMA_MAPPING_HYSTERESIS_ENABLED - if(m_ExtraMapping == 1) + if (m_ExtraMapping == 1) ++m_MajorCounter; else // m_ExtraMapping == 0 PostMinorCounter(); @@ -6041,10 +6041,10 @@ public: bool PostFree() { #if VMA_MAPPING_HYSTERESIS_ENABLED - if(m_ExtraMapping == 1) + if (m_ExtraMapping == 1) { ++m_MajorCounter; - if(m_MajorCounter >= COUNTER_MIN_EXTRA_MAPPING && + if (m_MajorCounter >= COUNTER_MIN_EXTRA_MAPPING && m_MajorCounter > m_MinorCounter + 1) { m_ExtraMapping = 0; @@ -6068,11 +6068,11 @@ private: void PostMinorCounter() { - if(m_MinorCounter < m_MajorCounter) + if (m_MinorCounter < m_MajorCounter) { ++m_MinorCounter; } - else if(m_MajorCounter > 0) + else if (m_MajorCounter > 0) { --m_MajorCounter; --m_MinorCounter; @@ -6093,7 +6093,7 @@ public: public: // Strengthened - VkResult GetHandle(VkDevice device, VkDeviceMemory memory, decltype(&vkGetMemoryWin32HandleKHR) pvkGetMemoryWin32HandleKHR, HANDLE hTargetProcess, HANDLE* pHandle) noexcept + VkResult GetHandle(VkDevice device, VkDeviceMemory memory, decltype(&vkGetMemoryWin32HandleKHR) pvkGetMemoryWin32HandleKHR, HANDLE hTargetProcess, bool useMutex, HANDLE* pHandle) noexcept { *pHandle = VMA_NULL; // We only care about atomicity of handle retrieval, not about memory order. @@ -6108,29 +6108,19 @@ public: HANDLE hCreatedHandle = VMA_NULL; + VkResult res = VK_SUCCESS; // If failed, try to create it. - VkResult res = Create(device, memory, pvkGetMemoryWin32HandleKHR, &hCreatedHandle); - if (res == VK_SUCCESS) { - // Successfully created handle, try to set it. - if (!m_hHandle.compare_exchange_strong(handle, hCreatedHandle, std::memory_order_relaxed)) + VmaMutexLockWrite lock(m_Mutex, useMutex); + if (m_hHandle.load(std::memory_order_relaxed) == VMA_NULL) { - // AMD workaround - if (hCreatedHandle != m_hHandle.load(std::memory_order_relaxed)) - { - ::CloseHandle(hCreatedHandle); - } + res = Create(device, memory, pvkGetMemoryWin32HandleKHR, &hCreatedHandle); + m_hHandle.store(hCreatedHandle, std::memory_order_relaxed); } } - - // If somehow it was set in the meantime, return it. - if (m_hHandle.load(std::memory_order_relaxed)) - { - *pHandle = Duplicate(hTargetProcess); - return VK_SUCCESS; - } + *pHandle = Duplicate(hTargetProcess); return res; -} + } operator bool() const noexcept { return m_hHandle != VMA_NULL; } private: @@ -6164,6 +6154,7 @@ private: } private: std::atomic m_hHandle; + VMA_RW_MUTEX m_Mutex; // Protects access m_Handle }; #else class VmaWin32Handle @@ -6274,8 +6265,8 @@ struct VmaAllocation_T enum FLAGS { - FLAG_PERSISTENT_MAP = 0x01, - FLAG_MAPPING_ALLOWED = 0x02, + FLAG_PERSISTENT_MAP = 0x01, + FLAG_MAPPING_ALLOWED = 0x02, }; public: @@ -6336,12 +6327,12 @@ public: #if VMA_STATS_STRING_ENABLED VmaBufferImageUsage GetBufferImageUsage() const { return m_BufferImageUsage; } - void InitBufferUsage(const VkBufferCreateInfo &createInfo, bool useKhrMaintenance5) + void InitBufferUsage(const VkBufferCreateInfo& createInfo, bool useKhrMaintenance5) { VMA_ASSERT(m_BufferImageUsage == VmaBufferImageUsage::UNKNOWN); m_BufferImageUsage = VmaBufferImageUsage(createInfo, useKhrMaintenance5); } - void InitImageUsage(const VkImageCreateInfo &createInfo) + void InitImageUsage(const VkImageCreateInfo& createInfo) { VMA_ASSERT(m_BufferImageUsage == VmaBufferImageUsage::UNKNOWN); m_BufferImageUsage = VmaBufferImageUsage(createInfo); @@ -6485,7 +6476,7 @@ bool VmaDedicatedAllocationList::Validate() void VmaDedicatedAllocationList::AddDetailedStatistics(VmaDetailedStatistics& inoutStats) { - for(auto* item = m_AllocationList.Front(); item != VMA_NULL; item = DedicatedAllocationLinkedList::GetNext(item)) + for (auto* item = m_AllocationList.Front(); item != VMA_NULL; item = DedicatedAllocationLinkedList::GetNext(item)) { const VkDeviceSize size = item->GetSize(); inoutStats.statistics.blockCount++; @@ -6502,7 +6493,7 @@ void VmaDedicatedAllocationList::AddStatistics(VmaStatistics& inoutStats) inoutStats.blockCount += allocCount; inoutStats.allocationCount += allocCount; - for(auto* item = m_AllocationList.Front(); item != VMA_NULL; item = DedicatedAllocationLinkedList::GetNext(item)) + for (auto* item = m_AllocationList.Front(); item != VMA_NULL; item = DedicatedAllocationLinkedList::GetNext(item)) { const VkDeviceSize size = item->GetSize(); inoutStats.blockBytes += size; @@ -8027,7 +8018,7 @@ bool VmaBlockMetadata_Linear::CreateAllocationRequest( VMA_ASSERT(pAllocationRequest != VMA_NULL); VMA_HEAVY_ASSERT(Validate()); - if(allocSize > GetSize()) + if (allocSize > GetSize()) return false; pAllocationRequest->size = allocSize; @@ -9169,7 +9160,7 @@ bool VmaBlockMetadata_TLSF::CreateAllocationRequest( nextListBlock = nextListBlock->NextFree(); } } - else if (strategy & VMA_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT ) + else if (strategy & VMA_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT) { // Perform search from the start VmaStlAllocator allocator(GetAllocationCallbacks()); @@ -9716,7 +9707,7 @@ public: size_t GetBlockCount() const { return m_Blocks.size(); } // To be used only while the m_Mutex is locked. Used during defragmentation. VmaDeviceMemoryBlock* GetBlock(size_t index) const { return m_Blocks[index]; } - VMA_RW_MUTEX &GetMutex() { return m_Mutex; } + VMA_RW_MUTEX& GetMutex() { return m_Mutex; } VkResult CreateMinBlocks(); void AddStatistics(VmaStatistics& inoutStats); @@ -10125,7 +10116,7 @@ VkResult VmaVirtualBlock_T::Allocate(const VmaVirtualAllocationCreateInfo& creat VMA_SUBALLOCATION_TYPE_UNKNOWN, // type - unimportant createInfo.pUserData); outAllocation = (VmaVirtualAllocation)request.allocHandle; - if(outOffset) + if (outOffset) *outOffset = m_Metadata->GetAllocationOffset(request.allocHandle); return VK_SUCCESS; } @@ -10527,7 +10518,7 @@ static T* VmaAllocateArray(VmaAllocator hAllocator, size_t count) template static void vma_delete(VmaAllocator hAllocator, T* ptr) { - if(ptr != VMA_NULL) + if (ptr != VMA_NULL) { ptr->~T(); VmaFree(hAllocator, ptr); @@ -10537,9 +10528,9 @@ static void vma_delete(VmaAllocator hAllocator, T* ptr) template static void vma_delete_array(VmaAllocator hAllocator, T* ptr, size_t count) { - if(ptr != VMA_NULL) + if (ptr != VMA_NULL) { - for(size_t i = count; i--; ) + for (size_t i = count; i--; ) ptr[i].~T(); VmaFree(hAllocator, ptr); } @@ -10624,7 +10615,7 @@ void VmaDeviceMemoryBlock::PostAlloc(VmaAllocator hAllocator) void VmaDeviceMemoryBlock::PostFree(VmaAllocator hAllocator) { VmaMutexLock lock(m_MapAndBindMutex, hAllocator->m_UseMutex); - if(m_MappingHysteresis.PostFree()) + if (m_MappingHysteresis.PostFree()) { VMA_ASSERT(m_MappingHysteresis.GetExtraMapping() == 0); if (m_MapCount == 0) @@ -10802,7 +10793,7 @@ VkResult VmaDeviceMemoryBlock::BindImageMemory( VkResult VmaDeviceMemoryBlock::CreateWin32Handle(const VmaAllocator hAllocator, decltype(&vkGetMemoryWin32HandleKHR) pvkGetMemoryWin32HandleKHR, HANDLE hTargetProcess, HANDLE* pHandle) noexcept { VMA_ASSERT(pHandle); - return m_Handle.GetHandle(hAllocator->m_hDevice, m_hMemory, &vkGetMemoryWin32HandleKHR, hTargetProcess, pHandle); + return m_Handle.GetHandle(hAllocator->m_hDevice, m_hMemory, &vkGetMemoryWin32HandleKHR, hTargetProcess, hAllocator->m_UseMutex, pHandle); } #endif // VK_USE_PLATFORM_WIN32_KHR #endif // _VMA_DEVICE_MEMORY_BLOCK_FUNCTIONS @@ -10819,7 +10810,7 @@ VmaAllocation_T::VmaAllocation_T(bool mappingAllowed) m_MapCount{ 0 }, m_Flags{ 0 } { - if(mappingAllowed) + if (mappingAllowed) m_Flags |= (uint8_t)FLAG_MAPPING_ALLOWED; } @@ -10846,7 +10837,7 @@ void VmaAllocation_T::InitBlockAllocation( m_Alignment = alignment; m_Size = size; m_MemoryTypeIndex = memoryTypeIndex; - if(mapped) + if (mapped) { VMA_ASSERT(IsMappingAllowed() && "Mapping is not allowed on this allocation! Please use one of the new VMA_ALLOCATION_CREATE_HOST_ACCESS_* flags when creating it."); m_Flags |= (uint8_t)FLAG_PERSISTENT_MAP; @@ -10871,7 +10862,7 @@ void VmaAllocation_T::InitDedicatedAllocation( m_Size = size; m_MemoryTypeIndex = memoryTypeIndex; m_SuballocationType = (uint8_t)suballocationType; - if(pMappedData != VMA_NULL) + if (pMappedData != VMA_NULL) { VMA_ASSERT(IsMappingAllowed() && "Mapping is not allowed on this allocation! Please use one of the new VMA_ALLOCATION_CREATE_HOST_ACCESS_* flags when creating it."); m_Flags |= (uint8_t)FLAG_PERSISTENT_MAP; @@ -11115,7 +11106,7 @@ VkResult VmaAllocation_T::GetWin32Handle(VmaAllocator hAllocator, HANDLE hTarget case ALLOCATION_TYPE_BLOCK: return m_BlockAllocation.m_Block->CreateWin32Handle(hAllocator, pvkGetMemoryWin32HandleKHR, hTargetProcess, pHandle); case ALLOCATION_TYPE_DEDICATED: - return m_DedicatedAllocation.m_Handle.GetHandle(hAllocator->m_hDevice, m_DedicatedAllocation.m_hMemory, pvkGetMemoryWin32HandleKHR, hTargetProcess, pHandle); + return m_DedicatedAllocation.m_Handle.GetHandle(hAllocator->m_hDevice, m_DedicatedAllocation.m_hMemory, pvkGetMemoryWin32HandleKHR, hTargetProcess, hAllocator->m_UseMutex, pHandle); default: VMA_ASSERT(0); return VK_ERROR_FEATURE_NOT_PRESENT; @@ -11126,7 +11117,7 @@ VkResult VmaAllocation_T::GetWin32Handle(VmaAllocator hAllocator, HANDLE hTarget void VmaAllocation_T::FreeName(VmaAllocator hAllocator) { - if(m_pName) + if (m_pName) { VmaFreeString(hAllocator->GetAllocationCallbacks(), m_pName); m_pName = VMA_NULL; @@ -11337,7 +11328,7 @@ VkResult VmaBlockVector::AllocatePage( { const bool isHostVisible = (m_hAllocator->m_MemProps.memoryTypes[m_MemoryTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0; - if(isHostVisible) + if (isHostVisible) { const bool isMappingAllowed = (createInfo.flags & (VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT)) != 0; @@ -11347,7 +11338,7 @@ VkResult VmaBlockVector::AllocatePage( This way, having many blocks, we will separate mappable and non-mappable allocations, hopefully limiting the number of blocks that are mapped, which will help tools like RenderDoc. */ - for(size_t mappingI = 0; mappingI < 2; ++mappingI) + for (size_t mappingI = 0; mappingI < 2; ++mappingI) { // Forward order in m_Blocks - prefer blocks with smallest amount of free space. for (size_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex) @@ -11355,7 +11346,7 @@ VkResult VmaBlockVector::AllocatePage( VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex]; VMA_ASSERT(pCurrBlock); const bool isBlockMapped = pCurrBlock->GetMappedData() != VMA_NULL; - if((mappingI == 0) == (isMappingAllowed == isBlockMapped)) + if ((mappingI == 0) == (isMappingAllowed == isBlockMapped)) { VkResult res = AllocateFromBlock( pCurrBlock, size, alignment, createInfo.flags, createInfo.pUserData, suballocType, strategy, pAllocation); @@ -12077,7 +12068,7 @@ VkResult VmaDefragmentationContext_T::DefragmentPassEnd(VmaDefragmentationPassMo m_PassStats.bytesFreed += freedBlockSize; } - if(m_Algorithm == VMA_DEFRAGMENTATION_FLAG_ALGORITHM_EXTENSIVE_BIT && + if (m_Algorithm == VMA_DEFRAGMENTATION_FLAG_ALGORITHM_EXTENSIVE_BIT && m_AlgorithmState != VMA_NULL) { // Avoid unnecessary tries to allocate when new free block is available @@ -12112,7 +12103,7 @@ VkResult VmaDefragmentationContext_T::DefragmentPassEnd(VmaDefragmentationPassMo { do { - if(m_Algorithm == VMA_DEFRAGMENTATION_FLAG_ALGORITHM_EXTENSIVE_BIT) + if (m_Algorithm == VMA_DEFRAGMENTATION_FLAG_ALGORITHM_EXTENSIVE_BIT) { if (m_AlgorithmState != VMA_NULL) { @@ -12750,7 +12741,7 @@ bool VmaDefragmentationContext_T::MoveDataToFreeBlocks(VmaSuballocationType curr bool& texturePresent, bool& bufferPresent, bool& otherPresent) { const size_t prevMoveCount = m_Moves.size(); - for (size_t i = firstFreeBlock ; i;) + for (size_t i = firstFreeBlock; i;) { VmaDeviceMemoryBlock* block = vector.GetBlock(--i); VmaBlockMetadata* metadata = block->m_pMetadata; @@ -12809,7 +12800,7 @@ VmaPool_T::VmaPool_T( createInfo.maxBlockCount, (createInfo.flags& VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT) != 0 ? 1 : hAllocator->GetBufferImageGranularity(), createInfo.blockSize != 0, // explicitBlockSize - createInfo.flags & VMA_POOL_CREATE_ALGORITHM_MASK, // algorithm + createInfo.flags& VMA_POOL_CREATE_ALGORITHM_MASK, // algorithm createInfo.priority, VMA_MAX(hAllocator->GetMemoryTypeMinAlignment(createInfo.memoryTypeIndex), createInfo.minAllocationAlignment), createInfo.pMemoryAllocateNext), @@ -12842,17 +12833,17 @@ void VmaPool_T::SetName(const char* pName) #ifndef _VMA_ALLOCATOR_T_FUNCTIONS VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) : - m_UseMutex((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT) == 0), + m_UseMutex((pCreateInfo->flags& VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT) == 0), m_VulkanApiVersion(pCreateInfo->vulkanApiVersion != 0 ? pCreateInfo->vulkanApiVersion : VK_API_VERSION_1_0), - m_UseKhrDedicatedAllocation((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT) != 0), - m_UseKhrBindMemory2((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT) != 0), - m_UseExtMemoryBudget((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT) != 0), - m_UseAmdDeviceCoherentMemory((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT) != 0), - m_UseKhrBufferDeviceAddress((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT) != 0), - m_UseExtMemoryPriority((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT) != 0), - m_UseKhrMaintenance4((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE4_BIT) != 0), - m_UseKhrMaintenance5((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT) != 0), - m_UseKhrExternalMemoryWin32((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_EXTERNAL_MEMORY_WIN32) != 0), + m_UseKhrDedicatedAllocation((pCreateInfo->flags& VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT) != 0), + m_UseKhrBindMemory2((pCreateInfo->flags& VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT) != 0), + m_UseExtMemoryBudget((pCreateInfo->flags& VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT) != 0), + m_UseAmdDeviceCoherentMemory((pCreateInfo->flags& VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT) != 0), + m_UseKhrBufferDeviceAddress((pCreateInfo->flags& VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT) != 0), + m_UseExtMemoryPriority((pCreateInfo->flags& VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT) != 0), + m_UseKhrMaintenance4((pCreateInfo->flags& VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE4_BIT) != 0), + m_UseKhrMaintenance5((pCreateInfo->flags& VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT) != 0), + m_UseKhrExternalMemoryWin32((pCreateInfo->flags& VMA_ALLOCATOR_CREATE_KHR_EXTERNAL_MEMORY_WIN32) != 0), m_hDevice(pCreateInfo->device), m_hInstance(pCreateInfo->instance), m_AllocationCallbacksSpecified(pCreateInfo->pAllocationCallbacks != VMA_NULL), @@ -12867,13 +12858,13 @@ VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) : m_NextPoolId(0), m_GlobalMemoryTypeBits(UINT32_MAX) { - if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + if (m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) { m_UseKhrDedicatedAllocation = false; m_UseKhrBindMemory2 = false; } - if(VMA_DEBUG_DETECT_CORRUPTION) + if (VMA_DEBUG_DETECT_CORRUPTION) { // Needs to be multiply of uint32_t size because we are going to write VMA_CORRUPTION_DETECTION_MAGIC_VALUE to it. VMA_ASSERT(VMA_DEBUG_MARGIN % sizeof(uint32_t) == 0); @@ -12881,84 +12872,84 @@ VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) : VMA_ASSERT(pCreateInfo->physicalDevice && pCreateInfo->device && pCreateInfo->instance); - if(m_VulkanApiVersion < VK_MAKE_VERSION(1, 1, 0)) + if (m_VulkanApiVersion < VK_MAKE_VERSION(1, 1, 0)) { #if !(VMA_DEDICATED_ALLOCATION) - if((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT) != 0) + if ((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT) != 0) { VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT set but required extensions are disabled by preprocessor macros."); } #endif #if !(VMA_BIND_MEMORY2) - if((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT) != 0) + if ((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT) != 0) { VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT set but required extension is disabled by preprocessor macros."); } #endif } #if !(VMA_MEMORY_BUDGET) - if((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT) != 0) + if ((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT) != 0) { VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT set but required extension is disabled by preprocessor macros."); } #endif #if !(VMA_BUFFER_DEVICE_ADDRESS) - if(m_UseKhrBufferDeviceAddress) + if (m_UseKhrBufferDeviceAddress) { VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT is set but required extension or Vulkan 1.2 is not available in your Vulkan header or its support in VMA has been disabled by a preprocessor macro."); } #endif #if VMA_VULKAN_VERSION < 1003000 - if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 3, 0)) + if (m_VulkanApiVersion >= VK_MAKE_VERSION(1, 3, 0)) { VMA_ASSERT(0 && "vulkanApiVersion >= VK_API_VERSION_1_3 but required Vulkan version is disabled by preprocessor macros."); } #endif #if VMA_VULKAN_VERSION < 1002000 - if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 2, 0)) + if (m_VulkanApiVersion >= VK_MAKE_VERSION(1, 2, 0)) { VMA_ASSERT(0 && "vulkanApiVersion >= VK_API_VERSION_1_2 but required Vulkan version is disabled by preprocessor macros."); } #endif #if VMA_VULKAN_VERSION < 1001000 - if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + if (m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) { VMA_ASSERT(0 && "vulkanApiVersion >= VK_API_VERSION_1_1 but required Vulkan version is disabled by preprocessor macros."); } #endif #if !(VMA_MEMORY_PRIORITY) - if(m_UseExtMemoryPriority) + if (m_UseExtMemoryPriority) { VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT is set but required extension is not available in your Vulkan header or its support in VMA has been disabled by a preprocessor macro."); } #endif #if !(VMA_KHR_MAINTENANCE4) - if(m_UseKhrMaintenance4) + if (m_UseKhrMaintenance4) { VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE4_BIT is set but required extension is not available in your Vulkan header or its support in VMA has been disabled by a preprocessor macro."); } #endif #if !(VMA_KHR_MAINTENANCE5) - if(m_UseKhrMaintenance5) + if (m_UseKhrMaintenance5) { VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT is set but required extension is not available in your Vulkan header or its support in VMA has been disabled by a preprocessor macro."); } #endif #if !(VMA_KHR_MAINTENANCE5) - if(m_UseKhrMaintenance5) + if (m_UseKhrMaintenance5) { VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT is set but required extension is not available in your Vulkan header or its support in VMA has been disabled by a preprocessor macro."); } #endif #if !defined(VK_USE_PLATFORM_WIN32_KHR) - if(m_UseKhrExternalMemoryWin32) + if (m_UseKhrExternalMemoryWin32) { VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT is set but required extension is not available in your Vulkan header or its support in VMA has been disabled by a preprocessor macro."); } #endif - memset(&m_DeviceMemoryCallbacks, 0 ,sizeof(m_DeviceMemoryCallbacks)); + memset(&m_DeviceMemoryCallbacks, 0, sizeof(m_DeviceMemoryCallbacks)); memset(&m_PhysicalDeviceProperties, 0, sizeof(m_PhysicalDeviceProperties)); memset(&m_MemProps, 0, sizeof(m_MemProps)); @@ -12969,7 +12960,7 @@ VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) : memset(&m_TypeExternalMemoryHandleTypes, 0, sizeof(m_TypeExternalMemoryHandleTypes)); #endif // #if VMA_EXTERNAL_MEMORY - if(pCreateInfo->pDeviceMemoryCallbacks != VMA_NULL) + if (pCreateInfo->pDeviceMemoryCallbacks != VMA_NULL) { m_DeviceMemoryCallbacks.pUserData = pCreateInfo->pDeviceMemoryCallbacks->pUserData; m_DeviceMemoryCallbacks.pfnAllocate = pCreateInfo->pDeviceMemoryCallbacks->pfnAllocate; @@ -12992,22 +12983,22 @@ VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) : m_GlobalMemoryTypeBits = CalculateGlobalMemoryTypeBits(); #if VMA_EXTERNAL_MEMORY - if(pCreateInfo->pTypeExternalMemoryHandleTypes != VMA_NULL) + if (pCreateInfo->pTypeExternalMemoryHandleTypes != VMA_NULL) { memcpy(m_TypeExternalMemoryHandleTypes, pCreateInfo->pTypeExternalMemoryHandleTypes, sizeof(VkExternalMemoryHandleTypeFlagsKHR) * GetMemoryTypeCount()); } #endif // #if VMA_EXTERNAL_MEMORY - if(pCreateInfo->pHeapSizeLimit != VMA_NULL) + if (pCreateInfo->pHeapSizeLimit != VMA_NULL) { - for(uint32_t heapIndex = 0; heapIndex < GetMemoryHeapCount(); ++heapIndex) + for (uint32_t heapIndex = 0; heapIndex < GetMemoryHeapCount(); ++heapIndex) { const VkDeviceSize limit = pCreateInfo->pHeapSizeLimit[heapIndex]; - if(limit != VK_WHOLE_SIZE) + if (limit != VK_WHOLE_SIZE) { m_HeapSizeLimitMask |= 1u << heapIndex; - if(limit < m_MemProps.memoryHeaps[heapIndex].size) + if (limit < m_MemProps.memoryHeaps[heapIndex].size) { m_MemProps.memoryHeaps[heapIndex].size = limit; } @@ -13015,10 +13006,10 @@ VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) : } } - for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) + for (uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) { // Create only supported types - if((m_GlobalMemoryTypeBits & (1u << memTypeIndex)) != 0) + if ((m_GlobalMemoryTypeBits & (1u << memTypeIndex)) != 0) { const VkDeviceSize preferredBlockSize = CalcPreferredBlockSize(memTypeIndex); m_pBlockVectors[memTypeIndex] = vma_new(this, VmaBlockVector)( @@ -13038,14 +13029,14 @@ VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) : // because minBlockCount is 0. } } -} + } VkResult VmaAllocator_T::Init(const VmaAllocatorCreateInfo* pCreateInfo) { VkResult res = VK_SUCCESS; #if VMA_MEMORY_BUDGET - if(m_UseExtMemoryBudget) + if (m_UseExtMemoryBudget) { UpdateVulkanBudget(); } @@ -13058,7 +13049,7 @@ VmaAllocator_T::~VmaAllocator_T() { VMA_ASSERT(m_Pools.IsEmpty()); - for(size_t memTypeIndex = GetMemoryTypeCount(); memTypeIndex--; ) + for (size_t memTypeIndex = GetMemoryTypeCount(); memTypeIndex--; ) { vma_delete(this, m_pBlockVectors[memTypeIndex]); } @@ -13070,7 +13061,7 @@ void VmaAllocator_T::ImportVulkanFunctions(const VmaVulkanFunctions* pVulkanFunc ImportVulkanFunctions_Static(); #endif - if(pVulkanFunctions != VMA_NULL) + if (pVulkanFunctions != VMA_NULL) { ImportVulkanFunctions_Custom(pVulkanFunctions); } @@ -13109,7 +13100,7 @@ void VmaAllocator_T::ImportVulkanFunctions_Static() // Vulkan 1.1 #if VMA_VULKAN_VERSION >= 1001000 - if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + if (m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) { m_VulkanFunctions.vkGetBufferMemoryRequirements2KHR = (PFN_vkGetBufferMemoryRequirements2)vkGetBufferMemoryRequirements2; m_VulkanFunctions.vkGetImageMemoryRequirements2KHR = (PFN_vkGetImageMemoryRequirements2)vkGetImageMemoryRequirements2; @@ -13119,14 +13110,14 @@ void VmaAllocator_T::ImportVulkanFunctions_Static() #endif #if VMA_VULKAN_VERSION >= 1001000 - if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + if (m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) { m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties2KHR = (PFN_vkGetPhysicalDeviceMemoryProperties2)vkGetPhysicalDeviceMemoryProperties2; } #endif #if VMA_VULKAN_VERSION >= 1003000 - if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 3, 0)) + if (m_VulkanApiVersion >= VK_MAKE_VERSION(1, 3, 0)) { m_VulkanFunctions.vkGetDeviceBufferMemoryRequirements = (PFN_vkGetDeviceBufferMemoryRequirements)vkGetDeviceBufferMemoryRequirements; m_VulkanFunctions.vkGetDeviceImageMemoryRequirements = (PFN_vkGetDeviceImageMemoryRequirements)vkGetDeviceImageMemoryRequirements; @@ -13229,7 +13220,7 @@ void VmaAllocator_T::ImportVulkanFunctions_Dynamic() VMA_FETCH_DEVICE_FUNC(vkCmdCopyBuffer, PFN_vkCmdCopyBuffer, "vkCmdCopyBuffer"); #if VMA_VULKAN_VERSION >= 1001000 - if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + if (m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) { VMA_FETCH_DEVICE_FUNC(vkGetBufferMemoryRequirements2KHR, PFN_vkGetBufferMemoryRequirements2, "vkGetBufferMemoryRequirements2"); VMA_FETCH_DEVICE_FUNC(vkGetImageMemoryRequirements2KHR, PFN_vkGetImageMemoryRequirements2, "vkGetImageMemoryRequirements2"); @@ -13239,18 +13230,18 @@ void VmaAllocator_T::ImportVulkanFunctions_Dynamic() #endif #if VMA_MEMORY_BUDGET || VMA_VULKAN_VERSION >= 1001000 - if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + if (m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) { VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, PFN_vkGetPhysicalDeviceMemoryProperties2KHR, "vkGetPhysicalDeviceMemoryProperties2"); } - else if(m_UseExtMemoryBudget) + else if (m_UseExtMemoryBudget) { VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, PFN_vkGetPhysicalDeviceMemoryProperties2KHR, "vkGetPhysicalDeviceMemoryProperties2KHR"); } #endif #if VMA_DEDICATED_ALLOCATION - if(m_UseKhrDedicatedAllocation) + if (m_UseKhrDedicatedAllocation) { VMA_FETCH_DEVICE_FUNC(vkGetBufferMemoryRequirements2KHR, PFN_vkGetBufferMemoryRequirements2KHR, "vkGetBufferMemoryRequirements2KHR"); VMA_FETCH_DEVICE_FUNC(vkGetImageMemoryRequirements2KHR, PFN_vkGetImageMemoryRequirements2KHR, "vkGetImageMemoryRequirements2KHR"); @@ -13258,7 +13249,7 @@ void VmaAllocator_T::ImportVulkanFunctions_Dynamic() #endif #if VMA_BIND_MEMORY2 - if(m_UseKhrBindMemory2) + if (m_UseKhrBindMemory2) { VMA_FETCH_DEVICE_FUNC(vkBindBufferMemory2KHR, PFN_vkBindBufferMemory2KHR, "vkBindBufferMemory2KHR"); VMA_FETCH_DEVICE_FUNC(vkBindImageMemory2KHR, PFN_vkBindImageMemory2KHR, "vkBindImageMemory2KHR"); @@ -13266,25 +13257,25 @@ void VmaAllocator_T::ImportVulkanFunctions_Dynamic() #endif // #if VMA_BIND_MEMORY2 #if VMA_MEMORY_BUDGET || VMA_VULKAN_VERSION >= 1001000 - if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + if (m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) { VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, PFN_vkGetPhysicalDeviceMemoryProperties2KHR, "vkGetPhysicalDeviceMemoryProperties2"); } - else if(m_UseExtMemoryBudget) + else if (m_UseExtMemoryBudget) { VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, PFN_vkGetPhysicalDeviceMemoryProperties2KHR, "vkGetPhysicalDeviceMemoryProperties2KHR"); } #endif // #if VMA_MEMORY_BUDGET #if VMA_VULKAN_VERSION >= 1003000 - if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 3, 0)) + if (m_VulkanApiVersion >= VK_MAKE_VERSION(1, 3, 0)) { VMA_FETCH_DEVICE_FUNC(vkGetDeviceBufferMemoryRequirements, PFN_vkGetDeviceBufferMemoryRequirements, "vkGetDeviceBufferMemoryRequirements"); VMA_FETCH_DEVICE_FUNC(vkGetDeviceImageMemoryRequirements, PFN_vkGetDeviceImageMemoryRequirements, "vkGetDeviceImageMemoryRequirements"); } #endif #if VMA_KHR_MAINTENANCE4 - if(m_UseKhrMaintenance4) + if (m_UseKhrMaintenance4) { VMA_FETCH_DEVICE_FUNC(vkGetDeviceBufferMemoryRequirements, PFN_vkGetDeviceBufferMemoryRequirementsKHR, "vkGetDeviceBufferMemoryRequirementsKHR"); VMA_FETCH_DEVICE_FUNC(vkGetDeviceImageMemoryRequirements, PFN_vkGetDeviceImageMemoryRequirementsKHR, "vkGetDeviceImageMemoryRequirementsKHR"); @@ -13323,7 +13314,7 @@ void VmaAllocator_T::ValidateVulkanFunctions() VMA_ASSERT(m_VulkanFunctions.vkCmdCopyBuffer != VMA_NULL); #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 - if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0) || m_UseKhrDedicatedAllocation) + if (m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0) || m_UseKhrDedicatedAllocation) { VMA_ASSERT(m_VulkanFunctions.vkGetBufferMemoryRequirements2KHR != VMA_NULL); VMA_ASSERT(m_VulkanFunctions.vkGetImageMemoryRequirements2KHR != VMA_NULL); @@ -13331,7 +13322,7 @@ void VmaAllocator_T::ValidateVulkanFunctions() #endif #if VMA_BIND_MEMORY2 || VMA_VULKAN_VERSION >= 1001000 - if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0) || m_UseKhrBindMemory2) + if (m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0) || m_UseKhrBindMemory2) { VMA_ASSERT(m_VulkanFunctions.vkBindBufferMemory2KHR != VMA_NULL); VMA_ASSERT(m_VulkanFunctions.vkBindImageMemory2KHR != VMA_NULL); @@ -13339,7 +13330,7 @@ void VmaAllocator_T::ValidateVulkanFunctions() #endif #if VMA_MEMORY_BUDGET || VMA_VULKAN_VERSION >= 1001000 - if(m_UseExtMemoryBudget || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + if (m_UseExtMemoryBudget || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) { VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties2KHR != VMA_NULL); } @@ -13392,10 +13383,10 @@ VkResult VmaAllocator_T::AllocateMemoryOfType( memTypeIndex, size, allocationCount); - if(res != VK_SUCCESS) + if (res != VK_SUCCESS) return res; - if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0) + if ((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0) { return AllocateDedicatedMemory( pool, @@ -13423,23 +13414,23 @@ VkResult VmaAllocator_T::AllocateMemoryOfType( (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) == 0 && (pool == VK_NULL_HANDLE || !blockVector.HasExplicitBlockSize()); - if(canAllocateDedicated) + if (canAllocateDedicated) { // Heuristics: Allocate dedicated memory if requested size if greater than half of preferred block size. - if(size > blockVector.GetPreferredBlockSize() / 2) + if (size > blockVector.GetPreferredBlockSize() / 2) { dedicatedPreferred = true; } // Protection against creating each allocation as dedicated when we reach or exceed heap size/budget, // which can quickly deplete maxMemoryAllocationCount: Don't prefer dedicated allocations when above // 3/4 of the maximum allocation count. - if(m_PhysicalDeviceProperties.limits.maxMemoryAllocationCount < UINT32_MAX / 4 && + if (m_PhysicalDeviceProperties.limits.maxMemoryAllocationCount < UINT32_MAX / 4 && m_DeviceMemoryCount.load() > m_PhysicalDeviceProperties.limits.maxMemoryAllocationCount * 3 / 4) { dedicatedPreferred = false; } - if(dedicatedPreferred) + if (dedicatedPreferred) { res = AllocateDedicatedMemory( pool, @@ -13460,7 +13451,7 @@ VkResult VmaAllocator_T::AllocateMemoryOfType( allocationCount, pAllocations, blockVector.GetAllocationNextPtr()); - if(res == VK_SUCCESS) + if (res == VK_SUCCESS) { // Succeeded: AllocateDedicatedMemory function already filled pMemory, nothing more to do here. VMA_DEBUG_LOG(" Allocated as DedicatedMemory"); @@ -13476,11 +13467,11 @@ VkResult VmaAllocator_T::AllocateMemoryOfType( suballocType, allocationCount, pAllocations); - if(res == VK_SUCCESS) + if (res == VK_SUCCESS) return VK_SUCCESS; // Try dedicated memory. - if(canAllocateDedicated && !dedicatedPreferred) + if (canAllocateDedicated && !dedicatedPreferred) { res = AllocateDedicatedMemory( pool, @@ -13501,7 +13492,7 @@ VkResult VmaAllocator_T::AllocateMemoryOfType( allocationCount, pAllocations, blockVector.GetAllocationNextPtr()); - if(res == VK_SUCCESS) + if (res == VK_SUCCESS) { // Succeeded: AllocateDedicatedMemory function already filled pMemory, nothing more to do here. VMA_DEBUG_LOG(" Allocated as DedicatedMemory"); @@ -13542,17 +13533,17 @@ VkResult VmaAllocator_T::AllocateDedicatedMemory( #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 VkMemoryDedicatedAllocateInfoKHR dedicatedAllocInfo = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR }; - if(!canAliasMemory) + if (!canAliasMemory) { - if(m_UseKhrDedicatedAllocation || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + if (m_UseKhrDedicatedAllocation || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) { - if(dedicatedBuffer != VK_NULL_HANDLE) + if (dedicatedBuffer != VK_NULL_HANDLE) { VMA_ASSERT(dedicatedImage == VK_NULL_HANDLE); dedicatedAllocInfo.buffer = dedicatedBuffer; VmaPnextChainPushFront(&allocInfo, &dedicatedAllocInfo); } - else if(dedicatedImage != VK_NULL_HANDLE) + else if (dedicatedImage != VK_NULL_HANDLE) { dedicatedAllocInfo.image = dedicatedImage; VmaPnextChainPushFront(&allocInfo, &dedicatedAllocInfo); @@ -13563,19 +13554,19 @@ VkResult VmaAllocator_T::AllocateDedicatedMemory( #if VMA_BUFFER_DEVICE_ADDRESS VkMemoryAllocateFlagsInfoKHR allocFlagsInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR }; - if(m_UseKhrBufferDeviceAddress) + if (m_UseKhrBufferDeviceAddress) { bool canContainBufferWithDeviceAddress = true; - if(dedicatedBuffer != VK_NULL_HANDLE) + if (dedicatedBuffer != VK_NULL_HANDLE) { canContainBufferWithDeviceAddress = dedicatedBufferImageUsage == VmaBufferImageUsage::UNKNOWN || dedicatedBufferImageUsage.Contains(VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT); } - else if(dedicatedImage != VK_NULL_HANDLE) + else if (dedicatedImage != VK_NULL_HANDLE) { canContainBufferWithDeviceAddress = false; } - if(canContainBufferWithDeviceAddress) + if (canContainBufferWithDeviceAddress) { allocFlagsInfo.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR; VmaPnextChainPushFront(&allocInfo, &allocFlagsInfo); @@ -13585,7 +13576,7 @@ VkResult VmaAllocator_T::AllocateDedicatedMemory( #if VMA_MEMORY_PRIORITY VkMemoryPriorityAllocateInfoEXT priorityInfo = { VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_INFO_EXT }; - if(m_UseExtMemoryPriority) + if (m_UseExtMemoryPriority) { VMA_ASSERT(priority >= 0.f && priority <= 1.f); priorityInfo.priority = priority; @@ -13597,7 +13588,7 @@ VkResult VmaAllocator_T::AllocateDedicatedMemory( // Attach VkExportMemoryAllocateInfoKHR if necessary. VkExportMemoryAllocateInfoKHR exportMemoryAllocInfo = { VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR }; exportMemoryAllocInfo.handleTypes = GetExternalMemoryHandleTypeFlags(memTypeIndex); - if(exportMemoryAllocInfo.handleTypes != 0) + if (exportMemoryAllocInfo.handleTypes != 0) { VmaPnextChainPushFront(&allocInfo, &exportMemoryAllocInfo); } @@ -13605,7 +13596,7 @@ VkResult VmaAllocator_T::AllocateDedicatedMemory( size_t allocIndex; VkResult res = VK_SUCCESS; - for(allocIndex = 0; allocIndex < allocationCount; ++allocIndex) + for (allocIndex = 0; allocIndex < allocationCount; ++allocIndex) { res = AllocateDedicatedMemoryPage( pool, @@ -13618,13 +13609,13 @@ VkResult VmaAllocator_T::AllocateDedicatedMemory( isMappingAllowed, pUserData, pAllocations + allocIndex); - if(res != VK_SUCCESS) + if (res != VK_SUCCESS) { break; } } - if(res == VK_SUCCESS) + if (res == VK_SUCCESS) { for (allocIndex = 0; allocIndex < allocationCount; ++allocIndex) { @@ -13635,7 +13626,7 @@ VkResult VmaAllocator_T::AllocateDedicatedMemory( else { // Free all already created allocations. - while(allocIndex--) + while (allocIndex--) { VmaAllocation currAlloc = pAllocations[allocIndex]; VkDeviceMemory hMemory = currAlloc->GetMemory(); @@ -13675,14 +13666,14 @@ VkResult VmaAllocator_T::AllocateDedicatedMemoryPage( { VkDeviceMemory hMemory = VK_NULL_HANDLE; VkResult res = AllocateVulkanMemory(&allocInfo, &hMemory); - if(res < 0) + if (res < 0) { VMA_DEBUG_LOG(" vkAllocateMemory FAILED"); return res; } void* pMappedData = VMA_NULL; - if(map) + if (map) { res = (*m_VulkanFunctions.vkMapMemory)( m_hDevice, @@ -13691,7 +13682,7 @@ VkResult VmaAllocator_T::AllocateDedicatedMemoryPage( VK_WHOLE_SIZE, 0, &pMappedData); - if(res < 0) + if (res < 0) { VMA_DEBUG_LOG(" vkMapMemory FAILED"); FreeVulkanMemory(memTypeIndex, size, hMemory); @@ -13706,7 +13697,7 @@ VkResult VmaAllocator_T::AllocateDedicatedMemoryPage( else (*pAllocation)->SetUserData(this, pUserData); m_Budget.AddAllocation(MemoryTypeIndexToHeapIndex(memTypeIndex), size); - if(VMA_DEBUG_INITIALIZE_ALLOCATIONS) + if (VMA_DEBUG_INITIALIZE_ALLOCATIONS) { FillAllocation(*pAllocation, VMA_ALLOCATION_FILL_PATTERN_CREATED); } @@ -13721,7 +13712,7 @@ void VmaAllocator_T::GetBufferMemoryRequirements( bool& prefersDedicatedAllocation) const { #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 - if(m_UseKhrDedicatedAllocation || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + if (m_UseKhrDedicatedAllocation || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) { VkBufferMemoryRequirementsInfo2KHR memReqInfo = { VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2_KHR }; memReqInfo.buffer = hBuffer; @@ -13735,14 +13726,14 @@ void VmaAllocator_T::GetBufferMemoryRequirements( memReq = memReq2.memoryRequirements; requiresDedicatedAllocation = (memDedicatedReq.requiresDedicatedAllocation != VK_FALSE); - prefersDedicatedAllocation = (memDedicatedReq.prefersDedicatedAllocation != VK_FALSE); + prefersDedicatedAllocation = (memDedicatedReq.prefersDedicatedAllocation != VK_FALSE); } else #endif // #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 { (*m_VulkanFunctions.vkGetBufferMemoryRequirements)(m_hDevice, hBuffer, &memReq); requiresDedicatedAllocation = false; - prefersDedicatedAllocation = false; + prefersDedicatedAllocation = false; } } @@ -13753,7 +13744,7 @@ void VmaAllocator_T::GetImageMemoryRequirements( bool& prefersDedicatedAllocation) const { #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 - if(m_UseKhrDedicatedAllocation || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + if (m_UseKhrDedicatedAllocation || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) { VkImageMemoryRequirementsInfo2KHR memReqInfo = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR }; memReqInfo.image = hImage; @@ -13767,14 +13758,14 @@ void VmaAllocator_T::GetImageMemoryRequirements( memReq = memReq2.memoryRequirements; requiresDedicatedAllocation = (memDedicatedReq.requiresDedicatedAllocation != VK_FALSE); - prefersDedicatedAllocation = (memDedicatedReq.prefersDedicatedAllocation != VK_FALSE); + prefersDedicatedAllocation = (memDedicatedReq.prefersDedicatedAllocation != VK_FALSE); } else #endif // #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 { (*m_VulkanFunctions.vkGetImageMemoryRequirements)(m_hDevice, hImage, &memReq); requiresDedicatedAllocation = false; - prefersDedicatedAllocation = false; + prefersDedicatedAllocation = false; } } @@ -13786,13 +13777,13 @@ VkResult VmaAllocator_T::FindMemoryTypeIndex( { memoryTypeBits &= GetGlobalMemoryTypeBits(); - if(pAllocationCreateInfo->memoryTypeBits != 0) + if (pAllocationCreateInfo->memoryTypeBits != 0) { memoryTypeBits &= pAllocationCreateInfo->memoryTypeBits; } VkMemoryPropertyFlags requiredFlags = 0, preferredFlags = 0, notPreferredFlags = 0; - if(!FindMemoryPreferences( + if (!FindMemoryPreferences( IsIntegratedGpu(), *pAllocationCreateInfo, bufImgUsage, @@ -13803,26 +13794,26 @@ VkResult VmaAllocator_T::FindMemoryTypeIndex( *pMemoryTypeIndex = UINT32_MAX; uint32_t minCost = UINT32_MAX; - for(uint32_t memTypeIndex = 0, memTypeBit = 1; + for (uint32_t memTypeIndex = 0, memTypeBit = 1; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex, memTypeBit <<= 1) { // This memory type is acceptable according to memoryTypeBits bitmask. - if((memTypeBit & memoryTypeBits) != 0) + if ((memTypeBit & memoryTypeBits) != 0) { const VkMemoryPropertyFlags currFlags = m_MemProps.memoryTypes[memTypeIndex].propertyFlags; // This memory type contains requiredFlags. - if((requiredFlags & ~currFlags) == 0) + if ((requiredFlags & ~currFlags) == 0) { // Calculate cost as number of bits from preferredFlags not present in this memory type. uint32_t currCost = VMA_COUNT_BITS_SET(preferredFlags & ~currFlags) + VMA_COUNT_BITS_SET(currFlags & notPreferredFlags); // Remember memory type with lowest cost. - if(currCost < minCost) + if (currCost < minCost) { *pMemoryTypeIndex = memTypeIndex; - if(currCost == 0) + if (currCost == 0) { return VK_SUCCESS; } @@ -13841,19 +13832,19 @@ VkResult VmaAllocator_T::CalcMemTypeParams( size_t allocationCount) { // If memory type is not HOST_VISIBLE, disable MAPPED. - if((inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0 && + if ((inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0 && (m_MemProps.memoryTypes[memTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) { inoutCreateInfo.flags &= ~VMA_ALLOCATION_CREATE_MAPPED_BIT; } - if((inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0 && + if ((inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0 && (inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT) != 0) { const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex); VmaBudget heapBudget = {}; GetHeapBudgets(&heapBudget, heapIndex, 1); - if(heapBudget.usage + size * allocationCount > heapBudget.budget) + if (heapBudget.usage + size * allocationCount > heapBudget.budget) { return VK_ERROR_OUT_OF_DEVICE_MEMORY; } @@ -13873,9 +13864,9 @@ VkResult VmaAllocator_T::CalcAllocationParams( VMA_ASSERT((((inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT) == 0 || (inoutCreateInfo.flags & (VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT)) != 0)) && "Specifying VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT requires also VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT."); - if(inoutCreateInfo.usage == VMA_MEMORY_USAGE_AUTO || inoutCreateInfo.usage == VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE || inoutCreateInfo.usage == VMA_MEMORY_USAGE_AUTO_PREFER_HOST) + if (inoutCreateInfo.usage == VMA_MEMORY_USAGE_AUTO || inoutCreateInfo.usage == VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE || inoutCreateInfo.usage == VMA_MEMORY_USAGE_AUTO_PREFER_HOST) { - if((inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0) + if ((inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0) { VMA_ASSERT((inoutCreateInfo.flags & (VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT)) != 0 && "When using VMA_ALLOCATION_CREATE_MAPPED_BIT and usage = VMA_MEMORY_USAGE_AUTO*, you must also specify VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT."); @@ -13883,15 +13874,15 @@ VkResult VmaAllocator_T::CalcAllocationParams( } // If memory is lazily allocated, it should be always dedicated. - if(dedicatedRequired || + if (dedicatedRequired || inoutCreateInfo.usage == VMA_MEMORY_USAGE_GPU_LAZILY_ALLOCATED) { inoutCreateInfo.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; } - if(inoutCreateInfo.pool != VK_NULL_HANDLE) + if (inoutCreateInfo.pool != VK_NULL_HANDLE) { - if(inoutCreateInfo.pool->m_BlockVector.HasExplicitBlockSize() && + if (inoutCreateInfo.pool->m_BlockVector.HasExplicitBlockSize() && (inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0) { VMA_ASSERT(0 && "Specifying VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT while current custom pool doesn't support dedicated allocations."); @@ -13900,14 +13891,14 @@ VkResult VmaAllocator_T::CalcAllocationParams( inoutCreateInfo.priority = inoutCreateInfo.pool->m_BlockVector.GetPriority(); } - if((inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0 && + if ((inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0 && (inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0) { VMA_ASSERT(0 && "Specifying VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT together with VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT makes no sense."); return VK_ERROR_FEATURE_NOT_PRESENT; } - if(VMA_DEBUG_ALWAYS_DEDICATED_MEMORY && + if (VMA_DEBUG_ALWAYS_DEDICATED_MEMORY && (inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0) { inoutCreateInfo.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; @@ -13917,11 +13908,11 @@ VkResult VmaAllocator_T::CalcAllocationParams( // And so does VMA_MEMORY_USAGE_UNKNOWN because it is used with custom pools. // Which specific flag is used doesn't matter. They change things only when used with VMA_MEMORY_USAGE_AUTO*. // Otherwise they just protect from assert on mapping. - if(inoutCreateInfo.usage != VMA_MEMORY_USAGE_AUTO && + if (inoutCreateInfo.usage != VMA_MEMORY_USAGE_AUTO && inoutCreateInfo.usage != VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE && inoutCreateInfo.usage != VMA_MEMORY_USAGE_AUTO_PREFER_HOST) { - if((inoutCreateInfo.flags & (VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT)) == 0) + if ((inoutCreateInfo.flags & (VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT)) == 0) { inoutCreateInfo.flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT; } @@ -13946,17 +13937,17 @@ VkResult VmaAllocator_T::AllocateMemory( VMA_ASSERT(VmaIsPow2(vkMemReq.alignment)); - if(vkMemReq.size == 0) + if (vkMemReq.size == 0) { return VK_ERROR_INITIALIZATION_FAILED; } VmaAllocationCreateInfo createInfoFinal = createInfo; VkResult res = CalcAllocationParams(createInfoFinal, requiresDedicatedAllocation, prefersDedicatedAllocation); - if(res != VK_SUCCESS) + if (res != VK_SUCCESS) return res; - if(createInfoFinal.pool != VK_NULL_HANDLE) + if (createInfoFinal.pool != VK_NULL_HANDLE) { VmaBlockVector& blockVector = createInfoFinal.pool->m_BlockVector; return AllocateMemoryOfType( @@ -13982,7 +13973,7 @@ VkResult VmaAllocator_T::AllocateMemory( uint32_t memTypeIndex = UINT32_MAX; res = FindMemoryTypeIndex(memoryTypeBits, &createInfoFinal, dedicatedBufferImageUsage, &memTypeIndex); // Can't find any single memory type matching requirements. res is VK_ERROR_FEATURE_NOT_PRESENT. - if(res != VK_SUCCESS) + if (res != VK_SUCCESS) return res; do { @@ -14004,14 +13995,14 @@ VkResult VmaAllocator_T::AllocateMemory( allocationCount, pAllocations); // Allocation succeeded - if(res == VK_SUCCESS) + if (res == VK_SUCCESS) return VK_SUCCESS; // Remove old memTypeIndex from list of possibilities. memoryTypeBits &= ~(1u << memTypeIndex); // Find alternative memTypeIndex. res = FindMemoryTypeIndex(memoryTypeBits, &createInfoFinal, dedicatedBufferImageUsage, &memTypeIndex); - } while(res == VK_SUCCESS); + } while (res == VK_SUCCESS); // No other matching memory type index could be found. // Not returning res, which is VK_ERROR_FEATURE_NOT_PRESENT, because we already failed to allocate once. @@ -14025,38 +14016,38 @@ void VmaAllocator_T::FreeMemory( { VMA_ASSERT(pAllocations); - for(size_t allocIndex = allocationCount; allocIndex--; ) + for (size_t allocIndex = allocationCount; allocIndex--; ) { VmaAllocation allocation = pAllocations[allocIndex]; - if(allocation != VK_NULL_HANDLE) + if (allocation != VK_NULL_HANDLE) { - if(VMA_DEBUG_INITIALIZE_ALLOCATIONS) + if (VMA_DEBUG_INITIALIZE_ALLOCATIONS) { FillAllocation(allocation, VMA_ALLOCATION_FILL_PATTERN_DESTROYED); } allocation->FreeName(this); - switch(allocation->GetType()) + switch (allocation->GetType()) { case VmaAllocation_T::ALLOCATION_TYPE_BLOCK: + { + VmaBlockVector* pBlockVector = VMA_NULL; + VmaPool hPool = allocation->GetParentPool(); + if (hPool != VK_NULL_HANDLE) { - VmaBlockVector* pBlockVector = VMA_NULL; - VmaPool hPool = allocation->GetParentPool(); - if(hPool != VK_NULL_HANDLE) - { - pBlockVector = &hPool->m_BlockVector; - } - else - { - const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex(); - pBlockVector = m_pBlockVectors[memTypeIndex]; - VMA_ASSERT(pBlockVector && "Trying to free memory of unsupported type!"); - } - pBlockVector->Free(allocation); + pBlockVector = &hPool->m_BlockVector; } - break; + else + { + const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex(); + pBlockVector = m_pBlockVectors[memTypeIndex]; + VMA_ASSERT(pBlockVector && "Trying to free memory of unsupported type!"); + } + pBlockVector->Free(allocation); + } + break; case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: FreeDedicatedMemory(allocation); break; @@ -14071,13 +14062,13 @@ void VmaAllocator_T::CalculateStatistics(VmaTotalStatistics* pStats) { // Initialize. VmaClearDetailedStatistics(pStats->total); - for(uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; ++i) + for (uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; ++i) VmaClearDetailedStatistics(pStats->memoryType[i]); - for(uint32_t i = 0; i < VK_MAX_MEMORY_HEAPS; ++i) + for (uint32_t i = 0; i < VK_MAX_MEMORY_HEAPS; ++i) VmaClearDetailedStatistics(pStats->memoryHeap[i]); // Process default pools. - for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) + for (uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) { VmaBlockVector* const pBlockVector = m_pBlockVectors[memTypeIndex]; if (pBlockVector != VMA_NULL) @@ -14087,7 +14078,7 @@ void VmaAllocator_T::CalculateStatistics(VmaTotalStatistics* pStats) // Process custom pools. { VmaMutexLockRead lock(m_PoolsMutex, m_UseMutex); - for(VmaPool pool = m_Pools.Front(); pool != VMA_NULL; pool = m_Pools.GetNext(pool)) + for (VmaPool pool = m_Pools.Front(); pool != VMA_NULL; pool = m_Pools.GetNext(pool)) { VmaBlockVector& blockVector = pool->m_BlockVector; const uint32_t memTypeIndex = blockVector.GetMemoryTypeIndex(); @@ -14097,20 +14088,20 @@ void VmaAllocator_T::CalculateStatistics(VmaTotalStatistics* pStats) } // Process dedicated allocations. - for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) + for (uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) { m_DedicatedAllocations[memTypeIndex].AddDetailedStatistics(pStats->memoryType[memTypeIndex]); } // Sum from memory types to memory heaps. - for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) + for (uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) { const uint32_t memHeapIndex = m_MemProps.memoryTypes[memTypeIndex].heapIndex; VmaAddDetailedStatistics(pStats->memoryHeap[memHeapIndex], pStats->memoryType[memTypeIndex]); } // Sum from memory heaps to total. - for(uint32_t memHeapIndex = 0; memHeapIndex < GetMemoryHeapCount(); ++memHeapIndex) + for (uint32_t memHeapIndex = 0; memHeapIndex < GetMemoryHeapCount(); ++memHeapIndex) VmaAddDetailedStatistics(pStats->total, pStats->memoryHeap[memHeapIndex]); VMA_ASSERT(pStats->total.statistics.allocationCount == 0 || @@ -14122,12 +14113,12 @@ void VmaAllocator_T::CalculateStatistics(VmaTotalStatistics* pStats) void VmaAllocator_T::GetHeapBudgets(VmaBudget* outBudgets, uint32_t firstHeap, uint32_t heapCount) { #if VMA_MEMORY_BUDGET - if(m_UseExtMemoryBudget) + if (m_UseExtMemoryBudget) { - if(m_Budget.m_OperationsSinceBudgetFetch < 30) + if (m_Budget.m_OperationsSinceBudgetFetch < 30) { VmaMutexLockRead lockRead(m_Budget.m_BudgetMutex, m_UseMutex); - for(uint32_t i = 0; i < heapCount; ++i, ++outBudgets) + for (uint32_t i = 0; i < heapCount; ++i, ++outBudgets) { const uint32_t heapIndex = firstHeap + i; @@ -14136,7 +14127,7 @@ void VmaAllocator_T::GetHeapBudgets(VmaBudget* outBudgets, uint32_t firstHeap, u outBudgets->statistics.blockBytes = m_Budget.m_BlockBytes[heapIndex]; outBudgets->statistics.allocationBytes = m_Budget.m_AllocationBytes[heapIndex]; - if(m_Budget.m_VulkanUsage[heapIndex] + outBudgets->statistics.blockBytes > m_Budget.m_BlockBytesAtBudgetFetch[heapIndex]) + if (m_Budget.m_VulkanUsage[heapIndex] + outBudgets->statistics.blockBytes > m_Budget.m_BlockBytesAtBudgetFetch[heapIndex]) { outBudgets->usage = m_Budget.m_VulkanUsage[heapIndex] + outBudgets->statistics.blockBytes - m_Budget.m_BlockBytesAtBudgetFetch[heapIndex]; @@ -14160,7 +14151,7 @@ void VmaAllocator_T::GetHeapBudgets(VmaBudget* outBudgets, uint32_t firstHeap, u else #endif { - for(uint32_t i = 0; i < heapCount; ++i, ++outBudgets) + for (uint32_t i = 0; i < heapCount; ++i, ++outBudgets) { const uint32_t heapIndex = firstHeap + i; @@ -14212,26 +14203,26 @@ VkResult VmaAllocator_T::CreatePool(const VmaPoolCreateInfo* pCreateInfo, VmaPoo VmaPoolCreateInfo newCreateInfo = *pCreateInfo; // Protection against uninitialized new structure member. If garbage data are left there, this pointer dereference would crash. - if(pCreateInfo->pMemoryAllocateNext) + if (pCreateInfo->pMemoryAllocateNext) { VMA_ASSERT(((const VkBaseInStructure*)pCreateInfo->pMemoryAllocateNext)->sType != 0); } - if(newCreateInfo.maxBlockCount == 0) + if (newCreateInfo.maxBlockCount == 0) { newCreateInfo.maxBlockCount = SIZE_MAX; } - if(newCreateInfo.minBlockCount > newCreateInfo.maxBlockCount) + if (newCreateInfo.minBlockCount > newCreateInfo.maxBlockCount) { return VK_ERROR_INITIALIZATION_FAILED; } // Memory type index out of range or forbidden. - if(pCreateInfo->memoryTypeIndex >= GetMemoryTypeCount() || + if (pCreateInfo->memoryTypeIndex >= GetMemoryTypeCount() || ((1u << pCreateInfo->memoryTypeIndex) & m_GlobalMemoryTypeBits) == 0) { return VK_ERROR_FEATURE_NOT_PRESENT; } - if(newCreateInfo.minAllocationAlignment > 0) + if (newCreateInfo.minAllocationAlignment > 0) { VMA_ASSERT(VmaIsPow2(newCreateInfo.minAllocationAlignment)); } @@ -14241,7 +14232,7 @@ VkResult VmaAllocator_T::CreatePool(const VmaPoolCreateInfo* pCreateInfo, VmaPoo *pPool = vma_new(this, VmaPool_T)(this, newCreateInfo, preferredBlockSize); VkResult res = (*pPool)->m_BlockVector.CreateMinBlocks(); - if(res != VK_SUCCESS) + if (res != VK_SUCCESS) { vma_delete(this, *pPool); *pPool = VMA_NULL; @@ -14288,7 +14279,7 @@ void VmaAllocator_T::SetCurrentFrameIndex(uint32_t frameIndex) m_CurrentFrameIndex.store(frameIndex); #if VMA_MEMORY_BUDGET - if(m_UseExtMemoryBudget) + if (m_UseExtMemoryBudget) { UpdateVulkanBudget(); } @@ -14305,13 +14296,13 @@ VkResult VmaAllocator_T::CheckCorruption(uint32_t memoryTypeBits) VkResult finalRes = VK_ERROR_FEATURE_NOT_PRESENT; // Process default pools. - for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) + for (uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) { VmaBlockVector* const pBlockVector = m_pBlockVectors[memTypeIndex]; - if(pBlockVector != VMA_NULL) + if (pBlockVector != VMA_NULL) { VkResult localRes = pBlockVector->CheckCorruption(); - switch(localRes) + switch (localRes) { case VK_ERROR_FEATURE_NOT_PRESENT: break; @@ -14327,12 +14318,12 @@ VkResult VmaAllocator_T::CheckCorruption(uint32_t memoryTypeBits) // Process custom pools. { VmaMutexLockRead lock(m_PoolsMutex, m_UseMutex); - for(VmaPool pool = m_Pools.Front(); pool != VMA_NULL; pool = m_Pools.GetNext(pool)) + for (VmaPool pool = m_Pools.Front(); pool != VMA_NULL; pool = m_Pools.GetNext(pool)) { - if(((1u << pool->m_BlockVector.GetMemoryTypeIndex()) & memoryTypeBits) != 0) + if (((1u << pool->m_BlockVector.GetMemoryTypeIndex()) & memoryTypeBits) != 0) { VkResult localRes = pool->m_BlockVector.CheckCorruption(); - switch(localRes) + switch (localRes) { case VK_ERROR_FEATURE_NOT_PRESENT: break; @@ -14354,7 +14345,7 @@ VkResult VmaAllocator_T::AllocateVulkanMemory(const VkMemoryAllocateInfo* pAlloc AtomicTransactionalIncrement deviceMemoryCountIncrement; const uint64_t prevDeviceMemoryCount = deviceMemoryCountIncrement.Increment(&m_DeviceMemoryCount); #if VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT - if(prevDeviceMemoryCount >= m_PhysicalDeviceProperties.limits.maxMemoryAllocationCount) + if (prevDeviceMemoryCount >= m_PhysicalDeviceProperties.limits.maxMemoryAllocationCount) { return VK_ERROR_TOO_MANY_OBJECTS; } @@ -14363,22 +14354,22 @@ VkResult VmaAllocator_T::AllocateVulkanMemory(const VkMemoryAllocateInfo* pAlloc const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(pAllocateInfo->memoryTypeIndex); // HeapSizeLimit is in effect for this heap. - if((m_HeapSizeLimitMask & (1u << heapIndex)) != 0) + if ((m_HeapSizeLimitMask & (1u << heapIndex)) != 0) { const VkDeviceSize heapSize = m_MemProps.memoryHeaps[heapIndex].size; VkDeviceSize blockBytes = m_Budget.m_BlockBytes[heapIndex]; - for(;;) + for (;;) { const VkDeviceSize blockBytesAfterAllocation = blockBytes + pAllocateInfo->allocationSize; - if(blockBytesAfterAllocation > heapSize) + if (blockBytesAfterAllocation > heapSize) { return VK_ERROR_OUT_OF_DEVICE_MEMORY; - } - if(m_Budget.m_BlockBytes[heapIndex].compare_exchange_strong(blockBytes, blockBytesAfterAllocation)) + } + if (m_Budget.m_BlockBytes[heapIndex].compare_exchange_strong(blockBytes, blockBytesAfterAllocation)) { break; } - } +} } else { @@ -14389,14 +14380,14 @@ VkResult VmaAllocator_T::AllocateVulkanMemory(const VkMemoryAllocateInfo* pAlloc // VULKAN CALL vkAllocateMemory. VkResult res = (*m_VulkanFunctions.vkAllocateMemory)(m_hDevice, pAllocateInfo, GetAllocationCallbacks(), pMemory); - if(res == VK_SUCCESS) + if (res == VK_SUCCESS) { #if VMA_MEMORY_BUDGET ++m_Budget.m_OperationsSinceBudgetFetch; #endif // Informative callback. - if(m_DeviceMemoryCallbacks.pfnAllocate != VMA_NULL) + if (m_DeviceMemoryCallbacks.pfnAllocate != VMA_NULL) { (*m_DeviceMemoryCallbacks.pfnAllocate)(this, pAllocateInfo->memoryTypeIndex, *pMemory, pAllocateInfo->allocationSize, m_DeviceMemoryCallbacks.pUserData); } @@ -14410,12 +14401,12 @@ VkResult VmaAllocator_T::AllocateVulkanMemory(const VkMemoryAllocateInfo* pAlloc } return res; -} + } void VmaAllocator_T::FreeVulkanMemory(uint32_t memoryType, VkDeviceSize size, VkDeviceMemory hMemory) { // Informative callback. - if(m_DeviceMemoryCallbacks.pfnFree != VMA_NULL) + if (m_DeviceMemoryCallbacks.pfnFree != VMA_NULL) { (*m_DeviceMemoryCallbacks.pfnFree)(this, memoryType, hMemory, size, m_DeviceMemoryCallbacks.pUserData); } @@ -14436,10 +14427,10 @@ VkResult VmaAllocator_T::BindVulkanBuffer( VkBuffer buffer, const void* pNext) { - if(pNext != VMA_NULL) + if (pNext != VMA_NULL) { #if VMA_VULKAN_VERSION >= 1001000 || VMA_BIND_MEMORY2 - if((m_UseKhrBindMemory2 || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) && + if ((m_UseKhrBindMemory2 || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) && m_VulkanFunctions.vkBindBufferMemory2KHR != VMA_NULL) { VkBindBufferMemoryInfoKHR bindBufferMemoryInfo = { VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHR }; @@ -14467,10 +14458,10 @@ VkResult VmaAllocator_T::BindVulkanImage( VkImage image, const void* pNext) { - if(pNext != VMA_NULL) + if (pNext != VMA_NULL) { #if VMA_VULKAN_VERSION >= 1001000 || VMA_BIND_MEMORY2 - if((m_UseKhrBindMemory2 || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) && + if ((m_UseKhrBindMemory2 || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) && m_VulkanFunctions.vkBindImageMemory2KHR != VMA_NULL) { VkBindImageMemoryInfoKHR bindBufferMemoryInfo = { VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHR }; @@ -14494,20 +14485,20 @@ VkResult VmaAllocator_T::BindVulkanImage( VkResult VmaAllocator_T::Map(VmaAllocation hAllocation, void** ppData) { - switch(hAllocation->GetType()) + switch (hAllocation->GetType()) { case VmaAllocation_T::ALLOCATION_TYPE_BLOCK: + { + VmaDeviceMemoryBlock* const pBlock = hAllocation->GetBlock(); + char* pBytes = VMA_NULL; + VkResult res = pBlock->Map(this, 1, (void**)&pBytes); + if (res == VK_SUCCESS) { - VmaDeviceMemoryBlock* const pBlock = hAllocation->GetBlock(); - char *pBytes = VMA_NULL; - VkResult res = pBlock->Map(this, 1, (void**)&pBytes); - if(res == VK_SUCCESS) - { - *ppData = pBytes + (ptrdiff_t)hAllocation->GetOffset(); - hAllocation->BlockAllocMap(); - } - return res; + *ppData = pBytes + (ptrdiff_t)hAllocation->GetOffset(); + hAllocation->BlockAllocMap(); } + return res; + } case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: return hAllocation->DedicatedAllocMap(this, ppData); default: @@ -14518,15 +14509,15 @@ VkResult VmaAllocator_T::Map(VmaAllocation hAllocation, void** ppData) void VmaAllocator_T::Unmap(VmaAllocation hAllocation) { - switch(hAllocation->GetType()) + switch (hAllocation->GetType()) { case VmaAllocation_T::ALLOCATION_TYPE_BLOCK: - { - VmaDeviceMemoryBlock* const pBlock = hAllocation->GetBlock(); - hAllocation->BlockAllocUnmap(); - pBlock->Unmap(this, 1); - } - break; + { + VmaDeviceMemoryBlock* const pBlock = hAllocation->GetBlock(); + hAllocation->BlockAllocUnmap(); + pBlock->Unmap(this, 1); + } + break; case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: hAllocation->DedicatedAllocUnmap(this); break; @@ -14542,7 +14533,7 @@ VkResult VmaAllocator_T::BindBufferMemory( const void* pNext) { VkResult res = VK_ERROR_UNKNOWN_COPY; - switch(hAllocation->GetType()) + switch (hAllocation->GetType()) { case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: res = BindVulkanBuffer(hAllocation->GetMemory(), allocationLocalOffset, hBuffer, pNext); @@ -14567,7 +14558,7 @@ VkResult VmaAllocator_T::BindImageMemory( const void* pNext) { VkResult res = VK_ERROR_UNKNOWN_COPY; - switch(hAllocation->GetType()) + switch (hAllocation->GetType()) { case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: res = BindVulkanImage(hAllocation->GetMemory(), allocationLocalOffset, hImage, pNext); @@ -14593,9 +14584,9 @@ VkResult VmaAllocator_T::FlushOrInvalidateAllocation( VkResult res = VK_SUCCESS; VkMappedMemoryRange memRange = {}; - if(GetFlushOrInvalidateRange(hAllocation, offset, size, memRange)) + if (GetFlushOrInvalidateRange(hAllocation, offset, size, memRange)) { - switch(op) + switch (op) { case VMA_CACHE_FLUSH: res = (*GetVulkanFunctions().vkFlushMappedMemoryRanges)(m_hDevice, 1, &memRange); @@ -14621,22 +14612,22 @@ VkResult VmaAllocator_T::FlushOrInvalidateAllocations( typedef VmaSmallVector RangeVector; RangeVector ranges = RangeVector(RangeAllocator(GetAllocationCallbacks())); - for(uint32_t allocIndex = 0; allocIndex < allocationCount; ++allocIndex) + for (uint32_t allocIndex = 0; allocIndex < allocationCount; ++allocIndex) { const VmaAllocation alloc = allocations[allocIndex]; const VkDeviceSize offset = offsets != VMA_NULL ? offsets[allocIndex] : 0; const VkDeviceSize size = sizes != VMA_NULL ? sizes[allocIndex] : VK_WHOLE_SIZE; VkMappedMemoryRange newRange; - if(GetFlushOrInvalidateRange(alloc, offset, size, newRange)) + if (GetFlushOrInvalidateRange(alloc, offset, size, newRange)) { ranges.push_back(newRange); } } VkResult res = VK_SUCCESS; - if(!ranges.empty()) + if (!ranges.empty()) { - switch(op) + switch (op) { case VMA_CACHE_FLUSH: res = (*GetVulkanFunctions().vkFlushMappedMemoryRanges)(m_hDevice, (uint32_t)ranges.size(), ranges.data()); @@ -14660,7 +14651,7 @@ VkResult VmaAllocator_T::CopyMemoryToAllocation( { void* dstMappedData = VMA_NULL; VkResult res = Map(dstAllocation, &dstMappedData); - if(res == VK_SUCCESS) + if (res == VK_SUCCESS) { memcpy((char*)dstMappedData + dstAllocationLocalOffset, pSrcHostPointer, (size_t)size); Unmap(dstAllocation); @@ -14677,10 +14668,10 @@ VkResult VmaAllocator_T::CopyAllocationToMemory( { void* srcMappedData = VMA_NULL; VkResult res = Map(srcAllocation, &srcMappedData); - if(res == VK_SUCCESS) + if (res == VK_SUCCESS) { res = FlushOrInvalidateAllocation(srcAllocation, srcAllocationLocalOffset, size, VMA_CACHE_INVALIDATE); - if(res == VK_SUCCESS) + if (res == VK_SUCCESS) { memcpy(pDstHostPointer, (const char*)srcMappedData + srcAllocationLocalOffset, (size_t)size); Unmap(srcAllocation); @@ -14695,7 +14686,7 @@ void VmaAllocator_T::FreeDedicatedMemory(const VmaAllocation allocation) const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex(); VmaPool parentPool = allocation->GetParentPool(); - if(parentPool == VK_NULL_HANDLE) + if (parentPool == VK_NULL_HANDLE) { // Default pool m_DedicatedAllocations[memTypeIndex].Unregister(allocation); @@ -14737,7 +14728,7 @@ uint32_t VmaAllocator_T::CalculateGpuDefragmentationMemoryTypeBits() const VkBuffer buf = VK_NULL_HANDLE; VkResult res = (*GetVulkanFunctions().vkCreateBuffer)( m_hDevice, &dummyBufCreateInfo, GetAllocationCallbacks(), &buf); - if(res == VK_SUCCESS) + if (res == VK_SUCCESS) { // Query for supported memory types. VkMemoryRequirements memReq; @@ -14758,12 +14749,12 @@ uint32_t VmaAllocator_T::CalculateGlobalMemoryTypeBits() const uint32_t memoryTypeBits = UINT32_MAX; - if(!m_UseAmdDeviceCoherentMemory) + if (!m_UseAmdDeviceCoherentMemory) { // Exclude memory types that have VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD. - for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) + for (uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) { - if((m_MemProps.memoryTypes[memTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY) != 0) + if ((m_MemProps.memoryTypes[memTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY) != 0) { memoryTypeBits &= ~(1u << memTypeIndex); } @@ -14779,7 +14770,7 @@ bool VmaAllocator_T::GetFlushOrInvalidateRange( VkMappedMemoryRange& outRange) const { const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex(); - if(size > 0 && IsMemoryTypeNonCoherent(memTypeIndex)) + if (size > 0 && IsMemoryTypeNonCoherent(memTypeIndex)) { const VkDeviceSize nonCoherentAtomSize = m_PhysicalDeviceProperties.limits.nonCoherentAtomSize; const VkDeviceSize allocationSize = allocation->GetSize(); @@ -14789,11 +14780,11 @@ bool VmaAllocator_T::GetFlushOrInvalidateRange( outRange.pNext = VMA_NULL; outRange.memory = allocation->GetMemory(); - switch(allocation->GetType()) + switch (allocation->GetType()) { case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: outRange.offset = VmaAlignDown(offset, nonCoherentAtomSize); - if(size == VK_WHOLE_SIZE) + if (size == VK_WHOLE_SIZE) { outRange.size = allocationSize - outRange.offset; } @@ -14809,7 +14800,7 @@ bool VmaAllocator_T::GetFlushOrInvalidateRange( { // 1. Still within this allocation. outRange.offset = VmaAlignDown(offset, nonCoherentAtomSize); - if(size == VK_WHOLE_SIZE) + if (size == VK_WHOLE_SIZE) { size = allocationSize - offset; } @@ -14851,22 +14842,22 @@ void VmaAllocator_T::UpdateVulkanBudget() { VmaMutexLockWrite lockWrite(m_Budget.m_BudgetMutex, m_UseMutex); - for(uint32_t heapIndex = 0; heapIndex < GetMemoryHeapCount(); ++heapIndex) + for (uint32_t heapIndex = 0; heapIndex < GetMemoryHeapCount(); ++heapIndex) { m_Budget.m_VulkanUsage[heapIndex] = budgetProps.heapUsage[heapIndex]; m_Budget.m_VulkanBudget[heapIndex] = budgetProps.heapBudget[heapIndex]; m_Budget.m_BlockBytesAtBudgetFetch[heapIndex] = m_Budget.m_BlockBytes[heapIndex].load(); // Some bugged drivers return the budget incorrectly, e.g. 0 or much bigger than heap size. - if(m_Budget.m_VulkanBudget[heapIndex] == 0) + if (m_Budget.m_VulkanBudget[heapIndex] == 0) { m_Budget.m_VulkanBudget[heapIndex] = m_MemProps.memoryHeaps[heapIndex].size * 8 / 10; // 80% heuristics. } - else if(m_Budget.m_VulkanBudget[heapIndex] > m_MemProps.memoryHeaps[heapIndex].size) + else if (m_Budget.m_VulkanBudget[heapIndex] > m_MemProps.memoryHeaps[heapIndex].size) { m_Budget.m_VulkanBudget[heapIndex] = m_MemProps.memoryHeaps[heapIndex].size; } - if(m_Budget.m_VulkanUsage[heapIndex] == 0 && m_Budget.m_BlockBytesAtBudgetFetch[heapIndex] > 0) + if (m_Budget.m_VulkanUsage[heapIndex] == 0 && m_Budget.m_BlockBytesAtBudgetFetch[heapIndex] > 0) { m_Budget.m_VulkanUsage[heapIndex] = m_Budget.m_BlockBytesAtBudgetFetch[heapIndex]; } @@ -14878,13 +14869,13 @@ void VmaAllocator_T::UpdateVulkanBudget() void VmaAllocator_T::FillAllocation(const VmaAllocation hAllocation, uint8_t pattern) { - if(VMA_DEBUG_INITIALIZE_ALLOCATIONS && + if (VMA_DEBUG_INITIALIZE_ALLOCATIONS && hAllocation->IsMappingAllowed() && (m_MemProps.memoryTypes[hAllocation->GetMemoryTypeIndex()].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0) { void* pData = VMA_NULL; VkResult res = Map(hAllocation, &pData); - if(res == VK_SUCCESS) + if (res == VK_SUCCESS) { memset(pData, (int)pattern, (size_t)hAllocation->GetSize()); FlushOrInvalidateAllocation(hAllocation, 0, VK_WHOLE_SIZE, VMA_CACHE_FLUSH); @@ -14900,7 +14891,7 @@ void VmaAllocator_T::FillAllocation(const VmaAllocation hAllocation, uint8_t pat uint32_t VmaAllocator_T::GetGpuDefragmentationMemoryTypeBits() { uint32_t memoryTypeBits = m_GpuDefragmentationMemoryTypeBits.load(); - if(memoryTypeBits == UINT32_MAX) + if (memoryTypeBits == UINT32_MAX) { memoryTypeBits = CalculateGpuDefragmentationMemoryTypeBits(); m_GpuDefragmentationMemoryTypeBits.store(memoryTypeBits); @@ -15011,7 +15002,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAllocator( VMA_DEBUG_LOG("vmaCreateAllocator"); *pAllocator = vma_new(pCreateInfo->pAllocationCallbacks, VmaAllocator_T)(pCreateInfo); VkResult result = (*pAllocator)->Init(pCreateInfo); - if(result < 0) + if (result < 0) { vma_delete(pCreateInfo->pAllocationCallbacks, *pAllocator); *pAllocator = VK_NULL_HANDLE; @@ -15022,7 +15013,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAllocator( VMA_CALL_PRE void VMA_CALL_POST vmaDestroyAllocator( VmaAllocator allocator) { - if(allocator != VK_NULL_HANDLE) + if (allocator != VK_NULL_HANDLE) { VMA_DEBUG_LOG("vmaDestroyAllocator"); VkAllocationCallbacks allocationCallbacks = allocator->m_AllocationCallbacks; // Have to copy the callbacks when destroying. @@ -15040,7 +15031,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocatorInfo(VmaAllocator allocator, VmaA VMA_CALL_PRE void VMA_CALL_POST vmaGetPhysicalDeviceProperties( VmaAllocator allocator, - const VkPhysicalDeviceProperties **ppPhysicalDeviceProperties) + const VkPhysicalDeviceProperties** ppPhysicalDeviceProperties) { VMA_ASSERT(allocator && ppPhysicalDeviceProperties); *ppPhysicalDeviceProperties = &allocator->m_PhysicalDeviceProperties; @@ -15072,7 +15063,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaSetCurrentFrameIndex( VMA_DEBUG_GLOBAL_MUTEX_LOCK - allocator->SetCurrentFrameIndex(frameIndex); + allocator->SetCurrentFrameIndex(frameIndex); } VMA_CALL_PRE void VMA_CALL_POST vmaCalculateStatistics( @@ -15081,7 +15072,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaCalculateStatistics( { VMA_ASSERT(allocator && pStats); VMA_DEBUG_GLOBAL_MUTEX_LOCK - allocator->CalculateStatistics(pStats); + allocator->CalculateStatistics(pStats); } VMA_CALL_PRE void VMA_CALL_POST vmaGetHeapBudgets( @@ -15090,7 +15081,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaGetHeapBudgets( { VMA_ASSERT(allocator && pBudgets); VMA_DEBUG_GLOBAL_MUTEX_LOCK - allocator->GetHeapBudgets(pBudgets, 0, allocator->GetMemoryHeapCount()); + allocator->GetHeapBudgets(pBudgets, 0, allocator->GetMemoryHeapCount()); } #if VMA_STATS_STRING_ENABLED @@ -15103,7 +15094,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaBuildStatsString( VMA_ASSERT(allocator && ppStatsString); VMA_DEBUG_GLOBAL_MUTEX_LOCK - VmaStringBuilder sb(allocator->GetAllocationCallbacks()); + VmaStringBuilder sb(allocator->GetAllocationCallbacks()); { VmaBudget budgets[VK_MAX_MEMORY_HEAPS]; allocator->GetHeapBudgets(budgets, 0, allocator->GetMemoryHeapCount()); @@ -15172,16 +15163,16 @@ VMA_CALL_PRE void VMA_CALL_POST vmaBuildStatsString( { if (heapInfo.flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) json.WriteString("DEVICE_LOCAL"); - #if VMA_VULKAN_VERSION >= 1001000 +#if VMA_VULKAN_VERSION >= 1001000 if (heapInfo.flags & VK_MEMORY_HEAP_MULTI_INSTANCE_BIT) json.WriteString("MULTI_INSTANCE"); - #endif +#endif VkMemoryHeapFlags flags = heapInfo.flags & ~(VK_MEMORY_HEAP_DEVICE_LOCAL_BIT - #if VMA_VULKAN_VERSION >= 1001000 +#if VMA_VULKAN_VERSION >= 1001000 | VK_MEMORY_HEAP_MULTI_INSTANCE_BIT - #endif +#endif ); if (flags != 0) json.WriteNumber(flags); @@ -15230,25 +15221,25 @@ VMA_CALL_PRE void VMA_CALL_POST vmaBuildStatsString( json.WriteString("HOST_CACHED"); if (flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) json.WriteString("LAZILY_ALLOCATED"); - #if VMA_VULKAN_VERSION >= 1001000 +#if VMA_VULKAN_VERSION >= 1001000 if (flags & VK_MEMORY_PROPERTY_PROTECTED_BIT) json.WriteString("PROTECTED"); - #endif - #if VK_AMD_device_coherent_memory +#endif +#if VK_AMD_device_coherent_memory if (flags & VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY) json.WriteString("DEVICE_COHERENT_AMD"); if (flags & VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD_COPY) json.WriteString("DEVICE_UNCACHED_AMD"); - #endif +#endif flags &= ~(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT - #if VMA_VULKAN_VERSION >= 1001000 +#if VMA_VULKAN_VERSION >= 1001000 | VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT - #endif - #if VK_AMD_device_coherent_memory +#endif +#if VK_AMD_device_coherent_memory | VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY | VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD_COPY - #endif +#endif | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT); @@ -15286,7 +15277,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaFreeStatsString( VmaAllocator allocator, char* pStatsString) { - if(pStatsString != VMA_NULL) + if (pStatsString != VMA_NULL) { VMA_ASSERT(allocator); VmaFreeString(allocator->GetAllocationCallbacks(), pStatsString); @@ -15327,13 +15318,13 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForBufferInfo( VkResult res; #if VMA_KHR_MAINTENANCE4 || VMA_VULKAN_VERSION >= 1003000 - if(funcs->vkGetDeviceBufferMemoryRequirements) + if (funcs->vkGetDeviceBufferMemoryRequirements) { // Can query straight from VkBufferCreateInfo :) - VkDeviceBufferMemoryRequirementsKHR devBufMemReq = {VK_STRUCTURE_TYPE_DEVICE_BUFFER_MEMORY_REQUIREMENTS_KHR}; + VkDeviceBufferMemoryRequirementsKHR devBufMemReq = { VK_STRUCTURE_TYPE_DEVICE_BUFFER_MEMORY_REQUIREMENTS_KHR }; devBufMemReq.pCreateInfo = pBufferCreateInfo; - VkMemoryRequirements2 memReq = {VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2}; + VkMemoryRequirements2 memReq = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2 }; (*funcs->vkGetDeviceBufferMemoryRequirements)(hDev, &devBufMemReq, &memReq); res = allocator->FindMemoryTypeIndex( @@ -15347,7 +15338,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForBufferInfo( VkBuffer hBuffer = VK_NULL_HANDLE; res = funcs->vkCreateBuffer( hDev, pBufferCreateInfo, allocator->GetAllocationCallbacks(), &hBuffer); - if(res == VK_SUCCESS) + if (res == VK_SUCCESS) { VkMemoryRequirements memReq = {}; funcs->vkGetBufferMemoryRequirements(hDev, hBuffer, &memReq); @@ -15379,15 +15370,15 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForImageInfo( VkResult res; #if VMA_KHR_MAINTENANCE4 || VMA_VULKAN_VERSION >= 1003000 - if(funcs->vkGetDeviceImageMemoryRequirements) + if (funcs->vkGetDeviceImageMemoryRequirements) { // Can query straight from VkImageCreateInfo :) - VkDeviceImageMemoryRequirementsKHR devImgMemReq = {VK_STRUCTURE_TYPE_DEVICE_IMAGE_MEMORY_REQUIREMENTS_KHR}; + VkDeviceImageMemoryRequirementsKHR devImgMemReq = { VK_STRUCTURE_TYPE_DEVICE_IMAGE_MEMORY_REQUIREMENTS_KHR }; devImgMemReq.pCreateInfo = pImageCreateInfo; VMA_ASSERT(pImageCreateInfo->tiling != VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT_COPY && (pImageCreateInfo->flags & VK_IMAGE_CREATE_DISJOINT_BIT_COPY) == 0 && "Cannot use this VkImageCreateInfo with vmaFindMemoryTypeIndexForImageInfo as I don't know what to pass as VkDeviceImageMemoryRequirements::planeAspect."); - VkMemoryRequirements2 memReq = {VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2}; + VkMemoryRequirements2 memReq = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2 }; (*funcs->vkGetDeviceImageMemoryRequirements)(hDev, &devImgMemReq, &memReq); res = allocator->FindMemoryTypeIndex( @@ -15401,7 +15392,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForImageInfo( VkImage hImage = VK_NULL_HANDLE; res = funcs->vkCreateImage( hDev, pImageCreateInfo, allocator->GetAllocationCallbacks(), &hImage); - if(res == VK_SUCCESS) + if (res == VK_SUCCESS) { VkMemoryRequirements memReq = {}; funcs->vkGetImageMemoryRequirements(hDev, hImage, &memReq); @@ -15428,7 +15419,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreatePool( VMA_DEBUG_GLOBAL_MUTEX_LOCK - return allocator->CreatePool(pCreateInfo, pPool); + return allocator->CreatePool(pCreateInfo, pPool); } VMA_CALL_PRE void VMA_CALL_POST vmaDestroyPool( @@ -15437,7 +15428,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaDestroyPool( { VMA_ASSERT(allocator); - if(pool == VK_NULL_HANDLE) + if (pool == VK_NULL_HANDLE) { return; } @@ -15446,7 +15437,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaDestroyPool( VMA_DEBUG_GLOBAL_MUTEX_LOCK - allocator->DestroyPool(pool); + allocator->DestroyPool(pool); } VMA_CALL_PRE void VMA_CALL_POST vmaGetPoolStatistics( @@ -15458,7 +15449,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaGetPoolStatistics( VMA_DEBUG_GLOBAL_MUTEX_LOCK - allocator->GetPoolStatistics(pool, pPoolStats); + allocator->GetPoolStatistics(pool, pPoolStats); } VMA_CALL_PRE void VMA_CALL_POST vmaCalculatePoolStatistics( @@ -15470,7 +15461,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaCalculatePoolStatistics( VMA_DEBUG_GLOBAL_MUTEX_LOCK - allocator->CalculatePoolStatistics(pool, pPoolStats); + allocator->CalculatePoolStatistics(pool, pPoolStats); } VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckPoolCorruption(VmaAllocator allocator, VmaPool pool) @@ -15479,7 +15470,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckPoolCorruption(VmaAllocator allocato VMA_DEBUG_GLOBAL_MUTEX_LOCK - VMA_DEBUG_LOG("vmaCheckPoolCorruption"); + VMA_DEBUG_LOG("vmaCheckPoolCorruption"); return allocator->CheckPoolCorruption(pool); } @@ -15495,7 +15486,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaGetPoolName( VMA_DEBUG_GLOBAL_MUTEX_LOCK - *ppName = pool->GetName(); + * ppName = pool->GetName(); } VMA_CALL_PRE void VMA_CALL_POST vmaSetPoolName( @@ -15509,7 +15500,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaSetPoolName( VMA_DEBUG_GLOBAL_MUTEX_LOCK - pool->SetName(pName); + pool->SetName(pName); } VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemory( @@ -15525,19 +15516,19 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemory( VMA_DEBUG_GLOBAL_MUTEX_LOCK - VkResult result = allocator->AllocateMemory( - *pVkMemoryRequirements, - false, // requiresDedicatedAllocation - false, // prefersDedicatedAllocation - VK_NULL_HANDLE, // dedicatedBuffer - VK_NULL_HANDLE, // dedicatedImage - VmaBufferImageUsage::UNKNOWN, // dedicatedBufferImageUsage - *pCreateInfo, - VMA_SUBALLOCATION_TYPE_UNKNOWN, - 1, // allocationCount - pAllocation); + VkResult result = allocator->AllocateMemory( + *pVkMemoryRequirements, + false, // requiresDedicatedAllocation + false, // prefersDedicatedAllocation + VK_NULL_HANDLE, // dedicatedBuffer + VK_NULL_HANDLE, // dedicatedImage + VmaBufferImageUsage::UNKNOWN, // dedicatedBufferImageUsage + *pCreateInfo, + VMA_SUBALLOCATION_TYPE_UNKNOWN, + 1, // allocationCount + pAllocation); - if(pAllocationInfo != VMA_NULL && result == VK_SUCCESS) + if (pAllocationInfo != VMA_NULL && result == VK_SUCCESS) { allocator->GetAllocationInfo(*pAllocation, pAllocationInfo); } @@ -15553,7 +15544,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryPages( VmaAllocation* pAllocations, VmaAllocationInfo* pAllocationInfo) { - if(allocationCount == 0) + if (allocationCount == 0) { return VK_SUCCESS; } @@ -15564,21 +15555,21 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryPages( VMA_DEBUG_GLOBAL_MUTEX_LOCK - VkResult result = allocator->AllocateMemory( - *pVkMemoryRequirements, - false, // requiresDedicatedAllocation - false, // prefersDedicatedAllocation - VK_NULL_HANDLE, // dedicatedBuffer - VK_NULL_HANDLE, // dedicatedImage - VmaBufferImageUsage::UNKNOWN, // dedicatedBufferImageUsage - *pCreateInfo, - VMA_SUBALLOCATION_TYPE_UNKNOWN, - allocationCount, - pAllocations); + VkResult result = allocator->AllocateMemory( + *pVkMemoryRequirements, + false, // requiresDedicatedAllocation + false, // prefersDedicatedAllocation + VK_NULL_HANDLE, // dedicatedBuffer + VK_NULL_HANDLE, // dedicatedImage + VmaBufferImageUsage::UNKNOWN, // dedicatedBufferImageUsage + *pCreateInfo, + VMA_SUBALLOCATION_TYPE_UNKNOWN, + allocationCount, + pAllocations); - if(pAllocationInfo != VMA_NULL && result == VK_SUCCESS) + if (pAllocationInfo != VMA_NULL && result == VK_SUCCESS) { - for(size_t i = 0; i < allocationCount; ++i) + for (size_t i = 0; i < allocationCount; ++i) { allocator->GetAllocationInfo(pAllocations[i], pAllocationInfo + i); } @@ -15600,7 +15591,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForBuffer( VMA_DEBUG_GLOBAL_MUTEX_LOCK - VkMemoryRequirements vkMemReq = {}; + VkMemoryRequirements vkMemReq = {}; bool requiresDedicatedAllocation = false; bool prefersDedicatedAllocation = false; allocator->GetBufferMemoryRequirements(buffer, vkMemReq, @@ -15619,7 +15610,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForBuffer( 1, // allocationCount pAllocation); - if(pAllocationInfo && result == VK_SUCCESS) + if (pAllocationInfo && result == VK_SUCCESS) { allocator->GetAllocationInfo(*pAllocation, pAllocationInfo); } @@ -15640,9 +15631,9 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForImage( VMA_DEBUG_GLOBAL_MUTEX_LOCK - VkMemoryRequirements vkMemReq = {}; + VkMemoryRequirements vkMemReq = {}; bool requiresDedicatedAllocation = false; - bool prefersDedicatedAllocation = false; + bool prefersDedicatedAllocation = false; allocator->GetImageMemoryRequirements(image, vkMemReq, requiresDedicatedAllocation, prefersDedicatedAllocation); @@ -15658,7 +15649,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForImage( 1, // allocationCount pAllocation); - if(pAllocationInfo && result == VK_SUCCESS) + if (pAllocationInfo && result == VK_SUCCESS) { allocator->GetAllocationInfo(*pAllocation, pAllocationInfo); } @@ -15672,7 +15663,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemory( { VMA_ASSERT(allocator); - if(allocation == VK_NULL_HANDLE) + if (allocation == VK_NULL_HANDLE) { return; } @@ -15681,9 +15672,9 @@ VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemory( VMA_DEBUG_GLOBAL_MUTEX_LOCK - allocator->FreeMemory( - 1, // allocationCount - &allocation); + allocator->FreeMemory( + 1, // allocationCount + &allocation); } VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemoryPages( @@ -15691,7 +15682,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemoryPages( size_t allocationCount, const VmaAllocation* pAllocations) { - if(allocationCount == 0) + if (allocationCount == 0) { return; } @@ -15702,7 +15693,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemoryPages( VMA_DEBUG_GLOBAL_MUTEX_LOCK - allocator->FreeMemory(allocationCount, pAllocations); + allocator->FreeMemory(allocationCount, pAllocations); } VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationInfo( @@ -15714,7 +15705,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationInfo( VMA_DEBUG_GLOBAL_MUTEX_LOCK - allocator->GetAllocationInfo(allocation, pAllocationInfo); + allocator->GetAllocationInfo(allocation, pAllocationInfo); } VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationInfo2( @@ -15726,7 +15717,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationInfo2( VMA_DEBUG_GLOBAL_MUTEX_LOCK - allocator->GetAllocationInfo2(allocation, pAllocationInfo); + allocator->GetAllocationInfo2(allocation, pAllocationInfo); } VMA_CALL_PRE void VMA_CALL_POST vmaSetAllocationUserData( @@ -15738,7 +15729,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaSetAllocationUserData( VMA_DEBUG_GLOBAL_MUTEX_LOCK - allocation->SetUserData(allocator, pUserData); + allocation->SetUserData(allocator, pUserData); } VMA_CALL_PRE void VMA_CALL_POST vmaSetAllocationName( @@ -15768,7 +15759,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaMapMemory( VMA_DEBUG_GLOBAL_MUTEX_LOCK - return allocator->Map(allocation, ppData); + return allocator->Map(allocation, ppData); } VMA_CALL_PRE void VMA_CALL_POST vmaUnmapMemory( @@ -15779,7 +15770,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaUnmapMemory( VMA_DEBUG_GLOBAL_MUTEX_LOCK - allocator->Unmap(allocation); + allocator->Unmap(allocation); } VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocation( @@ -15794,7 +15785,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocation( VMA_DEBUG_GLOBAL_MUTEX_LOCK - return allocator->FlushOrInvalidateAllocation(allocation, offset, size, VMA_CACHE_FLUSH); + return allocator->FlushOrInvalidateAllocation(allocation, offset, size, VMA_CACHE_FLUSH); } VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocation( @@ -15809,7 +15800,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocation( VMA_DEBUG_GLOBAL_MUTEX_LOCK - return allocator->FlushOrInvalidateAllocation(allocation, offset, size, VMA_CACHE_INVALIDATE); + return allocator->FlushOrInvalidateAllocation(allocation, offset, size, VMA_CACHE_INVALIDATE); } VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocations( @@ -15821,7 +15812,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocations( { VMA_ASSERT(allocator); - if(allocationCount == 0) + if (allocationCount == 0) { return VK_SUCCESS; } @@ -15832,7 +15823,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocations( VMA_DEBUG_GLOBAL_MUTEX_LOCK - return allocator->FlushOrInvalidateAllocations(allocationCount, allocations, offsets, sizes, VMA_CACHE_FLUSH); + return allocator->FlushOrInvalidateAllocations(allocationCount, allocations, offsets, sizes, VMA_CACHE_FLUSH); } VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocations( @@ -15844,7 +15835,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocations( { VMA_ASSERT(allocator); - if(allocationCount == 0) + if (allocationCount == 0) { return VK_SUCCESS; } @@ -15855,7 +15846,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocations( VMA_DEBUG_GLOBAL_MUTEX_LOCK - return allocator->FlushOrInvalidateAllocations(allocationCount, allocations, offsets, sizes, VMA_CACHE_INVALIDATE); + return allocator->FlushOrInvalidateAllocations(allocationCount, allocations, offsets, sizes, VMA_CACHE_INVALIDATE); } VMA_CALL_PRE VkResult VMA_CALL_POST vmaCopyMemoryToAllocation( @@ -15867,7 +15858,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCopyMemoryToAllocation( { VMA_ASSERT(allocator && pSrcHostPointer && dstAllocation); - if(size == 0) + if (size == 0) { return VK_SUCCESS; } @@ -15876,7 +15867,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCopyMemoryToAllocation( VMA_DEBUG_GLOBAL_MUTEX_LOCK - return allocator->CopyMemoryToAllocation(pSrcHostPointer, dstAllocation, dstAllocationLocalOffset, size); + return allocator->CopyMemoryToAllocation(pSrcHostPointer, dstAllocation, dstAllocationLocalOffset, size); } VMA_CALL_PRE VkResult VMA_CALL_POST vmaCopyAllocationToMemory( @@ -15888,7 +15879,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCopyAllocationToMemory( { VMA_ASSERT(allocator && srcAllocation && pDstHostPointer); - if(size == 0) + if (size == 0) { return VK_SUCCESS; } @@ -15897,7 +15888,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCopyAllocationToMemory( VMA_DEBUG_GLOBAL_MUTEX_LOCK - return allocator->CopyAllocationToMemory(srcAllocation, srcAllocationLocalOffset, pDstHostPointer, size); + return allocator->CopyAllocationToMemory(srcAllocation, srcAllocationLocalOffset, pDstHostPointer, size); } VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckCorruption( @@ -15910,7 +15901,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckCorruption( VMA_DEBUG_GLOBAL_MUTEX_LOCK - return allocator->CheckCorruption(memoryTypeBits); + return allocator->CheckCorruption(memoryTypeBits); } VMA_CALL_PRE VkResult VMA_CALL_POST vmaBeginDefragmentation( @@ -15931,7 +15922,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaBeginDefragmentation( VMA_DEBUG_GLOBAL_MUTEX_LOCK - *pContext = vma_new(allocator, VmaDefragmentationContext_T)(allocator, *pInfo); + * pContext = vma_new(allocator, VmaDefragmentationContext_T)(allocator, *pInfo); return VK_SUCCESS; } @@ -15946,8 +15937,8 @@ VMA_CALL_PRE void VMA_CALL_POST vmaEndDefragmentation( VMA_DEBUG_GLOBAL_MUTEX_LOCK - if (pStats) - context->GetStats(*pStats); + if (pStats) + context->GetStats(*pStats); vma_delete(allocator, context); } @@ -15962,7 +15953,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaBeginDefragmentationPass( VMA_DEBUG_GLOBAL_MUTEX_LOCK - return context->DefragmentPassBegin(*pPassInfo); + return context->DefragmentPassBegin(*pPassInfo); } VMA_CALL_PRE VkResult VMA_CALL_POST vmaEndDefragmentationPass( @@ -15976,7 +15967,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaEndDefragmentationPass( VMA_DEBUG_GLOBAL_MUTEX_LOCK - return context->DefragmentPassEnd(*pPassInfo); + return context->DefragmentPassEnd(*pPassInfo); } VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory( @@ -15990,7 +15981,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory( VMA_DEBUG_GLOBAL_MUTEX_LOCK - return allocator->BindBufferMemory(allocation, 0, buffer, VMA_NULL); + return allocator->BindBufferMemory(allocation, 0, buffer, VMA_NULL); } VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory2( @@ -16006,7 +15997,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory2( VMA_DEBUG_GLOBAL_MUTEX_LOCK - return allocator->BindBufferMemory(allocation, allocationLocalOffset, buffer, pNext); + return allocator->BindBufferMemory(allocation, allocationLocalOffset, buffer, pNext); } VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory( @@ -16020,7 +16011,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory( VMA_DEBUG_GLOBAL_MUTEX_LOCK - return allocator->BindImageMemory(allocation, 0, image, VMA_NULL); + return allocator->BindImageMemory(allocation, 0, image, VMA_NULL); } VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory2( @@ -16049,11 +16040,11 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBuffer( { VMA_ASSERT(allocator && pBufferCreateInfo && pAllocationCreateInfo && pBuffer && pAllocation); - if(pBufferCreateInfo->size == 0) + if (pBufferCreateInfo->size == 0) { return VK_ERROR_INITIALIZATION_FAILED; } - if((pBufferCreateInfo->usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_COPY) != 0 && + if ((pBufferCreateInfo->usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_COPY) != 0 && !allocator->m_UseKhrBufferDeviceAddress) { VMA_ASSERT(0 && "Creating a buffer with VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT is not valid if VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT was not used."); @@ -16064,7 +16055,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBuffer( VMA_DEBUG_GLOBAL_MUTEX_LOCK - *pBuffer = VK_NULL_HANDLE; + * pBuffer = VK_NULL_HANDLE; *pAllocation = VK_NULL_HANDLE; // 1. Create VkBuffer. @@ -16073,12 +16064,12 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBuffer( pBufferCreateInfo, allocator->GetAllocationCallbacks(), pBuffer); - if(res >= 0) + if (res >= 0) { // 2. vkGetBufferMemoryRequirements. VkMemoryRequirements vkMemReq = {}; bool requiresDedicatedAllocation = false; - bool prefersDedicatedAllocation = false; + bool prefersDedicatedAllocation = false; allocator->GetBufferMemoryRequirements(*pBuffer, vkMemReq, requiresDedicatedAllocation, prefersDedicatedAllocation); @@ -16095,20 +16086,20 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBuffer( 1, // allocationCount pAllocation); - if(res >= 0) + if (res >= 0) { // 3. Bind buffer with memory. - if((pAllocationCreateInfo->flags & VMA_ALLOCATION_CREATE_DONT_BIND_BIT) == 0) + if ((pAllocationCreateInfo->flags & VMA_ALLOCATION_CREATE_DONT_BIND_BIT) == 0) { res = allocator->BindBufferMemory(*pAllocation, 0, *pBuffer, VMA_NULL); } - if(res >= 0) + if (res >= 0) { // All steps succeeded. - #if VMA_STATS_STRING_ENABLED - (*pAllocation)->InitBufferUsage(*pBufferCreateInfo, allocator->m_UseKhrMaintenance5); - #endif - if(pAllocationInfo != VMA_NULL) +#if VMA_STATS_STRING_ENABLED + (*pAllocation)->InitBufferUsage(*pBufferCreateInfo, allocator->m_UseKhrMaintenance5); +#endif + if (pAllocationInfo != VMA_NULL) { allocator->GetAllocationInfo(*pAllocation, pAllocationInfo); } @@ -16141,11 +16132,11 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBufferWithAlignment( { VMA_ASSERT(allocator && pBufferCreateInfo && pAllocationCreateInfo && VmaIsPow2(minAlignment) && pBuffer && pAllocation); - if(pBufferCreateInfo->size == 0) + if (pBufferCreateInfo->size == 0) { return VK_ERROR_INITIALIZATION_FAILED; } - if((pBufferCreateInfo->usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_COPY) != 0 && + if ((pBufferCreateInfo->usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_COPY) != 0 && !allocator->m_UseKhrBufferDeviceAddress) { VMA_ASSERT(0 && "Creating a buffer with VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT is not valid if VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT was not used."); @@ -16156,7 +16147,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBufferWithAlignment( VMA_DEBUG_GLOBAL_MUTEX_LOCK - *pBuffer = VK_NULL_HANDLE; + * pBuffer = VK_NULL_HANDLE; *pAllocation = VK_NULL_HANDLE; // 1. Create VkBuffer. @@ -16165,12 +16156,12 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBufferWithAlignment( pBufferCreateInfo, allocator->GetAllocationCallbacks(), pBuffer); - if(res >= 0) + if (res >= 0) { // 2. vkGetBufferMemoryRequirements. VkMemoryRequirements vkMemReq = {}; bool requiresDedicatedAllocation = false; - bool prefersDedicatedAllocation = false; + bool prefersDedicatedAllocation = false; allocator->GetBufferMemoryRequirements(*pBuffer, vkMemReq, requiresDedicatedAllocation, prefersDedicatedAllocation); @@ -16190,20 +16181,20 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBufferWithAlignment( 1, // allocationCount pAllocation); - if(res >= 0) + if (res >= 0) { // 3. Bind buffer with memory. - if((pAllocationCreateInfo->flags & VMA_ALLOCATION_CREATE_DONT_BIND_BIT) == 0) + if ((pAllocationCreateInfo->flags & VMA_ALLOCATION_CREATE_DONT_BIND_BIT) == 0) { res = allocator->BindBufferMemory(*pAllocation, 0, *pBuffer, VMA_NULL); } - if(res >= 0) + if (res >= 0) { // All steps succeeded. - #if VMA_STATS_STRING_ENABLED - (*pAllocation)->InitBufferUsage(*pBufferCreateInfo, allocator->m_UseKhrMaintenance5); - #endif - if(pAllocationInfo != VMA_NULL) +#if VMA_STATS_STRING_ENABLED + (*pAllocation)->InitBufferUsage(*pBufferCreateInfo, allocator->m_UseKhrMaintenance5); +#endif + if (pAllocationInfo != VMA_NULL) { allocator->GetAllocationInfo(*pAllocation, pAllocationInfo); } @@ -16261,12 +16252,12 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAliasingBuffer2( VMA_DEBUG_GLOBAL_MUTEX_LOCK - // 1. Create VkBuffer. - VkResult res = (*allocator->GetVulkanFunctions().vkCreateBuffer)( - allocator->m_hDevice, - pBufferCreateInfo, - allocator->GetAllocationCallbacks(), - pBuffer); + // 1. Create VkBuffer. + VkResult res = (*allocator->GetVulkanFunctions().vkCreateBuffer)( + allocator->m_hDevice, + pBufferCreateInfo, + allocator->GetAllocationCallbacks(), + pBuffer); if (res >= 0) { // 2. Bind buffer with memory. @@ -16287,7 +16278,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaDestroyBuffer( { VMA_ASSERT(allocator); - if(buffer == VK_NULL_HANDLE && allocation == VK_NULL_HANDLE) + if (buffer == VK_NULL_HANDLE && allocation == VK_NULL_HANDLE) { return; } @@ -16296,12 +16287,12 @@ VMA_CALL_PRE void VMA_CALL_POST vmaDestroyBuffer( VMA_DEBUG_GLOBAL_MUTEX_LOCK - if(buffer != VK_NULL_HANDLE) - { - (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, buffer, allocator->GetAllocationCallbacks()); - } + if (buffer != VK_NULL_HANDLE) + { + (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, buffer, allocator->GetAllocationCallbacks()); + } - if(allocation != VK_NULL_HANDLE) + if (allocation != VK_NULL_HANDLE) { allocator->FreeMemory( 1, // allocationCount @@ -16319,7 +16310,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateImage( { VMA_ASSERT(allocator && pImageCreateInfo && pAllocationCreateInfo && pImage && pAllocation); - if(pImageCreateInfo->extent.width == 0 || + if (pImageCreateInfo->extent.width == 0 || pImageCreateInfo->extent.height == 0 || pImageCreateInfo->extent.depth == 0 || pImageCreateInfo->mipLevels == 0 || @@ -16332,7 +16323,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateImage( VMA_DEBUG_GLOBAL_MUTEX_LOCK - *pImage = VK_NULL_HANDLE; + * pImage = VK_NULL_HANDLE; *pAllocation = VK_NULL_HANDLE; // 1. Create VkImage. @@ -16341,7 +16332,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateImage( pImageCreateInfo, allocator->GetAllocationCallbacks(), pImage); - if(res >= 0) + if (res >= 0) { VmaSuballocationType suballocType = pImageCreateInfo->tiling == VK_IMAGE_TILING_OPTIMAL ? VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL : @@ -16350,7 +16341,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateImage( // 2. Allocate memory using allocator. VkMemoryRequirements vkMemReq = {}; bool requiresDedicatedAllocation = false; - bool prefersDedicatedAllocation = false; + bool prefersDedicatedAllocation = false; allocator->GetImageMemoryRequirements(*pImage, vkMemReq, requiresDedicatedAllocation, prefersDedicatedAllocation); @@ -16366,20 +16357,20 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateImage( 1, // allocationCount pAllocation); - if(res >= 0) + if (res >= 0) { // 3. Bind image with memory. - if((pAllocationCreateInfo->flags & VMA_ALLOCATION_CREATE_DONT_BIND_BIT) == 0) + if ((pAllocationCreateInfo->flags & VMA_ALLOCATION_CREATE_DONT_BIND_BIT) == 0) { res = allocator->BindImageMemory(*pAllocation, 0, *pImage, VMA_NULL); } - if(res >= 0) + if (res >= 0) { // All steps succeeded. - #if VMA_STATS_STRING_ENABLED - (*pAllocation)->InitImageUsage(*pImageCreateInfo); - #endif - if(pAllocationInfo != VMA_NULL) +#if VMA_STATS_STRING_ENABLED + (*pAllocation)->InitImageUsage(*pImageCreateInfo); +#endif + if (pAllocationInfo != VMA_NULL) { allocator->GetAllocationInfo(*pAllocation, pAllocationInfo); } @@ -16434,12 +16425,12 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAliasingImage2( VMA_DEBUG_GLOBAL_MUTEX_LOCK - // 1. Create VkImage. - VkResult res = (*allocator->GetVulkanFunctions().vkCreateImage)( - allocator->m_hDevice, - pImageCreateInfo, - allocator->GetAllocationCallbacks(), - pImage); + // 1. Create VkImage. + VkResult res = (*allocator->GetVulkanFunctions().vkCreateImage)( + allocator->m_hDevice, + pImageCreateInfo, + allocator->GetAllocationCallbacks(), + pImage); if (res >= 0) { // 2. Bind image with memory. @@ -16460,7 +16451,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaDestroyImage( { VMA_ASSERT(allocator); - if(image == VK_NULL_HANDLE && allocation == VK_NULL_HANDLE) + if (image == VK_NULL_HANDLE && allocation == VK_NULL_HANDLE) { return; } @@ -16469,11 +16460,11 @@ VMA_CALL_PRE void VMA_CALL_POST vmaDestroyImage( VMA_DEBUG_GLOBAL_MUTEX_LOCK - if(image != VK_NULL_HANDLE) - { - (*allocator->GetVulkanFunctions().vkDestroyImage)(allocator->m_hDevice, image, allocator->GetAllocationCallbacks()); - } - if(allocation != VK_NULL_HANDLE) + if (image != VK_NULL_HANDLE) + { + (*allocator->GetVulkanFunctions().vkDestroyImage)(allocator->m_hDevice, image, allocator->GetAllocationCallbacks()); + } + if (allocation != VK_NULL_HANDLE) { allocator->FreeMemory( 1, // allocationCount @@ -16483,7 +16474,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaDestroyImage( VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateVirtualBlock( const VmaVirtualBlockCreateInfo* VMA_NOT_NULL pCreateInfo, - VmaVirtualBlock VMA_NULLABLE * VMA_NOT_NULL pVirtualBlock) + VmaVirtualBlock VMA_NULLABLE* VMA_NOT_NULL pVirtualBlock) { VMA_ASSERT(pCreateInfo && pVirtualBlock); VMA_ASSERT(pCreateInfo->size > 0); @@ -16491,7 +16482,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateVirtualBlock( VMA_DEBUG_GLOBAL_MUTEX_LOCK; *pVirtualBlock = vma_new(pCreateInfo->pAllocationCallbacks, VmaVirtualBlock_T)(*pCreateInfo); VkResult res = (*pVirtualBlock)->Init(); - if(res < 0) + if (res < 0) { vma_delete(pCreateInfo->pAllocationCallbacks, *pVirtualBlock); *pVirtualBlock = VK_NULL_HANDLE; @@ -16501,7 +16492,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateVirtualBlock( VMA_CALL_PRE void VMA_CALL_POST vmaDestroyVirtualBlock(VmaVirtualBlock VMA_NULLABLE virtualBlock) { - if(virtualBlock != VK_NULL_HANDLE) + if (virtualBlock != VK_NULL_HANDLE) { VMA_DEBUG_LOG("vmaDestroyVirtualBlock"); VMA_DEBUG_GLOBAL_MUTEX_LOCK; @@ -16539,7 +16530,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaVirtualAllocate(VmaVirtualBlock VMA_NOT_N VMA_CALL_PRE void VMA_CALL_POST vmaVirtualFree(VmaVirtualBlock VMA_NOT_NULL virtualBlock, VmaVirtualAllocation VMA_NULLABLE_NON_DISPATCHABLE allocation) { - if(allocation != VK_NULL_HANDLE) + if (allocation != VK_NULL_HANDLE) { VMA_ASSERT(virtualBlock != VK_NULL_HANDLE); VMA_DEBUG_LOG("vmaVirtualFree"); @@ -16586,7 +16577,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaCalculateVirtualBlockStatistics(VmaVirtualBlo #if VMA_STATS_STRING_ENABLED VMA_CALL_PRE void VMA_CALL_POST vmaBuildVirtualBlockStatsString(VmaVirtualBlock VMA_NOT_NULL virtualBlock, - char* VMA_NULLABLE * VMA_NOT_NULL ppStatsString, VkBool32 detailedMap) + char* VMA_NULLABLE* VMA_NOT_NULL ppStatsString, VkBool32 detailedMap) { VMA_ASSERT(virtualBlock != VK_NULL_HANDLE && ppStatsString != VMA_NULL); VMA_DEBUG_GLOBAL_MUTEX_LOCK; @@ -16599,7 +16590,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaBuildVirtualBlockStatsString(VmaVirtualBlock VMA_CALL_PRE void VMA_CALL_POST vmaFreeVirtualBlockStatsString(VmaVirtualBlock VMA_NOT_NULL virtualBlock, char* VMA_NULLABLE pStatsString) { - if(pStatsString != VMA_NULL) + if (pStatsString != VMA_NULL) { VMA_ASSERT(virtualBlock != VK_NULL_HANDLE); VMA_DEBUG_GLOBAL_MUTEX_LOCK; From 9402a6bef9cf0700f487391a5fef584b09c0d556 Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Mon, 26 Aug 2024 14:33:32 +0200 Subject: [PATCH 05/10] New guard, fixed ABI issues --- include/vk_mem_alloc.h | 5841 ++++++++++++++++++++-------------------- 1 file changed, 2926 insertions(+), 2915 deletions(-) diff --git a/include/vk_mem_alloc.h b/include/vk_mem_alloc.h index fed962c..d3a9871 100644 --- a/include/vk_mem_alloc.h +++ b/include/vk_mem_alloc.h @@ -132,15 +132,15 @@ extern "C" { #endif #if !defined(VMA_VULKAN_VERSION) -#if defined(VK_VERSION_1_3) -#define VMA_VULKAN_VERSION 1003000 -#elif defined(VK_VERSION_1_2) -#define VMA_VULKAN_VERSION 1002000 -#elif defined(VK_VERSION_1_1) -#define VMA_VULKAN_VERSION 1001000 -#else -#define VMA_VULKAN_VERSION 1000000 -#endif + #if defined(VK_VERSION_1_3) + #define VMA_VULKAN_VERSION 1003000 + #elif defined(VK_VERSION_1_2) + #define VMA_VULKAN_VERSION 1002000 + #elif defined(VK_VERSION_1_1) + #define VMA_VULKAN_VERSION 1001000 + #else + #define VMA_VULKAN_VERSION 1000000 + #endif #endif #if defined(__ANDROID__) && defined(VK_NO_PROTOTYPES) && VMA_STATIC_VULKAN_FUNCTIONS @@ -163,83 +163,92 @@ extern "C" { extern PFN_vkCreateImage vkCreateImage; extern PFN_vkDestroyImage vkDestroyImage; extern PFN_vkCmdCopyBuffer vkCmdCopyBuffer; -#if VMA_VULKAN_VERSION >= 1001000 - extern PFN_vkGetBufferMemoryRequirements2 vkGetBufferMemoryRequirements2; - extern PFN_vkGetImageMemoryRequirements2 vkGetImageMemoryRequirements2; - extern PFN_vkBindBufferMemory2 vkBindBufferMemory2; - extern PFN_vkBindImageMemory2 vkBindImageMemory2; - extern PFN_vkGetPhysicalDeviceMemoryProperties2 vkGetPhysicalDeviceMemoryProperties2; -#endif // #if VMA_VULKAN_VERSION >= 1001000 + #if VMA_VULKAN_VERSION >= 1001000 + extern PFN_vkGetBufferMemoryRequirements2 vkGetBufferMemoryRequirements2; + extern PFN_vkGetImageMemoryRequirements2 vkGetImageMemoryRequirements2; + extern PFN_vkBindBufferMemory2 vkBindBufferMemory2; + extern PFN_vkBindImageMemory2 vkBindImageMemory2; + extern PFN_vkGetPhysicalDeviceMemoryProperties2 vkGetPhysicalDeviceMemoryProperties2; + #endif // #if VMA_VULKAN_VERSION >= 1001000 #endif // #if defined(__ANDROID__) && VMA_STATIC_VULKAN_FUNCTIONS && VK_NO_PROTOTYPES #if !defined(VMA_DEDICATED_ALLOCATION) -#if VK_KHR_get_memory_requirements2 && VK_KHR_dedicated_allocation -#define VMA_DEDICATED_ALLOCATION 1 -#else -#define VMA_DEDICATED_ALLOCATION 0 -#endif + #if VK_KHR_get_memory_requirements2 && VK_KHR_dedicated_allocation + #define VMA_DEDICATED_ALLOCATION 1 + #else + #define VMA_DEDICATED_ALLOCATION 0 + #endif #endif #if !defined(VMA_BIND_MEMORY2) -#if VK_KHR_bind_memory2 -#define VMA_BIND_MEMORY2 1 -#else -#define VMA_BIND_MEMORY2 0 -#endif + #if VK_KHR_bind_memory2 + #define VMA_BIND_MEMORY2 1 + #else + #define VMA_BIND_MEMORY2 0 + #endif #endif #if !defined(VMA_MEMORY_BUDGET) -#if VK_EXT_memory_budget && (VK_KHR_get_physical_device_properties2 || VMA_VULKAN_VERSION >= 1001000) -#define VMA_MEMORY_BUDGET 1 -#else -#define VMA_MEMORY_BUDGET 0 -#endif + #if VK_EXT_memory_budget && (VK_KHR_get_physical_device_properties2 || VMA_VULKAN_VERSION >= 1001000) + #define VMA_MEMORY_BUDGET 1 + #else + #define VMA_MEMORY_BUDGET 0 + #endif #endif - // Defined to 1 when VK_KHR_buffer_device_address device extension or equivalent core Vulkan 1.2 feature is defined in its headers. +// Defined to 1 when VK_KHR_buffer_device_address device extension or equivalent core Vulkan 1.2 feature is defined in its headers. #if !defined(VMA_BUFFER_DEVICE_ADDRESS) -#if VK_KHR_buffer_device_address || VMA_VULKAN_VERSION >= 1002000 -#define VMA_BUFFER_DEVICE_ADDRESS 1 -#else -#define VMA_BUFFER_DEVICE_ADDRESS 0 -#endif + #if VK_KHR_buffer_device_address || VMA_VULKAN_VERSION >= 1002000 + #define VMA_BUFFER_DEVICE_ADDRESS 1 + #else + #define VMA_BUFFER_DEVICE_ADDRESS 0 + #endif #endif // Defined to 1 when VK_EXT_memory_priority device extension is defined in Vulkan headers. #if !defined(VMA_MEMORY_PRIORITY) -#if VK_EXT_memory_priority -#define VMA_MEMORY_PRIORITY 1 -#else -#define VMA_MEMORY_PRIORITY 0 -#endif + #if VK_EXT_memory_priority + #define VMA_MEMORY_PRIORITY 1 + #else + #define VMA_MEMORY_PRIORITY 0 + #endif #endif // Defined to 1 when VK_KHR_maintenance4 device extension is defined in Vulkan headers. #if !defined(VMA_KHR_MAINTENANCE4) -#if VK_KHR_maintenance4 -#define VMA_KHR_MAINTENANCE4 1 -#else -#define VMA_KHR_MAINTENANCE4 0 -#endif + #if VK_KHR_maintenance4 + #define VMA_KHR_MAINTENANCE4 1 + #else + #define VMA_KHR_MAINTENANCE4 0 + #endif #endif // Defined to 1 when VK_KHR_maintenance5 device extension is defined in Vulkan headers. #if !defined(VMA_KHR_MAINTENANCE5) -#if VK_KHR_maintenance5 -#define VMA_KHR_MAINTENANCE5 1 -#else -#define VMA_KHR_MAINTENANCE5 0 -#endif + #if VK_KHR_maintenance5 + #define VMA_KHR_MAINTENANCE5 1 + #else + #define VMA_KHR_MAINTENANCE5 0 + #endif #endif // Defined to 1 when VK_KHR_external_memory device extension is defined in Vulkan headers. #if !defined(VMA_EXTERNAL_MEMORY) -#if VK_KHR_external_memory -#define VMA_EXTERNAL_MEMORY 1 -#else -#define VMA_EXTERNAL_MEMORY 0 + #if VK_KHR_external_memory + #define VMA_EXTERNAL_MEMORY 1 + #else + #define VMA_EXTERNAL_MEMORY 0 + #endif #endif + +// Defined to 1 when VK_KHR_external_memory device extension is defined in Vulkan headers. +#if !defined(VMA_EXTERNAL_MEMORY_WIN32) + #if VK_KHR_external_memory_win32 + #define VMA_EXTERNAL_MEMORY_WIN32 1 + #else + #define VMA_EXTERNAL_MEMORY_WIN32 0 + #endif #endif // Define these macros to decorate all public functions with additional code, @@ -248,16 +257,16 @@ extern "C" { // #define VMA_CALL_PRE __declspec(dllexport) // #define VMA_CALL_POST __cdecl #ifndef VMA_CALL_PRE -#define VMA_CALL_PRE + #define VMA_CALL_PRE #endif #ifndef VMA_CALL_POST -#define VMA_CALL_POST + #define VMA_CALL_POST #endif // Define this macro to decorate pNext pointers with an attribute specifying the Vulkan // structure that will be extended via the pNext chain. #ifndef VMA_EXTENDS_VK_STRUCT -#define VMA_EXTENDS_VK_STRUCT(vkStruct) + #define VMA_EXTENDS_VK_STRUCT(vkStruct) #endif // Define this macro to decorate pointers with an attribute specifying the @@ -272,49 +281,49 @@ extern "C" { // this means the number of memory heaps available in the device associated // with the VmaAllocator being dealt with. #ifndef VMA_LEN_IF_NOT_NULL -#define VMA_LEN_IF_NOT_NULL(len) + #define VMA_LEN_IF_NOT_NULL(len) #endif // The VMA_NULLABLE macro is defined to be _Nullable when compiling with Clang. // see: https://clang.llvm.org/docs/AttributeReference.html#nullable #ifndef VMA_NULLABLE -#ifdef __clang__ -#define VMA_NULLABLE _Nullable -#else -#define VMA_NULLABLE -#endif + #ifdef __clang__ + #define VMA_NULLABLE _Nullable + #else + #define VMA_NULLABLE + #endif #endif // The VMA_NOT_NULL macro is defined to be _Nonnull when compiling with Clang. // see: https://clang.llvm.org/docs/AttributeReference.html#nonnull #ifndef VMA_NOT_NULL -#ifdef __clang__ -#define VMA_NOT_NULL _Nonnull -#else -#define VMA_NOT_NULL -#endif + #ifdef __clang__ + #define VMA_NOT_NULL _Nonnull + #else + #define VMA_NOT_NULL + #endif #endif // If non-dispatchable handles are represented as pointers then we can give // then nullability annotations #ifndef VMA_NOT_NULL_NON_DISPATCHABLE -#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) -#define VMA_NOT_NULL_NON_DISPATCHABLE VMA_NOT_NULL -#else -#define VMA_NOT_NULL_NON_DISPATCHABLE -#endif + #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) + #define VMA_NOT_NULL_NON_DISPATCHABLE VMA_NOT_NULL + #else + #define VMA_NOT_NULL_NON_DISPATCHABLE + #endif #endif #ifndef VMA_NULLABLE_NON_DISPATCHABLE -#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) -#define VMA_NULLABLE_NON_DISPATCHABLE VMA_NULLABLE -#else -#define VMA_NULLABLE_NON_DISPATCHABLE -#endif + #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) + #define VMA_NULLABLE_NON_DISPATCHABLE VMA_NULLABLE + #else + #define VMA_NULLABLE_NON_DISPATCHABLE + #endif #endif #ifndef VMA_STATS_STRING_ENABLED -#define VMA_STATS_STRING_ENABLED 1 + #define VMA_STATS_STRING_ENABLED 1 #endif //////////////////////////////////////////////////////////////////////////////// @@ -334,525 +343,525 @@ extern "C" { */ /// Flags for created #VmaAllocator. - typedef enum VmaAllocatorCreateFlagBits - { - /** \brief Allocator and all objects created from it will not be synchronized internally, so you must guarantee they are used from only one thread at a time or synchronized externally by you. +typedef enum VmaAllocatorCreateFlagBits +{ + /** \brief Allocator and all objects created from it will not be synchronized internally, so you must guarantee they are used from only one thread at a time or synchronized externally by you. - Using this flag may increase performance because internal mutexes are not used. - */ - VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT = 0x00000001, - /** \brief Enables usage of VK_KHR_dedicated_allocation extension. + Using this flag may increase performance because internal mutexes are not used. + */ + VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT = 0x00000001, + /** \brief Enables usage of VK_KHR_dedicated_allocation extension. - The flag works only if VmaAllocatorCreateInfo::vulkanApiVersion `== VK_API_VERSION_1_0`. - When it is `VK_API_VERSION_1_1`, the flag is ignored because the extension has been promoted to Vulkan 1.1. + The flag works only if VmaAllocatorCreateInfo::vulkanApiVersion `== VK_API_VERSION_1_0`. + When it is `VK_API_VERSION_1_1`, the flag is ignored because the extension has been promoted to Vulkan 1.1. - Using this extension will automatically allocate dedicated blocks of memory for - some buffers and images instead of suballocating place for them out of bigger - memory blocks (as if you explicitly used #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT - flag) when it is recommended by the driver. It may improve performance on some - GPUs. + Using this extension will automatically allocate dedicated blocks of memory for + some buffers and images instead of suballocating place for them out of bigger + memory blocks (as if you explicitly used #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT + flag) when it is recommended by the driver. It may improve performance on some + GPUs. - You may set this flag only if you found out that following device extensions are - supported, you enabled them while creating Vulkan device passed as - VmaAllocatorCreateInfo::device, and you want them to be used internally by this - library: + You may set this flag only if you found out that following device extensions are + supported, you enabled them while creating Vulkan device passed as + VmaAllocatorCreateInfo::device, and you want them to be used internally by this + library: - - VK_KHR_get_memory_requirements2 (device extension) - - VK_KHR_dedicated_allocation (device extension) + - VK_KHR_get_memory_requirements2 (device extension) + - VK_KHR_dedicated_allocation (device extension) - When this flag is set, you can experience following warnings reported by Vulkan - validation layer. You can ignore them. + When this flag is set, you can experience following warnings reported by Vulkan + validation layer. You can ignore them. - > vkBindBufferMemory(): Binding memory to buffer 0x2d but vkGetBufferMemoryRequirements() has not been called on that buffer. - */ - VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT = 0x00000002, - /** - Enables usage of VK_KHR_bind_memory2 extension. + > vkBindBufferMemory(): Binding memory to buffer 0x2d but vkGetBufferMemoryRequirements() has not been called on that buffer. + */ + VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT = 0x00000002, + /** + Enables usage of VK_KHR_bind_memory2 extension. - The flag works only if VmaAllocatorCreateInfo::vulkanApiVersion `== VK_API_VERSION_1_0`. - When it is `VK_API_VERSION_1_1`, the flag is ignored because the extension has been promoted to Vulkan 1.1. + The flag works only if VmaAllocatorCreateInfo::vulkanApiVersion `== VK_API_VERSION_1_0`. + When it is `VK_API_VERSION_1_1`, the flag is ignored because the extension has been promoted to Vulkan 1.1. - You may set this flag only if you found out that this device extension is supported, - you enabled it while creating Vulkan device passed as VmaAllocatorCreateInfo::device, - and you want it to be used internally by this library. + You may set this flag only if you found out that this device extension is supported, + you enabled it while creating Vulkan device passed as VmaAllocatorCreateInfo::device, + and you want it to be used internally by this library. - The extension provides functions `vkBindBufferMemory2KHR` and `vkBindImageMemory2KHR`, - which allow to pass a chain of `pNext` structures while binding. - This flag is required if you use `pNext` parameter in vmaBindBufferMemory2() or vmaBindImageMemory2(). - */ - VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT = 0x00000004, - /** - Enables usage of VK_EXT_memory_budget extension. + The extension provides functions `vkBindBufferMemory2KHR` and `vkBindImageMemory2KHR`, + which allow to pass a chain of `pNext` structures while binding. + This flag is required if you use `pNext` parameter in vmaBindBufferMemory2() or vmaBindImageMemory2(). + */ + VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT = 0x00000004, + /** + Enables usage of VK_EXT_memory_budget extension. - You may set this flag only if you found out that this device extension is supported, - you enabled it while creating Vulkan device passed as VmaAllocatorCreateInfo::device, - and you want it to be used internally by this library, along with another instance extension - VK_KHR_get_physical_device_properties2, which is required by it (or Vulkan 1.1, where this extension is promoted). + You may set this flag only if you found out that this device extension is supported, + you enabled it while creating Vulkan device passed as VmaAllocatorCreateInfo::device, + and you want it to be used internally by this library, along with another instance extension + VK_KHR_get_physical_device_properties2, which is required by it (or Vulkan 1.1, where this extension is promoted). - The extension provides query for current memory usage and budget, which will probably - be more accurate than an estimation used by the library otherwise. - */ - VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT = 0x00000008, - /** - Enables usage of VK_AMD_device_coherent_memory extension. + The extension provides query for current memory usage and budget, which will probably + be more accurate than an estimation used by the library otherwise. + */ + VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT = 0x00000008, + /** + Enables usage of VK_AMD_device_coherent_memory extension. - You may set this flag only if you: + You may set this flag only if you: - - found out that this device extension is supported and enabled it while creating Vulkan device passed as VmaAllocatorCreateInfo::device, - - checked that `VkPhysicalDeviceCoherentMemoryFeaturesAMD::deviceCoherentMemory` is true and set it while creating the Vulkan device, - - want it to be used internally by this library. + - found out that this device extension is supported and enabled it while creating Vulkan device passed as VmaAllocatorCreateInfo::device, + - checked that `VkPhysicalDeviceCoherentMemoryFeaturesAMD::deviceCoherentMemory` is true and set it while creating the Vulkan device, + - want it to be used internally by this library. - The extension and accompanying device feature provide access to memory types with - `VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD` and `VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD` flags. - They are useful mostly for writing breadcrumb markers - a common method for debugging GPU crash/hang/TDR. + The extension and accompanying device feature provide access to memory types with + `VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD` and `VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD` flags. + They are useful mostly for writing breadcrumb markers - a common method for debugging GPU crash/hang/TDR. - When the extension is not enabled, such memory types are still enumerated, but their usage is illegal. - To protect from this error, if you don't create the allocator with this flag, it will refuse to allocate any memory or create a custom pool in such memory type, - returning `VK_ERROR_FEATURE_NOT_PRESENT`. - */ - VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT = 0x00000010, - /** - Enables usage of "buffer device address" feature, which allows you to use function - `vkGetBufferDeviceAddress*` to get raw GPU pointer to a buffer and pass it for usage inside a shader. + When the extension is not enabled, such memory types are still enumerated, but their usage is illegal. + To protect from this error, if you don't create the allocator with this flag, it will refuse to allocate any memory or create a custom pool in such memory type, + returning `VK_ERROR_FEATURE_NOT_PRESENT`. + */ + VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT = 0x00000010, + /** + Enables usage of "buffer device address" feature, which allows you to use function + `vkGetBufferDeviceAddress*` to get raw GPU pointer to a buffer and pass it for usage inside a shader. - You may set this flag only if you: + You may set this flag only if you: - 1. (For Vulkan version < 1.2) Found as available and enabled device extension - VK_KHR_buffer_device_address. - This extension is promoted to core Vulkan 1.2. - 2. Found as available and enabled device feature `VkPhysicalDeviceBufferDeviceAddressFeatures::bufferDeviceAddress`. + 1. (For Vulkan version < 1.2) Found as available and enabled device extension + VK_KHR_buffer_device_address. + This extension is promoted to core Vulkan 1.2. + 2. Found as available and enabled device feature `VkPhysicalDeviceBufferDeviceAddressFeatures::bufferDeviceAddress`. - When this flag is set, you can create buffers with `VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT` using VMA. - The library automatically adds `VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT` to - allocated memory blocks wherever it might be needed. + When this flag is set, you can create buffers with `VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT` using VMA. + The library automatically adds `VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT` to + allocated memory blocks wherever it might be needed. - For more information, see documentation chapter \ref enabling_buffer_device_address. - */ - VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT = 0x00000020, - /** - Enables usage of VK_EXT_memory_priority extension in the library. + For more information, see documentation chapter \ref enabling_buffer_device_address. + */ + VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT = 0x00000020, + /** + Enables usage of VK_EXT_memory_priority extension in the library. - You may set this flag only if you found available and enabled this device extension, - along with `VkPhysicalDeviceMemoryPriorityFeaturesEXT::memoryPriority == VK_TRUE`, - while creating Vulkan device passed as VmaAllocatorCreateInfo::device. + You may set this flag only if you found available and enabled this device extension, + along with `VkPhysicalDeviceMemoryPriorityFeaturesEXT::memoryPriority == VK_TRUE`, + while creating Vulkan device passed as VmaAllocatorCreateInfo::device. - When this flag is used, VmaAllocationCreateInfo::priority and VmaPoolCreateInfo::priority - are used to set priorities of allocated Vulkan memory. Without it, these variables are ignored. + When this flag is used, VmaAllocationCreateInfo::priority and VmaPoolCreateInfo::priority + are used to set priorities of allocated Vulkan memory. Without it, these variables are ignored. - A priority must be a floating-point value between 0 and 1, indicating the priority of the allocation relative to other memory allocations. - Larger values are higher priority. The granularity of the priorities is implementation-dependent. - It is automatically passed to every call to `vkAllocateMemory` done by the library using structure `VkMemoryPriorityAllocateInfoEXT`. - The value to be used for default priority is 0.5. - For more details, see the documentation of the VK_EXT_memory_priority extension. - */ - VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT = 0x00000040, - /** - Enables usage of VK_KHR_maintenance4 extension in the library. + A priority must be a floating-point value between 0 and 1, indicating the priority of the allocation relative to other memory allocations. + Larger values are higher priority. The granularity of the priorities is implementation-dependent. + It is automatically passed to every call to `vkAllocateMemory` done by the library using structure `VkMemoryPriorityAllocateInfoEXT`. + The value to be used for default priority is 0.5. + For more details, see the documentation of the VK_EXT_memory_priority extension. + */ + VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT = 0x00000040, + /** + Enables usage of VK_KHR_maintenance4 extension in the library. - You may set this flag only if you found available and enabled this device extension, - while creating Vulkan device passed as VmaAllocatorCreateInfo::device. - */ - VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE4_BIT = 0x00000080, - /** - Enables usage of VK_KHR_maintenance5 extension in the library. + You may set this flag only if you found available and enabled this device extension, + while creating Vulkan device passed as VmaAllocatorCreateInfo::device. + */ + VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE4_BIT = 0x00000080, + /** + Enables usage of VK_KHR_maintenance5 extension in the library. - You should set this flag if you found available and enabled this device extension, - while creating Vulkan device passed as VmaAllocatorCreateInfo::device. - */ - VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT = 0x00000100, - - /** - Enables usage of VK_KHR_external_memory_win32 extension in the library. - - You should set this flag if you found available and enabled this device extension, - while creating Vulkan device passed as VmaAllocatorCreateInfo::device. - */ - VMA_ALLOCATOR_CREATE_KHR_EXTERNAL_MEMORY_WIN32 = 0x00000200, - - VMA_ALLOCATOR_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF - } VmaAllocatorCreateFlagBits; - /// See #VmaAllocatorCreateFlagBits. - typedef VkFlags VmaAllocatorCreateFlags; - - /** @} */ + You should set this flag if you found available and enabled this device extension, + while creating Vulkan device passed as VmaAllocatorCreateInfo::device. + */ + VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT = 0x00000100, /** - \addtogroup group_alloc - @{ + Enables usage of VK_KHR_external_memory_win32 extension in the library. + + You should set this flag if you found available and enabled this device extension, + while creating Vulkan device passed as VmaAllocatorCreateInfo::device. */ + VMA_ALLOCATOR_CREATE_KHR_EXTERNAL_MEMORY_WIN32_BIT = 0x00000200, - /// \brief Intended usage of the allocated memory. - typedef enum VmaMemoryUsage - { - /** No intended memory usage specified. - Use other members of VmaAllocationCreateInfo to specify your requirements. - */ - VMA_MEMORY_USAGE_UNKNOWN = 0, - /** - \deprecated Obsolete, preserved for backward compatibility. - Prefers `VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT`. - */ - VMA_MEMORY_USAGE_GPU_ONLY = 1, - /** - \deprecated Obsolete, preserved for backward compatibility. - Guarantees `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT` and `VK_MEMORY_PROPERTY_HOST_COHERENT_BIT`. - */ - VMA_MEMORY_USAGE_CPU_ONLY = 2, - /** - \deprecated Obsolete, preserved for backward compatibility. - Guarantees `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT`, prefers `VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT`. - */ - VMA_MEMORY_USAGE_CPU_TO_GPU = 3, - /** - \deprecated Obsolete, preserved for backward compatibility. - Guarantees `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT`, prefers `VK_MEMORY_PROPERTY_HOST_CACHED_BIT`. - */ - VMA_MEMORY_USAGE_GPU_TO_CPU = 4, - /** - \deprecated Obsolete, preserved for backward compatibility. - Prefers not `VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT`. - */ - VMA_MEMORY_USAGE_CPU_COPY = 5, - /** - Lazily allocated GPU memory having `VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT`. - Exists mostly on mobile platforms. Using it on desktop PC or other GPUs with no such memory type present will fail the allocation. + VMA_ALLOCATOR_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VmaAllocatorCreateFlagBits; +/// See #VmaAllocatorCreateFlagBits. +typedef VkFlags VmaAllocatorCreateFlags; - Usage: Memory for transient attachment images (color attachments, depth attachments etc.), created with `VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT`. +/** @} */ - Allocations with this usage are always created as dedicated - it implies #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT. - */ - VMA_MEMORY_USAGE_GPU_LAZILY_ALLOCATED = 6, - /** - Selects best memory type automatically. - This flag is recommended for most common use cases. +/** +\addtogroup group_alloc +@{ +*/ - When using this flag, if you want to map the allocation (using vmaMapMemory() or #VMA_ALLOCATION_CREATE_MAPPED_BIT), - you must pass one of the flags: #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT - in VmaAllocationCreateInfo::flags. +/// \brief Intended usage of the allocated memory. +typedef enum VmaMemoryUsage +{ + /** No intended memory usage specified. + Use other members of VmaAllocationCreateInfo to specify your requirements. + */ + VMA_MEMORY_USAGE_UNKNOWN = 0, + /** + \deprecated Obsolete, preserved for backward compatibility. + Prefers `VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT`. + */ + VMA_MEMORY_USAGE_GPU_ONLY = 1, + /** + \deprecated Obsolete, preserved for backward compatibility. + Guarantees `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT` and `VK_MEMORY_PROPERTY_HOST_COHERENT_BIT`. + */ + VMA_MEMORY_USAGE_CPU_ONLY = 2, + /** + \deprecated Obsolete, preserved for backward compatibility. + Guarantees `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT`, prefers `VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT`. + */ + VMA_MEMORY_USAGE_CPU_TO_GPU = 3, + /** + \deprecated Obsolete, preserved for backward compatibility. + Guarantees `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT`, prefers `VK_MEMORY_PROPERTY_HOST_CACHED_BIT`. + */ + VMA_MEMORY_USAGE_GPU_TO_CPU = 4, + /** + \deprecated Obsolete, preserved for backward compatibility. + Prefers not `VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT`. + */ + VMA_MEMORY_USAGE_CPU_COPY = 5, + /** + Lazily allocated GPU memory having `VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT`. + Exists mostly on mobile platforms. Using it on desktop PC or other GPUs with no such memory type present will fail the allocation. - It can be used only with functions that let the library know `VkBufferCreateInfo` or `VkImageCreateInfo`, e.g. - vmaCreateBuffer(), vmaCreateImage(), vmaFindMemoryTypeIndexForBufferInfo(), vmaFindMemoryTypeIndexForImageInfo() - and not with generic memory allocation functions. - */ - VMA_MEMORY_USAGE_AUTO = 7, - /** - Selects best memory type automatically with preference for GPU (device) memory. + Usage: Memory for transient attachment images (color attachments, depth attachments etc.), created with `VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT`. - When using this flag, if you want to map the allocation (using vmaMapMemory() or #VMA_ALLOCATION_CREATE_MAPPED_BIT), - you must pass one of the flags: #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT - in VmaAllocationCreateInfo::flags. + Allocations with this usage are always created as dedicated - it implies #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT. + */ + VMA_MEMORY_USAGE_GPU_LAZILY_ALLOCATED = 6, + /** + Selects best memory type automatically. + This flag is recommended for most common use cases. - It can be used only with functions that let the library know `VkBufferCreateInfo` or `VkImageCreateInfo`, e.g. - vmaCreateBuffer(), vmaCreateImage(), vmaFindMemoryTypeIndexForBufferInfo(), vmaFindMemoryTypeIndexForImageInfo() - and not with generic memory allocation functions. - */ - VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE = 8, - /** - Selects best memory type automatically with preference for CPU (host) memory. + When using this flag, if you want to map the allocation (using vmaMapMemory() or #VMA_ALLOCATION_CREATE_MAPPED_BIT), + you must pass one of the flags: #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT + in VmaAllocationCreateInfo::flags. - When using this flag, if you want to map the allocation (using vmaMapMemory() or #VMA_ALLOCATION_CREATE_MAPPED_BIT), - you must pass one of the flags: #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT - in VmaAllocationCreateInfo::flags. + It can be used only with functions that let the library know `VkBufferCreateInfo` or `VkImageCreateInfo`, e.g. + vmaCreateBuffer(), vmaCreateImage(), vmaFindMemoryTypeIndexForBufferInfo(), vmaFindMemoryTypeIndexForImageInfo() + and not with generic memory allocation functions. + */ + VMA_MEMORY_USAGE_AUTO = 7, + /** + Selects best memory type automatically with preference for GPU (device) memory. - It can be used only with functions that let the library know `VkBufferCreateInfo` or `VkImageCreateInfo`, e.g. - vmaCreateBuffer(), vmaCreateImage(), vmaFindMemoryTypeIndexForBufferInfo(), vmaFindMemoryTypeIndexForImageInfo() - and not with generic memory allocation functions. - */ - VMA_MEMORY_USAGE_AUTO_PREFER_HOST = 9, + When using this flag, if you want to map the allocation (using vmaMapMemory() or #VMA_ALLOCATION_CREATE_MAPPED_BIT), + you must pass one of the flags: #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT + in VmaAllocationCreateInfo::flags. - VMA_MEMORY_USAGE_MAX_ENUM = 0x7FFFFFFF - } VmaMemoryUsage; + It can be used only with functions that let the library know `VkBufferCreateInfo` or `VkImageCreateInfo`, e.g. + vmaCreateBuffer(), vmaCreateImage(), vmaFindMemoryTypeIndexForBufferInfo(), vmaFindMemoryTypeIndexForImageInfo() + and not with generic memory allocation functions. + */ + VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE = 8, + /** + Selects best memory type automatically with preference for CPU (host) memory. - /// Flags to be passed as VmaAllocationCreateInfo::flags. - typedef enum VmaAllocationCreateFlagBits - { - /** \brief Set this flag if the allocation should have its own memory block. + When using this flag, if you want to map the allocation (using vmaMapMemory() or #VMA_ALLOCATION_CREATE_MAPPED_BIT), + you must pass one of the flags: #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT + in VmaAllocationCreateInfo::flags. - Use it for special, big resources, like fullscreen images used as attachments. + It can be used only with functions that let the library know `VkBufferCreateInfo` or `VkImageCreateInfo`, e.g. + vmaCreateBuffer(), vmaCreateImage(), vmaFindMemoryTypeIndexForBufferInfo(), vmaFindMemoryTypeIndexForImageInfo() + and not with generic memory allocation functions. + */ + VMA_MEMORY_USAGE_AUTO_PREFER_HOST = 9, - If you use this flag while creating a buffer or an image, `VkMemoryDedicatedAllocateInfo` - structure is applied if possible. - */ - VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT = 0x00000001, + VMA_MEMORY_USAGE_MAX_ENUM = 0x7FFFFFFF +} VmaMemoryUsage; - /** \brief Set this flag to only try to allocate from existing `VkDeviceMemory` blocks and never create new such block. +/// Flags to be passed as VmaAllocationCreateInfo::flags. +typedef enum VmaAllocationCreateFlagBits +{ + /** \brief Set this flag if the allocation should have its own memory block. - If new allocation cannot be placed in any of the existing blocks, allocation - fails with `VK_ERROR_OUT_OF_DEVICE_MEMORY` error. + Use it for special, big resources, like fullscreen images used as attachments. - You should not use #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT and - #VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT at the same time. It makes no sense. - */ - VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT = 0x00000002, - /** \brief Set this flag to use a memory that will be persistently mapped and retrieve pointer to it. + If you use this flag while creating a buffer or an image, `VkMemoryDedicatedAllocateInfo` + structure is applied if possible. + */ + VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT = 0x00000001, - Pointer to mapped memory will be returned through VmaAllocationInfo::pMappedData. + /** \brief Set this flag to only try to allocate from existing `VkDeviceMemory` blocks and never create new such block. - It is valid to use this flag for allocation made from memory type that is not - `HOST_VISIBLE`. This flag is then ignored and memory is not mapped. This is - useful if you need an allocation that is efficient to use on GPU - (`DEVICE_LOCAL`) and still want to map it directly if possible on platforms that - support it (e.g. Intel GPU). - */ - VMA_ALLOCATION_CREATE_MAPPED_BIT = 0x00000004, - /** \deprecated Preserved for backward compatibility. Consider using vmaSetAllocationName() instead. + If new allocation cannot be placed in any of the existing blocks, allocation + fails with `VK_ERROR_OUT_OF_DEVICE_MEMORY` error. - Set this flag to treat VmaAllocationCreateInfo::pUserData as pointer to a - null-terminated string. Instead of copying pointer value, a local copy of the - string is made and stored in allocation's `pName`. The string is automatically - freed together with the allocation. It is also used in vmaBuildStatsString(). - */ - VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT = 0x00000020, - /** Allocation will be created from upper stack in a double stack pool. + You should not use #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT and + #VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT at the same time. It makes no sense. + */ + VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT = 0x00000002, + /** \brief Set this flag to use a memory that will be persistently mapped and retrieve pointer to it. - This flag is only allowed for custom pools created with #VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT flag. - */ - VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT = 0x00000040, - /** Create both buffer/image and allocation, but don't bind them together. - It is useful when you want to bind yourself to do some more advanced binding, e.g. using some extensions. - The flag is meaningful only with functions that bind by default: vmaCreateBuffer(), vmaCreateImage(). - Otherwise it is ignored. + Pointer to mapped memory will be returned through VmaAllocationInfo::pMappedData. - If you want to make sure the new buffer/image is not tied to the new memory allocation - through `VkMemoryDedicatedAllocateInfoKHR` structure in case the allocation ends up in its own memory block, - use also flag #VMA_ALLOCATION_CREATE_CAN_ALIAS_BIT. - */ - VMA_ALLOCATION_CREATE_DONT_BIND_BIT = 0x00000080, - /** Create allocation only if additional device memory required for it, if any, won't exceed - memory budget. Otherwise return `VK_ERROR_OUT_OF_DEVICE_MEMORY`. - */ - VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT = 0x00000100, - /** \brief Set this flag if the allocated memory will have aliasing resources. + It is valid to use this flag for allocation made from memory type that is not + `HOST_VISIBLE`. This flag is then ignored and memory is not mapped. This is + useful if you need an allocation that is efficient to use on GPU + (`DEVICE_LOCAL`) and still want to map it directly if possible on platforms that + support it (e.g. Intel GPU). + */ + VMA_ALLOCATION_CREATE_MAPPED_BIT = 0x00000004, + /** \deprecated Preserved for backward compatibility. Consider using vmaSetAllocationName() instead. - Usage of this flag prevents supplying `VkMemoryDedicatedAllocateInfoKHR` when #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT is specified. - Otherwise created dedicated memory will not be suitable for aliasing resources, resulting in Vulkan Validation Layer errors. - */ - VMA_ALLOCATION_CREATE_CAN_ALIAS_BIT = 0x00000200, - /** - Requests possibility to map the allocation (using vmaMapMemory() or #VMA_ALLOCATION_CREATE_MAPPED_BIT). + Set this flag to treat VmaAllocationCreateInfo::pUserData as pointer to a + null-terminated string. Instead of copying pointer value, a local copy of the + string is made and stored in allocation's `pName`. The string is automatically + freed together with the allocation. It is also used in vmaBuildStatsString(). + */ + VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT = 0x00000020, + /** Allocation will be created from upper stack in a double stack pool. - - If you use #VMA_MEMORY_USAGE_AUTO or other `VMA_MEMORY_USAGE_AUTO*` value, - you must use this flag to be able to map the allocation. Otherwise, mapping is incorrect. - - If you use other value of #VmaMemoryUsage, this flag is ignored and mapping is always possible in memory types that are `HOST_VISIBLE`. - This includes allocations created in \ref custom_memory_pools. + This flag is only allowed for custom pools created with #VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT flag. + */ + VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT = 0x00000040, + /** Create both buffer/image and allocation, but don't bind them together. + It is useful when you want to bind yourself to do some more advanced binding, e.g. using some extensions. + The flag is meaningful only with functions that bind by default: vmaCreateBuffer(), vmaCreateImage(). + Otherwise it is ignored. - Declares that mapped memory will only be written sequentially, e.g. using `memcpy()` or a loop writing number-by-number, - never read or accessed randomly, so a memory type can be selected that is uncached and write-combined. + If you want to make sure the new buffer/image is not tied to the new memory allocation + through `VkMemoryDedicatedAllocateInfoKHR` structure in case the allocation ends up in its own memory block, + use also flag #VMA_ALLOCATION_CREATE_CAN_ALIAS_BIT. + */ + VMA_ALLOCATION_CREATE_DONT_BIND_BIT = 0x00000080, + /** Create allocation only if additional device memory required for it, if any, won't exceed + memory budget. Otherwise return `VK_ERROR_OUT_OF_DEVICE_MEMORY`. + */ + VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT = 0x00000100, + /** \brief Set this flag if the allocated memory will have aliasing resources. - \warning Violating this declaration may work correctly, but will likely be very slow. - Watch out for implicit reads introduced by doing e.g. `pMappedData[i] += x;` - Better prepare your data in a local variable and `memcpy()` it to the mapped pointer all at once. - */ - VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT = 0x00000400, - /** - Requests possibility to map the allocation (using vmaMapMemory() or #VMA_ALLOCATION_CREATE_MAPPED_BIT). + Usage of this flag prevents supplying `VkMemoryDedicatedAllocateInfoKHR` when #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT is specified. + Otherwise created dedicated memory will not be suitable for aliasing resources, resulting in Vulkan Validation Layer errors. + */ + VMA_ALLOCATION_CREATE_CAN_ALIAS_BIT = 0x00000200, + /** + Requests possibility to map the allocation (using vmaMapMemory() or #VMA_ALLOCATION_CREATE_MAPPED_BIT). - - If you use #VMA_MEMORY_USAGE_AUTO or other `VMA_MEMORY_USAGE_AUTO*` value, - you must use this flag to be able to map the allocation. Otherwise, mapping is incorrect. - - If you use other value of #VmaMemoryUsage, this flag is ignored and mapping is always possible in memory types that are `HOST_VISIBLE`. - This includes allocations created in \ref custom_memory_pools. + - If you use #VMA_MEMORY_USAGE_AUTO or other `VMA_MEMORY_USAGE_AUTO*` value, + you must use this flag to be able to map the allocation. Otherwise, mapping is incorrect. + - If you use other value of #VmaMemoryUsage, this flag is ignored and mapping is always possible in memory types that are `HOST_VISIBLE`. + This includes allocations created in \ref custom_memory_pools. - Declares that mapped memory can be read, written, and accessed in random order, - so a `HOST_CACHED` memory type is preferred. - */ - VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT = 0x00000800, - /** - Together with #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT, - it says that despite request for host access, a not-`HOST_VISIBLE` memory type can be selected - if it may improve performance. + Declares that mapped memory will only be written sequentially, e.g. using `memcpy()` or a loop writing number-by-number, + never read or accessed randomly, so a memory type can be selected that is uncached and write-combined. - By using this flag, you declare that you will check if the allocation ended up in a `HOST_VISIBLE` memory type - (e.g. using vmaGetAllocationMemoryProperties()) and if not, you will create some "staging" buffer and - issue an explicit transfer to write/read your data. - To prepare for this possibility, don't forget to add appropriate flags like - `VK_BUFFER_USAGE_TRANSFER_DST_BIT`, `VK_BUFFER_USAGE_TRANSFER_SRC_BIT` to the parameters of created buffer or image. - */ - VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT = 0x00001000, - /** Allocation strategy that chooses smallest possible free range for the allocation - to minimize memory usage and fragmentation, possibly at the expense of allocation time. - */ - VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT = 0x00010000, - /** Allocation strategy that chooses first suitable free range for the allocation - - not necessarily in terms of the smallest offset but the one that is easiest and fastest to find - to minimize allocation time, possibly at the expense of allocation quality. - */ - VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT = 0x00020000, - /** Allocation strategy that chooses always the lowest offset in available space. - This is not the most efficient strategy but achieves highly packed data. - Used internally by defragmentation, not recommended in typical usage. - */ - VMA_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT = 0x00040000, - /** Alias to #VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT. - */ - VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT = VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT, - /** Alias to #VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT. - */ - VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT = VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT, - /** A bit mask to extract only `STRATEGY` bits from entire set of flags. - */ - VMA_ALLOCATION_CREATE_STRATEGY_MASK = + \warning Violating this declaration may work correctly, but will likely be very slow. + Watch out for implicit reads introduced by doing e.g. `pMappedData[i] += x;` + Better prepare your data in a local variable and `memcpy()` it to the mapped pointer all at once. + */ + VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT = 0x00000400, + /** + Requests possibility to map the allocation (using vmaMapMemory() or #VMA_ALLOCATION_CREATE_MAPPED_BIT). + + - If you use #VMA_MEMORY_USAGE_AUTO or other `VMA_MEMORY_USAGE_AUTO*` value, + you must use this flag to be able to map the allocation. Otherwise, mapping is incorrect. + - If you use other value of #VmaMemoryUsage, this flag is ignored and mapping is always possible in memory types that are `HOST_VISIBLE`. + This includes allocations created in \ref custom_memory_pools. + + Declares that mapped memory can be read, written, and accessed in random order, + so a `HOST_CACHED` memory type is preferred. + */ + VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT = 0x00000800, + /** + Together with #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT, + it says that despite request for host access, a not-`HOST_VISIBLE` memory type can be selected + if it may improve performance. + + By using this flag, you declare that you will check if the allocation ended up in a `HOST_VISIBLE` memory type + (e.g. using vmaGetAllocationMemoryProperties()) and if not, you will create some "staging" buffer and + issue an explicit transfer to write/read your data. + To prepare for this possibility, don't forget to add appropriate flags like + `VK_BUFFER_USAGE_TRANSFER_DST_BIT`, `VK_BUFFER_USAGE_TRANSFER_SRC_BIT` to the parameters of created buffer or image. + */ + VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT = 0x00001000, + /** Allocation strategy that chooses smallest possible free range for the allocation + to minimize memory usage and fragmentation, possibly at the expense of allocation time. + */ + VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT = 0x00010000, + /** Allocation strategy that chooses first suitable free range for the allocation - + not necessarily in terms of the smallest offset but the one that is easiest and fastest to find + to minimize allocation time, possibly at the expense of allocation quality. + */ + VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT = 0x00020000, + /** Allocation strategy that chooses always the lowest offset in available space. + This is not the most efficient strategy but achieves highly packed data. + Used internally by defragmentation, not recommended in typical usage. + */ + VMA_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT = 0x00040000, + /** Alias to #VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT. + */ + VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT = VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT, + /** Alias to #VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT. + */ + VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT = VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT, + /** A bit mask to extract only `STRATEGY` bits from entire set of flags. + */ + VMA_ALLOCATION_CREATE_STRATEGY_MASK = VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT | VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT | VMA_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT, - VMA_ALLOCATION_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF - } VmaAllocationCreateFlagBits; - /// See #VmaAllocationCreateFlagBits. - typedef VkFlags VmaAllocationCreateFlags; + VMA_ALLOCATION_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VmaAllocationCreateFlagBits; +/// See #VmaAllocationCreateFlagBits. +typedef VkFlags VmaAllocationCreateFlags; - /// Flags to be passed as VmaPoolCreateInfo::flags. - typedef enum VmaPoolCreateFlagBits - { - /** \brief Use this flag if you always allocate only buffers and linear images or only optimal images out of this pool and so Buffer-Image Granularity can be ignored. +/// Flags to be passed as VmaPoolCreateInfo::flags. +typedef enum VmaPoolCreateFlagBits +{ + /** \brief Use this flag if you always allocate only buffers and linear images or only optimal images out of this pool and so Buffer-Image Granularity can be ignored. - This is an optional optimization flag. + This is an optional optimization flag. - If you always allocate using vmaCreateBuffer(), vmaCreateImage(), - vmaAllocateMemoryForBuffer(), then you don't need to use it because allocator - knows exact type of your allocations so it can handle Buffer-Image Granularity - in the optimal way. + If you always allocate using vmaCreateBuffer(), vmaCreateImage(), + vmaAllocateMemoryForBuffer(), then you don't need to use it because allocator + knows exact type of your allocations so it can handle Buffer-Image Granularity + in the optimal way. - If you also allocate using vmaAllocateMemoryForImage() or vmaAllocateMemory(), - exact type of such allocations is not known, so allocator must be conservative - in handling Buffer-Image Granularity, which can lead to suboptimal allocation - (wasted memory). In that case, if you can make sure you always allocate only - buffers and linear images or only optimal images out of this pool, use this flag - to make allocator disregard Buffer-Image Granularity and so make allocations - faster and more optimal. - */ - VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT = 0x00000002, + If you also allocate using vmaAllocateMemoryForImage() or vmaAllocateMemory(), + exact type of such allocations is not known, so allocator must be conservative + in handling Buffer-Image Granularity, which can lead to suboptimal allocation + (wasted memory). In that case, if you can make sure you always allocate only + buffers and linear images or only optimal images out of this pool, use this flag + to make allocator disregard Buffer-Image Granularity and so make allocations + faster and more optimal. + */ + VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT = 0x00000002, - /** \brief Enables alternative, linear allocation algorithm in this pool. + /** \brief Enables alternative, linear allocation algorithm in this pool. - Specify this flag to enable linear allocation algorithm, which always creates - new allocations after last one and doesn't reuse space from allocations freed in - between. It trades memory consumption for simplified algorithm and data - structure, which has better performance and uses less memory for metadata. + Specify this flag to enable linear allocation algorithm, which always creates + new allocations after last one and doesn't reuse space from allocations freed in + between. It trades memory consumption for simplified algorithm and data + structure, which has better performance and uses less memory for metadata. - By using this flag, you can achieve behavior of free-at-once, stack, - ring buffer, and double stack. - For details, see documentation chapter \ref linear_algorithm. - */ - VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT = 0x00000004, + By using this flag, you can achieve behavior of free-at-once, stack, + ring buffer, and double stack. + For details, see documentation chapter \ref linear_algorithm. + */ + VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT = 0x00000004, - /** Bit mask to extract only `ALGORITHM` bits from entire set of flags. - */ - VMA_POOL_CREATE_ALGORITHM_MASK = + /** Bit mask to extract only `ALGORITHM` bits from entire set of flags. + */ + VMA_POOL_CREATE_ALGORITHM_MASK = VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT, - VMA_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF - } VmaPoolCreateFlagBits; - /// Flags to be passed as VmaPoolCreateInfo::flags. See #VmaPoolCreateFlagBits. - typedef VkFlags VmaPoolCreateFlags; + VMA_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VmaPoolCreateFlagBits; +/// Flags to be passed as VmaPoolCreateInfo::flags. See #VmaPoolCreateFlagBits. +typedef VkFlags VmaPoolCreateFlags; - /// Flags to be passed as VmaDefragmentationInfo::flags. - typedef enum VmaDefragmentationFlagBits - { - /* \brief Use simple but fast algorithm for defragmentation. - May not achieve best results but will require least time to compute and least allocations to copy. - */ - VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FAST_BIT = 0x1, - /* \brief Default defragmentation algorithm, applied also when no `ALGORITHM` flag is specified. - Offers a balance between defragmentation quality and the amount of allocations and bytes that need to be moved. - */ - VMA_DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED_BIT = 0x2, - /* \brief Perform full defragmentation of memory. - Can result in notably more time to compute and allocations to copy, but will achieve best memory packing. - */ - VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FULL_BIT = 0x4, - /** \brief Use the most roboust algorithm at the cost of time to compute and number of copies to make. - Only available when bufferImageGranularity is greater than 1, since it aims to reduce - alignment issues between different types of resources. - Otherwise falls back to same behavior as #VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FULL_BIT. - */ - VMA_DEFRAGMENTATION_FLAG_ALGORITHM_EXTENSIVE_BIT = 0x8, +/// Flags to be passed as VmaDefragmentationInfo::flags. +typedef enum VmaDefragmentationFlagBits +{ + /* \brief Use simple but fast algorithm for defragmentation. + May not achieve best results but will require least time to compute and least allocations to copy. + */ + VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FAST_BIT = 0x1, + /* \brief Default defragmentation algorithm, applied also when no `ALGORITHM` flag is specified. + Offers a balance between defragmentation quality and the amount of allocations and bytes that need to be moved. + */ + VMA_DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED_BIT = 0x2, + /* \brief Perform full defragmentation of memory. + Can result in notably more time to compute and allocations to copy, but will achieve best memory packing. + */ + VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FULL_BIT = 0x4, + /** \brief Use the most roboust algorithm at the cost of time to compute and number of copies to make. + Only available when bufferImageGranularity is greater than 1, since it aims to reduce + alignment issues between different types of resources. + Otherwise falls back to same behavior as #VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FULL_BIT. + */ + VMA_DEFRAGMENTATION_FLAG_ALGORITHM_EXTENSIVE_BIT = 0x8, - /// A bit mask to extract only `ALGORITHM` bits from entire set of flags. - VMA_DEFRAGMENTATION_FLAG_ALGORITHM_MASK = + /// A bit mask to extract only `ALGORITHM` bits from entire set of flags. + VMA_DEFRAGMENTATION_FLAG_ALGORITHM_MASK = VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FAST_BIT | VMA_DEFRAGMENTATION_FLAG_ALGORITHM_BALANCED_BIT | VMA_DEFRAGMENTATION_FLAG_ALGORITHM_FULL_BIT | VMA_DEFRAGMENTATION_FLAG_ALGORITHM_EXTENSIVE_BIT, - VMA_DEFRAGMENTATION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF - } VmaDefragmentationFlagBits; - /// See #VmaDefragmentationFlagBits. - typedef VkFlags VmaDefragmentationFlags; + VMA_DEFRAGMENTATION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VmaDefragmentationFlagBits; +/// See #VmaDefragmentationFlagBits. +typedef VkFlags VmaDefragmentationFlags; - /// Operation performed on single defragmentation move. See structure #VmaDefragmentationMove. - typedef enum VmaDefragmentationMoveOperation - { - /// Buffer/image has been recreated at `dstTmpAllocation`, data has been copied, old buffer/image has been destroyed. `srcAllocation` should be changed to point to the new place. This is the default value set by vmaBeginDefragmentationPass(). - VMA_DEFRAGMENTATION_MOVE_OPERATION_COPY = 0, - /// Set this value if you cannot move the allocation. New place reserved at `dstTmpAllocation` will be freed. `srcAllocation` will remain unchanged. - VMA_DEFRAGMENTATION_MOVE_OPERATION_IGNORE = 1, - /// Set this value if you decide to abandon the allocation and you destroyed the buffer/image. New place reserved at `dstTmpAllocation` will be freed, along with `srcAllocation`, which will be destroyed. - VMA_DEFRAGMENTATION_MOVE_OPERATION_DESTROY = 2, - } VmaDefragmentationMoveOperation; +/// Operation performed on single defragmentation move. See structure #VmaDefragmentationMove. +typedef enum VmaDefragmentationMoveOperation +{ + /// Buffer/image has been recreated at `dstTmpAllocation`, data has been copied, old buffer/image has been destroyed. `srcAllocation` should be changed to point to the new place. This is the default value set by vmaBeginDefragmentationPass(). + VMA_DEFRAGMENTATION_MOVE_OPERATION_COPY = 0, + /// Set this value if you cannot move the allocation. New place reserved at `dstTmpAllocation` will be freed. `srcAllocation` will remain unchanged. + VMA_DEFRAGMENTATION_MOVE_OPERATION_IGNORE = 1, + /// Set this value if you decide to abandon the allocation and you destroyed the buffer/image. New place reserved at `dstTmpAllocation` will be freed, along with `srcAllocation`, which will be destroyed. + VMA_DEFRAGMENTATION_MOVE_OPERATION_DESTROY = 2, +} VmaDefragmentationMoveOperation; - /** @} */ +/** @} */ - /** - \addtogroup group_virtual - @{ +/** +\addtogroup group_virtual +@{ +*/ + +/// Flags to be passed as VmaVirtualBlockCreateInfo::flags. +typedef enum VmaVirtualBlockCreateFlagBits +{ + /** \brief Enables alternative, linear allocation algorithm in this virtual block. + + Specify this flag to enable linear allocation algorithm, which always creates + new allocations after last one and doesn't reuse space from allocations freed in + between. It trades memory consumption for simplified algorithm and data + structure, which has better performance and uses less memory for metadata. + + By using this flag, you can achieve behavior of free-at-once, stack, + ring buffer, and double stack. + For details, see documentation chapter \ref linear_algorithm. */ + VMA_VIRTUAL_BLOCK_CREATE_LINEAR_ALGORITHM_BIT = 0x00000001, - /// Flags to be passed as VmaVirtualBlockCreateInfo::flags. - typedef enum VmaVirtualBlockCreateFlagBits - { - /** \brief Enables alternative, linear allocation algorithm in this virtual block. - - Specify this flag to enable linear allocation algorithm, which always creates - new allocations after last one and doesn't reuse space from allocations freed in - between. It trades memory consumption for simplified algorithm and data - structure, which has better performance and uses less memory for metadata. - - By using this flag, you can achieve behavior of free-at-once, stack, - ring buffer, and double stack. - For details, see documentation chapter \ref linear_algorithm. - */ - VMA_VIRTUAL_BLOCK_CREATE_LINEAR_ALGORITHM_BIT = 0x00000001, - - /** \brief Bit mask to extract only `ALGORITHM` bits from entire set of flags. - */ - VMA_VIRTUAL_BLOCK_CREATE_ALGORITHM_MASK = + /** \brief Bit mask to extract only `ALGORITHM` bits from entire set of flags. + */ + VMA_VIRTUAL_BLOCK_CREATE_ALGORITHM_MASK = VMA_VIRTUAL_BLOCK_CREATE_LINEAR_ALGORITHM_BIT, - VMA_VIRTUAL_BLOCK_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF - } VmaVirtualBlockCreateFlagBits; - /// Flags to be passed as VmaVirtualBlockCreateInfo::flags. See #VmaVirtualBlockCreateFlagBits. - typedef VkFlags VmaVirtualBlockCreateFlags; + VMA_VIRTUAL_BLOCK_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VmaVirtualBlockCreateFlagBits; +/// Flags to be passed as VmaVirtualBlockCreateInfo::flags. See #VmaVirtualBlockCreateFlagBits. +typedef VkFlags VmaVirtualBlockCreateFlags; - /// Flags to be passed as VmaVirtualAllocationCreateInfo::flags. - typedef enum VmaVirtualAllocationCreateFlagBits - { - /** \brief Allocation will be created from upper stack in a double stack pool. +/// Flags to be passed as VmaVirtualAllocationCreateInfo::flags. +typedef enum VmaVirtualAllocationCreateFlagBits +{ + /** \brief Allocation will be created from upper stack in a double stack pool. - This flag is only allowed for virtual blocks created with #VMA_VIRTUAL_BLOCK_CREATE_LINEAR_ALGORITHM_BIT flag. - */ - VMA_VIRTUAL_ALLOCATION_CREATE_UPPER_ADDRESS_BIT = VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT, - /** \brief Allocation strategy that tries to minimize memory usage. - */ - VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT = VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT, - /** \brief Allocation strategy that tries to minimize allocation time. - */ - VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT = VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT, - /** Allocation strategy that chooses always the lowest offset in available space. - This is not the most efficient strategy but achieves highly packed data. - */ - VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT = VMA_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT, - /** \brief A bit mask to extract only `STRATEGY` bits from entire set of flags. + This flag is only allowed for virtual blocks created with #VMA_VIRTUAL_BLOCK_CREATE_LINEAR_ALGORITHM_BIT flag. + */ + VMA_VIRTUAL_ALLOCATION_CREATE_UPPER_ADDRESS_BIT = VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT, + /** \brief Allocation strategy that tries to minimize memory usage. + */ + VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT = VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT, + /** \brief Allocation strategy that tries to minimize allocation time. + */ + VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT = VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT, + /** Allocation strategy that chooses always the lowest offset in available space. + This is not the most efficient strategy but achieves highly packed data. + */ + VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT = VMA_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT, + /** \brief A bit mask to extract only `STRATEGY` bits from entire set of flags. - These strategy flags are binary compatible with equivalent flags in #VmaAllocationCreateFlagBits. - */ - VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MASK = VMA_ALLOCATION_CREATE_STRATEGY_MASK, + These strategy flags are binary compatible with equivalent flags in #VmaAllocationCreateFlagBits. + */ + VMA_VIRTUAL_ALLOCATION_CREATE_STRATEGY_MASK = VMA_ALLOCATION_CREATE_STRATEGY_MASK, - VMA_VIRTUAL_ALLOCATION_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF - } VmaVirtualAllocationCreateFlagBits; - /// Flags to be passed as VmaVirtualAllocationCreateInfo::flags. See #VmaVirtualAllocationCreateFlagBits. - typedef VkFlags VmaVirtualAllocationCreateFlags; + VMA_VIRTUAL_ALLOCATION_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF +} VmaVirtualAllocationCreateFlagBits; +/// Flags to be passed as VmaVirtualAllocationCreateInfo::flags. See #VmaVirtualAllocationCreateFlagBits. +typedef VkFlags VmaVirtualAllocationCreateFlags; - /** @} */ +/** @} */ #endif // _VMA_ENUM_DECLARATIONS @@ -871,781 +880,781 @@ Call function vmaDestroyAllocator() to destroy it. It is recommended to create just one object of this type per `VkDevice` object, right after Vulkan is initialized and keep it alive until before Vulkan device is destroyed. */ - VK_DEFINE_HANDLE(VmaAllocator) +VK_DEFINE_HANDLE(VmaAllocator) - /** @} */ +/** @} */ - /** - \addtogroup group_alloc - @{ - */ +/** +\addtogroup group_alloc +@{ +*/ - /** \struct VmaPool - \brief Represents custom memory pool +/** \struct VmaPool +\brief Represents custom memory pool - Fill structure VmaPoolCreateInfo and call function vmaCreatePool() to create it. - Call function vmaDestroyPool() to destroy it. +Fill structure VmaPoolCreateInfo and call function vmaCreatePool() to create it. +Call function vmaDestroyPool() to destroy it. - For more information see [Custom memory pools](@ref choosing_memory_type_custom_memory_pools). - */ - VK_DEFINE_HANDLE(VmaPool) +For more information see [Custom memory pools](@ref choosing_memory_type_custom_memory_pools). +*/ +VK_DEFINE_HANDLE(VmaPool) - /** \struct VmaAllocation - \brief Represents single memory allocation. +/** \struct VmaAllocation +\brief Represents single memory allocation. - It may be either dedicated block of `VkDeviceMemory` or a specific region of a bigger block of this type - plus unique offset. +It may be either dedicated block of `VkDeviceMemory` or a specific region of a bigger block of this type +plus unique offset. - There are multiple ways to create such object. - You need to fill structure VmaAllocationCreateInfo. - For more information see [Choosing memory type](@ref choosing_memory_type). +There are multiple ways to create such object. +You need to fill structure VmaAllocationCreateInfo. +For more information see [Choosing memory type](@ref choosing_memory_type). - Although the library provides convenience functions that create Vulkan buffer or image, - allocate memory for it and bind them together, - binding of the allocation to a buffer or an image is out of scope of the allocation itself. - Allocation object can exist without buffer/image bound, - binding can be done manually by the user, and destruction of it can be done - independently of destruction of the allocation. +Although the library provides convenience functions that create Vulkan buffer or image, +allocate memory for it and bind them together, +binding of the allocation to a buffer or an image is out of scope of the allocation itself. +Allocation object can exist without buffer/image bound, +binding can be done manually by the user, and destruction of it can be done +independently of destruction of the allocation. - The object also remembers its size and some other information. - To retrieve this information, use function vmaGetAllocationInfo() and inspect - returned structure VmaAllocationInfo. - */ - VK_DEFINE_HANDLE(VmaAllocation) +The object also remembers its size and some other information. +To retrieve this information, use function vmaGetAllocationInfo() and inspect +returned structure VmaAllocationInfo. +*/ +VK_DEFINE_HANDLE(VmaAllocation) - /** \struct VmaDefragmentationContext - \brief An opaque object that represents started defragmentation process. +/** \struct VmaDefragmentationContext +\brief An opaque object that represents started defragmentation process. - Fill structure #VmaDefragmentationInfo and call function vmaBeginDefragmentation() to create it. - Call function vmaEndDefragmentation() to destroy it. - */ - VK_DEFINE_HANDLE(VmaDefragmentationContext) +Fill structure #VmaDefragmentationInfo and call function vmaBeginDefragmentation() to create it. +Call function vmaEndDefragmentation() to destroy it. +*/ +VK_DEFINE_HANDLE(VmaDefragmentationContext) - /** @} */ +/** @} */ - /** - \addtogroup group_virtual - @{ - */ +/** +\addtogroup group_virtual +@{ +*/ - /** \struct VmaVirtualAllocation - \brief Represents single memory allocation done inside VmaVirtualBlock. +/** \struct VmaVirtualAllocation +\brief Represents single memory allocation done inside VmaVirtualBlock. - Use it as a unique identifier to virtual allocation within the single block. +Use it as a unique identifier to virtual allocation within the single block. - Use value `VK_NULL_HANDLE` to represent a null/invalid allocation. - */ - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VmaVirtualAllocation) +Use value `VK_NULL_HANDLE` to represent a null/invalid allocation. +*/ +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VmaVirtualAllocation) - /** @} */ +/** @} */ - /** - \addtogroup group_virtual - @{ - */ +/** +\addtogroup group_virtual +@{ +*/ - /** \struct VmaVirtualBlock - \brief Handle to a virtual block object that allows to use core allocation algorithm without allocating any real GPU memory. +/** \struct VmaVirtualBlock +\brief Handle to a virtual block object that allows to use core allocation algorithm without allocating any real GPU memory. - Fill in #VmaVirtualBlockCreateInfo structure and use vmaCreateVirtualBlock() to create it. Use vmaDestroyVirtualBlock() to destroy it. - For more information, see documentation chapter \ref virtual_allocator. +Fill in #VmaVirtualBlockCreateInfo structure and use vmaCreateVirtualBlock() to create it. Use vmaDestroyVirtualBlock() to destroy it. +For more information, see documentation chapter \ref virtual_allocator. - This object is not thread-safe - should not be used from multiple threads simultaneously, must be synchronized externally. - */ - VK_DEFINE_HANDLE(VmaVirtualBlock) +This object is not thread-safe - should not be used from multiple threads simultaneously, must be synchronized externally. +*/ +VK_DEFINE_HANDLE(VmaVirtualBlock) - /** @} */ +/** @} */ - /** - \addtogroup group_init - @{ - */ +/** +\addtogroup group_init +@{ +*/ - /// Callback function called after successful vkAllocateMemory. - typedef void (VKAPI_PTR* PFN_vmaAllocateDeviceMemoryFunction)( - VmaAllocator VMA_NOT_NULL allocator, - uint32_t memoryType, - VkDeviceMemory VMA_NOT_NULL_NON_DISPATCHABLE memory, - VkDeviceSize size, - void* VMA_NULLABLE pUserData); +/// Callback function called after successful vkAllocateMemory. +typedef void (VKAPI_PTR* PFN_vmaAllocateDeviceMemoryFunction)( + VmaAllocator VMA_NOT_NULL allocator, + uint32_t memoryType, + VkDeviceMemory VMA_NOT_NULL_NON_DISPATCHABLE memory, + VkDeviceSize size, + void* VMA_NULLABLE pUserData); - /// Callback function called before vkFreeMemory. - typedef void (VKAPI_PTR* PFN_vmaFreeDeviceMemoryFunction)( - VmaAllocator VMA_NOT_NULL allocator, - uint32_t memoryType, - VkDeviceMemory VMA_NOT_NULL_NON_DISPATCHABLE memory, - VkDeviceSize size, - void* VMA_NULLABLE pUserData); +/// Callback function called before vkFreeMemory. +typedef void (VKAPI_PTR* PFN_vmaFreeDeviceMemoryFunction)( + VmaAllocator VMA_NOT_NULL allocator, + uint32_t memoryType, + VkDeviceMemory VMA_NOT_NULL_NON_DISPATCHABLE memory, + VkDeviceSize size, + void* VMA_NULLABLE pUserData); - /** \brief Set of callbacks that the library will call for `vkAllocateMemory` and `vkFreeMemory`. +/** \brief Set of callbacks that the library will call for `vkAllocateMemory` and `vkFreeMemory`. - Provided for informative purpose, e.g. to gather statistics about number of - allocations or total amount of memory allocated in Vulkan. +Provided for informative purpose, e.g. to gather statistics about number of +allocations or total amount of memory allocated in Vulkan. - Used in VmaAllocatorCreateInfo::pDeviceMemoryCallbacks. - */ - typedef struct VmaDeviceMemoryCallbacks - { - /// Optional, can be null. - PFN_vmaAllocateDeviceMemoryFunction VMA_NULLABLE pfnAllocate; - /// Optional, can be null. - PFN_vmaFreeDeviceMemoryFunction VMA_NULLABLE pfnFree; - /// Optional, can be null. - void* VMA_NULLABLE pUserData; - } VmaDeviceMemoryCallbacks; +Used in VmaAllocatorCreateInfo::pDeviceMemoryCallbacks. +*/ +typedef struct VmaDeviceMemoryCallbacks +{ + /// Optional, can be null. + PFN_vmaAllocateDeviceMemoryFunction VMA_NULLABLE pfnAllocate; + /// Optional, can be null. + PFN_vmaFreeDeviceMemoryFunction VMA_NULLABLE pfnFree; + /// Optional, can be null. + void* VMA_NULLABLE pUserData; +} VmaDeviceMemoryCallbacks; - /** \brief Pointers to some Vulkan functions - a subset used by the library. +/** \brief Pointers to some Vulkan functions - a subset used by the library. - Used in VmaAllocatorCreateInfo::pVulkanFunctions. - */ - typedef struct VmaVulkanFunctions - { - /// Required when using VMA_DYNAMIC_VULKAN_FUNCTIONS. - PFN_vkGetInstanceProcAddr VMA_NULLABLE vkGetInstanceProcAddr; - /// Required when using VMA_DYNAMIC_VULKAN_FUNCTIONS. - PFN_vkGetDeviceProcAddr VMA_NULLABLE vkGetDeviceProcAddr; - PFN_vkGetPhysicalDeviceProperties VMA_NULLABLE vkGetPhysicalDeviceProperties; - PFN_vkGetPhysicalDeviceMemoryProperties VMA_NULLABLE vkGetPhysicalDeviceMemoryProperties; - PFN_vkAllocateMemory VMA_NULLABLE vkAllocateMemory; - PFN_vkFreeMemory VMA_NULLABLE vkFreeMemory; - PFN_vkMapMemory VMA_NULLABLE vkMapMemory; - PFN_vkUnmapMemory VMA_NULLABLE vkUnmapMemory; - PFN_vkFlushMappedMemoryRanges VMA_NULLABLE vkFlushMappedMemoryRanges; - PFN_vkInvalidateMappedMemoryRanges VMA_NULLABLE vkInvalidateMappedMemoryRanges; - PFN_vkBindBufferMemory VMA_NULLABLE vkBindBufferMemory; - PFN_vkBindImageMemory VMA_NULLABLE vkBindImageMemory; - PFN_vkGetBufferMemoryRequirements VMA_NULLABLE vkGetBufferMemoryRequirements; - PFN_vkGetImageMemoryRequirements VMA_NULLABLE vkGetImageMemoryRequirements; - PFN_vkCreateBuffer VMA_NULLABLE vkCreateBuffer; - PFN_vkDestroyBuffer VMA_NULLABLE vkDestroyBuffer; - PFN_vkCreateImage VMA_NULLABLE vkCreateImage; - PFN_vkDestroyImage VMA_NULLABLE vkDestroyImage; - PFN_vkCmdCopyBuffer VMA_NULLABLE vkCmdCopyBuffer; +Used in VmaAllocatorCreateInfo::pVulkanFunctions. +*/ +typedef struct VmaVulkanFunctions +{ + /// Required when using VMA_DYNAMIC_VULKAN_FUNCTIONS. + PFN_vkGetInstanceProcAddr VMA_NULLABLE vkGetInstanceProcAddr; + /// Required when using VMA_DYNAMIC_VULKAN_FUNCTIONS. + PFN_vkGetDeviceProcAddr VMA_NULLABLE vkGetDeviceProcAddr; + PFN_vkGetPhysicalDeviceProperties VMA_NULLABLE vkGetPhysicalDeviceProperties; + PFN_vkGetPhysicalDeviceMemoryProperties VMA_NULLABLE vkGetPhysicalDeviceMemoryProperties; + PFN_vkAllocateMemory VMA_NULLABLE vkAllocateMemory; + PFN_vkFreeMemory VMA_NULLABLE vkFreeMemory; + PFN_vkMapMemory VMA_NULLABLE vkMapMemory; + PFN_vkUnmapMemory VMA_NULLABLE vkUnmapMemory; + PFN_vkFlushMappedMemoryRanges VMA_NULLABLE vkFlushMappedMemoryRanges; + PFN_vkInvalidateMappedMemoryRanges VMA_NULLABLE vkInvalidateMappedMemoryRanges; + PFN_vkBindBufferMemory VMA_NULLABLE vkBindBufferMemory; + PFN_vkBindImageMemory VMA_NULLABLE vkBindImageMemory; + PFN_vkGetBufferMemoryRequirements VMA_NULLABLE vkGetBufferMemoryRequirements; + PFN_vkGetImageMemoryRequirements VMA_NULLABLE vkGetImageMemoryRequirements; + PFN_vkCreateBuffer VMA_NULLABLE vkCreateBuffer; + PFN_vkDestroyBuffer VMA_NULLABLE vkDestroyBuffer; + PFN_vkCreateImage VMA_NULLABLE vkCreateImage; + PFN_vkDestroyImage VMA_NULLABLE vkDestroyImage; + PFN_vkCmdCopyBuffer VMA_NULLABLE vkCmdCopyBuffer; #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 - /// Fetch "vkGetBufferMemoryRequirements2" on Vulkan >= 1.1, fetch "vkGetBufferMemoryRequirements2KHR" when using VK_KHR_dedicated_allocation extension. - PFN_vkGetBufferMemoryRequirements2KHR VMA_NULLABLE vkGetBufferMemoryRequirements2KHR; - /// Fetch "vkGetImageMemoryRequirements2" on Vulkan >= 1.1, fetch "vkGetImageMemoryRequirements2KHR" when using VK_KHR_dedicated_allocation extension. - PFN_vkGetImageMemoryRequirements2KHR VMA_NULLABLE vkGetImageMemoryRequirements2KHR; + /// Fetch "vkGetBufferMemoryRequirements2" on Vulkan >= 1.1, fetch "vkGetBufferMemoryRequirements2KHR" when using VK_KHR_dedicated_allocation extension. + PFN_vkGetBufferMemoryRequirements2KHR VMA_NULLABLE vkGetBufferMemoryRequirements2KHR; + /// Fetch "vkGetImageMemoryRequirements2" on Vulkan >= 1.1, fetch "vkGetImageMemoryRequirements2KHR" when using VK_KHR_dedicated_allocation extension. + PFN_vkGetImageMemoryRequirements2KHR VMA_NULLABLE vkGetImageMemoryRequirements2KHR; #endif #if VMA_BIND_MEMORY2 || VMA_VULKAN_VERSION >= 1001000 - /// Fetch "vkBindBufferMemory2" on Vulkan >= 1.1, fetch "vkBindBufferMemory2KHR" when using VK_KHR_bind_memory2 extension. - PFN_vkBindBufferMemory2KHR VMA_NULLABLE vkBindBufferMemory2KHR; - /// Fetch "vkBindImageMemory2" on Vulkan >= 1.1, fetch "vkBindImageMemory2KHR" when using VK_KHR_bind_memory2 extension. - PFN_vkBindImageMemory2KHR VMA_NULLABLE vkBindImageMemory2KHR; + /// Fetch "vkBindBufferMemory2" on Vulkan >= 1.1, fetch "vkBindBufferMemory2KHR" when using VK_KHR_bind_memory2 extension. + PFN_vkBindBufferMemory2KHR VMA_NULLABLE vkBindBufferMemory2KHR; + /// Fetch "vkBindImageMemory2" on Vulkan >= 1.1, fetch "vkBindImageMemory2KHR" when using VK_KHR_bind_memory2 extension. + PFN_vkBindImageMemory2KHR VMA_NULLABLE vkBindImageMemory2KHR; #endif #if VMA_MEMORY_BUDGET || VMA_VULKAN_VERSION >= 1001000 - /// Fetch from "vkGetPhysicalDeviceMemoryProperties2" on Vulkan >= 1.1, but you can also fetch it from "vkGetPhysicalDeviceMemoryProperties2KHR" if you enabled extension VK_KHR_get_physical_device_properties2. - PFN_vkGetPhysicalDeviceMemoryProperties2KHR VMA_NULLABLE vkGetPhysicalDeviceMemoryProperties2KHR; + /// Fetch from "vkGetPhysicalDeviceMemoryProperties2" on Vulkan >= 1.1, but you can also fetch it from "vkGetPhysicalDeviceMemoryProperties2KHR" if you enabled extension VK_KHR_get_physical_device_properties2. + PFN_vkGetPhysicalDeviceMemoryProperties2KHR VMA_NULLABLE vkGetPhysicalDeviceMemoryProperties2KHR; #endif #if VMA_KHR_MAINTENANCE4 || VMA_VULKAN_VERSION >= 1003000 - /// Fetch from "vkGetDeviceBufferMemoryRequirements" on Vulkan >= 1.3, but you can also fetch it from "vkGetDeviceBufferMemoryRequirementsKHR" if you enabled extension VK_KHR_maintenance4. - PFN_vkGetDeviceBufferMemoryRequirementsKHR VMA_NULLABLE vkGetDeviceBufferMemoryRequirements; - /// Fetch from "vkGetDeviceImageMemoryRequirements" on Vulkan >= 1.3, but you can also fetch it from "vkGetDeviceImageMemoryRequirementsKHR" if you enabled extension VK_KHR_maintenance4. - PFN_vkGetDeviceImageMemoryRequirementsKHR VMA_NULLABLE vkGetDeviceImageMemoryRequirements; + /// Fetch from "vkGetDeviceBufferMemoryRequirements" on Vulkan >= 1.3, but you can also fetch it from "vkGetDeviceBufferMemoryRequirementsKHR" if you enabled extension VK_KHR_maintenance4. + PFN_vkGetDeviceBufferMemoryRequirementsKHR VMA_NULLABLE vkGetDeviceBufferMemoryRequirements; + /// Fetch from "vkGetDeviceImageMemoryRequirements" on Vulkan >= 1.3, but you can also fetch it from "vkGetDeviceImageMemoryRequirementsKHR" if you enabled extension VK_KHR_maintenance4. + PFN_vkGetDeviceImageMemoryRequirementsKHR VMA_NULLABLE vkGetDeviceImageMemoryRequirements; #endif #ifdef VK_USE_PLATFORM_WIN32_KHR - PFN_vkGetMemoryWin32HandleKHR VMA_NULLABLE vkGetMemoryWin32HandleKHR; + PFN_vkGetMemoryWin32HandleKHR VMA_NULLABLE vkGetMemoryWin32HandleKHR; #else - void* VMA_NULLABLE vkGetMemoryWin32HandleKHR; + void* VMA_NULLABLE vkGetMemoryWin32HandleKHR; #endif - } VmaVulkanFunctions; +} VmaVulkanFunctions; - /// Description of a Allocator to be created. - typedef struct VmaAllocatorCreateInfo - { - /// Flags for created allocator. Use #VmaAllocatorCreateFlagBits enum. - VmaAllocatorCreateFlags flags; - /// Vulkan physical device. - /** It must be valid throughout whole lifetime of created allocator. */ - VkPhysicalDevice VMA_NOT_NULL physicalDevice; - /// Vulkan device. - /** It must be valid throughout whole lifetime of created allocator. */ - VkDevice VMA_NOT_NULL device; - /// Preferred size of a single `VkDeviceMemory` block to be allocated from large heaps > 1 GiB. Optional. - /** Set to 0 to use default, which is currently 256 MiB. */ - VkDeviceSize preferredLargeHeapBlockSize; - /// Custom CPU memory allocation callbacks. Optional. - /** Optional, can be null. When specified, will also be used for all CPU-side memory allocations. */ - const VkAllocationCallbacks* VMA_NULLABLE pAllocationCallbacks; - /// Informative callbacks for `vkAllocateMemory`, `vkFreeMemory`. Optional. - /** Optional, can be null. */ - const VmaDeviceMemoryCallbacks* VMA_NULLABLE pDeviceMemoryCallbacks; - /** \brief Either null or a pointer to an array of limits on maximum number of bytes that can be allocated out of particular Vulkan memory heap. +/// Description of a Allocator to be created. +typedef struct VmaAllocatorCreateInfo +{ + /// Flags for created allocator. Use #VmaAllocatorCreateFlagBits enum. + VmaAllocatorCreateFlags flags; + /// Vulkan physical device. + /** It must be valid throughout whole lifetime of created allocator. */ + VkPhysicalDevice VMA_NOT_NULL physicalDevice; + /// Vulkan device. + /** It must be valid throughout whole lifetime of created allocator. */ + VkDevice VMA_NOT_NULL device; + /// Preferred size of a single `VkDeviceMemory` block to be allocated from large heaps > 1 GiB. Optional. + /** Set to 0 to use default, which is currently 256 MiB. */ + VkDeviceSize preferredLargeHeapBlockSize; + /// Custom CPU memory allocation callbacks. Optional. + /** Optional, can be null. When specified, will also be used for all CPU-side memory allocations. */ + const VkAllocationCallbacks* VMA_NULLABLE pAllocationCallbacks; + /// Informative callbacks for `vkAllocateMemory`, `vkFreeMemory`. Optional. + /** Optional, can be null. */ + const VmaDeviceMemoryCallbacks* VMA_NULLABLE pDeviceMemoryCallbacks; + /** \brief Either null or a pointer to an array of limits on maximum number of bytes that can be allocated out of particular Vulkan memory heap. - If not NULL, it must be a pointer to an array of - `VkPhysicalDeviceMemoryProperties::memoryHeapCount` elements, defining limit on - maximum number of bytes that can be allocated out of particular Vulkan memory - heap. + If not NULL, it must be a pointer to an array of + `VkPhysicalDeviceMemoryProperties::memoryHeapCount` elements, defining limit on + maximum number of bytes that can be allocated out of particular Vulkan memory + heap. - Any of the elements may be equal to `VK_WHOLE_SIZE`, which means no limit on that - heap. This is also the default in case of `pHeapSizeLimit` = NULL. + Any of the elements may be equal to `VK_WHOLE_SIZE`, which means no limit on that + heap. This is also the default in case of `pHeapSizeLimit` = NULL. - If there is a limit defined for a heap: + If there is a limit defined for a heap: - - If user tries to allocate more memory from that heap using this allocator, - the allocation fails with `VK_ERROR_OUT_OF_DEVICE_MEMORY`. - - If the limit is smaller than heap size reported in `VkMemoryHeap::size`, the - value of this limit will be reported instead when using vmaGetMemoryProperties(). + - If user tries to allocate more memory from that heap using this allocator, + the allocation fails with `VK_ERROR_OUT_OF_DEVICE_MEMORY`. + - If the limit is smaller than heap size reported in `VkMemoryHeap::size`, the + value of this limit will be reported instead when using vmaGetMemoryProperties(). - Warning! Using this feature may not be equivalent to installing a GPU with - smaller amount of memory, because graphics driver doesn't necessary fail new - allocations with `VK_ERROR_OUT_OF_DEVICE_MEMORY` result when memory capacity is - exceeded. It may return success and just silently migrate some device memory - blocks to system RAM. This driver behavior can also be controlled using - VK_AMD_memory_overallocation_behavior extension. - */ - const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL("VkPhysicalDeviceMemoryProperties::memoryHeapCount") pHeapSizeLimit; + Warning! Using this feature may not be equivalent to installing a GPU with + smaller amount of memory, because graphics driver doesn't necessary fail new + allocations with `VK_ERROR_OUT_OF_DEVICE_MEMORY` result when memory capacity is + exceeded. It may return success and just silently migrate some device memory + blocks to system RAM. This driver behavior can also be controlled using + VK_AMD_memory_overallocation_behavior extension. + */ + const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL("VkPhysicalDeviceMemoryProperties::memoryHeapCount") pHeapSizeLimit; - /** \brief Pointers to Vulkan functions. Can be null. + /** \brief Pointers to Vulkan functions. Can be null. - For details see [Pointers to Vulkan functions](@ref config_Vulkan_functions). - */ - const VmaVulkanFunctions* VMA_NULLABLE pVulkanFunctions; - /** \brief Handle to Vulkan instance object. + For details see [Pointers to Vulkan functions](@ref config_Vulkan_functions). + */ + const VmaVulkanFunctions* VMA_NULLABLE pVulkanFunctions; + /** \brief Handle to Vulkan instance object. - Starting from version 3.0.0 this member is no longer optional, it must be set! - */ - VkInstance VMA_NOT_NULL instance; - /** \brief Optional. Vulkan version that the application uses. + Starting from version 3.0.0 this member is no longer optional, it must be set! + */ + VkInstance VMA_NOT_NULL instance; + /** \brief Optional. Vulkan version that the application uses. - It must be a value in the format as created by macro `VK_MAKE_VERSION` or a constant like: `VK_API_VERSION_1_1`, `VK_API_VERSION_1_0`. - The patch version number specified is ignored. Only the major and minor versions are considered. - Only versions 1.0, 1.1, 1.2, 1.3 are supported by the current implementation. - Leaving it initialized to zero is equivalent to `VK_API_VERSION_1_0`. - It must match the Vulkan version used by the application and supported on the selected physical device, - so it must be no higher than `VkApplicationInfo::apiVersion` passed to `vkCreateInstance` - and no higher than `VkPhysicalDeviceProperties::apiVersion` found on the physical device used. - */ - uint32_t vulkanApiVersion; + It must be a value in the format as created by macro `VK_MAKE_VERSION` or a constant like: `VK_API_VERSION_1_1`, `VK_API_VERSION_1_0`. + The patch version number specified is ignored. Only the major and minor versions are considered. + Only versions 1.0, 1.1, 1.2, 1.3 are supported by the current implementation. + Leaving it initialized to zero is equivalent to `VK_API_VERSION_1_0`. + It must match the Vulkan version used by the application and supported on the selected physical device, + so it must be no higher than `VkApplicationInfo::apiVersion` passed to `vkCreateInstance` + and no higher than `VkPhysicalDeviceProperties::apiVersion` found on the physical device used. + */ + uint32_t vulkanApiVersion; #if VMA_EXTERNAL_MEMORY - /** \brief Either null or a pointer to an array of external memory handle types for each Vulkan memory type. + /** \brief Either null or a pointer to an array of external memory handle types for each Vulkan memory type. - If not NULL, it must be a pointer to an array of `VkPhysicalDeviceMemoryProperties::memoryTypeCount` - elements, defining external memory handle types of particular Vulkan memory type, - to be passed using `VkExportMemoryAllocateInfoKHR`. + If not NULL, it must be a pointer to an array of `VkPhysicalDeviceMemoryProperties::memoryTypeCount` + elements, defining external memory handle types of particular Vulkan memory type, + to be passed using `VkExportMemoryAllocateInfoKHR`. - Any of the elements may be equal to 0, which means not to use `VkExportMemoryAllocateInfoKHR` on this memory type. - This is also the default in case of `pTypeExternalMemoryHandleTypes` = NULL. - */ - const VkExternalMemoryHandleTypeFlagsKHR* VMA_NULLABLE VMA_LEN_IF_NOT_NULL("VkPhysicalDeviceMemoryProperties::memoryTypeCount") pTypeExternalMemoryHandleTypes; + Any of the elements may be equal to 0, which means not to use `VkExportMemoryAllocateInfoKHR` on this memory type. + This is also the default in case of `pTypeExternalMemoryHandleTypes` = NULL. + */ + const VkExternalMemoryHandleTypeFlagsKHR* VMA_NULLABLE VMA_LEN_IF_NOT_NULL("VkPhysicalDeviceMemoryProperties::memoryTypeCount") pTypeExternalMemoryHandleTypes; #endif // #if VMA_EXTERNAL_MEMORY - } VmaAllocatorCreateInfo; +} VmaAllocatorCreateInfo; - /// Information about existing #VmaAllocator object. - typedef struct VmaAllocatorInfo - { - /** \brief Handle to Vulkan instance object. +/// Information about existing #VmaAllocator object. +typedef struct VmaAllocatorInfo +{ + /** \brief Handle to Vulkan instance object. - This is the same value as has been passed through VmaAllocatorCreateInfo::instance. - */ - VkInstance VMA_NOT_NULL instance; - /** \brief Handle to Vulkan physical device object. - - This is the same value as has been passed through VmaAllocatorCreateInfo::physicalDevice. - */ - VkPhysicalDevice VMA_NOT_NULL physicalDevice; - /** \brief Handle to Vulkan device object. - - This is the same value as has been passed through VmaAllocatorCreateInfo::device. - */ - VkDevice VMA_NOT_NULL device; - } VmaAllocatorInfo; - - /** @} */ - - /** - \addtogroup group_stats - @{ + This is the same value as has been passed through VmaAllocatorCreateInfo::instance. */ + VkInstance VMA_NOT_NULL instance; + /** \brief Handle to Vulkan physical device object. - /** \brief Calculated statistics of memory usage e.g. in a specific memory type, heap, custom pool, or total. - - These are fast to calculate. - See functions: vmaGetHeapBudgets(), vmaGetPoolStatistics(). + This is the same value as has been passed through VmaAllocatorCreateInfo::physicalDevice. */ - typedef struct VmaStatistics - { - /** \brief Number of `VkDeviceMemory` objects - Vulkan memory blocks allocated. - */ - uint32_t blockCount; - /** \brief Number of #VmaAllocation objects allocated. + VkPhysicalDevice VMA_NOT_NULL physicalDevice; + /** \brief Handle to Vulkan device object. - Dedicated allocations have their own blocks, so each one adds 1 to `allocationCount` as well as `blockCount`. - */ - uint32_t allocationCount; - /** \brief Number of bytes allocated in `VkDeviceMemory` blocks. - - \note To avoid confusion, please be aware that what Vulkan calls an "allocation" - a whole `VkDeviceMemory` object - (e.g. as in `VkPhysicalDeviceLimits::maxMemoryAllocationCount`) is called a "block" in VMA, while VMA calls - "allocation" a #VmaAllocation object that represents a memory region sub-allocated from such block, usually for a single buffer or image. - */ - VkDeviceSize blockBytes; - /** \brief Total number of bytes occupied by all #VmaAllocation objects. - - Always less or equal than `blockBytes`. - Difference `(blockBytes - allocationBytes)` is the amount of memory allocated from Vulkan - but unused by any #VmaAllocation. - */ - VkDeviceSize allocationBytes; - } VmaStatistics; - - /** \brief More detailed statistics than #VmaStatistics. - - These are slower to calculate. Use for debugging purposes. - See functions: vmaCalculateStatistics(), vmaCalculatePoolStatistics(). - - Previous version of the statistics API provided averages, but they have been removed - because they can be easily calculated as: - - \code - VkDeviceSize allocationSizeAvg = detailedStats.statistics.allocationBytes / detailedStats.statistics.allocationCount; - VkDeviceSize unusedBytes = detailedStats.statistics.blockBytes - detailedStats.statistics.allocationBytes; - VkDeviceSize unusedRangeSizeAvg = unusedBytes / detailedStats.unusedRangeCount; - \endcode + This is the same value as has been passed through VmaAllocatorCreateInfo::device. */ - typedef struct VmaDetailedStatistics - { - /// Basic statistics. - VmaStatistics statistics; - /// Number of free ranges of memory between allocations. - uint32_t unusedRangeCount; - /// Smallest allocation size. `VK_WHOLE_SIZE` if there are 0 allocations. - VkDeviceSize allocationSizeMin; - /// Largest allocation size. 0 if there are 0 allocations. - VkDeviceSize allocationSizeMax; - /// Smallest empty range size. `VK_WHOLE_SIZE` if there are 0 empty ranges. - VkDeviceSize unusedRangeSizeMin; - /// Largest empty range size. 0 if there are 0 empty ranges. - VkDeviceSize unusedRangeSizeMax; - } VmaDetailedStatistics; + VkDevice VMA_NOT_NULL device; +} VmaAllocatorInfo; - /** \brief General statistics from current state of the Allocator - - total memory usage across all memory heaps and types. +/** @} */ - These are slower to calculate. Use for debugging purposes. - See function vmaCalculateStatistics(). +/** +\addtogroup group_stats +@{ +*/ + +/** \brief Calculated statistics of memory usage e.g. in a specific memory type, heap, custom pool, or total. + +These are fast to calculate. +See functions: vmaGetHeapBudgets(), vmaGetPoolStatistics(). +*/ +typedef struct VmaStatistics +{ + /** \brief Number of `VkDeviceMemory` objects - Vulkan memory blocks allocated. */ - typedef struct VmaTotalStatistics - { - VmaDetailedStatistics memoryType[VK_MAX_MEMORY_TYPES]; - VmaDetailedStatistics memoryHeap[VK_MAX_MEMORY_HEAPS]; - VmaDetailedStatistics total; - } VmaTotalStatistics; + uint32_t blockCount; + /** \brief Number of #VmaAllocation objects allocated. - /** \brief Statistics of current memory usage and available budget for a specific memory heap. - - These are fast to calculate. - See function vmaGetHeapBudgets(). + Dedicated allocations have their own blocks, so each one adds 1 to `allocationCount` as well as `blockCount`. */ - typedef struct VmaBudget - { - /** \brief Statistics fetched from the library. - */ - VmaStatistics statistics; - /** \brief Estimated current memory usage of the program, in bytes. + uint32_t allocationCount; + /** \brief Number of bytes allocated in `VkDeviceMemory` blocks. - Fetched from system using VK_EXT_memory_budget extension if enabled. - - It might be different than `statistics.blockBytes` (usually higher) due to additional implicit objects - also occupying the memory, like swapchain, pipelines, descriptor heaps, command buffers, or - `VkDeviceMemory` blocks allocated outside of this library, if any. - */ - VkDeviceSize usage; - /** \brief Estimated amount of memory available to the program, in bytes. - - Fetched from system using VK_EXT_memory_budget extension if enabled. - - It might be different (most probably smaller) than `VkMemoryHeap::size[heapIndex]` due to factors - external to the program, decided by the operating system. - Difference `budget - usage` is the amount of additional memory that can probably - be allocated without problems. Exceeding the budget may result in various problems. - */ - VkDeviceSize budget; - } VmaBudget; - - /** @} */ - - /** - \addtogroup group_alloc - @{ + \note To avoid confusion, please be aware that what Vulkan calls an "allocation" - a whole `VkDeviceMemory` object + (e.g. as in `VkPhysicalDeviceLimits::maxMemoryAllocationCount`) is called a "block" in VMA, while VMA calls + "allocation" a #VmaAllocation object that represents a memory region sub-allocated from such block, usually for a single buffer or image. */ + VkDeviceSize blockBytes; + /** \brief Total number of bytes occupied by all #VmaAllocation objects. - /** \brief Parameters of new #VmaAllocation. - - To be used with functions like vmaCreateBuffer(), vmaCreateImage(), and many others. + Always less or equal than `blockBytes`. + Difference `(blockBytes - allocationBytes)` is the amount of memory allocated from Vulkan + but unused by any #VmaAllocation. */ - typedef struct VmaAllocationCreateInfo - { - /// Use #VmaAllocationCreateFlagBits enum. - VmaAllocationCreateFlags flags; - /** \brief Intended usage of memory. + VkDeviceSize allocationBytes; +} VmaStatistics; - You can leave #VMA_MEMORY_USAGE_UNKNOWN if you specify memory requirements in other way. \n - If `pool` is not null, this member is ignored. - */ - VmaMemoryUsage usage; - /** \brief Flags that must be set in a Memory Type chosen for an allocation. +/** \brief More detailed statistics than #VmaStatistics. - Leave 0 if you specify memory requirements in other way. \n - If `pool` is not null, this member is ignored.*/ - VkMemoryPropertyFlags requiredFlags; - /** \brief Flags that preferably should be set in a memory type chosen for an allocation. +These are slower to calculate. Use for debugging purposes. +See functions: vmaCalculateStatistics(), vmaCalculatePoolStatistics(). - Set to 0 if no additional flags are preferred. \n - If `pool` is not null, this member is ignored. */ - VkMemoryPropertyFlags preferredFlags; - /** \brief Bitmask containing one bit set for every memory type acceptable for this allocation. +Previous version of the statistics API provided averages, but they have been removed +because they can be easily calculated as: - Value 0 is equivalent to `UINT32_MAX` - it means any memory type is accepted if - it meets other requirements specified by this structure, with no further - restrictions on memory type index. \n - If `pool` is not null, this member is ignored. - */ - uint32_t memoryTypeBits; - /** \brief Pool that this allocation should be created in. +\code +VkDeviceSize allocationSizeAvg = detailedStats.statistics.allocationBytes / detailedStats.statistics.allocationCount; +VkDeviceSize unusedBytes = detailedStats.statistics.blockBytes - detailedStats.statistics.allocationBytes; +VkDeviceSize unusedRangeSizeAvg = unusedBytes / detailedStats.unusedRangeCount; +\endcode +*/ +typedef struct VmaDetailedStatistics +{ + /// Basic statistics. + VmaStatistics statistics; + /// Number of free ranges of memory between allocations. + uint32_t unusedRangeCount; + /// Smallest allocation size. `VK_WHOLE_SIZE` if there are 0 allocations. + VkDeviceSize allocationSizeMin; + /// Largest allocation size. 0 if there are 0 allocations. + VkDeviceSize allocationSizeMax; + /// Smallest empty range size. `VK_WHOLE_SIZE` if there are 0 empty ranges. + VkDeviceSize unusedRangeSizeMin; + /// Largest empty range size. 0 if there are 0 empty ranges. + VkDeviceSize unusedRangeSizeMax; +} VmaDetailedStatistics; - Leave `VK_NULL_HANDLE` to allocate from default pool. If not null, members: - `usage`, `requiredFlags`, `preferredFlags`, `memoryTypeBits` are ignored. - */ - VmaPool VMA_NULLABLE pool; - /** \brief Custom general-purpose pointer that will be stored in #VmaAllocation, can be read as VmaAllocationInfo::pUserData and changed using vmaSetAllocationUserData(). +/** \brief General statistics from current state of the Allocator - +total memory usage across all memory heaps and types. - If #VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT is used, it must be either - null or pointer to a null-terminated string. The string will be then copied to - internal buffer, so it doesn't need to be valid after allocation call. - */ - void* VMA_NULLABLE pUserData; - /** \brief A floating-point value between 0 and 1, indicating the priority of the allocation relative to other memory allocations. +These are slower to calculate. Use for debugging purposes. +See function vmaCalculateStatistics(). +*/ +typedef struct VmaTotalStatistics +{ + VmaDetailedStatistics memoryType[VK_MAX_MEMORY_TYPES]; + VmaDetailedStatistics memoryHeap[VK_MAX_MEMORY_HEAPS]; + VmaDetailedStatistics total; +} VmaTotalStatistics; - It is used only when #VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT flag was used during creation of the #VmaAllocator object - and this allocation ends up as dedicated or is explicitly forced as dedicated using #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT. - Otherwise, it has the priority of a memory block where it is placed and this variable is ignored. - */ - float priority; - } VmaAllocationCreateInfo; +/** \brief Statistics of current memory usage and available budget for a specific memory heap. - /// Describes parameter of created #VmaPool. - typedef struct VmaPoolCreateInfo - { - /** \brief Vulkan memory type index to allocate this pool from. - */ - uint32_t memoryTypeIndex; - /** \brief Use combination of #VmaPoolCreateFlagBits. - */ - VmaPoolCreateFlags flags; - /** \brief Size of a single `VkDeviceMemory` block to be allocated as part of this pool, in bytes. Optional. - - Specify nonzero to set explicit, constant size of memory blocks used by this - pool. - - Leave 0 to use default and let the library manage block sizes automatically. - Sizes of particular blocks may vary. - In this case, the pool will also support dedicated allocations. - */ - VkDeviceSize blockSize; - /** \brief Minimum number of blocks to be always allocated in this pool, even if they stay empty. - - Set to 0 to have no preallocated blocks and allow the pool be completely empty. - */ - size_t minBlockCount; - /** \brief Maximum number of blocks that can be allocated in this pool. Optional. - - Set to 0 to use default, which is `SIZE_MAX`, which means no limit. - - Set to same value as VmaPoolCreateInfo::minBlockCount to have fixed amount of memory allocated - throughout whole lifetime of this pool. - */ - size_t maxBlockCount; - /** \brief A floating-point value between 0 and 1, indicating the priority of the allocations in this pool relative to other memory allocations. - - It is used only when #VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT flag was used during creation of the #VmaAllocator object. - Otherwise, this variable is ignored. - */ - float priority; - /** \brief Additional minimum alignment to be used for all allocations created from this pool. Can be 0. - - Leave 0 (default) not to impose any additional alignment. If not 0, it must be a power of two. - It can be useful in cases where alignment returned by Vulkan by functions like `vkGetBufferMemoryRequirements` is not enough, - e.g. when doing interop with OpenGL. - */ - VkDeviceSize minAllocationAlignment; - /** \brief Additional `pNext` chain to be attached to `VkMemoryAllocateInfo` used for every allocation made by this pool. Optional. - - Optional, can be null. If not null, it must point to a `pNext` chain of structures that can be attached to `VkMemoryAllocateInfo`. - It can be useful for special needs such as adding `VkExportMemoryAllocateInfoKHR`. - Structures pointed by this member must remain alive and unchanged for the whole lifetime of the custom pool. - - Please note that some structures, e.g. `VkMemoryPriorityAllocateInfoEXT`, `VkMemoryDedicatedAllocateInfoKHR`, - can be attached automatically by this library when using other, more convenient of its features. - */ - void* VMA_NULLABLE VMA_EXTENDS_VK_STRUCT(VkMemoryAllocateInfo) pMemoryAllocateNext; - } VmaPoolCreateInfo; - - /** @} */ - - /** - \addtogroup group_alloc - @{ +These are fast to calculate. +See function vmaGetHeapBudgets(). +*/ +typedef struct VmaBudget +{ + /** \brief Statistics fetched from the library. */ + VmaStatistics statistics; + /** \brief Estimated current memory usage of the program, in bytes. - /** - Parameters of #VmaAllocation objects, that can be retrieved using function vmaGetAllocationInfo(). + Fetched from system using VK_EXT_memory_budget extension if enabled. - There is also an extended version of this structure that carries additional parameters: #VmaAllocationInfo2. + It might be different than `statistics.blockBytes` (usually higher) due to additional implicit objects + also occupying the memory, like swapchain, pipelines, descriptor heaps, command buffers, or + `VkDeviceMemory` blocks allocated outside of this library, if any. */ - typedef struct VmaAllocationInfo - { - /** \brief Memory type index that this allocation was allocated from. + VkDeviceSize usage; + /** \brief Estimated amount of memory available to the program, in bytes. - It never changes. - */ - uint32_t memoryType; - /** \brief Handle to Vulkan memory object. + Fetched from system using VK_EXT_memory_budget extension if enabled. - Same memory object can be shared by multiple allocations. - - It can change after the allocation is moved during \ref defragmentation. - */ - VkDeviceMemory VMA_NULLABLE_NON_DISPATCHABLE deviceMemory; - /** \brief Offset in `VkDeviceMemory` object to the beginning of this allocation, in bytes. `(deviceMemory, offset)` pair is unique to this allocation. - - You usually don't need to use this offset. If you create a buffer or an image together with the allocation using e.g. function - vmaCreateBuffer(), vmaCreateImage(), functions that operate on these resources refer to the beginning of the buffer or image, - not entire device memory block. Functions like vmaMapMemory(), vmaBindBufferMemory() also refer to the beginning of the allocation - and apply this offset automatically. - - It can change after the allocation is moved during \ref defragmentation. - */ - VkDeviceSize offset; - /** \brief Size of this allocation, in bytes. - - It never changes. - - \note Allocation size returned in this variable may be greater than the size - requested for the resource e.g. as `VkBufferCreateInfo::size`. Whole size of the - allocation is accessible for operations on memory e.g. using a pointer after - mapping with vmaMapMemory(), but operations on the resource e.g. using - `vkCmdCopyBuffer` must be limited to the size of the resource. - */ - VkDeviceSize size; - /** \brief Pointer to the beginning of this allocation as mapped data. - - If the allocation hasn't been mapped using vmaMapMemory() and hasn't been - created with #VMA_ALLOCATION_CREATE_MAPPED_BIT flag, this value is null. - - It can change after call to vmaMapMemory(), vmaUnmapMemory(). - It can also change after the allocation is moved during \ref defragmentation. - */ - void* VMA_NULLABLE pMappedData; - /** \brief Custom general-purpose pointer that was passed as VmaAllocationCreateInfo::pUserData or set using vmaSetAllocationUserData(). - - It can change after call to vmaSetAllocationUserData() for this allocation. - */ - void* VMA_NULLABLE pUserData; - /** \brief Custom allocation name that was set with vmaSetAllocationName(). - - It can change after call to vmaSetAllocationName() for this allocation. - - Another way to set custom name is to pass it in VmaAllocationCreateInfo::pUserData with - additional flag #VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT set [DEPRECATED]. - */ - const char* VMA_NULLABLE pName; - } VmaAllocationInfo; - - /// Extended parameters of a #VmaAllocation object that can be retrieved using function vmaGetAllocationInfo2(). - typedef struct VmaAllocationInfo2 - { - /** \brief Basic parameters of the allocation. - - If you need only these, you can use function vmaGetAllocationInfo() and structure #VmaAllocationInfo instead. - */ - VmaAllocationInfo allocationInfo; - /** \brief Size of the `VkDeviceMemory` block that the allocation belongs to. - - In case of an allocation with dedicated memory, it will be equal to `allocationInfo.size`. - */ - VkDeviceSize blockSize; - /** \brief `VK_TRUE` if the allocation has dedicated memory, `VK_FALSE` if it was placed as part of a larger memory block. - - When `VK_TRUE`, it also means `VkMemoryDedicatedAllocateInfo` was used when creating the allocation - (if VK_KHR_dedicated_allocation extension or Vulkan version >= 1.1 is enabled). - */ - VkBool32 dedicatedMemory; - } VmaAllocationInfo2; - - /** Callback function called during vmaBeginDefragmentation() to check custom criterion about ending current defragmentation pass. - - Should return true if the defragmentation needs to stop current pass. + It might be different (most probably smaller) than `VkMemoryHeap::size[heapIndex]` due to factors + external to the program, decided by the operating system. + Difference `budget - usage` is the amount of additional memory that can probably + be allocated without problems. Exceeding the budget may result in various problems. */ - typedef VkBool32(VKAPI_PTR* PFN_vmaCheckDefragmentationBreakFunction)(void* VMA_NULLABLE pUserData); + VkDeviceSize budget; +} VmaBudget; - /** \brief Parameters for defragmentation. +/** @} */ - To be used with function vmaBeginDefragmentation(). +/** +\addtogroup group_alloc +@{ +*/ + +/** \brief Parameters of new #VmaAllocation. + +To be used with functions like vmaCreateBuffer(), vmaCreateImage(), and many others. +*/ +typedef struct VmaAllocationCreateInfo +{ + /// Use #VmaAllocationCreateFlagBits enum. + VmaAllocationCreateFlags flags; + /** \brief Intended usage of memory. + + You can leave #VMA_MEMORY_USAGE_UNKNOWN if you specify memory requirements in other way. \n + If `pool` is not null, this member is ignored. */ - typedef struct VmaDefragmentationInfo - { - /// \brief Use combination of #VmaDefragmentationFlagBits. - VmaDefragmentationFlags flags; - /** \brief Custom pool to be defragmented. + VmaMemoryUsage usage; + /** \brief Flags that must be set in a Memory Type chosen for an allocation. - If null then default pools will undergo defragmentation process. - */ - VmaPool VMA_NULLABLE pool; - /** \brief Maximum numbers of bytes that can be copied during single pass, while moving allocations to different places. + Leave 0 if you specify memory requirements in other way. \n + If `pool` is not null, this member is ignored.*/ + VkMemoryPropertyFlags requiredFlags; + /** \brief Flags that preferably should be set in a memory type chosen for an allocation. - `0` means no limit. - */ - VkDeviceSize maxBytesPerPass; - /** \brief Maximum number of allocations that can be moved during single pass to a different place. + Set to 0 if no additional flags are preferred. \n + If `pool` is not null, this member is ignored. */ + VkMemoryPropertyFlags preferredFlags; + /** \brief Bitmask containing one bit set for every memory type acceptable for this allocation. - `0` means no limit. - */ - uint32_t maxAllocationsPerPass; - /** \brief Optional custom callback for stopping vmaBeginDefragmentation(). - - Have to return true for breaking current defragmentation pass. - */ - PFN_vmaCheckDefragmentationBreakFunction VMA_NULLABLE pfnBreakCallback; - /// \brief Optional data to pass to custom callback for stopping pass of defragmentation. - void* VMA_NULLABLE pBreakCallbackUserData; - } VmaDefragmentationInfo; - - /// Single move of an allocation to be done for defragmentation. - typedef struct VmaDefragmentationMove - { - /// Operation to be performed on the allocation by vmaEndDefragmentationPass(). Default value is #VMA_DEFRAGMENTATION_MOVE_OPERATION_COPY. You can modify it. - VmaDefragmentationMoveOperation operation; - /// Allocation that should be moved. - VmaAllocation VMA_NOT_NULL srcAllocation; - /** \brief Temporary allocation pointing to destination memory that will replace `srcAllocation`. - - \warning Do not store this allocation in your data structures! It exists only temporarily, for the duration of the defragmentation pass, - to be used for binding new buffer/image to the destination memory using e.g. vmaBindBufferMemory(). - vmaEndDefragmentationPass() will destroy it and make `srcAllocation` point to this memory. - */ - VmaAllocation VMA_NOT_NULL dstTmpAllocation; - } VmaDefragmentationMove; - - /** \brief Parameters for incremental defragmentation steps. - - To be used with function vmaBeginDefragmentationPass(). + Value 0 is equivalent to `UINT32_MAX` - it means any memory type is accepted if + it meets other requirements specified by this structure, with no further + restrictions on memory type index. \n + If `pool` is not null, this member is ignored. */ - typedef struct VmaDefragmentationPassMoveInfo - { - /// Number of elements in the `pMoves` array. - uint32_t moveCount; - /** \brief Array of moves to be performed by the user in the current defragmentation pass. + uint32_t memoryTypeBits; + /** \brief Pool that this allocation should be created in. - Pointer to an array of `moveCount` elements, owned by VMA, created in vmaBeginDefragmentationPass(), destroyed in vmaEndDefragmentationPass(). - - For each element, you should: - - 1. Create a new buffer/image in the place pointed by VmaDefragmentationMove::dstMemory + VmaDefragmentationMove::dstOffset. - 2. Copy data from the VmaDefragmentationMove::srcAllocation e.g. using `vkCmdCopyBuffer`, `vkCmdCopyImage`. - 3. Make sure these commands finished executing on the GPU. - 4. Destroy the old buffer/image. - - Only then you can finish defragmentation pass by calling vmaEndDefragmentationPass(). - After this call, the allocation will point to the new place in memory. - - Alternatively, if you cannot move specific allocation, you can set VmaDefragmentationMove::operation to #VMA_DEFRAGMENTATION_MOVE_OPERATION_IGNORE. - - Alternatively, if you decide you want to completely remove the allocation: - - 1. Destroy its buffer/image. - 2. Set VmaDefragmentationMove::operation to #VMA_DEFRAGMENTATION_MOVE_OPERATION_DESTROY. - - Then, after vmaEndDefragmentationPass() the allocation will be freed. - */ - VmaDefragmentationMove* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(moveCount) pMoves; - } VmaDefragmentationPassMoveInfo; - - /// Statistics returned for defragmentation process in function vmaEndDefragmentation(). - typedef struct VmaDefragmentationStats - { - /// Total number of bytes that have been copied while moving allocations to different places. - VkDeviceSize bytesMoved; - /// Total number of bytes that have been released to the system by freeing empty `VkDeviceMemory` objects. - VkDeviceSize bytesFreed; - /// Number of allocations that have been moved to different places. - uint32_t allocationsMoved; - /// Number of empty `VkDeviceMemory` objects that have been released to the system. - uint32_t deviceMemoryBlocksFreed; - } VmaDefragmentationStats; - - /** @} */ - - /** - \addtogroup group_virtual - @{ + Leave `VK_NULL_HANDLE` to allocate from default pool. If not null, members: + `usage`, `requiredFlags`, `preferredFlags`, `memoryTypeBits` are ignored. */ + VmaPool VMA_NULLABLE pool; + /** \brief Custom general-purpose pointer that will be stored in #VmaAllocation, can be read as VmaAllocationInfo::pUserData and changed using vmaSetAllocationUserData(). - /// Parameters of created #VmaVirtualBlock object to be passed to vmaCreateVirtualBlock(). - typedef struct VmaVirtualBlockCreateInfo - { - /** \brief Total size of the virtual block. + If #VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT is used, it must be either + null or pointer to a null-terminated string. The string will be then copied to + internal buffer, so it doesn't need to be valid after allocation call. + */ + void* VMA_NULLABLE pUserData; + /** \brief A floating-point value between 0 and 1, indicating the priority of the allocation relative to other memory allocations. - Sizes can be expressed in bytes or any units you want as long as you are consistent in using them. - For example, if you allocate from some array of structures, 1 can mean single instance of entire structure. - */ - VkDeviceSize size; + It is used only when #VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT flag was used during creation of the #VmaAllocator object + and this allocation ends up as dedicated or is explicitly forced as dedicated using #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT. + Otherwise, it has the priority of a memory block where it is placed and this variable is ignored. + */ + float priority; +} VmaAllocationCreateInfo; - /** \brief Use combination of #VmaVirtualBlockCreateFlagBits. - */ - VmaVirtualBlockCreateFlags flags; +/// Describes parameter of created #VmaPool. +typedef struct VmaPoolCreateInfo +{ + /** \brief Vulkan memory type index to allocate this pool from. + */ + uint32_t memoryTypeIndex; + /** \brief Use combination of #VmaPoolCreateFlagBits. + */ + VmaPoolCreateFlags flags; + /** \brief Size of a single `VkDeviceMemory` block to be allocated as part of this pool, in bytes. Optional. - /** \brief Custom CPU memory allocation callbacks. Optional. + Specify nonzero to set explicit, constant size of memory blocks used by this + pool. - Optional, can be null. When specified, they will be used for all CPU-side memory allocations. - */ - const VkAllocationCallbacks* VMA_NULLABLE pAllocationCallbacks; - } VmaVirtualBlockCreateInfo; + Leave 0 to use default and let the library manage block sizes automatically. + Sizes of particular blocks may vary. + In this case, the pool will also support dedicated allocations. + */ + VkDeviceSize blockSize; + /** \brief Minimum number of blocks to be always allocated in this pool, even if they stay empty. - /// Parameters of created virtual allocation to be passed to vmaVirtualAllocate(). - typedef struct VmaVirtualAllocationCreateInfo - { - /** \brief Size of the allocation. + Set to 0 to have no preallocated blocks and allow the pool be completely empty. + */ + size_t minBlockCount; + /** \brief Maximum number of blocks that can be allocated in this pool. Optional. - Cannot be zero. - */ - VkDeviceSize size; - /** \brief Required alignment of the allocation. Optional. + Set to 0 to use default, which is `SIZE_MAX`, which means no limit. - Must be power of two. Special value 0 has the same meaning as 1 - means no special alignment is required, so allocation can start at any offset. - */ - VkDeviceSize alignment; - /** \brief Use combination of #VmaVirtualAllocationCreateFlagBits. - */ - VmaVirtualAllocationCreateFlags flags; - /** \brief Custom pointer to be associated with the allocation. Optional. + Set to same value as VmaPoolCreateInfo::minBlockCount to have fixed amount of memory allocated + throughout whole lifetime of this pool. + */ + size_t maxBlockCount; + /** \brief A floating-point value between 0 and 1, indicating the priority of the allocations in this pool relative to other memory allocations. - It can be any value and can be used for user-defined purposes. It can be fetched or changed later. - */ - void* VMA_NULLABLE pUserData; - } VmaVirtualAllocationCreateInfo; + It is used only when #VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT flag was used during creation of the #VmaAllocator object. + Otherwise, this variable is ignored. + */ + float priority; + /** \brief Additional minimum alignment to be used for all allocations created from this pool. Can be 0. - /// Parameters of an existing virtual allocation, returned by vmaGetVirtualAllocationInfo(). - typedef struct VmaVirtualAllocationInfo - { - /** \brief Offset of the allocation. + Leave 0 (default) not to impose any additional alignment. If not 0, it must be a power of two. + It can be useful in cases where alignment returned by Vulkan by functions like `vkGetBufferMemoryRequirements` is not enough, + e.g. when doing interop with OpenGL. + */ + VkDeviceSize minAllocationAlignment; + /** \brief Additional `pNext` chain to be attached to `VkMemoryAllocateInfo` used for every allocation made by this pool. Optional. - Offset at which the allocation was made. - */ - VkDeviceSize offset; - /** \brief Size of the allocation. + Optional, can be null. If not null, it must point to a `pNext` chain of structures that can be attached to `VkMemoryAllocateInfo`. + It can be useful for special needs such as adding `VkExportMemoryAllocateInfoKHR`. + Structures pointed by this member must remain alive and unchanged for the whole lifetime of the custom pool. - Same value as passed in VmaVirtualAllocationCreateInfo::size. - */ - VkDeviceSize size; - /** \brief Custom pointer associated with the allocation. + Please note that some structures, e.g. `VkMemoryPriorityAllocateInfoEXT`, `VkMemoryDedicatedAllocateInfoKHR`, + can be attached automatically by this library when using other, more convenient of its features. + */ + void* VMA_NULLABLE VMA_EXTENDS_VK_STRUCT(VkMemoryAllocateInfo) pMemoryAllocateNext; +} VmaPoolCreateInfo; - Same value as passed in VmaVirtualAllocationCreateInfo::pUserData or to vmaSetVirtualAllocationUserData(). - */ - void* VMA_NULLABLE pUserData; - } VmaVirtualAllocationInfo; +/** @} */ - /** @} */ +/** +\addtogroup group_alloc +@{ +*/ + +/** +Parameters of #VmaAllocation objects, that can be retrieved using function vmaGetAllocationInfo(). + +There is also an extended version of this structure that carries additional parameters: #VmaAllocationInfo2. +*/ +typedef struct VmaAllocationInfo +{ + /** \brief Memory type index that this allocation was allocated from. + + It never changes. + */ + uint32_t memoryType; + /** \brief Handle to Vulkan memory object. + + Same memory object can be shared by multiple allocations. + + It can change after the allocation is moved during \ref defragmentation. + */ + VkDeviceMemory VMA_NULLABLE_NON_DISPATCHABLE deviceMemory; + /** \brief Offset in `VkDeviceMemory` object to the beginning of this allocation, in bytes. `(deviceMemory, offset)` pair is unique to this allocation. + + You usually don't need to use this offset. If you create a buffer or an image together with the allocation using e.g. function + vmaCreateBuffer(), vmaCreateImage(), functions that operate on these resources refer to the beginning of the buffer or image, + not entire device memory block. Functions like vmaMapMemory(), vmaBindBufferMemory() also refer to the beginning of the allocation + and apply this offset automatically. + + It can change after the allocation is moved during \ref defragmentation. + */ + VkDeviceSize offset; + /** \brief Size of this allocation, in bytes. + + It never changes. + + \note Allocation size returned in this variable may be greater than the size + requested for the resource e.g. as `VkBufferCreateInfo::size`. Whole size of the + allocation is accessible for operations on memory e.g. using a pointer after + mapping with vmaMapMemory(), but operations on the resource e.g. using + `vkCmdCopyBuffer` must be limited to the size of the resource. + */ + VkDeviceSize size; + /** \brief Pointer to the beginning of this allocation as mapped data. + + If the allocation hasn't been mapped using vmaMapMemory() and hasn't been + created with #VMA_ALLOCATION_CREATE_MAPPED_BIT flag, this value is null. + + It can change after call to vmaMapMemory(), vmaUnmapMemory(). + It can also change after the allocation is moved during \ref defragmentation. + */ + void* VMA_NULLABLE pMappedData; + /** \brief Custom general-purpose pointer that was passed as VmaAllocationCreateInfo::pUserData or set using vmaSetAllocationUserData(). + + It can change after call to vmaSetAllocationUserData() for this allocation. + */ + void* VMA_NULLABLE pUserData; + /** \brief Custom allocation name that was set with vmaSetAllocationName(). + + It can change after call to vmaSetAllocationName() for this allocation. + + Another way to set custom name is to pass it in VmaAllocationCreateInfo::pUserData with + additional flag #VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT set [DEPRECATED]. + */ + const char* VMA_NULLABLE pName; +} VmaAllocationInfo; + +/// Extended parameters of a #VmaAllocation object that can be retrieved using function vmaGetAllocationInfo2(). +typedef struct VmaAllocationInfo2 +{ + /** \brief Basic parameters of the allocation. + + If you need only these, you can use function vmaGetAllocationInfo() and structure #VmaAllocationInfo instead. + */ + VmaAllocationInfo allocationInfo; + /** \brief Size of the `VkDeviceMemory` block that the allocation belongs to. + + In case of an allocation with dedicated memory, it will be equal to `allocationInfo.size`. + */ + VkDeviceSize blockSize; + /** \brief `VK_TRUE` if the allocation has dedicated memory, `VK_FALSE` if it was placed as part of a larger memory block. + + When `VK_TRUE`, it also means `VkMemoryDedicatedAllocateInfo` was used when creating the allocation + (if VK_KHR_dedicated_allocation extension or Vulkan version >= 1.1 is enabled). + */ + VkBool32 dedicatedMemory; +} VmaAllocationInfo2; + +/** Callback function called during vmaBeginDefragmentation() to check custom criterion about ending current defragmentation pass. + +Should return true if the defragmentation needs to stop current pass. +*/ +typedef VkBool32 (VKAPI_PTR* PFN_vmaCheckDefragmentationBreakFunction)(void* VMA_NULLABLE pUserData); + +/** \brief Parameters for defragmentation. + +To be used with function vmaBeginDefragmentation(). +*/ +typedef struct VmaDefragmentationInfo +{ + /// \brief Use combination of #VmaDefragmentationFlagBits. + VmaDefragmentationFlags flags; + /** \brief Custom pool to be defragmented. + + If null then default pools will undergo defragmentation process. + */ + VmaPool VMA_NULLABLE pool; + /** \brief Maximum numbers of bytes that can be copied during single pass, while moving allocations to different places. + + `0` means no limit. + */ + VkDeviceSize maxBytesPerPass; + /** \brief Maximum number of allocations that can be moved during single pass to a different place. + + `0` means no limit. + */ + uint32_t maxAllocationsPerPass; + /** \brief Optional custom callback for stopping vmaBeginDefragmentation(). + + Have to return true for breaking current defragmentation pass. + */ + PFN_vmaCheckDefragmentationBreakFunction VMA_NULLABLE pfnBreakCallback; + /// \brief Optional data to pass to custom callback for stopping pass of defragmentation. + void* VMA_NULLABLE pBreakCallbackUserData; +} VmaDefragmentationInfo; + +/// Single move of an allocation to be done for defragmentation. +typedef struct VmaDefragmentationMove +{ + /// Operation to be performed on the allocation by vmaEndDefragmentationPass(). Default value is #VMA_DEFRAGMENTATION_MOVE_OPERATION_COPY. You can modify it. + VmaDefragmentationMoveOperation operation; + /// Allocation that should be moved. + VmaAllocation VMA_NOT_NULL srcAllocation; + /** \brief Temporary allocation pointing to destination memory that will replace `srcAllocation`. + + \warning Do not store this allocation in your data structures! It exists only temporarily, for the duration of the defragmentation pass, + to be used for binding new buffer/image to the destination memory using e.g. vmaBindBufferMemory(). + vmaEndDefragmentationPass() will destroy it and make `srcAllocation` point to this memory. + */ + VmaAllocation VMA_NOT_NULL dstTmpAllocation; +} VmaDefragmentationMove; + +/** \brief Parameters for incremental defragmentation steps. + +To be used with function vmaBeginDefragmentationPass(). +*/ +typedef struct VmaDefragmentationPassMoveInfo +{ + /// Number of elements in the `pMoves` array. + uint32_t moveCount; + /** \brief Array of moves to be performed by the user in the current defragmentation pass. + + Pointer to an array of `moveCount` elements, owned by VMA, created in vmaBeginDefragmentationPass(), destroyed in vmaEndDefragmentationPass(). + + For each element, you should: + + 1. Create a new buffer/image in the place pointed by VmaDefragmentationMove::dstMemory + VmaDefragmentationMove::dstOffset. + 2. Copy data from the VmaDefragmentationMove::srcAllocation e.g. using `vkCmdCopyBuffer`, `vkCmdCopyImage`. + 3. Make sure these commands finished executing on the GPU. + 4. Destroy the old buffer/image. + + Only then you can finish defragmentation pass by calling vmaEndDefragmentationPass(). + After this call, the allocation will point to the new place in memory. + + Alternatively, if you cannot move specific allocation, you can set VmaDefragmentationMove::operation to #VMA_DEFRAGMENTATION_MOVE_OPERATION_IGNORE. + + Alternatively, if you decide you want to completely remove the allocation: + + 1. Destroy its buffer/image. + 2. Set VmaDefragmentationMove::operation to #VMA_DEFRAGMENTATION_MOVE_OPERATION_DESTROY. + + Then, after vmaEndDefragmentationPass() the allocation will be freed. + */ + VmaDefragmentationMove* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(moveCount) pMoves; +} VmaDefragmentationPassMoveInfo; + +/// Statistics returned for defragmentation process in function vmaEndDefragmentation(). +typedef struct VmaDefragmentationStats +{ + /// Total number of bytes that have been copied while moving allocations to different places. + VkDeviceSize bytesMoved; + /// Total number of bytes that have been released to the system by freeing empty `VkDeviceMemory` objects. + VkDeviceSize bytesFreed; + /// Number of allocations that have been moved to different places. + uint32_t allocationsMoved; + /// Number of empty `VkDeviceMemory` objects that have been released to the system. + uint32_t deviceMemoryBlocksFreed; +} VmaDefragmentationStats; + +/** @} */ + +/** +\addtogroup group_virtual +@{ +*/ + +/// Parameters of created #VmaVirtualBlock object to be passed to vmaCreateVirtualBlock(). +typedef struct VmaVirtualBlockCreateInfo +{ + /** \brief Total size of the virtual block. + + Sizes can be expressed in bytes or any units you want as long as you are consistent in using them. + For example, if you allocate from some array of structures, 1 can mean single instance of entire structure. + */ + VkDeviceSize size; + + /** \brief Use combination of #VmaVirtualBlockCreateFlagBits. + */ + VmaVirtualBlockCreateFlags flags; + + /** \brief Custom CPU memory allocation callbacks. Optional. + + Optional, can be null. When specified, they will be used for all CPU-side memory allocations. + */ + const VkAllocationCallbacks* VMA_NULLABLE pAllocationCallbacks; +} VmaVirtualBlockCreateInfo; + +/// Parameters of created virtual allocation to be passed to vmaVirtualAllocate(). +typedef struct VmaVirtualAllocationCreateInfo +{ + /** \brief Size of the allocation. + + Cannot be zero. + */ + VkDeviceSize size; + /** \brief Required alignment of the allocation. Optional. + + Must be power of two. Special value 0 has the same meaning as 1 - means no special alignment is required, so allocation can start at any offset. + */ + VkDeviceSize alignment; + /** \brief Use combination of #VmaVirtualAllocationCreateFlagBits. + */ + VmaVirtualAllocationCreateFlags flags; + /** \brief Custom pointer to be associated with the allocation. Optional. + + It can be any value and can be used for user-defined purposes. It can be fetched or changed later. + */ + void* VMA_NULLABLE pUserData; +} VmaVirtualAllocationCreateInfo; + +/// Parameters of an existing virtual allocation, returned by vmaGetVirtualAllocationInfo(). +typedef struct VmaVirtualAllocationInfo +{ + /** \brief Offset of the allocation. + + Offset at which the allocation was made. + */ + VkDeviceSize offset; + /** \brief Size of the allocation. + + Same value as passed in VmaVirtualAllocationCreateInfo::size. + */ + VkDeviceSize size; + /** \brief Custom pointer associated with the allocation. + + Same value as passed in VmaVirtualAllocationCreateInfo::pUserData or to vmaSetVirtualAllocationUserData(). + */ + void* VMA_NULLABLE pUserData; +} VmaVirtualAllocationInfo; + +/** @} */ #endif // _VMA_DATA_TYPES_DECLARATIONS @@ -1657,1051 +1666,1051 @@ right after Vulkan is initialized and keep it alive until before Vulkan device i */ /// Creates #VmaAllocator object. - VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAllocator( - const VmaAllocatorCreateInfo* VMA_NOT_NULL pCreateInfo, - VmaAllocator VMA_NULLABLE* VMA_NOT_NULL pAllocator); - - /// Destroys allocator object. - VMA_CALL_PRE void VMA_CALL_POST vmaDestroyAllocator( - VmaAllocator VMA_NULLABLE allocator); - - /** \brief Returns information about existing #VmaAllocator object - handle to Vulkan device etc. - - It might be useful if you want to keep just the #VmaAllocator handle and fetch other required handles to - `VkPhysicalDevice`, `VkDevice` etc. every time using this function. - */ - VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocatorInfo( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocatorInfo* VMA_NOT_NULL pAllocatorInfo); - - /** - PhysicalDeviceProperties are fetched from physicalDevice by the allocator. - You can access it here, without fetching it again on your own. - */ - VMA_CALL_PRE void VMA_CALL_POST vmaGetPhysicalDeviceProperties( - VmaAllocator VMA_NOT_NULL allocator, - const VkPhysicalDeviceProperties* VMA_NULLABLE* VMA_NOT_NULL ppPhysicalDeviceProperties); - - /** - PhysicalDeviceMemoryProperties are fetched from physicalDevice by the allocator. - You can access it here, without fetching it again on your own. - */ - VMA_CALL_PRE void VMA_CALL_POST vmaGetMemoryProperties( - VmaAllocator VMA_NOT_NULL allocator, - const VkPhysicalDeviceMemoryProperties* VMA_NULLABLE* VMA_NOT_NULL ppPhysicalDeviceMemoryProperties); - - /** - \brief Given Memory Type Index, returns Property Flags of this memory type. - - This is just a convenience function. Same information can be obtained using - vmaGetMemoryProperties(). - */ - VMA_CALL_PRE void VMA_CALL_POST vmaGetMemoryTypeProperties( - VmaAllocator VMA_NOT_NULL allocator, - uint32_t memoryTypeIndex, - VkMemoryPropertyFlags* VMA_NOT_NULL pFlags); - - /** \brief Sets index of the current frame. - */ - VMA_CALL_PRE void VMA_CALL_POST vmaSetCurrentFrameIndex( - VmaAllocator VMA_NOT_NULL allocator, - uint32_t frameIndex); - - /** @} */ - - /** - \addtogroup group_stats - @{ - */ - - /** \brief Retrieves statistics from current state of the Allocator. - - This function is called "calculate" not "get" because it has to traverse all - internal data structures, so it may be quite slow. Use it for debugging purposes. - For faster but more brief statistics suitable to be called every frame or every allocation, - use vmaGetHeapBudgets(). - - Note that when using allocator from multiple threads, returned information may immediately - become outdated. - */ - VMA_CALL_PRE void VMA_CALL_POST vmaCalculateStatistics( - VmaAllocator VMA_NOT_NULL allocator, - VmaTotalStatistics* VMA_NOT_NULL pStats); - - /** \brief Retrieves information about current memory usage and budget for all memory heaps. - - \param allocator - \param[out] pBudgets Must point to array with number of elements at least equal to number of memory heaps in physical device used. - - This function is called "get" not "calculate" because it is very fast, suitable to be called - every frame or every allocation. For more detailed statistics use vmaCalculateStatistics(). - - Note that when using allocator from multiple threads, returned information may immediately - become outdated. - */ - VMA_CALL_PRE void VMA_CALL_POST vmaGetHeapBudgets( - VmaAllocator VMA_NOT_NULL allocator, - VmaBudget* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL("VkPhysicalDeviceMemoryProperties::memoryHeapCount") pBudgets); - - /** @} */ - - /** - \addtogroup group_alloc - @{ - */ - - /** - \brief Helps to find memoryTypeIndex, given memoryTypeBits and VmaAllocationCreateInfo. - - This algorithm tries to find a memory type that: - - - Is allowed by memoryTypeBits. - - Contains all the flags from pAllocationCreateInfo->requiredFlags. - - Matches intended usage. - - Has as many flags from pAllocationCreateInfo->preferredFlags as possible. - - \return Returns VK_ERROR_FEATURE_NOT_PRESENT if not found. Receiving such result - from this function or any other allocating function probably means that your - device doesn't support any memory type with requested features for the specific - type of resource you want to use it for. Please check parameters of your - resource, like image layout (OPTIMAL versus LINEAR) or mip level count. - */ - VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndex( - VmaAllocator VMA_NOT_NULL allocator, - uint32_t memoryTypeBits, - const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, - uint32_t* VMA_NOT_NULL pMemoryTypeIndex); - - /** - \brief Helps to find memoryTypeIndex, given VkBufferCreateInfo and VmaAllocationCreateInfo. - - It can be useful e.g. to determine value to be used as VmaPoolCreateInfo::memoryTypeIndex. - It internally creates a temporary, dummy buffer that never has memory bound. - */ - VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForBufferInfo( - VmaAllocator VMA_NOT_NULL allocator, - const VkBufferCreateInfo* VMA_NOT_NULL pBufferCreateInfo, - const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, - uint32_t* VMA_NOT_NULL pMemoryTypeIndex); - - /** - \brief Helps to find memoryTypeIndex, given VkImageCreateInfo and VmaAllocationCreateInfo. - - It can be useful e.g. to determine value to be used as VmaPoolCreateInfo::memoryTypeIndex. - It internally creates a temporary, dummy image that never has memory bound. - */ - VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForImageInfo( - VmaAllocator VMA_NOT_NULL allocator, - const VkImageCreateInfo* VMA_NOT_NULL pImageCreateInfo, - const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, - uint32_t* VMA_NOT_NULL pMemoryTypeIndex); - - /** \brief Allocates Vulkan device memory and creates #VmaPool object. - - \param allocator Allocator object. - \param pCreateInfo Parameters of pool to create. - \param[out] pPool Handle to created pool. - */ - VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreatePool( - VmaAllocator VMA_NOT_NULL allocator, - const VmaPoolCreateInfo* VMA_NOT_NULL pCreateInfo, - VmaPool VMA_NULLABLE* VMA_NOT_NULL pPool); - - /** \brief Destroys #VmaPool object and frees Vulkan device memory. - */ - VMA_CALL_PRE void VMA_CALL_POST vmaDestroyPool( - VmaAllocator VMA_NOT_NULL allocator, - VmaPool VMA_NULLABLE pool); - - /** @} */ - - /** - \addtogroup group_stats - @{ - */ - - /** \brief Retrieves statistics of existing #VmaPool object. - - \param allocator Allocator object. - \param pool Pool object. - \param[out] pPoolStats Statistics of specified pool. - */ - VMA_CALL_PRE void VMA_CALL_POST vmaGetPoolStatistics( - VmaAllocator VMA_NOT_NULL allocator, - VmaPool VMA_NOT_NULL pool, - VmaStatistics* VMA_NOT_NULL pPoolStats); - - /** \brief Retrieves detailed statistics of existing #VmaPool object. - - \param allocator Allocator object. - \param pool Pool object. - \param[out] pPoolStats Statistics of specified pool. - */ - VMA_CALL_PRE void VMA_CALL_POST vmaCalculatePoolStatistics( - VmaAllocator VMA_NOT_NULL allocator, - VmaPool VMA_NOT_NULL pool, - VmaDetailedStatistics* VMA_NOT_NULL pPoolStats); - - /** @} */ - - /** - \addtogroup group_alloc - @{ - */ - - /** \brief Checks magic number in margins around all allocations in given memory pool in search for corruptions. - - Corruption detection is enabled only when `VMA_DEBUG_DETECT_CORRUPTION` macro is defined to nonzero, - `VMA_DEBUG_MARGIN` is defined to nonzero and the pool is created in memory type that is - `HOST_VISIBLE` and `HOST_COHERENT`. For more information, see [Corruption detection](@ref debugging_memory_usage_corruption_detection). - - Possible return values: - - - `VK_ERROR_FEATURE_NOT_PRESENT` - corruption detection is not enabled for specified pool. - - `VK_SUCCESS` - corruption detection has been performed and succeeded. - - `VK_ERROR_UNKNOWN` - corruption detection has been performed and found memory corruptions around one of the allocations. - `VMA_ASSERT` is also fired in that case. - - Other value: Error returned by Vulkan, e.g. memory mapping failure. - */ - VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckPoolCorruption( - VmaAllocator VMA_NOT_NULL allocator, - VmaPool VMA_NOT_NULL pool); - - /** \brief Retrieves name of a custom pool. - - After the call `ppName` is either null or points to an internally-owned null-terminated string - containing name of the pool that was previously set. The pointer becomes invalid when the pool is - destroyed or its name is changed using vmaSetPoolName(). - */ - VMA_CALL_PRE void VMA_CALL_POST vmaGetPoolName( - VmaAllocator VMA_NOT_NULL allocator, - VmaPool VMA_NOT_NULL pool, - const char* VMA_NULLABLE* VMA_NOT_NULL ppName); - - /** \brief Sets name of a custom pool. - - `pName` can be either null or pointer to a null-terminated string with new name for the pool. - Function makes internal copy of the string, so it can be changed or freed immediately after this call. - */ - VMA_CALL_PRE void VMA_CALL_POST vmaSetPoolName( - VmaAllocator VMA_NOT_NULL allocator, - VmaPool VMA_NOT_NULL pool, - const char* VMA_NULLABLE pName); - - /** \brief General purpose memory allocation. - - \param allocator - \param pVkMemoryRequirements - \param pCreateInfo - \param[out] pAllocation Handle to allocated memory. - \param[out] pAllocationInfo Optional. Information about allocated memory. It can be later fetched using function vmaGetAllocationInfo(). - - You should free the memory using vmaFreeMemory() or vmaFreeMemoryPages(). - - It is recommended to use vmaAllocateMemoryForBuffer(), vmaAllocateMemoryForImage(), - vmaCreateBuffer(), vmaCreateImage() instead whenever possible. - */ - VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemory( - VmaAllocator VMA_NOT_NULL allocator, - const VkMemoryRequirements* VMA_NOT_NULL pVkMemoryRequirements, - const VmaAllocationCreateInfo* VMA_NOT_NULL pCreateInfo, - VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation, - VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); - - /** \brief General purpose memory allocation for multiple allocation objects at once. - - \param allocator Allocator object. - \param pVkMemoryRequirements Memory requirements for each allocation. - \param pCreateInfo Creation parameters for each allocation. - \param allocationCount Number of allocations to make. - \param[out] pAllocations Pointer to array that will be filled with handles to created allocations. - \param[out] pAllocationInfo Optional. Pointer to array that will be filled with parameters of created allocations. - - You should free the memory using vmaFreeMemory() or vmaFreeMemoryPages(). - - Word "pages" is just a suggestion to use this function to allocate pieces of memory needed for sparse binding. - It is just a general purpose allocation function able to make multiple allocations at once. - It may be internally optimized to be more efficient than calling vmaAllocateMemory() `allocationCount` times. - - All allocations are made using same parameters. All of them are created out of the same memory pool and type. - If any allocation fails, all allocations already made within this function call are also freed, so that when - returned result is not `VK_SUCCESS`, `pAllocation` array is always entirely filled with `VK_NULL_HANDLE`. - */ - VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryPages( - VmaAllocator VMA_NOT_NULL allocator, - const VkMemoryRequirements* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(allocationCount) pVkMemoryRequirements, - const VmaAllocationCreateInfo* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(allocationCount) pCreateInfo, - size_t allocationCount, - VmaAllocation VMA_NULLABLE* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(allocationCount) pAllocations, - VmaAllocationInfo* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) pAllocationInfo); - - /** \brief Allocates memory suitable for given `VkBuffer`. - - \param allocator - \param buffer - \param pCreateInfo - \param[out] pAllocation Handle to allocated memory. - \param[out] pAllocationInfo Optional. Information about allocated memory. It can be later fetched using function vmaGetAllocationInfo(). - - It only creates #VmaAllocation. To bind the memory to the buffer, use vmaBindBufferMemory(). - - This is a special-purpose function. In most cases you should use vmaCreateBuffer(). - - You must free the allocation using vmaFreeMemory() when no longer needed. - */ - VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForBuffer( - VmaAllocator VMA_NOT_NULL allocator, - VkBuffer VMA_NOT_NULL_NON_DISPATCHABLE buffer, - const VmaAllocationCreateInfo* VMA_NOT_NULL pCreateInfo, - VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation, - VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); - - /** \brief Allocates memory suitable for given `VkImage`. - - \param allocator - \param image - \param pCreateInfo - \param[out] pAllocation Handle to allocated memory. - \param[out] pAllocationInfo Optional. Information about allocated memory. It can be later fetched using function vmaGetAllocationInfo(). - - It only creates #VmaAllocation. To bind the memory to the buffer, use vmaBindImageMemory(). - - This is a special-purpose function. In most cases you should use vmaCreateImage(). - - You must free the allocation using vmaFreeMemory() when no longer needed. - */ - VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForImage( - VmaAllocator VMA_NOT_NULL allocator, - VkImage VMA_NOT_NULL_NON_DISPATCHABLE image, - const VmaAllocationCreateInfo* VMA_NOT_NULL pCreateInfo, - VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation, - VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); - - /** \brief Frees memory previously allocated using vmaAllocateMemory(), vmaAllocateMemoryForBuffer(), or vmaAllocateMemoryForImage(). - - Passing `VK_NULL_HANDLE` as `allocation` is valid. Such function call is just skipped. - */ - VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemory( - VmaAllocator VMA_NOT_NULL allocator, - const VmaAllocation VMA_NULLABLE allocation); - - /** \brief Frees memory and destroys multiple allocations. - - Word "pages" is just a suggestion to use this function to free pieces of memory used for sparse binding. - It is just a general purpose function to free memory and destroy allocations made using e.g. vmaAllocateMemory(), - vmaAllocateMemoryPages() and other functions. - It may be internally optimized to be more efficient than calling vmaFreeMemory() `allocationCount` times. - - Allocations in `pAllocations` array can come from any memory pools and types. - Passing `VK_NULL_HANDLE` as elements of `pAllocations` array is valid. Such entries are just skipped. - */ - VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemoryPages( - VmaAllocator VMA_NOT_NULL allocator, - size_t allocationCount, - const VmaAllocation VMA_NULLABLE* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(allocationCount) pAllocations); - - /** \brief Returns current information about specified allocation. - - Current parameters of given allocation are returned in `pAllocationInfo`. - - Although this function doesn't lock any mutex, so it should be quite efficient, - you should avoid calling it too often. - You can retrieve same VmaAllocationInfo structure while creating your resource, from function - vmaCreateBuffer(), vmaCreateImage(). You can remember it if you are sure parameters don't change - (e.g. due to defragmentation). - - There is also a new function vmaGetAllocationInfo2() that offers extended information - about the allocation, returned using new structure #VmaAllocationInfo2. - */ - VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationInfo( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocation VMA_NOT_NULL allocation, - VmaAllocationInfo* VMA_NOT_NULL pAllocationInfo); - - /** \brief Returns extended information about specified allocation. - - Current parameters of given allocation are returned in `pAllocationInfo`. - Extended parameters in structure #VmaAllocationInfo2 include memory block size - and a flag telling whether the allocation has dedicated memory. - It can be useful e.g. for interop with OpenGL. - */ - VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationInfo2( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocation VMA_NOT_NULL allocation, - VmaAllocationInfo2* VMA_NOT_NULL pAllocationInfo); - - /** \brief Sets pUserData in given allocation to new value. - - The value of pointer `pUserData` is copied to allocation's `pUserData`. - It is opaque, so you can use it however you want - e.g. - as a pointer, ordinal number or some handle to you own data. - */ - VMA_CALL_PRE void VMA_CALL_POST vmaSetAllocationUserData( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocation VMA_NOT_NULL allocation, - void* VMA_NULLABLE pUserData); - - /** \brief Sets pName in given allocation to new value. - - `pName` must be either null, or pointer to a null-terminated string. The function - makes local copy of the string and sets it as allocation's `pName`. String - passed as pName doesn't need to be valid for whole lifetime of the allocation - - you can free it after this call. String previously pointed by allocation's - `pName` is freed from memory. - */ - VMA_CALL_PRE void VMA_CALL_POST vmaSetAllocationName( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocation VMA_NOT_NULL allocation, - const char* VMA_NULLABLE pName); - - /** - \brief Given an allocation, returns Property Flags of its memory type. - - This is just a convenience function. Same information can be obtained using - vmaGetAllocationInfo() + vmaGetMemoryProperties(). - */ - VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationMemoryProperties( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocation VMA_NOT_NULL allocation, - VkMemoryPropertyFlags* VMA_NOT_NULL pFlags); - - /** \brief Maps memory represented by given allocation and returns pointer to it. - - Maps memory represented by given allocation to make it accessible to CPU code. - When succeeded, `*ppData` contains pointer to first byte of this memory. - - \warning - If the allocation is part of a bigger `VkDeviceMemory` block, returned pointer is - correctly offsetted to the beginning of region assigned to this particular allocation. - Unlike the result of `vkMapMemory`, it points to the allocation, not to the beginning of the whole block. - You should not add VmaAllocationInfo::offset to it! - - Mapping is internally reference-counted and synchronized, so despite raw Vulkan - function `vkMapMemory()` cannot be used to map same block of `VkDeviceMemory` - multiple times simultaneously, it is safe to call this function on allocations - assigned to the same memory block. Actual Vulkan memory will be mapped on first - mapping and unmapped on last unmapping. - - If the function succeeded, you must call vmaUnmapMemory() to unmap the - allocation when mapping is no longer needed or before freeing the allocation, at - the latest. - - It also safe to call this function multiple times on the same allocation. You - must call vmaUnmapMemory() same number of times as you called vmaMapMemory(). - - It is also safe to call this function on allocation created with - #VMA_ALLOCATION_CREATE_MAPPED_BIT flag. Its memory stays mapped all the time. - You must still call vmaUnmapMemory() same number of times as you called - vmaMapMemory(). You must not call vmaUnmapMemory() additional time to free the - "0-th" mapping made automatically due to #VMA_ALLOCATION_CREATE_MAPPED_BIT flag. - - This function fails when used on allocation made in memory type that is not - `HOST_VISIBLE`. - - This function doesn't automatically flush or invalidate caches. - If the allocation is made from a memory types that is not `HOST_COHERENT`, - you also need to use vmaInvalidateAllocation() / vmaFlushAllocation(), as required by Vulkan specification. - */ - VMA_CALL_PRE VkResult VMA_CALL_POST vmaMapMemory( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocation VMA_NOT_NULL allocation, - void* VMA_NULLABLE* VMA_NOT_NULL ppData); - - /** \brief Unmaps memory represented by given allocation, mapped previously using vmaMapMemory(). - - For details, see description of vmaMapMemory(). - - This function doesn't automatically flush or invalidate caches. - If the allocation is made from a memory types that is not `HOST_COHERENT`, - you also need to use vmaInvalidateAllocation() / vmaFlushAllocation(), as required by Vulkan specification. - */ - VMA_CALL_PRE void VMA_CALL_POST vmaUnmapMemory( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocation VMA_NOT_NULL allocation); - - /** \brief Flushes memory of given allocation. - - Calls `vkFlushMappedMemoryRanges()` for memory associated with given range of given allocation. - It needs to be called after writing to a mapped memory for memory types that are not `HOST_COHERENT`. - Unmap operation doesn't do that automatically. - - - `offset` must be relative to the beginning of allocation. - - `size` can be `VK_WHOLE_SIZE`. It means all memory from `offset` the the end of given allocation. - - `offset` and `size` don't have to be aligned. - They are internally rounded down/up to multiply of `nonCoherentAtomSize`. - - If `size` is 0, this call is ignored. - - If memory type that the `allocation` belongs to is not `HOST_VISIBLE` or it is `HOST_COHERENT`, - this call is ignored. - - Warning! `offset` and `size` are relative to the contents of given `allocation`. - If you mean whole allocation, you can pass 0 and `VK_WHOLE_SIZE`, respectively. - Do not pass allocation's offset as `offset`!!! - - This function returns the `VkResult` from `vkFlushMappedMemoryRanges` if it is - called, otherwise `VK_SUCCESS`. - */ - VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocation( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocation VMA_NOT_NULL allocation, - VkDeviceSize offset, - VkDeviceSize size); - - /** \brief Invalidates memory of given allocation. - - Calls `vkInvalidateMappedMemoryRanges()` for memory associated with given range of given allocation. - It needs to be called before reading from a mapped memory for memory types that are not `HOST_COHERENT`. - Map operation doesn't do that automatically. - - - `offset` must be relative to the beginning of allocation. - - `size` can be `VK_WHOLE_SIZE`. It means all memory from `offset` the the end of given allocation. - - `offset` and `size` don't have to be aligned. - They are internally rounded down/up to multiply of `nonCoherentAtomSize`. - - If `size` is 0, this call is ignored. - - If memory type that the `allocation` belongs to is not `HOST_VISIBLE` or it is `HOST_COHERENT`, - this call is ignored. - - Warning! `offset` and `size` are relative to the contents of given `allocation`. - If you mean whole allocation, you can pass 0 and `VK_WHOLE_SIZE`, respectively. - Do not pass allocation's offset as `offset`!!! - - This function returns the `VkResult` from `vkInvalidateMappedMemoryRanges` if - it is called, otherwise `VK_SUCCESS`. - */ - VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocation( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocation VMA_NOT_NULL allocation, - VkDeviceSize offset, - VkDeviceSize size); - - /** \brief Flushes memory of given set of allocations. - - Calls `vkFlushMappedMemoryRanges()` for memory associated with given ranges of given allocations. - For more information, see documentation of vmaFlushAllocation(). - - \param allocator - \param allocationCount - \param allocations - \param offsets If not null, it must point to an array of offsets of regions to flush, relative to the beginning of respective allocations. Null means all offsets are zero. - \param sizes If not null, it must point to an array of sizes of regions to flush in respective allocations. Null means `VK_WHOLE_SIZE` for all allocations. - - This function returns the `VkResult` from `vkFlushMappedMemoryRanges` if it is - called, otherwise `VK_SUCCESS`. - */ - VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocations( - VmaAllocator VMA_NOT_NULL allocator, - uint32_t allocationCount, - const VmaAllocation VMA_NOT_NULL* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) allocations, - const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) offsets, - const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) sizes); - - /** \brief Invalidates memory of given set of allocations. - - Calls `vkInvalidateMappedMemoryRanges()` for memory associated with given ranges of given allocations. - For more information, see documentation of vmaInvalidateAllocation(). - - \param allocator - \param allocationCount - \param allocations - \param offsets If not null, it must point to an array of offsets of regions to flush, relative to the beginning of respective allocations. Null means all offsets are zero. - \param sizes If not null, it must point to an array of sizes of regions to flush in respective allocations. Null means `VK_WHOLE_SIZE` for all allocations. - - This function returns the `VkResult` from `vkInvalidateMappedMemoryRanges` if it is - called, otherwise `VK_SUCCESS`. - */ - VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocations( - VmaAllocator VMA_NOT_NULL allocator, - uint32_t allocationCount, - const VmaAllocation VMA_NOT_NULL* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) allocations, - const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) offsets, - const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) sizes); - - /** \brief Maps the allocation temporarily if needed, copies data from specified host pointer to it, and flushes the memory from the host caches if needed. - - \param allocator - \param pSrcHostPointer Pointer to the host data that become source of the copy. - \param dstAllocation Handle to the allocation that becomes destination of the copy. - \param dstAllocationLocalOffset Offset within `dstAllocation` where to write copied data, in bytes. - \param size Number of bytes to copy. - - This is a convenience function that allows to copy data from a host pointer to an allocation easily. - Same behavior can be achieved by calling vmaMapMemory(), `memcpy()`, vmaUnmapMemory(), vmaFlushAllocation(). - - This function can be called only for allocations created in a memory type that has `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT` flag. - It can be ensured e.g. by using #VMA_MEMORY_USAGE_AUTO and #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or - #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT. - Otherwise, the function will fail and generate a Validation Layers error. - - `dstAllocationLocalOffset` is relative to the contents of given `dstAllocation`. - If you mean whole allocation, you should pass 0. - Do not pass allocation's offset within device memory block this parameter! - */ - VMA_CALL_PRE VkResult VMA_CALL_POST vmaCopyMemoryToAllocation( - VmaAllocator VMA_NOT_NULL allocator, - const void* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(size) pSrcHostPointer, - VmaAllocation VMA_NOT_NULL dstAllocation, - VkDeviceSize dstAllocationLocalOffset, - VkDeviceSize size); - - /** \brief Invalidates memory in the host caches if needed, maps the allocation temporarily if needed, and copies data from it to a specified host pointer. - - \param allocator - \param srcAllocation Handle to the allocation that becomes source of the copy. - \param srcAllocationLocalOffset Offset within `srcAllocation` where to read copied data, in bytes. - \param pDstHostPointer Pointer to the host memory that become destination of the copy. - \param size Number of bytes to copy. - - This is a convenience function that allows to copy data from an allocation to a host pointer easily. - Same behavior can be achieved by calling vmaInvalidateAllocation(), vmaMapMemory(), `memcpy()`, vmaUnmapMemory(). - - This function should be called only for allocations created in a memory type that has `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT` - and `VK_MEMORY_PROPERTY_HOST_CACHED_BIT` flag. - It can be ensured e.g. by using #VMA_MEMORY_USAGE_AUTO and #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT. - Otherwise, the function may fail and generate a Validation Layers error. - It may also work very slowly when reading from an uncached memory. - - `srcAllocationLocalOffset` is relative to the contents of given `srcAllocation`. - If you mean whole allocation, you should pass 0. - Do not pass allocation's offset within device memory block as this parameter! - */ - VMA_CALL_PRE VkResult VMA_CALL_POST vmaCopyAllocationToMemory( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocation VMA_NOT_NULL srcAllocation, - VkDeviceSize srcAllocationLocalOffset, - void* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(size) pDstHostPointer, - VkDeviceSize size); - - /** \brief Checks magic number in margins around all allocations in given memory types (in both default and custom pools) in search for corruptions. - - \param allocator - \param memoryTypeBits Bit mask, where each bit set means that a memory type with that index should be checked. - - Corruption detection is enabled only when `VMA_DEBUG_DETECT_CORRUPTION` macro is defined to nonzero, - `VMA_DEBUG_MARGIN` is defined to nonzero and only for memory types that are - `HOST_VISIBLE` and `HOST_COHERENT`. For more information, see [Corruption detection](@ref debugging_memory_usage_corruption_detection). - - Possible return values: - - - `VK_ERROR_FEATURE_NOT_PRESENT` - corruption detection is not enabled for any of specified memory types. - - `VK_SUCCESS` - corruption detection has been performed and succeeded. - - `VK_ERROR_UNKNOWN` - corruption detection has been performed and found memory corruptions around one of the allocations. - `VMA_ASSERT` is also fired in that case. - - Other value: Error returned by Vulkan, e.g. memory mapping failure. - */ - VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckCorruption( - VmaAllocator VMA_NOT_NULL allocator, - uint32_t memoryTypeBits); - - /** \brief Begins defragmentation process. - - \param allocator Allocator object. - \param pInfo Structure filled with parameters of defragmentation. - \param[out] pContext Context object that must be passed to vmaEndDefragmentation() to finish defragmentation. - \returns - - `VK_SUCCESS` if defragmentation can begin. - - `VK_ERROR_FEATURE_NOT_PRESENT` if defragmentation is not supported. - - For more information about defragmentation, see documentation chapter: - [Defragmentation](@ref defragmentation). - */ - VMA_CALL_PRE VkResult VMA_CALL_POST vmaBeginDefragmentation( - VmaAllocator VMA_NOT_NULL allocator, - const VmaDefragmentationInfo* VMA_NOT_NULL pInfo, - VmaDefragmentationContext VMA_NULLABLE* VMA_NOT_NULL pContext); - - /** \brief Ends defragmentation process. - - \param allocator Allocator object. - \param context Context object that has been created by vmaBeginDefragmentation(). - \param[out] pStats Optional stats for the defragmentation. Can be null. - - Use this function to finish defragmentation started by vmaBeginDefragmentation(). - */ - VMA_CALL_PRE void VMA_CALL_POST vmaEndDefragmentation( - VmaAllocator VMA_NOT_NULL allocator, - VmaDefragmentationContext VMA_NOT_NULL context, - VmaDefragmentationStats* VMA_NULLABLE pStats); - - /** \brief Starts single defragmentation pass. - - \param allocator Allocator object. - \param context Context object that has been created by vmaBeginDefragmentation(). - \param[out] pPassInfo Computed information for current pass. - \returns - - `VK_SUCCESS` if no more moves are possible. Then you can omit call to vmaEndDefragmentationPass() and simply end whole defragmentation. - - `VK_INCOMPLETE` if there are pending moves returned in `pPassInfo`. You need to perform them, call vmaEndDefragmentationPass(), - and then preferably try another pass with vmaBeginDefragmentationPass(). - */ - VMA_CALL_PRE VkResult VMA_CALL_POST vmaBeginDefragmentationPass( - VmaAllocator VMA_NOT_NULL allocator, - VmaDefragmentationContext VMA_NOT_NULL context, - VmaDefragmentationPassMoveInfo* VMA_NOT_NULL pPassInfo); - - /** \brief Ends single defragmentation pass. - - \param allocator Allocator object. - \param context Context object that has been created by vmaBeginDefragmentation(). - \param pPassInfo Computed information for current pass filled by vmaBeginDefragmentationPass() and possibly modified by you. - - Returns `VK_SUCCESS` if no more moves are possible or `VK_INCOMPLETE` if more defragmentations are possible. - - Ends incremental defragmentation pass and commits all defragmentation moves from `pPassInfo`. - After this call: - - - Allocations at `pPassInfo[i].srcAllocation` that had `pPassInfo[i].operation ==` #VMA_DEFRAGMENTATION_MOVE_OPERATION_COPY - (which is the default) will be pointing to the new destination place. - - Allocation at `pPassInfo[i].srcAllocation` that had `pPassInfo[i].operation ==` #VMA_DEFRAGMENTATION_MOVE_OPERATION_DESTROY - will be freed. - - If no more moves are possible you can end whole defragmentation. - */ - VMA_CALL_PRE VkResult VMA_CALL_POST vmaEndDefragmentationPass( - VmaAllocator VMA_NOT_NULL allocator, - VmaDefragmentationContext VMA_NOT_NULL context, - VmaDefragmentationPassMoveInfo* VMA_NOT_NULL pPassInfo); - - /** \brief Binds buffer to allocation. - - Binds specified buffer to region of memory represented by specified allocation. - Gets `VkDeviceMemory` handle and offset from the allocation. - If you want to create a buffer, allocate memory for it and bind them together separately, - you should use this function for binding instead of standard `vkBindBufferMemory()`, - because it ensures proper synchronization so that when a `VkDeviceMemory` object is used by multiple - allocations, calls to `vkBind*Memory()` or `vkMapMemory()` won't happen from multiple threads simultaneously - (which is illegal in Vulkan). - - It is recommended to use function vmaCreateBuffer() instead of this one. - */ - VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocation VMA_NOT_NULL allocation, - VkBuffer VMA_NOT_NULL_NON_DISPATCHABLE buffer); - - /** \brief Binds buffer to allocation with additional parameters. - - \param allocator - \param allocation - \param allocationLocalOffset Additional offset to be added while binding, relative to the beginning of the `allocation`. Normally it should be 0. - \param buffer - \param pNext A chain of structures to be attached to `VkBindBufferMemoryInfoKHR` structure used internally. Normally it should be null. - - This function is similar to vmaBindBufferMemory(), but it provides additional parameters. - - If `pNext` is not null, #VmaAllocator object must have been created with #VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT flag - or with VmaAllocatorCreateInfo::vulkanApiVersion `>= VK_API_VERSION_1_1`. Otherwise the call fails. - */ - VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory2( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocation VMA_NOT_NULL allocation, - VkDeviceSize allocationLocalOffset, - VkBuffer VMA_NOT_NULL_NON_DISPATCHABLE buffer, - const void* VMA_NULLABLE VMA_EXTENDS_VK_STRUCT(VkBindBufferMemoryInfoKHR) pNext); - - /** \brief Binds image to allocation. - - Binds specified image to region of memory represented by specified allocation. - Gets `VkDeviceMemory` handle and offset from the allocation. - If you want to create an image, allocate memory for it and bind them together separately, - you should use this function for binding instead of standard `vkBindImageMemory()`, - because it ensures proper synchronization so that when a `VkDeviceMemory` object is used by multiple - allocations, calls to `vkBind*Memory()` or `vkMapMemory()` won't happen from multiple threads simultaneously - (which is illegal in Vulkan). - - It is recommended to use function vmaCreateImage() instead of this one. - */ - VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocation VMA_NOT_NULL allocation, - VkImage VMA_NOT_NULL_NON_DISPATCHABLE image); - - /** \brief Binds image to allocation with additional parameters. - - \param allocator - \param allocation - \param allocationLocalOffset Additional offset to be added while binding, relative to the beginning of the `allocation`. Normally it should be 0. - \param image - \param pNext A chain of structures to be attached to `VkBindImageMemoryInfoKHR` structure used internally. Normally it should be null. - - This function is similar to vmaBindImageMemory(), but it provides additional parameters. - - If `pNext` is not null, #VmaAllocator object must have been created with #VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT flag - or with VmaAllocatorCreateInfo::vulkanApiVersion `>= VK_API_VERSION_1_1`. Otherwise the call fails. - */ - VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory2( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocation VMA_NOT_NULL allocation, - VkDeviceSize allocationLocalOffset, - VkImage VMA_NOT_NULL_NON_DISPATCHABLE image, - const void* VMA_NULLABLE VMA_EXTENDS_VK_STRUCT(VkBindImageMemoryInfoKHR) pNext); - - /** \brief Creates a new `VkBuffer`, allocates and binds memory for it. - - \param allocator - \param pBufferCreateInfo - \param pAllocationCreateInfo - \param[out] pBuffer Buffer that was created. - \param[out] pAllocation Allocation that was created. - \param[out] pAllocationInfo Optional. Information about allocated memory. It can be later fetched using function vmaGetAllocationInfo(). - - This function automatically: - - -# Creates buffer. - -# Allocates appropriate memory for it. - -# Binds the buffer with the memory. - - If any of these operations fail, buffer and allocation are not created, - returned value is negative error code, `*pBuffer` and `*pAllocation` are null. - - If the function succeeded, you must destroy both buffer and allocation when you - no longer need them using either convenience function vmaDestroyBuffer() or - separately, using `vkDestroyBuffer()` and vmaFreeMemory(). - - If #VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT flag was used, - VK_KHR_dedicated_allocation extension is used internally to query driver whether - it requires or prefers the new buffer to have dedicated allocation. If yes, - and if dedicated allocation is possible - (#VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT is not used), it creates dedicated - allocation for this buffer, just like when using - #VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT. - - \note This function creates a new `VkBuffer`. Sub-allocation of parts of one large buffer, - although recommended as a good practice, is out of scope of this library and could be implemented - by the user as a higher-level logic on top of VMA. - */ - VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBuffer( - VmaAllocator VMA_NOT_NULL allocator, - const VkBufferCreateInfo* VMA_NOT_NULL pBufferCreateInfo, - const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, - VkBuffer VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pBuffer, - VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation, - VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); - - /** \brief Creates a buffer with additional minimum alignment. - - Similar to vmaCreateBuffer() but provides additional parameter `minAlignment` which allows to specify custom, - minimum alignment to be used when placing the buffer inside a larger memory block, which may be needed e.g. - for interop with OpenGL. - */ - VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBufferWithAlignment( - VmaAllocator VMA_NOT_NULL allocator, - const VkBufferCreateInfo* VMA_NOT_NULL pBufferCreateInfo, - const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, - VkDeviceSize minAlignment, - VkBuffer VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pBuffer, - VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation, - VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); - - /** \brief Creates a new `VkBuffer`, binds already created memory for it. - - \param allocator - \param allocation Allocation that provides memory to be used for binding new buffer to it. - \param pBufferCreateInfo - \param[out] pBuffer Buffer that was created. - - This function automatically: - - -# Creates buffer. - -# Binds the buffer with the supplied memory. - - If any of these operations fail, buffer is not created, - returned value is negative error code and `*pBuffer` is null. - - If the function succeeded, you must destroy the buffer when you - no longer need it using `vkDestroyBuffer()`. If you want to also destroy the corresponding - allocation you can use convenience function vmaDestroyBuffer(). - - \note There is a new version of this function augmented with parameter `allocationLocalOffset` - see vmaCreateAliasingBuffer2(). - */ - VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAliasingBuffer( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocation VMA_NOT_NULL allocation, - const VkBufferCreateInfo* VMA_NOT_NULL pBufferCreateInfo, - VkBuffer VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pBuffer); - - /** \brief Creates a new `VkBuffer`, binds already created memory for it. - - \param allocator - \param allocation Allocation that provides memory to be used for binding new buffer to it. - \param allocationLocalOffset Additional offset to be added while binding, relative to the beginning of the allocation. Normally it should be 0. - \param pBufferCreateInfo - \param[out] pBuffer Buffer that was created. - - This function automatically: - - -# Creates buffer. - -# Binds the buffer with the supplied memory. - - If any of these operations fail, buffer is not created, - returned value is negative error code and `*pBuffer` is null. - - If the function succeeded, you must destroy the buffer when you - no longer need it using `vkDestroyBuffer()`. If you want to also destroy the corresponding - allocation you can use convenience function vmaDestroyBuffer(). - - \note This is a new version of the function augmented with parameter `allocationLocalOffset`. - */ - VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAliasingBuffer2( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocation VMA_NOT_NULL allocation, - VkDeviceSize allocationLocalOffset, - const VkBufferCreateInfo* VMA_NOT_NULL pBufferCreateInfo, - VkBuffer VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pBuffer); - - /** \brief Destroys Vulkan buffer and frees allocated memory. - - This is just a convenience function equivalent to: - - \code - vkDestroyBuffer(device, buffer, allocationCallbacks); - vmaFreeMemory(allocator, allocation); - \endcode - - It is safe to pass null as buffer and/or allocation. - */ - VMA_CALL_PRE void VMA_CALL_POST vmaDestroyBuffer( - VmaAllocator VMA_NOT_NULL allocator, - VkBuffer VMA_NULLABLE_NON_DISPATCHABLE buffer, - VmaAllocation VMA_NULLABLE allocation); - - /// Function similar to vmaCreateBuffer(). - VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateImage( - VmaAllocator VMA_NOT_NULL allocator, - const VkImageCreateInfo* VMA_NOT_NULL pImageCreateInfo, - const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, - VkImage VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pImage, - VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation, - VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); - - /// Function similar to vmaCreateAliasingBuffer() but for images. - VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAliasingImage( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocation VMA_NOT_NULL allocation, - const VkImageCreateInfo* VMA_NOT_NULL pImageCreateInfo, - VkImage VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pImage); - - /// Function similar to vmaCreateAliasingBuffer2() but for images. - VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAliasingImage2( - VmaAllocator VMA_NOT_NULL allocator, - VmaAllocation VMA_NOT_NULL allocation, - VkDeviceSize allocationLocalOffset, - const VkImageCreateInfo* VMA_NOT_NULL pImageCreateInfo, - VkImage VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pImage); - - /** \brief Destroys Vulkan image and frees allocated memory. - - This is just a convenience function equivalent to: - - \code - vkDestroyImage(device, image, allocationCallbacks); - vmaFreeMemory(allocator, allocation); - \endcode - - It is safe to pass null as image and/or allocation. - */ - VMA_CALL_PRE void VMA_CALL_POST vmaDestroyImage( - VmaAllocator VMA_NOT_NULL allocator, - VkImage VMA_NULLABLE_NON_DISPATCHABLE image, - VmaAllocation VMA_NULLABLE allocation); - - /** @} */ - - /** - \addtogroup group_virtual - @{ - */ - - /** \brief Creates new #VmaVirtualBlock object. - - \param pCreateInfo Parameters for creation. - \param[out] pVirtualBlock Returned virtual block object or `VMA_NULL` if creation failed. - */ - VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateVirtualBlock( - const VmaVirtualBlockCreateInfo* VMA_NOT_NULL pCreateInfo, - VmaVirtualBlock VMA_NULLABLE* VMA_NOT_NULL pVirtualBlock); - - /** \brief Destroys #VmaVirtualBlock object. - - Please note that you should consciously handle virtual allocations that could remain unfreed in the block. - You should either free them individually using vmaVirtualFree() or call vmaClearVirtualBlock() - if you are sure this is what you want. If you do neither, an assert is called. - - If you keep pointers to some additional metadata associated with your virtual allocations in their `pUserData`, - don't forget to free them. - */ - VMA_CALL_PRE void VMA_CALL_POST vmaDestroyVirtualBlock( - VmaVirtualBlock VMA_NULLABLE virtualBlock); - - /** \brief Returns true of the #VmaVirtualBlock is empty - contains 0 virtual allocations and has all its space available for new allocations. - */ - VMA_CALL_PRE VkBool32 VMA_CALL_POST vmaIsVirtualBlockEmpty( - VmaVirtualBlock VMA_NOT_NULL virtualBlock); - - /** \brief Returns information about a specific virtual allocation within a virtual block, like its size and `pUserData` pointer. - */ - VMA_CALL_PRE void VMA_CALL_POST vmaGetVirtualAllocationInfo( - VmaVirtualBlock VMA_NOT_NULL virtualBlock, - VmaVirtualAllocation VMA_NOT_NULL_NON_DISPATCHABLE allocation, VmaVirtualAllocationInfo* VMA_NOT_NULL pVirtualAllocInfo); - - /** \brief Allocates new virtual allocation inside given #VmaVirtualBlock. - - If the allocation fails due to not enough free space available, `VK_ERROR_OUT_OF_DEVICE_MEMORY` is returned - (despite the function doesn't ever allocate actual GPU memory). - `pAllocation` is then set to `VK_NULL_HANDLE` and `pOffset`, if not null, it set to `UINT64_MAX`. - - \param virtualBlock Virtual block - \param pCreateInfo Parameters for the allocation - \param[out] pAllocation Returned handle of the new allocation - \param[out] pOffset Returned offset of the new allocation. Optional, can be null. - */ - VMA_CALL_PRE VkResult VMA_CALL_POST vmaVirtualAllocate( - VmaVirtualBlock VMA_NOT_NULL virtualBlock, - const VmaVirtualAllocationCreateInfo* VMA_NOT_NULL pCreateInfo, - VmaVirtualAllocation VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pAllocation, - VkDeviceSize* VMA_NULLABLE pOffset); - - /** \brief Frees virtual allocation inside given #VmaVirtualBlock. - - It is correct to call this function with `allocation == VK_NULL_HANDLE` - it does nothing. - */ - VMA_CALL_PRE void VMA_CALL_POST vmaVirtualFree( - VmaVirtualBlock VMA_NOT_NULL virtualBlock, - VmaVirtualAllocation VMA_NULLABLE_NON_DISPATCHABLE allocation); - - /** \brief Frees all virtual allocations inside given #VmaVirtualBlock. - - You must either call this function or free each virtual allocation individually with vmaVirtualFree() - before destroying a virtual block. Otherwise, an assert is called. - - If you keep pointer to some additional metadata associated with your virtual allocation in its `pUserData`, - don't forget to free it as well. - */ - VMA_CALL_PRE void VMA_CALL_POST vmaClearVirtualBlock( - VmaVirtualBlock VMA_NOT_NULL virtualBlock); - - /** \brief Changes custom pointer associated with given virtual allocation. - */ - VMA_CALL_PRE void VMA_CALL_POST vmaSetVirtualAllocationUserData( - VmaVirtualBlock VMA_NOT_NULL virtualBlock, - VmaVirtualAllocation VMA_NOT_NULL_NON_DISPATCHABLE allocation, - void* VMA_NULLABLE pUserData); - - /** \brief Calculates and returns statistics about virtual allocations and memory usage in given #VmaVirtualBlock. - - This function is fast to call. For more detailed statistics, see vmaCalculateVirtualBlockStatistics(). - */ - VMA_CALL_PRE void VMA_CALL_POST vmaGetVirtualBlockStatistics( - VmaVirtualBlock VMA_NOT_NULL virtualBlock, - VmaStatistics* VMA_NOT_NULL pStats); - - /** \brief Calculates and returns detailed statistics about virtual allocations and memory usage in given #VmaVirtualBlock. - - This function is slow to call. Use for debugging purposes. - For less detailed statistics, see vmaGetVirtualBlockStatistics(). - */ - VMA_CALL_PRE void VMA_CALL_POST vmaCalculateVirtualBlockStatistics( - VmaVirtualBlock VMA_NOT_NULL virtualBlock, - VmaDetailedStatistics* VMA_NOT_NULL pStats); - - /** @} */ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAllocator( + const VmaAllocatorCreateInfo* VMA_NOT_NULL pCreateInfo, + VmaAllocator VMA_NULLABLE* VMA_NOT_NULL pAllocator); + +/// Destroys allocator object. +VMA_CALL_PRE void VMA_CALL_POST vmaDestroyAllocator( + VmaAllocator VMA_NULLABLE allocator); + +/** \brief Returns information about existing #VmaAllocator object - handle to Vulkan device etc. + +It might be useful if you want to keep just the #VmaAllocator handle and fetch other required handles to +`VkPhysicalDevice`, `VkDevice` etc. every time using this function. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocatorInfo( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocatorInfo* VMA_NOT_NULL pAllocatorInfo); + +/** +PhysicalDeviceProperties are fetched from physicalDevice by the allocator. +You can access it here, without fetching it again on your own. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaGetPhysicalDeviceProperties( + VmaAllocator VMA_NOT_NULL allocator, + const VkPhysicalDeviceProperties* VMA_NULLABLE* VMA_NOT_NULL ppPhysicalDeviceProperties); + +/** +PhysicalDeviceMemoryProperties are fetched from physicalDevice by the allocator. +You can access it here, without fetching it again on your own. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaGetMemoryProperties( + VmaAllocator VMA_NOT_NULL allocator, + const VkPhysicalDeviceMemoryProperties* VMA_NULLABLE* VMA_NOT_NULL ppPhysicalDeviceMemoryProperties); + +/** +\brief Given Memory Type Index, returns Property Flags of this memory type. + +This is just a convenience function. Same information can be obtained using +vmaGetMemoryProperties(). +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaGetMemoryTypeProperties( + VmaAllocator VMA_NOT_NULL allocator, + uint32_t memoryTypeIndex, + VkMemoryPropertyFlags* VMA_NOT_NULL pFlags); + +/** \brief Sets index of the current frame. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaSetCurrentFrameIndex( + VmaAllocator VMA_NOT_NULL allocator, + uint32_t frameIndex); + +/** @} */ + +/** +\addtogroup group_stats +@{ +*/ + +/** \brief Retrieves statistics from current state of the Allocator. + +This function is called "calculate" not "get" because it has to traverse all +internal data structures, so it may be quite slow. Use it for debugging purposes. +For faster but more brief statistics suitable to be called every frame or every allocation, +use vmaGetHeapBudgets(). + +Note that when using allocator from multiple threads, returned information may immediately +become outdated. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaCalculateStatistics( + VmaAllocator VMA_NOT_NULL allocator, + VmaTotalStatistics* VMA_NOT_NULL pStats); + +/** \brief Retrieves information about current memory usage and budget for all memory heaps. + +\param allocator +\param[out] pBudgets Must point to array with number of elements at least equal to number of memory heaps in physical device used. + +This function is called "get" not "calculate" because it is very fast, suitable to be called +every frame or every allocation. For more detailed statistics use vmaCalculateStatistics(). + +Note that when using allocator from multiple threads, returned information may immediately +become outdated. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaGetHeapBudgets( + VmaAllocator VMA_NOT_NULL allocator, + VmaBudget* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL("VkPhysicalDeviceMemoryProperties::memoryHeapCount") pBudgets); + +/** @} */ + +/** +\addtogroup group_alloc +@{ +*/ + +/** +\brief Helps to find memoryTypeIndex, given memoryTypeBits and VmaAllocationCreateInfo. + +This algorithm tries to find a memory type that: + +- Is allowed by memoryTypeBits. +- Contains all the flags from pAllocationCreateInfo->requiredFlags. +- Matches intended usage. +- Has as many flags from pAllocationCreateInfo->preferredFlags as possible. + +\return Returns VK_ERROR_FEATURE_NOT_PRESENT if not found. Receiving such result +from this function or any other allocating function probably means that your +device doesn't support any memory type with requested features for the specific +type of resource you want to use it for. Please check parameters of your +resource, like image layout (OPTIMAL versus LINEAR) or mip level count. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndex( + VmaAllocator VMA_NOT_NULL allocator, + uint32_t memoryTypeBits, + const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, + uint32_t* VMA_NOT_NULL pMemoryTypeIndex); + +/** +\brief Helps to find memoryTypeIndex, given VkBufferCreateInfo and VmaAllocationCreateInfo. + +It can be useful e.g. to determine value to be used as VmaPoolCreateInfo::memoryTypeIndex. +It internally creates a temporary, dummy buffer that never has memory bound. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForBufferInfo( + VmaAllocator VMA_NOT_NULL allocator, + const VkBufferCreateInfo* VMA_NOT_NULL pBufferCreateInfo, + const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, + uint32_t* VMA_NOT_NULL pMemoryTypeIndex); + +/** +\brief Helps to find memoryTypeIndex, given VkImageCreateInfo and VmaAllocationCreateInfo. + +It can be useful e.g. to determine value to be used as VmaPoolCreateInfo::memoryTypeIndex. +It internally creates a temporary, dummy image that never has memory bound. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForImageInfo( + VmaAllocator VMA_NOT_NULL allocator, + const VkImageCreateInfo* VMA_NOT_NULL pImageCreateInfo, + const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, + uint32_t* VMA_NOT_NULL pMemoryTypeIndex); + +/** \brief Allocates Vulkan device memory and creates #VmaPool object. + +\param allocator Allocator object. +\param pCreateInfo Parameters of pool to create. +\param[out] pPool Handle to created pool. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreatePool( + VmaAllocator VMA_NOT_NULL allocator, + const VmaPoolCreateInfo* VMA_NOT_NULL pCreateInfo, + VmaPool VMA_NULLABLE* VMA_NOT_NULL pPool); + +/** \brief Destroys #VmaPool object and frees Vulkan device memory. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaDestroyPool( + VmaAllocator VMA_NOT_NULL allocator, + VmaPool VMA_NULLABLE pool); + +/** @} */ + +/** +\addtogroup group_stats +@{ +*/ + +/** \brief Retrieves statistics of existing #VmaPool object. + +\param allocator Allocator object. +\param pool Pool object. +\param[out] pPoolStats Statistics of specified pool. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaGetPoolStatistics( + VmaAllocator VMA_NOT_NULL allocator, + VmaPool VMA_NOT_NULL pool, + VmaStatistics* VMA_NOT_NULL pPoolStats); + +/** \brief Retrieves detailed statistics of existing #VmaPool object. + +\param allocator Allocator object. +\param pool Pool object. +\param[out] pPoolStats Statistics of specified pool. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaCalculatePoolStatistics( + VmaAllocator VMA_NOT_NULL allocator, + VmaPool VMA_NOT_NULL pool, + VmaDetailedStatistics* VMA_NOT_NULL pPoolStats); + +/** @} */ + +/** +\addtogroup group_alloc +@{ +*/ + +/** \brief Checks magic number in margins around all allocations in given memory pool in search for corruptions. + +Corruption detection is enabled only when `VMA_DEBUG_DETECT_CORRUPTION` macro is defined to nonzero, +`VMA_DEBUG_MARGIN` is defined to nonzero and the pool is created in memory type that is +`HOST_VISIBLE` and `HOST_COHERENT`. For more information, see [Corruption detection](@ref debugging_memory_usage_corruption_detection). + +Possible return values: + +- `VK_ERROR_FEATURE_NOT_PRESENT` - corruption detection is not enabled for specified pool. +- `VK_SUCCESS` - corruption detection has been performed and succeeded. +- `VK_ERROR_UNKNOWN` - corruption detection has been performed and found memory corruptions around one of the allocations. + `VMA_ASSERT` is also fired in that case. +- Other value: Error returned by Vulkan, e.g. memory mapping failure. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckPoolCorruption( + VmaAllocator VMA_NOT_NULL allocator, + VmaPool VMA_NOT_NULL pool); + +/** \brief Retrieves name of a custom pool. + +After the call `ppName` is either null or points to an internally-owned null-terminated string +containing name of the pool that was previously set. The pointer becomes invalid when the pool is +destroyed or its name is changed using vmaSetPoolName(). +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaGetPoolName( + VmaAllocator VMA_NOT_NULL allocator, + VmaPool VMA_NOT_NULL pool, + const char* VMA_NULLABLE* VMA_NOT_NULL ppName); + +/** \brief Sets name of a custom pool. + +`pName` can be either null or pointer to a null-terminated string with new name for the pool. +Function makes internal copy of the string, so it can be changed or freed immediately after this call. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaSetPoolName( + VmaAllocator VMA_NOT_NULL allocator, + VmaPool VMA_NOT_NULL pool, + const char* VMA_NULLABLE pName); + +/** \brief General purpose memory allocation. + +\param allocator +\param pVkMemoryRequirements +\param pCreateInfo +\param[out] pAllocation Handle to allocated memory. +\param[out] pAllocationInfo Optional. Information about allocated memory. It can be later fetched using function vmaGetAllocationInfo(). + +You should free the memory using vmaFreeMemory() or vmaFreeMemoryPages(). + +It is recommended to use vmaAllocateMemoryForBuffer(), vmaAllocateMemoryForImage(), +vmaCreateBuffer(), vmaCreateImage() instead whenever possible. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemory( + VmaAllocator VMA_NOT_NULL allocator, + const VkMemoryRequirements* VMA_NOT_NULL pVkMemoryRequirements, + const VmaAllocationCreateInfo* VMA_NOT_NULL pCreateInfo, + VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation, + VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); + +/** \brief General purpose memory allocation for multiple allocation objects at once. + +\param allocator Allocator object. +\param pVkMemoryRequirements Memory requirements for each allocation. +\param pCreateInfo Creation parameters for each allocation. +\param allocationCount Number of allocations to make. +\param[out] pAllocations Pointer to array that will be filled with handles to created allocations. +\param[out] pAllocationInfo Optional. Pointer to array that will be filled with parameters of created allocations. + +You should free the memory using vmaFreeMemory() or vmaFreeMemoryPages(). + +Word "pages" is just a suggestion to use this function to allocate pieces of memory needed for sparse binding. +It is just a general purpose allocation function able to make multiple allocations at once. +It may be internally optimized to be more efficient than calling vmaAllocateMemory() `allocationCount` times. + +All allocations are made using same parameters. All of them are created out of the same memory pool and type. +If any allocation fails, all allocations already made within this function call are also freed, so that when +returned result is not `VK_SUCCESS`, `pAllocation` array is always entirely filled with `VK_NULL_HANDLE`. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryPages( + VmaAllocator VMA_NOT_NULL allocator, + const VkMemoryRequirements* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(allocationCount) pVkMemoryRequirements, + const VmaAllocationCreateInfo* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(allocationCount) pCreateInfo, + size_t allocationCount, + VmaAllocation VMA_NULLABLE* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(allocationCount) pAllocations, + VmaAllocationInfo* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) pAllocationInfo); + +/** \brief Allocates memory suitable for given `VkBuffer`. + +\param allocator +\param buffer +\param pCreateInfo +\param[out] pAllocation Handle to allocated memory. +\param[out] pAllocationInfo Optional. Information about allocated memory. It can be later fetched using function vmaGetAllocationInfo(). + +It only creates #VmaAllocation. To bind the memory to the buffer, use vmaBindBufferMemory(). + +This is a special-purpose function. In most cases you should use vmaCreateBuffer(). + +You must free the allocation using vmaFreeMemory() when no longer needed. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForBuffer( + VmaAllocator VMA_NOT_NULL allocator, + VkBuffer VMA_NOT_NULL_NON_DISPATCHABLE buffer, + const VmaAllocationCreateInfo* VMA_NOT_NULL pCreateInfo, + VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation, + VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); + +/** \brief Allocates memory suitable for given `VkImage`. + +\param allocator +\param image +\param pCreateInfo +\param[out] pAllocation Handle to allocated memory. +\param[out] pAllocationInfo Optional. Information about allocated memory. It can be later fetched using function vmaGetAllocationInfo(). + +It only creates #VmaAllocation. To bind the memory to the buffer, use vmaBindImageMemory(). + +This is a special-purpose function. In most cases you should use vmaCreateImage(). + +You must free the allocation using vmaFreeMemory() when no longer needed. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForImage( + VmaAllocator VMA_NOT_NULL allocator, + VkImage VMA_NOT_NULL_NON_DISPATCHABLE image, + const VmaAllocationCreateInfo* VMA_NOT_NULL pCreateInfo, + VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation, + VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); + +/** \brief Frees memory previously allocated using vmaAllocateMemory(), vmaAllocateMemoryForBuffer(), or vmaAllocateMemoryForImage(). + +Passing `VK_NULL_HANDLE` as `allocation` is valid. Such function call is just skipped. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemory( + VmaAllocator VMA_NOT_NULL allocator, + const VmaAllocation VMA_NULLABLE allocation); + +/** \brief Frees memory and destroys multiple allocations. + +Word "pages" is just a suggestion to use this function to free pieces of memory used for sparse binding. +It is just a general purpose function to free memory and destroy allocations made using e.g. vmaAllocateMemory(), +vmaAllocateMemoryPages() and other functions. +It may be internally optimized to be more efficient than calling vmaFreeMemory() `allocationCount` times. + +Allocations in `pAllocations` array can come from any memory pools and types. +Passing `VK_NULL_HANDLE` as elements of `pAllocations` array is valid. Such entries are just skipped. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemoryPages( + VmaAllocator VMA_NOT_NULL allocator, + size_t allocationCount, + const VmaAllocation VMA_NULLABLE* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(allocationCount) pAllocations); + +/** \brief Returns current information about specified allocation. + +Current parameters of given allocation are returned in `pAllocationInfo`. + +Although this function doesn't lock any mutex, so it should be quite efficient, +you should avoid calling it too often. +You can retrieve same VmaAllocationInfo structure while creating your resource, from function +vmaCreateBuffer(), vmaCreateImage(). You can remember it if you are sure parameters don't change +(e.g. due to defragmentation). + +There is also a new function vmaGetAllocationInfo2() that offers extended information +about the allocation, returned using new structure #VmaAllocationInfo2. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationInfo( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VmaAllocationInfo* VMA_NOT_NULL pAllocationInfo); + +/** \brief Returns extended information about specified allocation. + +Current parameters of given allocation are returned in `pAllocationInfo`. +Extended parameters in structure #VmaAllocationInfo2 include memory block size +and a flag telling whether the allocation has dedicated memory. +It can be useful e.g. for interop with OpenGL. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationInfo2( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VmaAllocationInfo2* VMA_NOT_NULL pAllocationInfo); + +/** \brief Sets pUserData in given allocation to new value. + +The value of pointer `pUserData` is copied to allocation's `pUserData`. +It is opaque, so you can use it however you want - e.g. +as a pointer, ordinal number or some handle to you own data. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaSetAllocationUserData( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + void* VMA_NULLABLE pUserData); + +/** \brief Sets pName in given allocation to new value. + +`pName` must be either null, or pointer to a null-terminated string. The function +makes local copy of the string and sets it as allocation's `pName`. String +passed as pName doesn't need to be valid for whole lifetime of the allocation - +you can free it after this call. String previously pointed by allocation's +`pName` is freed from memory. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaSetAllocationName( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + const char* VMA_NULLABLE pName); + +/** +\brief Given an allocation, returns Property Flags of its memory type. + +This is just a convenience function. Same information can be obtained using +vmaGetAllocationInfo() + vmaGetMemoryProperties(). +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationMemoryProperties( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkMemoryPropertyFlags* VMA_NOT_NULL pFlags); + +/** \brief Maps memory represented by given allocation and returns pointer to it. + +Maps memory represented by given allocation to make it accessible to CPU code. +When succeeded, `*ppData` contains pointer to first byte of this memory. + +\warning +If the allocation is part of a bigger `VkDeviceMemory` block, returned pointer is +correctly offsetted to the beginning of region assigned to this particular allocation. +Unlike the result of `vkMapMemory`, it points to the allocation, not to the beginning of the whole block. +You should not add VmaAllocationInfo::offset to it! + +Mapping is internally reference-counted and synchronized, so despite raw Vulkan +function `vkMapMemory()` cannot be used to map same block of `VkDeviceMemory` +multiple times simultaneously, it is safe to call this function on allocations +assigned to the same memory block. Actual Vulkan memory will be mapped on first +mapping and unmapped on last unmapping. + +If the function succeeded, you must call vmaUnmapMemory() to unmap the +allocation when mapping is no longer needed or before freeing the allocation, at +the latest. + +It also safe to call this function multiple times on the same allocation. You +must call vmaUnmapMemory() same number of times as you called vmaMapMemory(). + +It is also safe to call this function on allocation created with +#VMA_ALLOCATION_CREATE_MAPPED_BIT flag. Its memory stays mapped all the time. +You must still call vmaUnmapMemory() same number of times as you called +vmaMapMemory(). You must not call vmaUnmapMemory() additional time to free the +"0-th" mapping made automatically due to #VMA_ALLOCATION_CREATE_MAPPED_BIT flag. + +This function fails when used on allocation made in memory type that is not +`HOST_VISIBLE`. + +This function doesn't automatically flush or invalidate caches. +If the allocation is made from a memory types that is not `HOST_COHERENT`, +you also need to use vmaInvalidateAllocation() / vmaFlushAllocation(), as required by Vulkan specification. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaMapMemory( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + void* VMA_NULLABLE* VMA_NOT_NULL ppData); + +/** \brief Unmaps memory represented by given allocation, mapped previously using vmaMapMemory(). + +For details, see description of vmaMapMemory(). + +This function doesn't automatically flush or invalidate caches. +If the allocation is made from a memory types that is not `HOST_COHERENT`, +you also need to use vmaInvalidateAllocation() / vmaFlushAllocation(), as required by Vulkan specification. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaUnmapMemory( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation); + +/** \brief Flushes memory of given allocation. + +Calls `vkFlushMappedMemoryRanges()` for memory associated with given range of given allocation. +It needs to be called after writing to a mapped memory for memory types that are not `HOST_COHERENT`. +Unmap operation doesn't do that automatically. + +- `offset` must be relative to the beginning of allocation. +- `size` can be `VK_WHOLE_SIZE`. It means all memory from `offset` the the end of given allocation. +- `offset` and `size` don't have to be aligned. + They are internally rounded down/up to multiply of `nonCoherentAtomSize`. +- If `size` is 0, this call is ignored. +- If memory type that the `allocation` belongs to is not `HOST_VISIBLE` or it is `HOST_COHERENT`, + this call is ignored. + +Warning! `offset` and `size` are relative to the contents of given `allocation`. +If you mean whole allocation, you can pass 0 and `VK_WHOLE_SIZE`, respectively. +Do not pass allocation's offset as `offset`!!! + +This function returns the `VkResult` from `vkFlushMappedMemoryRanges` if it is +called, otherwise `VK_SUCCESS`. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocation( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkDeviceSize offset, + VkDeviceSize size); + +/** \brief Invalidates memory of given allocation. + +Calls `vkInvalidateMappedMemoryRanges()` for memory associated with given range of given allocation. +It needs to be called before reading from a mapped memory for memory types that are not `HOST_COHERENT`. +Map operation doesn't do that automatically. + +- `offset` must be relative to the beginning of allocation. +- `size` can be `VK_WHOLE_SIZE`. It means all memory from `offset` the the end of given allocation. +- `offset` and `size` don't have to be aligned. + They are internally rounded down/up to multiply of `nonCoherentAtomSize`. +- If `size` is 0, this call is ignored. +- If memory type that the `allocation` belongs to is not `HOST_VISIBLE` or it is `HOST_COHERENT`, + this call is ignored. + +Warning! `offset` and `size` are relative to the contents of given `allocation`. +If you mean whole allocation, you can pass 0 and `VK_WHOLE_SIZE`, respectively. +Do not pass allocation's offset as `offset`!!! + +This function returns the `VkResult` from `vkInvalidateMappedMemoryRanges` if +it is called, otherwise `VK_SUCCESS`. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocation( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkDeviceSize offset, + VkDeviceSize size); + +/** \brief Flushes memory of given set of allocations. + +Calls `vkFlushMappedMemoryRanges()` for memory associated with given ranges of given allocations. +For more information, see documentation of vmaFlushAllocation(). + +\param allocator +\param allocationCount +\param allocations +\param offsets If not null, it must point to an array of offsets of regions to flush, relative to the beginning of respective allocations. Null means all offsets are zero. +\param sizes If not null, it must point to an array of sizes of regions to flush in respective allocations. Null means `VK_WHOLE_SIZE` for all allocations. + +This function returns the `VkResult` from `vkFlushMappedMemoryRanges` if it is +called, otherwise `VK_SUCCESS`. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocations( + VmaAllocator VMA_NOT_NULL allocator, + uint32_t allocationCount, + const VmaAllocation VMA_NOT_NULL* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) allocations, + const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) offsets, + const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) sizes); + +/** \brief Invalidates memory of given set of allocations. + +Calls `vkInvalidateMappedMemoryRanges()` for memory associated with given ranges of given allocations. +For more information, see documentation of vmaInvalidateAllocation(). + +\param allocator +\param allocationCount +\param allocations +\param offsets If not null, it must point to an array of offsets of regions to flush, relative to the beginning of respective allocations. Null means all offsets are zero. +\param sizes If not null, it must point to an array of sizes of regions to flush in respective allocations. Null means `VK_WHOLE_SIZE` for all allocations. + +This function returns the `VkResult` from `vkInvalidateMappedMemoryRanges` if it is +called, otherwise `VK_SUCCESS`. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocations( + VmaAllocator VMA_NOT_NULL allocator, + uint32_t allocationCount, + const VmaAllocation VMA_NOT_NULL* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) allocations, + const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) offsets, + const VkDeviceSize* VMA_NULLABLE VMA_LEN_IF_NOT_NULL(allocationCount) sizes); + +/** \brief Maps the allocation temporarily if needed, copies data from specified host pointer to it, and flushes the memory from the host caches if needed. + +\param allocator +\param pSrcHostPointer Pointer to the host data that become source of the copy. +\param dstAllocation Handle to the allocation that becomes destination of the copy. +\param dstAllocationLocalOffset Offset within `dstAllocation` where to write copied data, in bytes. +\param size Number of bytes to copy. + +This is a convenience function that allows to copy data from a host pointer to an allocation easily. +Same behavior can be achieved by calling vmaMapMemory(), `memcpy()`, vmaUnmapMemory(), vmaFlushAllocation(). + +This function can be called only for allocations created in a memory type that has `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT` flag. +It can be ensured e.g. by using #VMA_MEMORY_USAGE_AUTO and #VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or +#VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT. +Otherwise, the function will fail and generate a Validation Layers error. + +`dstAllocationLocalOffset` is relative to the contents of given `dstAllocation`. +If you mean whole allocation, you should pass 0. +Do not pass allocation's offset within device memory block this parameter! +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCopyMemoryToAllocation( + VmaAllocator VMA_NOT_NULL allocator, + const void* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(size) pSrcHostPointer, + VmaAllocation VMA_NOT_NULL dstAllocation, + VkDeviceSize dstAllocationLocalOffset, + VkDeviceSize size); + +/** \brief Invalidates memory in the host caches if needed, maps the allocation temporarily if needed, and copies data from it to a specified host pointer. + +\param allocator +\param srcAllocation Handle to the allocation that becomes source of the copy. +\param srcAllocationLocalOffset Offset within `srcAllocation` where to read copied data, in bytes. +\param pDstHostPointer Pointer to the host memory that become destination of the copy. +\param size Number of bytes to copy. + +This is a convenience function that allows to copy data from an allocation to a host pointer easily. +Same behavior can be achieved by calling vmaInvalidateAllocation(), vmaMapMemory(), `memcpy()`, vmaUnmapMemory(). + +This function should be called only for allocations created in a memory type that has `VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT` +and `VK_MEMORY_PROPERTY_HOST_CACHED_BIT` flag. +It can be ensured e.g. by using #VMA_MEMORY_USAGE_AUTO and #VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT. +Otherwise, the function may fail and generate a Validation Layers error. +It may also work very slowly when reading from an uncached memory. + +`srcAllocationLocalOffset` is relative to the contents of given `srcAllocation`. +If you mean whole allocation, you should pass 0. +Do not pass allocation's offset within device memory block as this parameter! +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCopyAllocationToMemory( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL srcAllocation, + VkDeviceSize srcAllocationLocalOffset, + void* VMA_NOT_NULL VMA_LEN_IF_NOT_NULL(size) pDstHostPointer, + VkDeviceSize size); + +/** \brief Checks magic number in margins around all allocations in given memory types (in both default and custom pools) in search for corruptions. + +\param allocator +\param memoryTypeBits Bit mask, where each bit set means that a memory type with that index should be checked. + +Corruption detection is enabled only when `VMA_DEBUG_DETECT_CORRUPTION` macro is defined to nonzero, +`VMA_DEBUG_MARGIN` is defined to nonzero and only for memory types that are +`HOST_VISIBLE` and `HOST_COHERENT`. For more information, see [Corruption detection](@ref debugging_memory_usage_corruption_detection). + +Possible return values: + +- `VK_ERROR_FEATURE_NOT_PRESENT` - corruption detection is not enabled for any of specified memory types. +- `VK_SUCCESS` - corruption detection has been performed and succeeded. +- `VK_ERROR_UNKNOWN` - corruption detection has been performed and found memory corruptions around one of the allocations. + `VMA_ASSERT` is also fired in that case. +- Other value: Error returned by Vulkan, e.g. memory mapping failure. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckCorruption( + VmaAllocator VMA_NOT_NULL allocator, + uint32_t memoryTypeBits); + +/** \brief Begins defragmentation process. + +\param allocator Allocator object. +\param pInfo Structure filled with parameters of defragmentation. +\param[out] pContext Context object that must be passed to vmaEndDefragmentation() to finish defragmentation. +\returns +- `VK_SUCCESS` if defragmentation can begin. +- `VK_ERROR_FEATURE_NOT_PRESENT` if defragmentation is not supported. + +For more information about defragmentation, see documentation chapter: +[Defragmentation](@ref defragmentation). +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaBeginDefragmentation( + VmaAllocator VMA_NOT_NULL allocator, + const VmaDefragmentationInfo* VMA_NOT_NULL pInfo, + VmaDefragmentationContext VMA_NULLABLE* VMA_NOT_NULL pContext); + +/** \brief Ends defragmentation process. + +\param allocator Allocator object. +\param context Context object that has been created by vmaBeginDefragmentation(). +\param[out] pStats Optional stats for the defragmentation. Can be null. + +Use this function to finish defragmentation started by vmaBeginDefragmentation(). +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaEndDefragmentation( + VmaAllocator VMA_NOT_NULL allocator, + VmaDefragmentationContext VMA_NOT_NULL context, + VmaDefragmentationStats* VMA_NULLABLE pStats); + +/** \brief Starts single defragmentation pass. + +\param allocator Allocator object. +\param context Context object that has been created by vmaBeginDefragmentation(). +\param[out] pPassInfo Computed information for current pass. +\returns +- `VK_SUCCESS` if no more moves are possible. Then you can omit call to vmaEndDefragmentationPass() and simply end whole defragmentation. +- `VK_INCOMPLETE` if there are pending moves returned in `pPassInfo`. You need to perform them, call vmaEndDefragmentationPass(), + and then preferably try another pass with vmaBeginDefragmentationPass(). +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaBeginDefragmentationPass( + VmaAllocator VMA_NOT_NULL allocator, + VmaDefragmentationContext VMA_NOT_NULL context, + VmaDefragmentationPassMoveInfo* VMA_NOT_NULL pPassInfo); + +/** \brief Ends single defragmentation pass. + +\param allocator Allocator object. +\param context Context object that has been created by vmaBeginDefragmentation(). +\param pPassInfo Computed information for current pass filled by vmaBeginDefragmentationPass() and possibly modified by you. + +Returns `VK_SUCCESS` if no more moves are possible or `VK_INCOMPLETE` if more defragmentations are possible. + +Ends incremental defragmentation pass and commits all defragmentation moves from `pPassInfo`. +After this call: + +- Allocations at `pPassInfo[i].srcAllocation` that had `pPassInfo[i].operation ==` #VMA_DEFRAGMENTATION_MOVE_OPERATION_COPY + (which is the default) will be pointing to the new destination place. +- Allocation at `pPassInfo[i].srcAllocation` that had `pPassInfo[i].operation ==` #VMA_DEFRAGMENTATION_MOVE_OPERATION_DESTROY + will be freed. + +If no more moves are possible you can end whole defragmentation. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaEndDefragmentationPass( + VmaAllocator VMA_NOT_NULL allocator, + VmaDefragmentationContext VMA_NOT_NULL context, + VmaDefragmentationPassMoveInfo* VMA_NOT_NULL pPassInfo); + +/** \brief Binds buffer to allocation. + +Binds specified buffer to region of memory represented by specified allocation. +Gets `VkDeviceMemory` handle and offset from the allocation. +If you want to create a buffer, allocate memory for it and bind them together separately, +you should use this function for binding instead of standard `vkBindBufferMemory()`, +because it ensures proper synchronization so that when a `VkDeviceMemory` object is used by multiple +allocations, calls to `vkBind*Memory()` or `vkMapMemory()` won't happen from multiple threads simultaneously +(which is illegal in Vulkan). + +It is recommended to use function vmaCreateBuffer() instead of this one. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkBuffer VMA_NOT_NULL_NON_DISPATCHABLE buffer); + +/** \brief Binds buffer to allocation with additional parameters. + +\param allocator +\param allocation +\param allocationLocalOffset Additional offset to be added while binding, relative to the beginning of the `allocation`. Normally it should be 0. +\param buffer +\param pNext A chain of structures to be attached to `VkBindBufferMemoryInfoKHR` structure used internally. Normally it should be null. + +This function is similar to vmaBindBufferMemory(), but it provides additional parameters. + +If `pNext` is not null, #VmaAllocator object must have been created with #VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT flag +or with VmaAllocatorCreateInfo::vulkanApiVersion `>= VK_API_VERSION_1_1`. Otherwise the call fails. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory2( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkDeviceSize allocationLocalOffset, + VkBuffer VMA_NOT_NULL_NON_DISPATCHABLE buffer, + const void* VMA_NULLABLE VMA_EXTENDS_VK_STRUCT(VkBindBufferMemoryInfoKHR) pNext); + +/** \brief Binds image to allocation. + +Binds specified image to region of memory represented by specified allocation. +Gets `VkDeviceMemory` handle and offset from the allocation. +If you want to create an image, allocate memory for it and bind them together separately, +you should use this function for binding instead of standard `vkBindImageMemory()`, +because it ensures proper synchronization so that when a `VkDeviceMemory` object is used by multiple +allocations, calls to `vkBind*Memory()` or `vkMapMemory()` won't happen from multiple threads simultaneously +(which is illegal in Vulkan). + +It is recommended to use function vmaCreateImage() instead of this one. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkImage VMA_NOT_NULL_NON_DISPATCHABLE image); + +/** \brief Binds image to allocation with additional parameters. + +\param allocator +\param allocation +\param allocationLocalOffset Additional offset to be added while binding, relative to the beginning of the `allocation`. Normally it should be 0. +\param image +\param pNext A chain of structures to be attached to `VkBindImageMemoryInfoKHR` structure used internally. Normally it should be null. + +This function is similar to vmaBindImageMemory(), but it provides additional parameters. + +If `pNext` is not null, #VmaAllocator object must have been created with #VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT flag +or with VmaAllocatorCreateInfo::vulkanApiVersion `>= VK_API_VERSION_1_1`. Otherwise the call fails. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory2( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkDeviceSize allocationLocalOffset, + VkImage VMA_NOT_NULL_NON_DISPATCHABLE image, + const void* VMA_NULLABLE VMA_EXTENDS_VK_STRUCT(VkBindImageMemoryInfoKHR) pNext); + +/** \brief Creates a new `VkBuffer`, allocates and binds memory for it. + +\param allocator +\param pBufferCreateInfo +\param pAllocationCreateInfo +\param[out] pBuffer Buffer that was created. +\param[out] pAllocation Allocation that was created. +\param[out] pAllocationInfo Optional. Information about allocated memory. It can be later fetched using function vmaGetAllocationInfo(). + +This function automatically: + +-# Creates buffer. +-# Allocates appropriate memory for it. +-# Binds the buffer with the memory. + +If any of these operations fail, buffer and allocation are not created, +returned value is negative error code, `*pBuffer` and `*pAllocation` are null. + +If the function succeeded, you must destroy both buffer and allocation when you +no longer need them using either convenience function vmaDestroyBuffer() or +separately, using `vkDestroyBuffer()` and vmaFreeMemory(). + +If #VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT flag was used, +VK_KHR_dedicated_allocation extension is used internally to query driver whether +it requires or prefers the new buffer to have dedicated allocation. If yes, +and if dedicated allocation is possible +(#VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT is not used), it creates dedicated +allocation for this buffer, just like when using +#VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT. + +\note This function creates a new `VkBuffer`. Sub-allocation of parts of one large buffer, +although recommended as a good practice, is out of scope of this library and could be implemented +by the user as a higher-level logic on top of VMA. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBuffer( + VmaAllocator VMA_NOT_NULL allocator, + const VkBufferCreateInfo* VMA_NOT_NULL pBufferCreateInfo, + const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, + VkBuffer VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pBuffer, + VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation, + VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); + +/** \brief Creates a buffer with additional minimum alignment. + +Similar to vmaCreateBuffer() but provides additional parameter `minAlignment` which allows to specify custom, +minimum alignment to be used when placing the buffer inside a larger memory block, which may be needed e.g. +for interop with OpenGL. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBufferWithAlignment( + VmaAllocator VMA_NOT_NULL allocator, + const VkBufferCreateInfo* VMA_NOT_NULL pBufferCreateInfo, + const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, + VkDeviceSize minAlignment, + VkBuffer VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pBuffer, + VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation, + VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); + +/** \brief Creates a new `VkBuffer`, binds already created memory for it. + +\param allocator +\param allocation Allocation that provides memory to be used for binding new buffer to it. +\param pBufferCreateInfo +\param[out] pBuffer Buffer that was created. + +This function automatically: + +-# Creates buffer. +-# Binds the buffer with the supplied memory. + +If any of these operations fail, buffer is not created, +returned value is negative error code and `*pBuffer` is null. + +If the function succeeded, you must destroy the buffer when you +no longer need it using `vkDestroyBuffer()`. If you want to also destroy the corresponding +allocation you can use convenience function vmaDestroyBuffer(). + +\note There is a new version of this function augmented with parameter `allocationLocalOffset` - see vmaCreateAliasingBuffer2(). +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAliasingBuffer( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + const VkBufferCreateInfo* VMA_NOT_NULL pBufferCreateInfo, + VkBuffer VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pBuffer); + +/** \brief Creates a new `VkBuffer`, binds already created memory for it. + +\param allocator +\param allocation Allocation that provides memory to be used for binding new buffer to it. +\param allocationLocalOffset Additional offset to be added while binding, relative to the beginning of the allocation. Normally it should be 0. +\param pBufferCreateInfo +\param[out] pBuffer Buffer that was created. + +This function automatically: + +-# Creates buffer. +-# Binds the buffer with the supplied memory. + +If any of these operations fail, buffer is not created, +returned value is negative error code and `*pBuffer` is null. + +If the function succeeded, you must destroy the buffer when you +no longer need it using `vkDestroyBuffer()`. If you want to also destroy the corresponding +allocation you can use convenience function vmaDestroyBuffer(). + +\note This is a new version of the function augmented with parameter `allocationLocalOffset`. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAliasingBuffer2( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkDeviceSize allocationLocalOffset, + const VkBufferCreateInfo* VMA_NOT_NULL pBufferCreateInfo, + VkBuffer VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pBuffer); + +/** \brief Destroys Vulkan buffer and frees allocated memory. + +This is just a convenience function equivalent to: + +\code +vkDestroyBuffer(device, buffer, allocationCallbacks); +vmaFreeMemory(allocator, allocation); +\endcode + +It is safe to pass null as buffer and/or allocation. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaDestroyBuffer( + VmaAllocator VMA_NOT_NULL allocator, + VkBuffer VMA_NULLABLE_NON_DISPATCHABLE buffer, + VmaAllocation VMA_NULLABLE allocation); + +/// Function similar to vmaCreateBuffer(). +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateImage( + VmaAllocator VMA_NOT_NULL allocator, + const VkImageCreateInfo* VMA_NOT_NULL pImageCreateInfo, + const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo, + VkImage VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pImage, + VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation, + VmaAllocationInfo* VMA_NULLABLE pAllocationInfo); + +/// Function similar to vmaCreateAliasingBuffer() but for images. +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAliasingImage( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + const VkImageCreateInfo* VMA_NOT_NULL pImageCreateInfo, + VkImage VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pImage); + +/// Function similar to vmaCreateAliasingBuffer2() but for images. +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAliasingImage2( + VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, + VkDeviceSize allocationLocalOffset, + const VkImageCreateInfo* VMA_NOT_NULL pImageCreateInfo, + VkImage VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pImage); + +/** \brief Destroys Vulkan image and frees allocated memory. + +This is just a convenience function equivalent to: + +\code +vkDestroyImage(device, image, allocationCallbacks); +vmaFreeMemory(allocator, allocation); +\endcode + +It is safe to pass null as image and/or allocation. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaDestroyImage( + VmaAllocator VMA_NOT_NULL allocator, + VkImage VMA_NULLABLE_NON_DISPATCHABLE image, + VmaAllocation VMA_NULLABLE allocation); + +/** @} */ + +/** +\addtogroup group_virtual +@{ +*/ + +/** \brief Creates new #VmaVirtualBlock object. + +\param pCreateInfo Parameters for creation. +\param[out] pVirtualBlock Returned virtual block object or `VMA_NULL` if creation failed. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateVirtualBlock( + const VmaVirtualBlockCreateInfo* VMA_NOT_NULL pCreateInfo, + VmaVirtualBlock VMA_NULLABLE* VMA_NOT_NULL pVirtualBlock); + +/** \brief Destroys #VmaVirtualBlock object. + +Please note that you should consciously handle virtual allocations that could remain unfreed in the block. +You should either free them individually using vmaVirtualFree() or call vmaClearVirtualBlock() +if you are sure this is what you want. If you do neither, an assert is called. + +If you keep pointers to some additional metadata associated with your virtual allocations in their `pUserData`, +don't forget to free them. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaDestroyVirtualBlock( + VmaVirtualBlock VMA_NULLABLE virtualBlock); + +/** \brief Returns true of the #VmaVirtualBlock is empty - contains 0 virtual allocations and has all its space available for new allocations. +*/ +VMA_CALL_PRE VkBool32 VMA_CALL_POST vmaIsVirtualBlockEmpty( + VmaVirtualBlock VMA_NOT_NULL virtualBlock); + +/** \brief Returns information about a specific virtual allocation within a virtual block, like its size and `pUserData` pointer. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaGetVirtualAllocationInfo( + VmaVirtualBlock VMA_NOT_NULL virtualBlock, + VmaVirtualAllocation VMA_NOT_NULL_NON_DISPATCHABLE allocation, VmaVirtualAllocationInfo* VMA_NOT_NULL pVirtualAllocInfo); + +/** \brief Allocates new virtual allocation inside given #VmaVirtualBlock. + +If the allocation fails due to not enough free space available, `VK_ERROR_OUT_OF_DEVICE_MEMORY` is returned +(despite the function doesn't ever allocate actual GPU memory). +`pAllocation` is then set to `VK_NULL_HANDLE` and `pOffset`, if not null, it set to `UINT64_MAX`. + +\param virtualBlock Virtual block +\param pCreateInfo Parameters for the allocation +\param[out] pAllocation Returned handle of the new allocation +\param[out] pOffset Returned offset of the new allocation. Optional, can be null. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaVirtualAllocate( + VmaVirtualBlock VMA_NOT_NULL virtualBlock, + const VmaVirtualAllocationCreateInfo* VMA_NOT_NULL pCreateInfo, + VmaVirtualAllocation VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pAllocation, + VkDeviceSize* VMA_NULLABLE pOffset); + +/** \brief Frees virtual allocation inside given #VmaVirtualBlock. + +It is correct to call this function with `allocation == VK_NULL_HANDLE` - it does nothing. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaVirtualFree( + VmaVirtualBlock VMA_NOT_NULL virtualBlock, + VmaVirtualAllocation VMA_NULLABLE_NON_DISPATCHABLE allocation); + +/** \brief Frees all virtual allocations inside given #VmaVirtualBlock. + +You must either call this function or free each virtual allocation individually with vmaVirtualFree() +before destroying a virtual block. Otherwise, an assert is called. + +If you keep pointer to some additional metadata associated with your virtual allocation in its `pUserData`, +don't forget to free it as well. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaClearVirtualBlock( + VmaVirtualBlock VMA_NOT_NULL virtualBlock); + +/** \brief Changes custom pointer associated with given virtual allocation. +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaSetVirtualAllocationUserData( + VmaVirtualBlock VMA_NOT_NULL virtualBlock, + VmaVirtualAllocation VMA_NOT_NULL_NON_DISPATCHABLE allocation, + void* VMA_NULLABLE pUserData); + +/** \brief Calculates and returns statistics about virtual allocations and memory usage in given #VmaVirtualBlock. + +This function is fast to call. For more detailed statistics, see vmaCalculateVirtualBlockStatistics(). +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaGetVirtualBlockStatistics( + VmaVirtualBlock VMA_NOT_NULL virtualBlock, + VmaStatistics* VMA_NOT_NULL pStats); + +/** \brief Calculates and returns detailed statistics about virtual allocations and memory usage in given #VmaVirtualBlock. + +This function is slow to call. Use for debugging purposes. +For less detailed statistics, see vmaGetVirtualBlockStatistics(). +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaCalculateVirtualBlockStatistics( + VmaVirtualBlock VMA_NOT_NULL virtualBlock, + VmaDetailedStatistics* VMA_NOT_NULL pStats); + +/** @} */ #if VMA_STATS_STRING_ENABLED /** @@ -2716,31 +2725,31 @@ right after Vulkan is initialized and keep it alive until before Vulkan device i Returned string must be freed using vmaFreeVirtualBlockStatsString(). */ - VMA_CALL_PRE void VMA_CALL_POST vmaBuildVirtualBlockStatsString( - VmaVirtualBlock VMA_NOT_NULL virtualBlock, - char* VMA_NULLABLE* VMA_NOT_NULL ppStatsString, - VkBool32 detailedMap); +VMA_CALL_PRE void VMA_CALL_POST vmaBuildVirtualBlockStatsString( + VmaVirtualBlock VMA_NOT_NULL virtualBlock, + char* VMA_NULLABLE* VMA_NOT_NULL ppStatsString, + VkBool32 detailedMap); - /// Frees a string returned by vmaBuildVirtualBlockStatsString(). - VMA_CALL_PRE void VMA_CALL_POST vmaFreeVirtualBlockStatsString( - VmaVirtualBlock VMA_NOT_NULL virtualBlock, - char* VMA_NULLABLE pStatsString); +/// Frees a string returned by vmaBuildVirtualBlockStatsString(). +VMA_CALL_PRE void VMA_CALL_POST vmaFreeVirtualBlockStatsString( + VmaVirtualBlock VMA_NOT_NULL virtualBlock, + char* VMA_NULLABLE pStatsString); - /** \brief Builds and returns statistics as a null-terminated string in JSON format. - \param allocator - \param[out] ppStatsString Must be freed using vmaFreeStatsString() function. - \param detailedMap - */ - VMA_CALL_PRE void VMA_CALL_POST vmaBuildStatsString( - VmaAllocator VMA_NOT_NULL allocator, - char* VMA_NULLABLE* VMA_NOT_NULL ppStatsString, - VkBool32 detailedMap); +/** \brief Builds and returns statistics as a null-terminated string in JSON format. +\param allocator +\param[out] ppStatsString Must be freed using vmaFreeStatsString() function. +\param detailedMap +*/ +VMA_CALL_PRE void VMA_CALL_POST vmaBuildStatsString( + VmaAllocator VMA_NOT_NULL allocator, + char* VMA_NULLABLE* VMA_NOT_NULL ppStatsString, + VkBool32 detailedMap); - VMA_CALL_PRE void VMA_CALL_POST vmaFreeStatsString( - VmaAllocator VMA_NOT_NULL allocator, - char* VMA_NULLABLE pStatsString); +VMA_CALL_PRE void VMA_CALL_POST vmaFreeStatsString( + VmaAllocator VMA_NOT_NULL allocator, + char* VMA_NULLABLE pStatsString); - /** @} */ +/** @} */ #endif // VMA_STATS_STRING_ENABLED @@ -2776,22 +2785,22 @@ Returned string must be freed using vmaFreeVirtualBlockStatsString(). #include #if !defined(VMA_CPP20) -#if __cplusplus >= 202002L || _MSVC_LANG >= 202002L // C++20 -#define VMA_CPP20 1 -#else -#define VMA_CPP20 0 -#endif + #if __cplusplus >= 202002L || _MSVC_LANG >= 202002L // C++20 + #define VMA_CPP20 1 + #else + #define VMA_CPP20 0 + #endif #endif #ifdef _MSC_VER -#include // For functions like __popcnt, _BitScanForward etc. + #include // For functions like __popcnt, _BitScanForward etc. #endif #if VMA_CPP20 -#include + #include #endif #if VMA_STATS_STRING_ENABLED -#include // For snprintf + #include // For snprintf #endif /******************************************************************************* @@ -2809,7 +2818,7 @@ internally, like: vulkanFunctions.vkAllocateMemory = &vkAllocateMemory; */ #if !defined(VMA_STATIC_VULKAN_FUNCTIONS) && !defined(VK_NO_PROTOTYPES) -#define VMA_STATIC_VULKAN_FUNCTIONS 1 + #define VMA_STATIC_VULKAN_FUNCTIONS 1 #endif /* @@ -2823,19 +2832,19 @@ VmaVulkanFunctions::vkGetInstanceProcAddr and vkGetDeviceProcAddr as VmaAllocatorCreateInfo::pVulkanFunctions. Other members can be null. */ #if !defined(VMA_DYNAMIC_VULKAN_FUNCTIONS) -#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 + #define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 #endif #ifndef VMA_USE_STL_SHARED_MUTEX -#if __cplusplus >= 201703L || _MSVC_LANG >= 201703L // C++17 -#define VMA_USE_STL_SHARED_MUTEX 1 -// Visual studio defines __cplusplus properly only when passed additional parameter: /Zc:__cplusplus -// Otherwise it is always 199711L, despite shared_mutex works since Visual Studio 2015 Update 2. -#elif defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023918 && __cplusplus == 199711L && _MSVC_LANG >= 201703L -#define VMA_USE_STL_SHARED_MUTEX 1 -#else -#define VMA_USE_STL_SHARED_MUTEX 0 -#endif + #if __cplusplus >= 201703L || _MSVC_LANG >= 201703L // C++17 + #define VMA_USE_STL_SHARED_MUTEX 1 + // Visual studio defines __cplusplus properly only when passed additional parameter: /Zc:__cplusplus + // Otherwise it is always 199711L, despite shared_mutex works since Visual Studio 2015 Update 2. + #elif defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023918 && __cplusplus == 199711L && _MSVC_LANG >= 201703L + #define VMA_USE_STL_SHARED_MUTEX 1 + #else + #define VMA_USE_STL_SHARED_MUTEX 0 + #endif #endif /* @@ -2860,48 +2869,48 @@ The following headers are used in this CONFIGURATION section only, so feel free remove them if not needed. */ #if !defined(VMA_CONFIGURATION_USER_INCLUDES_H) -#include // for assert -#include // for min, max, swap -#include + #include // for assert + #include // for min, max, swap + #include #else -#include VMA_CONFIGURATION_USER_INCLUDES_H + #include VMA_CONFIGURATION_USER_INCLUDES_H #endif #ifndef VMA_NULL -// Value used as null pointer. Define it to e.g.: nullptr, NULL, 0, (void*)0. -#define VMA_NULL nullptr + // Value used as null pointer. Define it to e.g.: nullptr, NULL, 0, (void*)0. + #define VMA_NULL nullptr #endif #ifndef VMA_FALLTHROUGH -#if __cplusplus >= 201703L || _MSVC_LANG >= 201703L // C++17 -#define VMA_FALLTHROUGH [[fallthrough]] -#else -#define VMA_FALLTHROUGH -#endif + #if __cplusplus >= 201703L || _MSVC_LANG >= 201703L // C++17 + #define VMA_FALLTHROUGH [[fallthrough]] + #else + #define VMA_FALLTHROUGH + #endif #endif // Normal assert to check for programmer's errors, especially in Debug configuration. #ifndef VMA_ASSERT -#ifdef NDEBUG -#define VMA_ASSERT(expr) -#else -#define VMA_ASSERT(expr) assert(expr) -#endif + #ifdef NDEBUG + #define VMA_ASSERT(expr) + #else + #define VMA_ASSERT(expr) assert(expr) + #endif #endif // Assert that will be called very often, like inside data structures e.g. operator[]. // Making it non-empty can make program slow. #ifndef VMA_HEAVY_ASSERT -#ifdef NDEBUG -#define VMA_HEAVY_ASSERT(expr) -#else -#define VMA_HEAVY_ASSERT(expr) //VMA_ASSERT(expr) -#endif + #ifdef NDEBUG + #define VMA_HEAVY_ASSERT(expr) + #else + #define VMA_HEAVY_ASSERT(expr) //VMA_ASSERT(expr) + #endif #endif // Assert used for reporting memory leaks - unfreed allocations. #ifndef VMA_ASSERT_LEAK -#define VMA_ASSERT_LEAK(expr) VMA_ASSERT(expr) + #define VMA_ASSERT_LEAK(expr) VMA_ASSERT(expr) #endif // If your compiler is not compatible with C++17 and definition of @@ -2914,7 +2923,7 @@ remove them if not needed. static void* vma_aligned_alloc(size_t alignment, size_t size) { // alignment must be >= sizeof(void*) - if (alignment < sizeof(void*)) + if(alignment < sizeof(void*)) { alignment = sizeof(void*); } @@ -2946,13 +2955,13 @@ static void* vma_aligned_alloc(size_t alignment, size_t size) //#endif // alignment must be >= sizeof(void*) - if (alignment < sizeof(void*)) + if(alignment < sizeof(void*)) { alignment = sizeof(void*); } - void* pointer; - if (posix_memalign(&pointer, alignment, size) == 0) + void *pointer; + if(posix_memalign(&pointer, alignment, size) == 0) return pointer; return VMA_NULL; } @@ -2987,75 +2996,75 @@ static void vma_aligned_free(void* VMA_NULLABLE ptr) #endif #ifndef VMA_ALIGN_OF -#define VMA_ALIGN_OF(type) (alignof(type)) + #define VMA_ALIGN_OF(type) (alignof(type)) #endif #ifndef VMA_SYSTEM_ALIGNED_MALLOC -#define VMA_SYSTEM_ALIGNED_MALLOC(size, alignment) vma_aligned_alloc((alignment), (size)) + #define VMA_SYSTEM_ALIGNED_MALLOC(size, alignment) vma_aligned_alloc((alignment), (size)) #endif #ifndef VMA_SYSTEM_ALIGNED_FREE -// VMA_SYSTEM_FREE is the old name, but might have been defined by the user -#if defined(VMA_SYSTEM_FREE) -#define VMA_SYSTEM_ALIGNED_FREE(ptr) VMA_SYSTEM_FREE(ptr) -#else -#define VMA_SYSTEM_ALIGNED_FREE(ptr) vma_aligned_free(ptr) -#endif + // VMA_SYSTEM_FREE is the old name, but might have been defined by the user + #if defined(VMA_SYSTEM_FREE) + #define VMA_SYSTEM_ALIGNED_FREE(ptr) VMA_SYSTEM_FREE(ptr) + #else + #define VMA_SYSTEM_ALIGNED_FREE(ptr) vma_aligned_free(ptr) + #endif #endif #ifndef VMA_COUNT_BITS_SET // Returns number of bits set to 1 in (v) -#define VMA_COUNT_BITS_SET(v) VmaCountBitsSet(v) + #define VMA_COUNT_BITS_SET(v) VmaCountBitsSet(v) #endif #ifndef VMA_BITSCAN_LSB // Scans integer for index of first nonzero value from the Least Significant Bit (LSB). If mask is 0 then returns UINT8_MAX -#define VMA_BITSCAN_LSB(mask) VmaBitScanLSB(mask) + #define VMA_BITSCAN_LSB(mask) VmaBitScanLSB(mask) #endif #ifndef VMA_BITSCAN_MSB // Scans integer for index of first nonzero value from the Most Significant Bit (MSB). If mask is 0 then returns UINT8_MAX -#define VMA_BITSCAN_MSB(mask) VmaBitScanMSB(mask) + #define VMA_BITSCAN_MSB(mask) VmaBitScanMSB(mask) #endif #ifndef VMA_MIN -#define VMA_MIN(v1, v2) ((std::min)((v1), (v2))) + #define VMA_MIN(v1, v2) ((std::min)((v1), (v2))) #endif #ifndef VMA_MAX -#define VMA_MAX(v1, v2) ((std::max)((v1), (v2))) + #define VMA_MAX(v1, v2) ((std::max)((v1), (v2))) #endif #ifndef VMA_SORT -#define VMA_SORT(beg, end, cmp) std::sort(beg, end, cmp) + #define VMA_SORT(beg, end, cmp) std::sort(beg, end, cmp) #endif #ifndef VMA_DEBUG_LOG_FORMAT -#define VMA_DEBUG_LOG_FORMAT(format, ...) -/* -#define VMA_DEBUG_LOG_FORMAT(format, ...) do { \ - printf((format), __VA_ARGS__); \ - printf("\n"); \ -} while(false) -*/ + #define VMA_DEBUG_LOG_FORMAT(format, ...) + /* + #define VMA_DEBUG_LOG_FORMAT(format, ...) do { \ + printf((format), __VA_ARGS__); \ + printf("\n"); \ + } while(false) + */ #endif #ifndef VMA_DEBUG_LOG -#define VMA_DEBUG_LOG(str) VMA_DEBUG_LOG_FORMAT("%s", (str)) + #define VMA_DEBUG_LOG(str) VMA_DEBUG_LOG_FORMAT("%s", (str)) #endif #ifndef VMA_LEAK_LOG_FORMAT -#define VMA_LEAK_LOG_FORMAT(format, ...) VMA_DEBUG_LOG_FORMAT(format, __VA_ARGS__) + #define VMA_LEAK_LOG_FORMAT(format, ...) VMA_DEBUG_LOG_FORMAT(format, __VA_ARGS__) #endif #ifndef VMA_CLASS_NO_COPY -#define VMA_CLASS_NO_COPY(className) \ + #define VMA_CLASS_NO_COPY(className) \ private: \ className(const className&) = delete; \ className& operator=(const className&) = delete; #endif #ifndef VMA_CLASS_NO_COPY_NO_MOVE -#define VMA_CLASS_NO_COPY_NO_MOVE(className) \ + #define VMA_CLASS_NO_COPY_NO_MOVE(className) \ private: \ className(const className&) = delete; \ className(className&&) = delete; \ @@ -3065,178 +3074,178 @@ static void vma_aligned_free(void* VMA_NULLABLE ptr) // Define this macro to 1 to enable functions: vmaBuildStatsString, vmaFreeStatsString. #if VMA_STATS_STRING_ENABLED -static inline void VmaUint32ToStr(char* VMA_NOT_NULL outStr, size_t strLen, uint32_t num) -{ - snprintf(outStr, strLen, "%" PRIu32, num); -} -static inline void VmaUint64ToStr(char* VMA_NOT_NULL outStr, size_t strLen, uint64_t num) -{ - snprintf(outStr, strLen, "%" PRIu64, num); -} -static inline void VmaPtrToStr(char* VMA_NOT_NULL outStr, size_t strLen, const void* ptr) -{ - snprintf(outStr, strLen, "%p", ptr); -} + static inline void VmaUint32ToStr(char* VMA_NOT_NULL outStr, size_t strLen, uint32_t num) + { + snprintf(outStr, strLen, "%" PRIu32, num); + } + static inline void VmaUint64ToStr(char* VMA_NOT_NULL outStr, size_t strLen, uint64_t num) + { + snprintf(outStr, strLen, "%" PRIu64, num); + } + static inline void VmaPtrToStr(char* VMA_NOT_NULL outStr, size_t strLen, const void* ptr) + { + snprintf(outStr, strLen, "%p", ptr); + } #endif #ifndef VMA_MUTEX -class VmaMutex -{ + class VmaMutex + { VMA_CLASS_NO_COPY_NO_MOVE(VmaMutex) -public: - VmaMutex() { } - void Lock() { m_Mutex.lock(); } - void Unlock() { m_Mutex.unlock(); } - bool TryLock() { return m_Mutex.try_lock(); } -private: - std::mutex m_Mutex; -}; -#define VMA_MUTEX VmaMutex + public: + VmaMutex() { } + void Lock() { m_Mutex.lock(); } + void Unlock() { m_Mutex.unlock(); } + bool TryLock() { return m_Mutex.try_lock(); } + private: + std::mutex m_Mutex; + }; + #define VMA_MUTEX VmaMutex #endif // Read-write mutex, where "read" is shared access, "write" is exclusive access. #ifndef VMA_RW_MUTEX -#if VMA_USE_STL_SHARED_MUTEX - // Use std::shared_mutex from C++17. -#include -class VmaRWMutex -{ -public: - void LockRead() { m_Mutex.lock_shared(); } - void UnlockRead() { m_Mutex.unlock_shared(); } - bool TryLockRead() { return m_Mutex.try_lock_shared(); } - void LockWrite() { m_Mutex.lock(); } - void UnlockWrite() { m_Mutex.unlock(); } - bool TryLockWrite() { return m_Mutex.try_lock(); } -private: - std::shared_mutex m_Mutex; -}; -#define VMA_RW_MUTEX VmaRWMutex -#elif defined(_WIN32) && defined(WINVER) && WINVER >= 0x0600 - // Use SRWLOCK from WinAPI. - // Minimum supported client = Windows Vista, server = Windows Server 2008. -class VmaRWMutex -{ -public: - VmaRWMutex() { InitializeSRWLock(&m_Lock); } - void LockRead() { AcquireSRWLockShared(&m_Lock); } - void UnlockRead() { ReleaseSRWLockShared(&m_Lock); } - bool TryLockRead() { return TryAcquireSRWLockShared(&m_Lock) != FALSE; } - void LockWrite() { AcquireSRWLockExclusive(&m_Lock); } - void UnlockWrite() { ReleaseSRWLockExclusive(&m_Lock); } - bool TryLockWrite() { return TryAcquireSRWLockExclusive(&m_Lock) != FALSE; } -private: - SRWLOCK m_Lock; -}; -#define VMA_RW_MUTEX VmaRWMutex -#else - // Less efficient fallback: Use normal mutex. -class VmaRWMutex -{ -public: - void LockRead() { m_Mutex.Lock(); } - void UnlockRead() { m_Mutex.Unlock(); } - bool TryLockRead() { return m_Mutex.TryLock(); } - void LockWrite() { m_Mutex.Lock(); } - void UnlockWrite() { m_Mutex.Unlock(); } - bool TryLockWrite() { return m_Mutex.TryLock(); } -private: - VMA_MUTEX m_Mutex; -}; -#define VMA_RW_MUTEX VmaRWMutex -#endif // #if VMA_USE_STL_SHARED_MUTEX + #if VMA_USE_STL_SHARED_MUTEX + // Use std::shared_mutex from C++17. + #include + class VmaRWMutex + { + public: + void LockRead() { m_Mutex.lock_shared(); } + void UnlockRead() { m_Mutex.unlock_shared(); } + bool TryLockRead() { return m_Mutex.try_lock_shared(); } + void LockWrite() { m_Mutex.lock(); } + void UnlockWrite() { m_Mutex.unlock(); } + bool TryLockWrite() { return m_Mutex.try_lock(); } + private: + std::shared_mutex m_Mutex; + }; + #define VMA_RW_MUTEX VmaRWMutex + #elif defined(_WIN32) && defined(WINVER) && WINVER >= 0x0600 + // Use SRWLOCK from WinAPI. + // Minimum supported client = Windows Vista, server = Windows Server 2008. + class VmaRWMutex + { + public: + VmaRWMutex() { InitializeSRWLock(&m_Lock); } + void LockRead() { AcquireSRWLockShared(&m_Lock); } + void UnlockRead() { ReleaseSRWLockShared(&m_Lock); } + bool TryLockRead() { return TryAcquireSRWLockShared(&m_Lock) != FALSE; } + void LockWrite() { AcquireSRWLockExclusive(&m_Lock); } + void UnlockWrite() { ReleaseSRWLockExclusive(&m_Lock); } + bool TryLockWrite() { return TryAcquireSRWLockExclusive(&m_Lock) != FALSE; } + private: + SRWLOCK m_Lock; + }; + #define VMA_RW_MUTEX VmaRWMutex + #else + // Less efficient fallback: Use normal mutex. + class VmaRWMutex + { + public: + void LockRead() { m_Mutex.Lock(); } + void UnlockRead() { m_Mutex.Unlock(); } + bool TryLockRead() { return m_Mutex.TryLock(); } + void LockWrite() { m_Mutex.Lock(); } + void UnlockWrite() { m_Mutex.Unlock(); } + bool TryLockWrite() { return m_Mutex.TryLock(); } + private: + VMA_MUTEX m_Mutex; + }; + #define VMA_RW_MUTEX VmaRWMutex + #endif // #if VMA_USE_STL_SHARED_MUTEX #endif // #ifndef VMA_RW_MUTEX /* If providing your own implementation, you need to implement a subset of std::atomic. */ #ifndef VMA_ATOMIC_UINT32 -#include -#define VMA_ATOMIC_UINT32 std::atomic + #include + #define VMA_ATOMIC_UINT32 std::atomic #endif #ifndef VMA_ATOMIC_UINT64 -#include -#define VMA_ATOMIC_UINT64 std::atomic + #include + #define VMA_ATOMIC_UINT64 std::atomic #endif #ifndef VMA_DEBUG_ALWAYS_DEDICATED_MEMORY -/** -Every allocation will have its own memory block. -Define to 1 for debugging purposes only. -*/ -#define VMA_DEBUG_ALWAYS_DEDICATED_MEMORY (0) + /** + Every allocation will have its own memory block. + Define to 1 for debugging purposes only. + */ + #define VMA_DEBUG_ALWAYS_DEDICATED_MEMORY (0) #endif #ifndef VMA_MIN_ALIGNMENT -/** -Minimum alignment of all allocations, in bytes. -Set to more than 1 for debugging purposes. Must be power of two. -*/ -#ifdef VMA_DEBUG_ALIGNMENT // Old name -#define VMA_MIN_ALIGNMENT VMA_DEBUG_ALIGNMENT -#else -#define VMA_MIN_ALIGNMENT (1) -#endif + /** + Minimum alignment of all allocations, in bytes. + Set to more than 1 for debugging purposes. Must be power of two. + */ + #ifdef VMA_DEBUG_ALIGNMENT // Old name + #define VMA_MIN_ALIGNMENT VMA_DEBUG_ALIGNMENT + #else + #define VMA_MIN_ALIGNMENT (1) + #endif #endif #ifndef VMA_DEBUG_MARGIN -/** -Minimum margin after every allocation, in bytes. -Set nonzero for debugging purposes only. -*/ -#define VMA_DEBUG_MARGIN (0) + /** + Minimum margin after every allocation, in bytes. + Set nonzero for debugging purposes only. + */ + #define VMA_DEBUG_MARGIN (0) #endif #ifndef VMA_DEBUG_INITIALIZE_ALLOCATIONS -/** -Define this macro to 1 to automatically fill new allocations and destroyed -allocations with some bit pattern. -*/ -#define VMA_DEBUG_INITIALIZE_ALLOCATIONS (0) + /** + Define this macro to 1 to automatically fill new allocations and destroyed + allocations with some bit pattern. + */ + #define VMA_DEBUG_INITIALIZE_ALLOCATIONS (0) #endif #ifndef VMA_DEBUG_DETECT_CORRUPTION -/** -Define this macro to 1 together with non-zero value of VMA_DEBUG_MARGIN to -enable writing magic value to the margin after every allocation and -validating it, so that memory corruptions (out-of-bounds writes) are detected. -*/ -#define VMA_DEBUG_DETECT_CORRUPTION (0) + /** + Define this macro to 1 together with non-zero value of VMA_DEBUG_MARGIN to + enable writing magic value to the margin after every allocation and + validating it, so that memory corruptions (out-of-bounds writes) are detected. + */ + #define VMA_DEBUG_DETECT_CORRUPTION (0) #endif #ifndef VMA_DEBUG_GLOBAL_MUTEX -/** -Set this to 1 for debugging purposes only, to enable single mutex protecting all -entry calls to the library. Can be useful for debugging multithreading issues. -*/ -#define VMA_DEBUG_GLOBAL_MUTEX (0) + /** + Set this to 1 for debugging purposes only, to enable single mutex protecting all + entry calls to the library. Can be useful for debugging multithreading issues. + */ + #define VMA_DEBUG_GLOBAL_MUTEX (0) #endif #ifndef VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY -/** -Minimum value for VkPhysicalDeviceLimits::bufferImageGranularity. -Set to more than 1 for debugging purposes only. Must be power of two. -*/ -#define VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY (1) + /** + Minimum value for VkPhysicalDeviceLimits::bufferImageGranularity. + Set to more than 1 for debugging purposes only. Must be power of two. + */ + #define VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY (1) #endif #ifndef VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT -/* -Set this to 1 to make VMA never exceed VkPhysicalDeviceLimits::maxMemoryAllocationCount -and return error instead of leaving up to Vulkan implementation what to do in such cases. -*/ -#define VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT (0) + /* + Set this to 1 to make VMA never exceed VkPhysicalDeviceLimits::maxMemoryAllocationCount + and return error instead of leaving up to Vulkan implementation what to do in such cases. + */ + #define VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT (0) #endif #ifndef VMA_SMALL_HEAP_MAX_SIZE -/// Maximum size of a memory heap in Vulkan to consider it "small". -#define VMA_SMALL_HEAP_MAX_SIZE (1024ull * 1024 * 1024) + /// Maximum size of a memory heap in Vulkan to consider it "small". + #define VMA_SMALL_HEAP_MAX_SIZE (1024ull * 1024 * 1024) #endif #ifndef VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE /// Default size of a block allocated as single VkDeviceMemory from a "large" heap. -#define VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE (256ull * 1024 * 1024) + #define VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE (256ull * 1024 * 1024) #endif /* @@ -3247,7 +3256,7 @@ vkMapMemory/vkUnmapMemory too many times, which may improve performance and help tools like RenderDoc. */ #ifndef VMA_MAPPING_HYSTERESIS_ENABLED -#define VMA_MAPPING_HYSTERESIS_ENABLED 1 + #define VMA_MAPPING_HYSTERESIS_ENABLED 1 #endif #define VMA_VALIDATE(cond) do { if(!(cond)) { \ @@ -3296,7 +3305,7 @@ static const char* VMA_SUBALLOCATION_TYPE_NAMES[] = #endif static VkAllocationCallbacks VmaEmptyAllocationCallbacks = -{ VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL }; + { VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL }; #ifndef _VMA_ENUM_DECLARATIONS @@ -3436,7 +3445,7 @@ static inline uint8_t VmaBitScanLSB(uint64_t mask) return static_cast(pos); return UINT8_MAX; #elif VMA_CPP20 - if (mask) + if(mask) return static_cast(std::countr_zero(mask)); return UINT8_MAX; #elif defined __GNUC__ || defined __clang__ @@ -3462,7 +3471,7 @@ static inline uint8_t VmaBitScanLSB(uint32_t mask) return static_cast(pos); return UINT8_MAX; #elif VMA_CPP20 - if (mask) + if(mask) return static_cast(std::countr_zero(mask)); return UINT8_MAX; #elif defined __GNUC__ || defined __clang__ @@ -3487,7 +3496,7 @@ static inline uint8_t VmaBitScanMSB(uint64_t mask) if (_BitScanReverse64(&pos, mask)) return static_cast(pos); #elif VMA_CPP20 - if (mask) + if(mask) return 63 - static_cast(std::countl_zero(mask)); #elif defined __GNUC__ || defined __clang__ if (mask) @@ -3512,7 +3521,7 @@ static inline uint8_t VmaBitScanMSB(uint32_t mask) if (_BitScanReverse(&pos, mask)) return static_cast(pos); #elif VMA_CPP20 - if (mask) + if(mask) return 31 - static_cast(std::countl_zero(mask)); #elif defined __GNUC__ || defined __clang__ if (mask) @@ -3811,10 +3820,10 @@ static inline void VmaPnextChainPushFront(MainT* mainStruct, NewT* newStruct) template static inline const FindT* VmaPnextChainFind(const MainT* mainStruct, VkStructureType sType) { - for (const VkBaseInStructure* s = (const VkBaseInStructure*)mainStruct->pNext; + for(const VkBaseInStructure* s = (const VkBaseInStructure*)mainStruct->pNext; s != VMA_NULL; s = s->pNext) { - if (s->sType == sType) + if(s->sType == sType) { return (const FindT*)s; } @@ -3837,8 +3846,8 @@ struct VmaBufferImageUsage VmaBufferImageUsage() { *this = UNKNOWN; } explicit VmaBufferImageUsage(BaseType usage) : Value(usage) { } - VmaBufferImageUsage(const VkBufferCreateInfo& createInfo, bool useKhrMaintenance5); - explicit VmaBufferImageUsage(const VkImageCreateInfo& createInfo); + VmaBufferImageUsage(const VkBufferCreateInfo &createInfo, bool useKhrMaintenance5); + explicit VmaBufferImageUsage(const VkImageCreateInfo &createInfo); bool operator==(const VmaBufferImageUsage& rhs) const { return Value == rhs.Value; } bool operator!=(const VmaBufferImageUsage& rhs) const { return Value != rhs.Value; } @@ -3853,18 +3862,18 @@ struct VmaBufferImageUsage const VmaBufferImageUsage VmaBufferImageUsage::UNKNOWN = VmaBufferImageUsage(0); -VmaBufferImageUsage::VmaBufferImageUsage(const VkBufferCreateInfo& createInfo, +VmaBufferImageUsage::VmaBufferImageUsage(const VkBufferCreateInfo &createInfo, bool useKhrMaintenance5) { #if VMA_KHR_MAINTENANCE5 - if (useKhrMaintenance5) + if(useKhrMaintenance5) { // If VkBufferCreateInfo::pNext chain contains VkBufferUsageFlags2CreateInfoKHR, // take usage from it and ignore VkBufferCreateInfo::usage, per specification // of the VK_KHR_maintenance5 extension. const VkBufferUsageFlags2CreateInfoKHR* const usageFlags2 = VmaPnextChainFind(&createInfo, VK_STRUCTURE_TYPE_BUFFER_USAGE_FLAGS_2_CREATE_INFO_KHR); - if (usageFlags2) + if(usageFlags2) { this->Value = usageFlags2->usage; return; @@ -3875,7 +3884,7 @@ VmaBufferImageUsage::VmaBufferImageUsage(const VkBufferCreateInfo& createInfo, this->Value = (BaseType)createInfo.usage; } -VmaBufferImageUsage::VmaBufferImageUsage(const VkImageCreateInfo& createInfo) +VmaBufferImageUsage::VmaBufferImageUsage(const VkImageCreateInfo &createInfo) { // Maybe in the future there will be VK_KHR_maintenanceN extension with structure // VkImageUsageFlags2CreateInfoKHR, like the one for buffers... @@ -3897,12 +3906,12 @@ static bool FindMemoryPreferences( outPreferredFlags = allocCreateInfo.preferredFlags; outNotPreferredFlags = 0; - switch (allocCreateInfo.usage) + switch(allocCreateInfo.usage) { case VMA_MEMORY_USAGE_UNKNOWN: break; case VMA_MEMORY_USAGE_GPU_ONLY: - if (!isIntegratedGPU || (outPreferredFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) + if(!isIntegratedGPU || (outPreferredFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) { outPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; } @@ -3912,7 +3921,7 @@ static bool FindMemoryPreferences( break; case VMA_MEMORY_USAGE_CPU_TO_GPU: outRequiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; - if (!isIntegratedGPU || (outPreferredFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) + if(!isIntegratedGPU || (outPreferredFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) { outPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; } @@ -3931,10 +3940,10 @@ static bool FindMemoryPreferences( case VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE: case VMA_MEMORY_USAGE_AUTO_PREFER_HOST: { - if (bufImgUsage == VmaBufferImageUsage::UNKNOWN) + if(bufImgUsage == VmaBufferImageUsage::UNKNOWN) { VMA_ASSERT(0 && "VMA_MEMORY_USAGE_AUTO* values can only be used with functions like vmaCreateBuffer, vmaCreateImage so that the details of the created resource are known." - " Maybe you use VkBufferUsageFlags2CreateInfoKHR but forgot to use VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT?"); + " Maybe you use VkBufferUsageFlags2CreateInfoKHR but forgot to use VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT?" ); return false; } @@ -3946,7 +3955,7 @@ static bool FindMemoryPreferences( const bool preferHost = allocCreateInfo.usage == VMA_MEMORY_USAGE_AUTO_PREFER_HOST; // CPU random access - e.g. a buffer written to or transferred from GPU to read back on CPU. - if (hostAccessRandom) + if(hostAccessRandom) { // Prefer cached. Cannot require it, because some platforms don't have it (e.g. Raspberry Pi - see #362)! outPreferredFlags |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT; @@ -3966,12 +3975,12 @@ static bool FindMemoryPreferences( } } // CPU sequential write - may be CPU or host-visible GPU memory, uncached and write-combined. - else if (hostAccessSequentialWrite) + else if(hostAccessSequentialWrite) { // Want uncached and write-combined. outNotPreferredFlags |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT; - if (!isIntegratedGPU && deviceAccess && hostAccessAllowTransferInstead && !preferHost) + if(!isIntegratedGPU && deviceAccess && hostAccessAllowTransferInstead && !preferHost) { outPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; } @@ -3979,10 +3988,10 @@ static bool FindMemoryPreferences( { outRequiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; // Direct GPU access, CPU sequential write (e.g. a dynamic uniform buffer updated every frame) - if (deviceAccess) + if(deviceAccess) { // Could go to CPU memory or GPU BAR/unified. Up to the user to decide. If no preference, choose GPU memory. - if (preferHost) + if(preferHost) outNotPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; else outPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; @@ -3991,7 +4000,7 @@ static bool FindMemoryPreferences( else { // Could go to CPU memory or GPU BAR/unified. Up to the user to decide. If no preference, choose CPU memory. - if (preferDevice) + if(preferDevice) outPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; else outNotPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; @@ -4013,7 +4022,7 @@ static bool FindMemoryPreferences( // a "swap file" copy to free some GPU memory (then better CPU memory). // Up to the user to decide. If no preferece, assume the former and choose GPU memory. - if (preferHost) + if(preferHost) outNotPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; else outPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; @@ -4025,7 +4034,7 @@ static bool FindMemoryPreferences( } // Avoid DEVICE_COHERENT unless explicitly requested. - if (((allocCreateInfo.requiredFlags | allocCreateInfo.preferredFlags) & + if(((allocCreateInfo.requiredFlags | allocCreateInfo.preferredFlags) & (VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY | VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD_COPY)) == 0) { outNotPreferredFlags |= VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD_COPY; @@ -4238,7 +4247,7 @@ public: { if (m_pMutex) { m_pMutex->Lock(); } } - ~VmaMutexLock() { if (m_pMutex) { m_pMutex->Unlock(); } } + ~VmaMutexLock() { if (m_pMutex) { m_pMutex->Unlock(); } } private: VMA_MUTEX* m_pMutex; @@ -4277,10 +4286,10 @@ private: }; #if VMA_DEBUG_GLOBAL_MUTEX -static VMA_MUTEX gDebugGlobalMutex; -#define VMA_DEBUG_GLOBAL_MUTEX_LOCK VmaMutexLock debugGlobalMutexLock(gDebugGlobalMutex, true); + static VMA_MUTEX gDebugGlobalMutex; + #define VMA_DEBUG_GLOBAL_MUTEX_LOCK VmaMutexLock debugGlobalMutexLock(gDebugGlobalMutex, true); #else -#define VMA_DEBUG_GLOBAL_MUTEX_LOCK + #define VMA_DEBUG_GLOBAL_MUTEX_LOCK #endif #endif // _VMA_MUTEX_LOCK @@ -4294,7 +4303,7 @@ public: ~AtomicTransactionalIncrement() { - if (m_Atomic) + if(m_Atomic) --(*m_Atomic); } @@ -4929,7 +4938,7 @@ VmaListItem* VmaRawList::PushBack() { ItemType* const pNewItem = m_ItemAllocator.Alloc(); pNewItem->pNext = VMA_NULL; - if (IsEmpty()) + if(IsEmpty()) { pNewItem->pPrev = VMA_NULL; m_pFront = pNewItem; @@ -4983,7 +4992,7 @@ void VmaRawList::PopBack() VMA_HEAVY_ASSERT(m_Count > 0); ItemType* const pBackItem = m_pBack; ItemType* const pPrevItem = pBackItem->pPrev; - if (pPrevItem != VMA_NULL) + if(pPrevItem != VMA_NULL) { pPrevItem->pNext = VMA_NULL; } @@ -5016,7 +5025,7 @@ void VmaRawList::Remove(ItemType* pItem) VMA_HEAVY_ASSERT(pItem != VMA_NULL); VMA_HEAVY_ASSERT(m_Count > 0); - if (pItem->pPrev != VMA_NULL) + if(pItem->pPrev != VMA_NULL) { pItem->pPrev->pNext = pItem->pNext; } @@ -5026,7 +5035,7 @@ void VmaRawList::Remove(ItemType* pItem) m_pFront = pItem->pNext; } - if (pItem->pNext != VMA_NULL) + if(pItem->pNext != VMA_NULL) { pItem->pNext->pPrev = pItem->pPrev; } @@ -5043,14 +5052,14 @@ void VmaRawList::Remove(ItemType* pItem) template VmaListItem* VmaRawList::InsertBefore(ItemType* pItem) { - if (pItem != VMA_NULL) + if(pItem != VMA_NULL) { ItemType* const prevItem = pItem->pPrev; ItemType* const newItem = m_ItemAllocator.Alloc(); newItem->pPrev = prevItem; newItem->pNext = pItem; pItem->pPrev = newItem; - if (prevItem != VMA_NULL) + if(prevItem != VMA_NULL) { prevItem->pNext = newItem; } @@ -5069,14 +5078,14 @@ VmaListItem* VmaRawList::InsertBefore(ItemType* pItem) template VmaListItem* VmaRawList::InsertAfter(ItemType* pItem) { - if (pItem != VMA_NULL) + if(pItem != VMA_NULL) { ItemType* const nextItem = pItem->pNext; ItemType* const newItem = m_ItemAllocator.Alloc(); newItem->pNext = nextItem; newItem->pPrev = pItem; pItem->pNext = newItem; - if (nextItem != VMA_NULL) + if(nextItem != VMA_NULL) { nextItem->pPrev = newItem; } @@ -5125,7 +5134,7 @@ public: friend class const_iterator; friend class VmaList; public: - iterator() : m_pList(VMA_NULL), m_pItem(VMA_NULL) {} + iterator() : m_pList(VMA_NULL), m_pItem(VMA_NULL) {} iterator(const reverse_iterator& src) : m_pList(src.m_pList), m_pItem(src.m_pItem) {} T& operator*() const { VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); return m_pItem->Value; } @@ -5144,7 +5153,7 @@ public: VmaRawList* m_pList; VmaListItem* m_pItem; - iterator(VmaRawList* pList, VmaListItem* pItem) : m_pList(pList), m_pItem(pItem) {} + iterator(VmaRawList* pList, VmaListItem* pItem) : m_pList(pList), m_pItem(pItem) {} }; class reverse_iterator { @@ -5160,8 +5169,8 @@ public: bool operator==(const reverse_iterator& rhs) const { VMA_HEAVY_ASSERT(m_pList == rhs.m_pList); return m_pItem == rhs.m_pItem; } bool operator!=(const reverse_iterator& rhs) const { VMA_HEAVY_ASSERT(m_pList == rhs.m_pList); return m_pItem != rhs.m_pItem; } - reverse_iterator operator++(int) { reverse_iterator result = *this; ++*this; return result; } - reverse_iterator operator--(int) { reverse_iterator result = *this; --*this; return result; } + reverse_iterator operator++(int) { reverse_iterator result = *this; ++* this; return result; } + reverse_iterator operator--(int) { reverse_iterator result = *this; --* this; return result; } reverse_iterator& operator++() { VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); m_pItem = m_pItem->pPrev; return *this; } reverse_iterator& operator--(); @@ -5170,7 +5179,7 @@ public: VmaRawList* m_pList; VmaListItem* m_pItem; - reverse_iterator(VmaRawList* pList, VmaListItem* pItem) : m_pList(pList), m_pItem(pItem) {} + reverse_iterator(VmaRawList* pList, VmaListItem* pItem) : m_pList(pList), m_pItem(pItem) {} }; class const_iterator { @@ -5188,8 +5197,8 @@ public: bool operator==(const const_iterator& rhs) const { VMA_HEAVY_ASSERT(m_pList == rhs.m_pList); return m_pItem == rhs.m_pItem; } bool operator!=(const const_iterator& rhs) const { VMA_HEAVY_ASSERT(m_pList == rhs.m_pList); return m_pItem != rhs.m_pItem; } - const_iterator operator++(int) { const_iterator result = *this; ++*this; return result; } - const_iterator operator--(int) { const_iterator result = *this; --*this; return result; } + const_iterator operator++(int) { const_iterator result = *this; ++* this; return result; } + const_iterator operator--(int) { const_iterator result = *this; --* this; return result; } const_iterator& operator++() { VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); m_pItem = m_pItem->pNext; return *this; } const_iterator& operator--(); @@ -5216,8 +5225,8 @@ public: bool operator==(const const_reverse_iterator& rhs) const { VMA_HEAVY_ASSERT(m_pList == rhs.m_pList); return m_pItem == rhs.m_pItem; } bool operator!=(const const_reverse_iterator& rhs) const { VMA_HEAVY_ASSERT(m_pList == rhs.m_pList); return m_pItem != rhs.m_pItem; } - const_reverse_iterator operator++(int) { const_reverse_iterator result = *this; ++*this; return result; } - const_reverse_iterator operator--(int) { const_reverse_iterator result = *this; --*this; return result; } + const_reverse_iterator operator++(int) { const_reverse_iterator result = *this; ++* this; return result; } + const_reverse_iterator operator--(int) { const_reverse_iterator result = *this; --* this; return result; } const_reverse_iterator& operator++() { VMA_HEAVY_ASSERT(m_pItem != VMA_NULL); m_pItem = m_pItem->pPrev; return *this; } const_reverse_iterator& operator--(); @@ -5347,7 +5356,7 @@ public: // Movable, not copyable. VmaIntrusiveLinkedList() = default; - VmaIntrusiveLinkedList(VmaIntrusiveLinkedList&& src); + VmaIntrusiveLinkedList(VmaIntrusiveLinkedList && src); VmaIntrusiveLinkedList(const VmaIntrusiveLinkedList&) = delete; VmaIntrusiveLinkedList& operator=(VmaIntrusiveLinkedList&& src); VmaIntrusiveLinkedList& operator=(const VmaIntrusiveLinkedList&) = delete; @@ -5997,10 +6006,10 @@ public: bool PostMap() { #if VMA_MAPPING_HYSTERESIS_ENABLED - if (m_ExtraMapping == 0) + if(m_ExtraMapping == 0) { ++m_MajorCounter; - if (m_MajorCounter >= COUNTER_MIN_EXTRA_MAPPING) + if(m_MajorCounter >= COUNTER_MIN_EXTRA_MAPPING) { m_ExtraMapping = 1; m_MajorCounter = 0; @@ -6018,7 +6027,7 @@ public: void PostUnmap() { #if VMA_MAPPING_HYSTERESIS_ENABLED - if (m_ExtraMapping == 0) + if(m_ExtraMapping == 0) ++m_MajorCounter; else // m_ExtraMapping == 1 PostMinorCounter(); @@ -6029,7 +6038,7 @@ public: void PostAlloc() { #if VMA_MAPPING_HYSTERESIS_ENABLED - if (m_ExtraMapping == 1) + if(m_ExtraMapping == 1) ++m_MajorCounter; else // m_ExtraMapping == 0 PostMinorCounter(); @@ -6041,10 +6050,10 @@ public: bool PostFree() { #if VMA_MAPPING_HYSTERESIS_ENABLED - if (m_ExtraMapping == 1) + if(m_ExtraMapping == 1) { ++m_MajorCounter; - if (m_MajorCounter >= COUNTER_MIN_EXTRA_MAPPING && + if(m_MajorCounter >= COUNTER_MIN_EXTRA_MAPPING && m_MajorCounter > m_MinorCounter + 1) { m_ExtraMapping = 0; @@ -6068,11 +6077,11 @@ private: void PostMinorCounter() { - if (m_MinorCounter < m_MajorCounter) + if(m_MinorCounter < m_MajorCounter) { ++m_MinorCounter; } - else if (m_MajorCounter > 0) + else if(m_MajorCounter > 0) { --m_MajorCounter; --m_MinorCounter; @@ -6082,7 +6091,7 @@ private: #endif // _VMA_MAPPING_HYSTERESIS -#if defined(VK_USE_PLATFORM_WIN32_KHR) +#if VMA_EXTERNAL_MEMORY_WIN32 class VmaWin32Handle { public: @@ -6114,13 +6123,14 @@ public: VmaMutexLockWrite lock(m_Mutex, useMutex); if (m_hHandle.load(std::memory_order_relaxed) == VMA_NULL) { - res = Create(device, memory, pvkGetMemoryWin32HandleKHR, &hCreatedHandle); + VkResult res = Create(device, memory, pvkGetMemoryWin32HandleKHR, &hCreatedHandle); m_hHandle.store(hCreatedHandle, std::memory_order_relaxed); } } + *pHandle = Duplicate(hTargetProcess); return res; - } +} operator bool() const noexcept { return m_hHandle != VMA_NULL; } private: @@ -6161,8 +6171,9 @@ class VmaWin32Handle { // ABI compatibility void* placeholder = VMA_NULL; + VMA_RW_MUTEX placeholder2; }; -#endif // VK_USE_PLATFORM_WIN32_KHR +#endif // VMA_EXTERNAL_MEMORY_WIN32 #ifndef _VMA_DEVICE_MEMORY_BLOCK @@ -6231,13 +6242,13 @@ public: VkDeviceSize allocationLocalOffset, VkImage hImage, const void* pNext); -#ifdef VK_USE_PLATFORM_WIN32_KHR +#if VMA_EXTERNAL_MEMORY_WIN32 VkResult CreateWin32Handle( const VmaAllocator hAllocator, decltype(&vkGetMemoryWin32HandleKHR) pvkGetMemoryWin32HandleKHR, HANDLE hTargetProcess, HANDLE* pHandle)noexcept; -#endif // VK_USE_PLATFORM_WIN32_KHR +#endif // VMA_EXTERNAL_MEMORY_WIN32 private: VmaPool m_hParentPool; // VK_NULL_HANDLE if not belongs to custom pool. uint32_t m_MemoryTypeIndex; @@ -6265,8 +6276,8 @@ struct VmaAllocation_T enum FLAGS { - FLAG_PERSISTENT_MAP = 0x01, - FLAG_MAPPING_ALLOWED = 0x02, + FLAG_PERSISTENT_MAP = 0x01, + FLAG_MAPPING_ALLOWED = 0x02, }; public: @@ -6327,12 +6338,12 @@ public: #if VMA_STATS_STRING_ENABLED VmaBufferImageUsage GetBufferImageUsage() const { return m_BufferImageUsage; } - void InitBufferUsage(const VkBufferCreateInfo& createInfo, bool useKhrMaintenance5) + void InitBufferUsage(const VkBufferCreateInfo &createInfo, bool useKhrMaintenance5) { VMA_ASSERT(m_BufferImageUsage == VmaBufferImageUsage::UNKNOWN); m_BufferImageUsage = VmaBufferImageUsage(createInfo, useKhrMaintenance5); } - void InitImageUsage(const VkImageCreateInfo& createInfo) + void InitImageUsage(const VkImageCreateInfo &createInfo) { VMA_ASSERT(m_BufferImageUsage == VmaBufferImageUsage::UNKNOWN); m_BufferImageUsage = VmaBufferImageUsage(createInfo); @@ -6340,9 +6351,9 @@ public: void PrintParameters(class VmaJsonWriter& json) const; #endif -#ifdef VK_USE_PLATFORM_WIN32_KHR +#if VMA_EXTERNAL_MEMORY_WIN32 VkResult GetWin32Handle(VmaAllocator hAllocator, HANDLE hTargetProcess, HANDLE* hHandle) const noexcept; -#endif // VK_USE_PLATFORM_WIN32_KHR +#endif // VMA_EXTERNAL_MEMORY_WIN32 private: // Allocation out of VmaDeviceMemoryBlock. @@ -6476,7 +6487,7 @@ bool VmaDedicatedAllocationList::Validate() void VmaDedicatedAllocationList::AddDetailedStatistics(VmaDetailedStatistics& inoutStats) { - for (auto* item = m_AllocationList.Front(); item != VMA_NULL; item = DedicatedAllocationLinkedList::GetNext(item)) + for(auto* item = m_AllocationList.Front(); item != VMA_NULL; item = DedicatedAllocationLinkedList::GetNext(item)) { const VkDeviceSize size = item->GetSize(); inoutStats.statistics.blockCount++; @@ -6493,7 +6504,7 @@ void VmaDedicatedAllocationList::AddStatistics(VmaStatistics& inoutStats) inoutStats.blockCount += allocCount; inoutStats.allocationCount += allocCount; - for (auto* item = m_AllocationList.Front(); item != VMA_NULL; item = DedicatedAllocationLinkedList::GetNext(item)) + for(auto* item = m_AllocationList.Front(); item != VMA_NULL; item = DedicatedAllocationLinkedList::GetNext(item)) { const VkDeviceSize size = item->GetSize(); inoutStats.blockBytes += size; @@ -8018,7 +8029,7 @@ bool VmaBlockMetadata_Linear::CreateAllocationRequest( VMA_ASSERT(pAllocationRequest != VMA_NULL); VMA_HEAVY_ASSERT(Validate()); - if (allocSize > GetSize()) + if(allocSize > GetSize()) return false; pAllocationRequest->size = allocSize; @@ -9160,7 +9171,7 @@ bool VmaBlockMetadata_TLSF::CreateAllocationRequest( nextListBlock = nextListBlock->NextFree(); } } - else if (strategy & VMA_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT) + else if (strategy & VMA_ALLOCATION_CREATE_STRATEGY_MIN_OFFSET_BIT ) { // Perform search from the start VmaStlAllocator allocator(GetAllocationCallbacks()); @@ -9707,7 +9718,7 @@ public: size_t GetBlockCount() const { return m_Blocks.size(); } // To be used only while the m_Mutex is locked. Used during defragmentation. VmaDeviceMemoryBlock* GetBlock(size_t index) const { return m_Blocks[index]; } - VMA_RW_MUTEX& GetMutex() { return m_Mutex; } + VMA_RW_MUTEX &GetMutex() { return m_Mutex; } VkResult CreateMinBlocks(); void AddStatistics(VmaStatistics& inoutStats); @@ -10116,7 +10127,7 @@ VkResult VmaVirtualBlock_T::Allocate(const VmaVirtualAllocationCreateInfo& creat VMA_SUBALLOCATION_TYPE_UNKNOWN, // type - unimportant createInfo.pUserData); outAllocation = (VmaVirtualAllocation)request.allocHandle; - if (outOffset) + if(outOffset) *outOffset = m_Metadata->GetAllocationOffset(request.allocHandle); return VK_SUCCESS; } @@ -10518,7 +10529,7 @@ static T* VmaAllocateArray(VmaAllocator hAllocator, size_t count) template static void vma_delete(VmaAllocator hAllocator, T* ptr) { - if (ptr != VMA_NULL) + if(ptr != VMA_NULL) { ptr->~T(); VmaFree(hAllocator, ptr); @@ -10528,9 +10539,9 @@ static void vma_delete(VmaAllocator hAllocator, T* ptr) template static void vma_delete_array(VmaAllocator hAllocator, T* ptr, size_t count) { - if (ptr != VMA_NULL) + if(ptr != VMA_NULL) { - for (size_t i = count; i--; ) + for(size_t i = count; i--; ) ptr[i].~T(); VmaFree(hAllocator, ptr); } @@ -10615,7 +10626,7 @@ void VmaDeviceMemoryBlock::PostAlloc(VmaAllocator hAllocator) void VmaDeviceMemoryBlock::PostFree(VmaAllocator hAllocator) { VmaMutexLock lock(m_MapAndBindMutex, hAllocator->m_UseMutex); - if (m_MappingHysteresis.PostFree()) + if(m_MappingHysteresis.PostFree()) { VMA_ASSERT(m_MappingHysteresis.GetExtraMapping() == 0); if (m_MapCount == 0) @@ -10789,13 +10800,13 @@ VkResult VmaDeviceMemoryBlock::BindImageMemory( return hAllocator->BindVulkanImage(m_hMemory, memoryOffset, hImage, pNext); } -#ifdef VK_USE_PLATFORM_WIN32_KHR +#if VMA_EXTERNAL_MEMORY_WIN32 VkResult VmaDeviceMemoryBlock::CreateWin32Handle(const VmaAllocator hAllocator, decltype(&vkGetMemoryWin32HandleKHR) pvkGetMemoryWin32HandleKHR, HANDLE hTargetProcess, HANDLE* pHandle) noexcept { VMA_ASSERT(pHandle); return m_Handle.GetHandle(hAllocator->m_hDevice, m_hMemory, &vkGetMemoryWin32HandleKHR, hTargetProcess, hAllocator->m_UseMutex, pHandle); } -#endif // VK_USE_PLATFORM_WIN32_KHR +#endif // VMA_EXTERNAL_MEMORY_WIN32 #endif // _VMA_DEVICE_MEMORY_BLOCK_FUNCTIONS #ifndef _VMA_ALLOCATION_T_FUNCTIONS @@ -10810,7 +10821,7 @@ VmaAllocation_T::VmaAllocation_T(bool mappingAllowed) m_MapCount{ 0 }, m_Flags{ 0 } { - if (mappingAllowed) + if(mappingAllowed) m_Flags |= (uint8_t)FLAG_MAPPING_ALLOWED; } @@ -10837,7 +10848,7 @@ void VmaAllocation_T::InitBlockAllocation( m_Alignment = alignment; m_Size = size; m_MemoryTypeIndex = memoryTypeIndex; - if (mapped) + if(mapped) { VMA_ASSERT(IsMappingAllowed() && "Mapping is not allowed on this allocation! Please use one of the new VMA_ALLOCATION_CREATE_HOST_ACCESS_* flags when creating it."); m_Flags |= (uint8_t)FLAG_PERSISTENT_MAP; @@ -10862,7 +10873,7 @@ void VmaAllocation_T::InitDedicatedAllocation( m_Size = size; m_MemoryTypeIndex = memoryTypeIndex; m_SuballocationType = (uint8_t)suballocationType; - if (pMappedData != VMA_NULL) + if(pMappedData != VMA_NULL) { VMA_ASSERT(IsMappingAllowed() && "Mapping is not allowed on this allocation! Please use one of the new VMA_ALLOCATION_CREATE_HOST_ACCESS_* flags when creating it."); m_Flags |= (uint8_t)FLAG_PERSISTENT_MAP; @@ -11096,7 +11107,7 @@ void VmaAllocation_T::PrintParameters(class VmaJsonWriter& json) const json.WriteString(m_pName); } } -#ifdef VK_USE_PLATFORM_WIN32_KHR +#if VMA_EXTERNAL_MEMORY_WIN32 VkResult VmaAllocation_T::GetWin32Handle(VmaAllocator hAllocator, HANDLE hTargetProcess, HANDLE* pHandle) const noexcept { // Where do we get this function from? @@ -11112,12 +11123,12 @@ VkResult VmaAllocation_T::GetWin32Handle(VmaAllocator hAllocator, HANDLE hTarget return VK_ERROR_FEATURE_NOT_PRESENT; } } -#endif // VK_USE_PLATFORM_WIN32_KHR +#endif // VMA_EXTERNAL_MEMORY_WIN32 #endif // VMA_STATS_STRING_ENABLED void VmaAllocation_T::FreeName(VmaAllocator hAllocator) { - if (m_pName) + if(m_pName) { VmaFreeString(hAllocator->GetAllocationCallbacks(), m_pName); m_pName = VMA_NULL; @@ -11328,7 +11339,7 @@ VkResult VmaBlockVector::AllocatePage( { const bool isHostVisible = (m_hAllocator->m_MemProps.memoryTypes[m_MemoryTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0; - if (isHostVisible) + if(isHostVisible) { const bool isMappingAllowed = (createInfo.flags & (VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT)) != 0; @@ -11338,7 +11349,7 @@ VkResult VmaBlockVector::AllocatePage( This way, having many blocks, we will separate mappable and non-mappable allocations, hopefully limiting the number of blocks that are mapped, which will help tools like RenderDoc. */ - for (size_t mappingI = 0; mappingI < 2; ++mappingI) + for(size_t mappingI = 0; mappingI < 2; ++mappingI) { // Forward order in m_Blocks - prefer blocks with smallest amount of free space. for (size_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex) @@ -11346,7 +11357,7 @@ VkResult VmaBlockVector::AllocatePage( VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex]; VMA_ASSERT(pCurrBlock); const bool isBlockMapped = pCurrBlock->GetMappedData() != VMA_NULL; - if ((mappingI == 0) == (isMappingAllowed == isBlockMapped)) + if((mappingI == 0) == (isMappingAllowed == isBlockMapped)) { VkResult res = AllocateFromBlock( pCurrBlock, size, alignment, createInfo.flags, createInfo.pUserData, suballocType, strategy, pAllocation); @@ -12068,7 +12079,7 @@ VkResult VmaDefragmentationContext_T::DefragmentPassEnd(VmaDefragmentationPassMo m_PassStats.bytesFreed += freedBlockSize; } - if (m_Algorithm == VMA_DEFRAGMENTATION_FLAG_ALGORITHM_EXTENSIVE_BIT && + if(m_Algorithm == VMA_DEFRAGMENTATION_FLAG_ALGORITHM_EXTENSIVE_BIT && m_AlgorithmState != VMA_NULL) { // Avoid unnecessary tries to allocate when new free block is available @@ -12103,7 +12114,7 @@ VkResult VmaDefragmentationContext_T::DefragmentPassEnd(VmaDefragmentationPassMo { do { - if (m_Algorithm == VMA_DEFRAGMENTATION_FLAG_ALGORITHM_EXTENSIVE_BIT) + if(m_Algorithm == VMA_DEFRAGMENTATION_FLAG_ALGORITHM_EXTENSIVE_BIT) { if (m_AlgorithmState != VMA_NULL) { @@ -12741,7 +12752,7 @@ bool VmaDefragmentationContext_T::MoveDataToFreeBlocks(VmaSuballocationType curr bool& texturePresent, bool& bufferPresent, bool& otherPresent) { const size_t prevMoveCount = m_Moves.size(); - for (size_t i = firstFreeBlock; i;) + for (size_t i = firstFreeBlock ; i;) { VmaDeviceMemoryBlock* block = vector.GetBlock(--i); VmaBlockMetadata* metadata = block->m_pMetadata; @@ -12800,7 +12811,7 @@ VmaPool_T::VmaPool_T( createInfo.maxBlockCount, (createInfo.flags& VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT) != 0 ? 1 : hAllocator->GetBufferImageGranularity(), createInfo.blockSize != 0, // explicitBlockSize - createInfo.flags& VMA_POOL_CREATE_ALGORITHM_MASK, // algorithm + createInfo.flags & VMA_POOL_CREATE_ALGORITHM_MASK, // algorithm createInfo.priority, VMA_MAX(hAllocator->GetMemoryTypeMinAlignment(createInfo.memoryTypeIndex), createInfo.minAllocationAlignment), createInfo.pMemoryAllocateNext), @@ -12833,17 +12844,17 @@ void VmaPool_T::SetName(const char* pName) #ifndef _VMA_ALLOCATOR_T_FUNCTIONS VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) : - m_UseMutex((pCreateInfo->flags& VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT) == 0), + m_UseMutex((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT) == 0), m_VulkanApiVersion(pCreateInfo->vulkanApiVersion != 0 ? pCreateInfo->vulkanApiVersion : VK_API_VERSION_1_0), - m_UseKhrDedicatedAllocation((pCreateInfo->flags& VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT) != 0), - m_UseKhrBindMemory2((pCreateInfo->flags& VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT) != 0), - m_UseExtMemoryBudget((pCreateInfo->flags& VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT) != 0), - m_UseAmdDeviceCoherentMemory((pCreateInfo->flags& VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT) != 0), - m_UseKhrBufferDeviceAddress((pCreateInfo->flags& VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT) != 0), - m_UseExtMemoryPriority((pCreateInfo->flags& VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT) != 0), - m_UseKhrMaintenance4((pCreateInfo->flags& VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE4_BIT) != 0), - m_UseKhrMaintenance5((pCreateInfo->flags& VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT) != 0), - m_UseKhrExternalMemoryWin32((pCreateInfo->flags& VMA_ALLOCATOR_CREATE_KHR_EXTERNAL_MEMORY_WIN32) != 0), + m_UseKhrDedicatedAllocation((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT) != 0), + m_UseKhrBindMemory2((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT) != 0), + m_UseExtMemoryBudget((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT) != 0), + m_UseAmdDeviceCoherentMemory((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT) != 0), + m_UseKhrBufferDeviceAddress((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT) != 0), + m_UseExtMemoryPriority((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT) != 0), + m_UseKhrMaintenance4((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE4_BIT) != 0), + m_UseKhrMaintenance5((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT) != 0), + m_UseKhrExternalMemoryWin32((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_EXTERNAL_MEMORY_WIN32_BIT) != 0), m_hDevice(pCreateInfo->device), m_hInstance(pCreateInfo->instance), m_AllocationCallbacksSpecified(pCreateInfo->pAllocationCallbacks != VMA_NULL), @@ -12858,13 +12869,13 @@ VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) : m_NextPoolId(0), m_GlobalMemoryTypeBits(UINT32_MAX) { - if (m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) { m_UseKhrDedicatedAllocation = false; m_UseKhrBindMemory2 = false; } - if (VMA_DEBUG_DETECT_CORRUPTION) + if(VMA_DEBUG_DETECT_CORRUPTION) { // Needs to be multiply of uint32_t size because we are going to write VMA_CORRUPTION_DETECTION_MAGIC_VALUE to it. VMA_ASSERT(VMA_DEBUG_MARGIN % sizeof(uint32_t) == 0); @@ -12872,84 +12883,84 @@ VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) : VMA_ASSERT(pCreateInfo->physicalDevice && pCreateInfo->device && pCreateInfo->instance); - if (m_VulkanApiVersion < VK_MAKE_VERSION(1, 1, 0)) + if(m_VulkanApiVersion < VK_MAKE_VERSION(1, 1, 0)) { #if !(VMA_DEDICATED_ALLOCATION) - if ((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT) != 0) + if((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT) != 0) { VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT set but required extensions are disabled by preprocessor macros."); } #endif #if !(VMA_BIND_MEMORY2) - if ((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT) != 0) + if((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT) != 0) { VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT set but required extension is disabled by preprocessor macros."); } #endif } #if !(VMA_MEMORY_BUDGET) - if ((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT) != 0) + if((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT) != 0) { VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT set but required extension is disabled by preprocessor macros."); } #endif #if !(VMA_BUFFER_DEVICE_ADDRESS) - if (m_UseKhrBufferDeviceAddress) + if(m_UseKhrBufferDeviceAddress) { VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT is set but required extension or Vulkan 1.2 is not available in your Vulkan header or its support in VMA has been disabled by a preprocessor macro."); } #endif #if VMA_VULKAN_VERSION < 1003000 - if (m_VulkanApiVersion >= VK_MAKE_VERSION(1, 3, 0)) + if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 3, 0)) { VMA_ASSERT(0 && "vulkanApiVersion >= VK_API_VERSION_1_3 but required Vulkan version is disabled by preprocessor macros."); } #endif #if VMA_VULKAN_VERSION < 1002000 - if (m_VulkanApiVersion >= VK_MAKE_VERSION(1, 2, 0)) + if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 2, 0)) { VMA_ASSERT(0 && "vulkanApiVersion >= VK_API_VERSION_1_2 but required Vulkan version is disabled by preprocessor macros."); } #endif #if VMA_VULKAN_VERSION < 1001000 - if (m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) { VMA_ASSERT(0 && "vulkanApiVersion >= VK_API_VERSION_1_1 but required Vulkan version is disabled by preprocessor macros."); } #endif #if !(VMA_MEMORY_PRIORITY) - if (m_UseExtMemoryPriority) + if(m_UseExtMemoryPriority) { VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT is set but required extension is not available in your Vulkan header or its support in VMA has been disabled by a preprocessor macro."); } #endif #if !(VMA_KHR_MAINTENANCE4) - if (m_UseKhrMaintenance4) + if(m_UseKhrMaintenance4) { VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE4_BIT is set but required extension is not available in your Vulkan header or its support in VMA has been disabled by a preprocessor macro."); } #endif #if !(VMA_KHR_MAINTENANCE5) - if (m_UseKhrMaintenance5) + if(m_UseKhrMaintenance5) { VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT is set but required extension is not available in your Vulkan header or its support in VMA has been disabled by a preprocessor macro."); } #endif #if !(VMA_KHR_MAINTENANCE5) - if (m_UseKhrMaintenance5) + if(m_UseKhrMaintenance5) { VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT is set but required extension is not available in your Vulkan header or its support in VMA has been disabled by a preprocessor macro."); } #endif -#if !defined(VK_USE_PLATFORM_WIN32_KHR) - if (m_UseKhrExternalMemoryWin32) +#if !(VMA_EXTERNAL_MEMORY_WIN32) + if(m_UseKhrExternalMemoryWin32) { - VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT is set but required extension is not available in your Vulkan header or its support in VMA has been disabled by a preprocessor macro."); + VMA_ASSERT(0 && "VMA_ALLOCATOR_CREATE_KHR_EXTERNAL_MEMORY_WIN32_BIT is set but required extension is not available in your Vulkan header or its support in VMA has been disabled by a preprocessor macro."); } #endif - memset(&m_DeviceMemoryCallbacks, 0, sizeof(m_DeviceMemoryCallbacks)); + memset(&m_DeviceMemoryCallbacks, 0 ,sizeof(m_DeviceMemoryCallbacks)); memset(&m_PhysicalDeviceProperties, 0, sizeof(m_PhysicalDeviceProperties)); memset(&m_MemProps, 0, sizeof(m_MemProps)); @@ -12960,7 +12971,7 @@ VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) : memset(&m_TypeExternalMemoryHandleTypes, 0, sizeof(m_TypeExternalMemoryHandleTypes)); #endif // #if VMA_EXTERNAL_MEMORY - if (pCreateInfo->pDeviceMemoryCallbacks != VMA_NULL) + if(pCreateInfo->pDeviceMemoryCallbacks != VMA_NULL) { m_DeviceMemoryCallbacks.pUserData = pCreateInfo->pDeviceMemoryCallbacks->pUserData; m_DeviceMemoryCallbacks.pfnAllocate = pCreateInfo->pDeviceMemoryCallbacks->pfnAllocate; @@ -12983,22 +12994,22 @@ VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) : m_GlobalMemoryTypeBits = CalculateGlobalMemoryTypeBits(); #if VMA_EXTERNAL_MEMORY - if (pCreateInfo->pTypeExternalMemoryHandleTypes != VMA_NULL) + if(pCreateInfo->pTypeExternalMemoryHandleTypes != VMA_NULL) { memcpy(m_TypeExternalMemoryHandleTypes, pCreateInfo->pTypeExternalMemoryHandleTypes, sizeof(VkExternalMemoryHandleTypeFlagsKHR) * GetMemoryTypeCount()); } #endif // #if VMA_EXTERNAL_MEMORY - if (pCreateInfo->pHeapSizeLimit != VMA_NULL) + if(pCreateInfo->pHeapSizeLimit != VMA_NULL) { - for (uint32_t heapIndex = 0; heapIndex < GetMemoryHeapCount(); ++heapIndex) + for(uint32_t heapIndex = 0; heapIndex < GetMemoryHeapCount(); ++heapIndex) { const VkDeviceSize limit = pCreateInfo->pHeapSizeLimit[heapIndex]; - if (limit != VK_WHOLE_SIZE) + if(limit != VK_WHOLE_SIZE) { m_HeapSizeLimitMask |= 1u << heapIndex; - if (limit < m_MemProps.memoryHeaps[heapIndex].size) + if(limit < m_MemProps.memoryHeaps[heapIndex].size) { m_MemProps.memoryHeaps[heapIndex].size = limit; } @@ -13006,10 +13017,10 @@ VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) : } } - for (uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) + for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) { // Create only supported types - if ((m_GlobalMemoryTypeBits & (1u << memTypeIndex)) != 0) + if((m_GlobalMemoryTypeBits & (1u << memTypeIndex)) != 0) { const VkDeviceSize preferredBlockSize = CalcPreferredBlockSize(memTypeIndex); m_pBlockVectors[memTypeIndex] = vma_new(this, VmaBlockVector)( @@ -13029,14 +13040,14 @@ VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) : // because minBlockCount is 0. } } - } +} VkResult VmaAllocator_T::Init(const VmaAllocatorCreateInfo* pCreateInfo) { VkResult res = VK_SUCCESS; #if VMA_MEMORY_BUDGET - if (m_UseExtMemoryBudget) + if(m_UseExtMemoryBudget) { UpdateVulkanBudget(); } @@ -13049,7 +13060,7 @@ VmaAllocator_T::~VmaAllocator_T() { VMA_ASSERT(m_Pools.IsEmpty()); - for (size_t memTypeIndex = GetMemoryTypeCount(); memTypeIndex--; ) + for(size_t memTypeIndex = GetMemoryTypeCount(); memTypeIndex--; ) { vma_delete(this, m_pBlockVectors[memTypeIndex]); } @@ -13061,7 +13072,7 @@ void VmaAllocator_T::ImportVulkanFunctions(const VmaVulkanFunctions* pVulkanFunc ImportVulkanFunctions_Static(); #endif - if (pVulkanFunctions != VMA_NULL) + if(pVulkanFunctions != VMA_NULL) { ImportVulkanFunctions_Custom(pVulkanFunctions); } @@ -13100,7 +13111,7 @@ void VmaAllocator_T::ImportVulkanFunctions_Static() // Vulkan 1.1 #if VMA_VULKAN_VERSION >= 1001000 - if (m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) { m_VulkanFunctions.vkGetBufferMemoryRequirements2KHR = (PFN_vkGetBufferMemoryRequirements2)vkGetBufferMemoryRequirements2; m_VulkanFunctions.vkGetImageMemoryRequirements2KHR = (PFN_vkGetImageMemoryRequirements2)vkGetImageMemoryRequirements2; @@ -13110,20 +13121,20 @@ void VmaAllocator_T::ImportVulkanFunctions_Static() #endif #if VMA_VULKAN_VERSION >= 1001000 - if (m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) { m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties2KHR = (PFN_vkGetPhysicalDeviceMemoryProperties2)vkGetPhysicalDeviceMemoryProperties2; } #endif #if VMA_VULKAN_VERSION >= 1003000 - if (m_VulkanApiVersion >= VK_MAKE_VERSION(1, 3, 0)) + if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 3, 0)) { m_VulkanFunctions.vkGetDeviceBufferMemoryRequirements = (PFN_vkGetDeviceBufferMemoryRequirements)vkGetDeviceBufferMemoryRequirements; m_VulkanFunctions.vkGetDeviceImageMemoryRequirements = (PFN_vkGetDeviceImageMemoryRequirements)vkGetDeviceImageMemoryRequirements; } #endif -#ifdef VK_USE_PLATFORM_WIN32_KHR +#if VMA_EXTERNAL_MEMORY_WIN32 m_VulkanFunctions.vkGetMemoryWin32HandleKHR = (PFN_vkGetMemoryWin32HandleKHR)vkGetMemoryWin32HandleKHR; #else m_VulkanFunctions.vkGetMemoryWin32HandleKHR = VMA_NULL; @@ -13177,7 +13188,7 @@ void VmaAllocator_T::ImportVulkanFunctions_Custom(const VmaVulkanFunctions* pVul VMA_COPY_IF_NOT_NULL(vkGetDeviceBufferMemoryRequirements); VMA_COPY_IF_NOT_NULL(vkGetDeviceImageMemoryRequirements); #endif -#ifdef VK_USE_PLATFORM_WIN32_KHR +#if VMA_EXTERNAL_MEMORY_WIN32 VMA_COPY_IF_NOT_NULL(vkGetMemoryWin32HandleKHR); #endif #undef VMA_COPY_IF_NOT_NULL @@ -13220,7 +13231,7 @@ void VmaAllocator_T::ImportVulkanFunctions_Dynamic() VMA_FETCH_DEVICE_FUNC(vkCmdCopyBuffer, PFN_vkCmdCopyBuffer, "vkCmdCopyBuffer"); #if VMA_VULKAN_VERSION >= 1001000 - if (m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) { VMA_FETCH_DEVICE_FUNC(vkGetBufferMemoryRequirements2KHR, PFN_vkGetBufferMemoryRequirements2, "vkGetBufferMemoryRequirements2"); VMA_FETCH_DEVICE_FUNC(vkGetImageMemoryRequirements2KHR, PFN_vkGetImageMemoryRequirements2, "vkGetImageMemoryRequirements2"); @@ -13230,18 +13241,18 @@ void VmaAllocator_T::ImportVulkanFunctions_Dynamic() #endif #if VMA_MEMORY_BUDGET || VMA_VULKAN_VERSION >= 1001000 - if (m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) { VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, PFN_vkGetPhysicalDeviceMemoryProperties2KHR, "vkGetPhysicalDeviceMemoryProperties2"); } - else if (m_UseExtMemoryBudget) + else if(m_UseExtMemoryBudget) { VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, PFN_vkGetPhysicalDeviceMemoryProperties2KHR, "vkGetPhysicalDeviceMemoryProperties2KHR"); } #endif #if VMA_DEDICATED_ALLOCATION - if (m_UseKhrDedicatedAllocation) + if(m_UseKhrDedicatedAllocation) { VMA_FETCH_DEVICE_FUNC(vkGetBufferMemoryRequirements2KHR, PFN_vkGetBufferMemoryRequirements2KHR, "vkGetBufferMemoryRequirements2KHR"); VMA_FETCH_DEVICE_FUNC(vkGetImageMemoryRequirements2KHR, PFN_vkGetImageMemoryRequirements2KHR, "vkGetImageMemoryRequirements2KHR"); @@ -13249,7 +13260,7 @@ void VmaAllocator_T::ImportVulkanFunctions_Dynamic() #endif #if VMA_BIND_MEMORY2 - if (m_UseKhrBindMemory2) + if(m_UseKhrBindMemory2) { VMA_FETCH_DEVICE_FUNC(vkBindBufferMemory2KHR, PFN_vkBindBufferMemory2KHR, "vkBindBufferMemory2KHR"); VMA_FETCH_DEVICE_FUNC(vkBindImageMemory2KHR, PFN_vkBindImageMemory2KHR, "vkBindImageMemory2KHR"); @@ -13257,31 +13268,31 @@ void VmaAllocator_T::ImportVulkanFunctions_Dynamic() #endif // #if VMA_BIND_MEMORY2 #if VMA_MEMORY_BUDGET || VMA_VULKAN_VERSION >= 1001000 - if (m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) { VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, PFN_vkGetPhysicalDeviceMemoryProperties2KHR, "vkGetPhysicalDeviceMemoryProperties2"); } - else if (m_UseExtMemoryBudget) + else if(m_UseExtMemoryBudget) { VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, PFN_vkGetPhysicalDeviceMemoryProperties2KHR, "vkGetPhysicalDeviceMemoryProperties2KHR"); } #endif // #if VMA_MEMORY_BUDGET #if VMA_VULKAN_VERSION >= 1003000 - if (m_VulkanApiVersion >= VK_MAKE_VERSION(1, 3, 0)) + if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 3, 0)) { VMA_FETCH_DEVICE_FUNC(vkGetDeviceBufferMemoryRequirements, PFN_vkGetDeviceBufferMemoryRequirements, "vkGetDeviceBufferMemoryRequirements"); VMA_FETCH_DEVICE_FUNC(vkGetDeviceImageMemoryRequirements, PFN_vkGetDeviceImageMemoryRequirements, "vkGetDeviceImageMemoryRequirements"); } #endif #if VMA_KHR_MAINTENANCE4 - if (m_UseKhrMaintenance4) + if(m_UseKhrMaintenance4) { VMA_FETCH_DEVICE_FUNC(vkGetDeviceBufferMemoryRequirements, PFN_vkGetDeviceBufferMemoryRequirementsKHR, "vkGetDeviceBufferMemoryRequirementsKHR"); VMA_FETCH_DEVICE_FUNC(vkGetDeviceImageMemoryRequirements, PFN_vkGetDeviceImageMemoryRequirementsKHR, "vkGetDeviceImageMemoryRequirementsKHR"); } #endif -#ifdef VK_USE_PLATFORM_WIN32_KHR +#if VMA_EXTERNAL_MEMORY_WIN32 if (m_UseKhrExternalMemoryWin32) { VMA_FETCH_DEVICE_FUNC(vkGetMemoryWin32HandleKHR, PFN_vkGetMemoryWin32HandleKHR, "vkGetMemoryWin32HandleKHR"); @@ -13314,7 +13325,7 @@ void VmaAllocator_T::ValidateVulkanFunctions() VMA_ASSERT(m_VulkanFunctions.vkCmdCopyBuffer != VMA_NULL); #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 - if (m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0) || m_UseKhrDedicatedAllocation) + if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0) || m_UseKhrDedicatedAllocation) { VMA_ASSERT(m_VulkanFunctions.vkGetBufferMemoryRequirements2KHR != VMA_NULL); VMA_ASSERT(m_VulkanFunctions.vkGetImageMemoryRequirements2KHR != VMA_NULL); @@ -13322,7 +13333,7 @@ void VmaAllocator_T::ValidateVulkanFunctions() #endif #if VMA_BIND_MEMORY2 || VMA_VULKAN_VERSION >= 1001000 - if (m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0) || m_UseKhrBindMemory2) + if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0) || m_UseKhrBindMemory2) { VMA_ASSERT(m_VulkanFunctions.vkBindBufferMemory2KHR != VMA_NULL); VMA_ASSERT(m_VulkanFunctions.vkBindImageMemory2KHR != VMA_NULL); @@ -13330,12 +13341,12 @@ void VmaAllocator_T::ValidateVulkanFunctions() #endif #if VMA_MEMORY_BUDGET || VMA_VULKAN_VERSION >= 1001000 - if (m_UseExtMemoryBudget || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + if(m_UseExtMemoryBudget || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) { VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties2KHR != VMA_NULL); } #endif -#ifdef VK_USE_PLATFORM_WIN32_KHR +#if VMA_EXTERNAL_MEMORY_WIN32 if (m_UseKhrExternalMemoryWin32) { VMA_ASSERT(m_VulkanFunctions.vkGetMemoryWin32HandleKHR != VMA_NULL); @@ -13383,10 +13394,10 @@ VkResult VmaAllocator_T::AllocateMemoryOfType( memTypeIndex, size, allocationCount); - if (res != VK_SUCCESS) + if(res != VK_SUCCESS) return res; - if ((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0) + if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0) { return AllocateDedicatedMemory( pool, @@ -13414,23 +13425,23 @@ VkResult VmaAllocator_T::AllocateMemoryOfType( (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) == 0 && (pool == VK_NULL_HANDLE || !blockVector.HasExplicitBlockSize()); - if (canAllocateDedicated) + if(canAllocateDedicated) { // Heuristics: Allocate dedicated memory if requested size if greater than half of preferred block size. - if (size > blockVector.GetPreferredBlockSize() / 2) + if(size > blockVector.GetPreferredBlockSize() / 2) { dedicatedPreferred = true; } // Protection against creating each allocation as dedicated when we reach or exceed heap size/budget, // which can quickly deplete maxMemoryAllocationCount: Don't prefer dedicated allocations when above // 3/4 of the maximum allocation count. - if (m_PhysicalDeviceProperties.limits.maxMemoryAllocationCount < UINT32_MAX / 4 && + if(m_PhysicalDeviceProperties.limits.maxMemoryAllocationCount < UINT32_MAX / 4 && m_DeviceMemoryCount.load() > m_PhysicalDeviceProperties.limits.maxMemoryAllocationCount * 3 / 4) { dedicatedPreferred = false; } - if (dedicatedPreferred) + if(dedicatedPreferred) { res = AllocateDedicatedMemory( pool, @@ -13451,7 +13462,7 @@ VkResult VmaAllocator_T::AllocateMemoryOfType( allocationCount, pAllocations, blockVector.GetAllocationNextPtr()); - if (res == VK_SUCCESS) + if(res == VK_SUCCESS) { // Succeeded: AllocateDedicatedMemory function already filled pMemory, nothing more to do here. VMA_DEBUG_LOG(" Allocated as DedicatedMemory"); @@ -13467,11 +13478,11 @@ VkResult VmaAllocator_T::AllocateMemoryOfType( suballocType, allocationCount, pAllocations); - if (res == VK_SUCCESS) + if(res == VK_SUCCESS) return VK_SUCCESS; // Try dedicated memory. - if (canAllocateDedicated && !dedicatedPreferred) + if(canAllocateDedicated && !dedicatedPreferred) { res = AllocateDedicatedMemory( pool, @@ -13492,7 +13503,7 @@ VkResult VmaAllocator_T::AllocateMemoryOfType( allocationCount, pAllocations, blockVector.GetAllocationNextPtr()); - if (res == VK_SUCCESS) + if(res == VK_SUCCESS) { // Succeeded: AllocateDedicatedMemory function already filled pMemory, nothing more to do here. VMA_DEBUG_LOG(" Allocated as DedicatedMemory"); @@ -13533,17 +13544,17 @@ VkResult VmaAllocator_T::AllocateDedicatedMemory( #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 VkMemoryDedicatedAllocateInfoKHR dedicatedAllocInfo = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR }; - if (!canAliasMemory) + if(!canAliasMemory) { - if (m_UseKhrDedicatedAllocation || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + if(m_UseKhrDedicatedAllocation || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) { - if (dedicatedBuffer != VK_NULL_HANDLE) + if(dedicatedBuffer != VK_NULL_HANDLE) { VMA_ASSERT(dedicatedImage == VK_NULL_HANDLE); dedicatedAllocInfo.buffer = dedicatedBuffer; VmaPnextChainPushFront(&allocInfo, &dedicatedAllocInfo); } - else if (dedicatedImage != VK_NULL_HANDLE) + else if(dedicatedImage != VK_NULL_HANDLE) { dedicatedAllocInfo.image = dedicatedImage; VmaPnextChainPushFront(&allocInfo, &dedicatedAllocInfo); @@ -13554,19 +13565,19 @@ VkResult VmaAllocator_T::AllocateDedicatedMemory( #if VMA_BUFFER_DEVICE_ADDRESS VkMemoryAllocateFlagsInfoKHR allocFlagsInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR }; - if (m_UseKhrBufferDeviceAddress) + if(m_UseKhrBufferDeviceAddress) { bool canContainBufferWithDeviceAddress = true; - if (dedicatedBuffer != VK_NULL_HANDLE) + if(dedicatedBuffer != VK_NULL_HANDLE) { canContainBufferWithDeviceAddress = dedicatedBufferImageUsage == VmaBufferImageUsage::UNKNOWN || dedicatedBufferImageUsage.Contains(VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT); } - else if (dedicatedImage != VK_NULL_HANDLE) + else if(dedicatedImage != VK_NULL_HANDLE) { canContainBufferWithDeviceAddress = false; } - if (canContainBufferWithDeviceAddress) + if(canContainBufferWithDeviceAddress) { allocFlagsInfo.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR; VmaPnextChainPushFront(&allocInfo, &allocFlagsInfo); @@ -13576,7 +13587,7 @@ VkResult VmaAllocator_T::AllocateDedicatedMemory( #if VMA_MEMORY_PRIORITY VkMemoryPriorityAllocateInfoEXT priorityInfo = { VK_STRUCTURE_TYPE_MEMORY_PRIORITY_ALLOCATE_INFO_EXT }; - if (m_UseExtMemoryPriority) + if(m_UseExtMemoryPriority) { VMA_ASSERT(priority >= 0.f && priority <= 1.f); priorityInfo.priority = priority; @@ -13588,7 +13599,7 @@ VkResult VmaAllocator_T::AllocateDedicatedMemory( // Attach VkExportMemoryAllocateInfoKHR if necessary. VkExportMemoryAllocateInfoKHR exportMemoryAllocInfo = { VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR }; exportMemoryAllocInfo.handleTypes = GetExternalMemoryHandleTypeFlags(memTypeIndex); - if (exportMemoryAllocInfo.handleTypes != 0) + if(exportMemoryAllocInfo.handleTypes != 0) { VmaPnextChainPushFront(&allocInfo, &exportMemoryAllocInfo); } @@ -13596,7 +13607,7 @@ VkResult VmaAllocator_T::AllocateDedicatedMemory( size_t allocIndex; VkResult res = VK_SUCCESS; - for (allocIndex = 0; allocIndex < allocationCount; ++allocIndex) + for(allocIndex = 0; allocIndex < allocationCount; ++allocIndex) { res = AllocateDedicatedMemoryPage( pool, @@ -13609,13 +13620,13 @@ VkResult VmaAllocator_T::AllocateDedicatedMemory( isMappingAllowed, pUserData, pAllocations + allocIndex); - if (res != VK_SUCCESS) + if(res != VK_SUCCESS) { break; } } - if (res == VK_SUCCESS) + if(res == VK_SUCCESS) { for (allocIndex = 0; allocIndex < allocationCount; ++allocIndex) { @@ -13626,7 +13637,7 @@ VkResult VmaAllocator_T::AllocateDedicatedMemory( else { // Free all already created allocations. - while (allocIndex--) + while(allocIndex--) { VmaAllocation currAlloc = pAllocations[allocIndex]; VkDeviceMemory hMemory = currAlloc->GetMemory(); @@ -13666,14 +13677,14 @@ VkResult VmaAllocator_T::AllocateDedicatedMemoryPage( { VkDeviceMemory hMemory = VK_NULL_HANDLE; VkResult res = AllocateVulkanMemory(&allocInfo, &hMemory); - if (res < 0) + if(res < 0) { VMA_DEBUG_LOG(" vkAllocateMemory FAILED"); return res; } void* pMappedData = VMA_NULL; - if (map) + if(map) { res = (*m_VulkanFunctions.vkMapMemory)( m_hDevice, @@ -13682,7 +13693,7 @@ VkResult VmaAllocator_T::AllocateDedicatedMemoryPage( VK_WHOLE_SIZE, 0, &pMappedData); - if (res < 0) + if(res < 0) { VMA_DEBUG_LOG(" vkMapMemory FAILED"); FreeVulkanMemory(memTypeIndex, size, hMemory); @@ -13697,7 +13708,7 @@ VkResult VmaAllocator_T::AllocateDedicatedMemoryPage( else (*pAllocation)->SetUserData(this, pUserData); m_Budget.AddAllocation(MemoryTypeIndexToHeapIndex(memTypeIndex), size); - if (VMA_DEBUG_INITIALIZE_ALLOCATIONS) + if(VMA_DEBUG_INITIALIZE_ALLOCATIONS) { FillAllocation(*pAllocation, VMA_ALLOCATION_FILL_PATTERN_CREATED); } @@ -13712,7 +13723,7 @@ void VmaAllocator_T::GetBufferMemoryRequirements( bool& prefersDedicatedAllocation) const { #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 - if (m_UseKhrDedicatedAllocation || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + if(m_UseKhrDedicatedAllocation || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) { VkBufferMemoryRequirementsInfo2KHR memReqInfo = { VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2_KHR }; memReqInfo.buffer = hBuffer; @@ -13726,14 +13737,14 @@ void VmaAllocator_T::GetBufferMemoryRequirements( memReq = memReq2.memoryRequirements; requiresDedicatedAllocation = (memDedicatedReq.requiresDedicatedAllocation != VK_FALSE); - prefersDedicatedAllocation = (memDedicatedReq.prefersDedicatedAllocation != VK_FALSE); + prefersDedicatedAllocation = (memDedicatedReq.prefersDedicatedAllocation != VK_FALSE); } else #endif // #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 { (*m_VulkanFunctions.vkGetBufferMemoryRequirements)(m_hDevice, hBuffer, &memReq); requiresDedicatedAllocation = false; - prefersDedicatedAllocation = false; + prefersDedicatedAllocation = false; } } @@ -13744,7 +13755,7 @@ void VmaAllocator_T::GetImageMemoryRequirements( bool& prefersDedicatedAllocation) const { #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 - if (m_UseKhrDedicatedAllocation || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + if(m_UseKhrDedicatedAllocation || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) { VkImageMemoryRequirementsInfo2KHR memReqInfo = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR }; memReqInfo.image = hImage; @@ -13758,14 +13769,14 @@ void VmaAllocator_T::GetImageMemoryRequirements( memReq = memReq2.memoryRequirements; requiresDedicatedAllocation = (memDedicatedReq.requiresDedicatedAllocation != VK_FALSE); - prefersDedicatedAllocation = (memDedicatedReq.prefersDedicatedAllocation != VK_FALSE); + prefersDedicatedAllocation = (memDedicatedReq.prefersDedicatedAllocation != VK_FALSE); } else #endif // #if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000 { (*m_VulkanFunctions.vkGetImageMemoryRequirements)(m_hDevice, hImage, &memReq); requiresDedicatedAllocation = false; - prefersDedicatedAllocation = false; + prefersDedicatedAllocation = false; } } @@ -13777,13 +13788,13 @@ VkResult VmaAllocator_T::FindMemoryTypeIndex( { memoryTypeBits &= GetGlobalMemoryTypeBits(); - if (pAllocationCreateInfo->memoryTypeBits != 0) + if(pAllocationCreateInfo->memoryTypeBits != 0) { memoryTypeBits &= pAllocationCreateInfo->memoryTypeBits; } VkMemoryPropertyFlags requiredFlags = 0, preferredFlags = 0, notPreferredFlags = 0; - if (!FindMemoryPreferences( + if(!FindMemoryPreferences( IsIntegratedGpu(), *pAllocationCreateInfo, bufImgUsage, @@ -13794,26 +13805,26 @@ VkResult VmaAllocator_T::FindMemoryTypeIndex( *pMemoryTypeIndex = UINT32_MAX; uint32_t minCost = UINT32_MAX; - for (uint32_t memTypeIndex = 0, memTypeBit = 1; + for(uint32_t memTypeIndex = 0, memTypeBit = 1; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex, memTypeBit <<= 1) { // This memory type is acceptable according to memoryTypeBits bitmask. - if ((memTypeBit & memoryTypeBits) != 0) + if((memTypeBit & memoryTypeBits) != 0) { const VkMemoryPropertyFlags currFlags = m_MemProps.memoryTypes[memTypeIndex].propertyFlags; // This memory type contains requiredFlags. - if ((requiredFlags & ~currFlags) == 0) + if((requiredFlags & ~currFlags) == 0) { // Calculate cost as number of bits from preferredFlags not present in this memory type. uint32_t currCost = VMA_COUNT_BITS_SET(preferredFlags & ~currFlags) + VMA_COUNT_BITS_SET(currFlags & notPreferredFlags); // Remember memory type with lowest cost. - if (currCost < minCost) + if(currCost < minCost) { *pMemoryTypeIndex = memTypeIndex; - if (currCost == 0) + if(currCost == 0) { return VK_SUCCESS; } @@ -13832,19 +13843,19 @@ VkResult VmaAllocator_T::CalcMemTypeParams( size_t allocationCount) { // If memory type is not HOST_VISIBLE, disable MAPPED. - if ((inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0 && + if((inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0 && (m_MemProps.memoryTypes[memTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) { inoutCreateInfo.flags &= ~VMA_ALLOCATION_CREATE_MAPPED_BIT; } - if ((inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0 && + if((inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0 && (inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT) != 0) { const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex); VmaBudget heapBudget = {}; GetHeapBudgets(&heapBudget, heapIndex, 1); - if (heapBudget.usage + size * allocationCount > heapBudget.budget) + if(heapBudget.usage + size * allocationCount > heapBudget.budget) { return VK_ERROR_OUT_OF_DEVICE_MEMORY; } @@ -13864,9 +13875,9 @@ VkResult VmaAllocator_T::CalcAllocationParams( VMA_ASSERT((((inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT) == 0 || (inoutCreateInfo.flags & (VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT)) != 0)) && "Specifying VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT requires also VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT."); - if (inoutCreateInfo.usage == VMA_MEMORY_USAGE_AUTO || inoutCreateInfo.usage == VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE || inoutCreateInfo.usage == VMA_MEMORY_USAGE_AUTO_PREFER_HOST) + if(inoutCreateInfo.usage == VMA_MEMORY_USAGE_AUTO || inoutCreateInfo.usage == VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE || inoutCreateInfo.usage == VMA_MEMORY_USAGE_AUTO_PREFER_HOST) { - if ((inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0) + if((inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0) { VMA_ASSERT((inoutCreateInfo.flags & (VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT)) != 0 && "When using VMA_ALLOCATION_CREATE_MAPPED_BIT and usage = VMA_MEMORY_USAGE_AUTO*, you must also specify VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT or VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT."); @@ -13874,15 +13885,15 @@ VkResult VmaAllocator_T::CalcAllocationParams( } // If memory is lazily allocated, it should be always dedicated. - if (dedicatedRequired || + if(dedicatedRequired || inoutCreateInfo.usage == VMA_MEMORY_USAGE_GPU_LAZILY_ALLOCATED) { inoutCreateInfo.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; } - if (inoutCreateInfo.pool != VK_NULL_HANDLE) + if(inoutCreateInfo.pool != VK_NULL_HANDLE) { - if (inoutCreateInfo.pool->m_BlockVector.HasExplicitBlockSize() && + if(inoutCreateInfo.pool->m_BlockVector.HasExplicitBlockSize() && (inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0) { VMA_ASSERT(0 && "Specifying VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT while current custom pool doesn't support dedicated allocations."); @@ -13891,14 +13902,14 @@ VkResult VmaAllocator_T::CalcAllocationParams( inoutCreateInfo.priority = inoutCreateInfo.pool->m_BlockVector.GetPriority(); } - if ((inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0 && + if((inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0 && (inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0) { VMA_ASSERT(0 && "Specifying VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT together with VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT makes no sense."); return VK_ERROR_FEATURE_NOT_PRESENT; } - if (VMA_DEBUG_ALWAYS_DEDICATED_MEMORY && + if(VMA_DEBUG_ALWAYS_DEDICATED_MEMORY && (inoutCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0) { inoutCreateInfo.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; @@ -13908,11 +13919,11 @@ VkResult VmaAllocator_T::CalcAllocationParams( // And so does VMA_MEMORY_USAGE_UNKNOWN because it is used with custom pools. // Which specific flag is used doesn't matter. They change things only when used with VMA_MEMORY_USAGE_AUTO*. // Otherwise they just protect from assert on mapping. - if (inoutCreateInfo.usage != VMA_MEMORY_USAGE_AUTO && + if(inoutCreateInfo.usage != VMA_MEMORY_USAGE_AUTO && inoutCreateInfo.usage != VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE && inoutCreateInfo.usage != VMA_MEMORY_USAGE_AUTO_PREFER_HOST) { - if ((inoutCreateInfo.flags & (VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT)) == 0) + if((inoutCreateInfo.flags & (VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT)) == 0) { inoutCreateInfo.flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT; } @@ -13937,17 +13948,17 @@ VkResult VmaAllocator_T::AllocateMemory( VMA_ASSERT(VmaIsPow2(vkMemReq.alignment)); - if (vkMemReq.size == 0) + if(vkMemReq.size == 0) { return VK_ERROR_INITIALIZATION_FAILED; } VmaAllocationCreateInfo createInfoFinal = createInfo; VkResult res = CalcAllocationParams(createInfoFinal, requiresDedicatedAllocation, prefersDedicatedAllocation); - if (res != VK_SUCCESS) + if(res != VK_SUCCESS) return res; - if (createInfoFinal.pool != VK_NULL_HANDLE) + if(createInfoFinal.pool != VK_NULL_HANDLE) { VmaBlockVector& blockVector = createInfoFinal.pool->m_BlockVector; return AllocateMemoryOfType( @@ -13973,7 +13984,7 @@ VkResult VmaAllocator_T::AllocateMemory( uint32_t memTypeIndex = UINT32_MAX; res = FindMemoryTypeIndex(memoryTypeBits, &createInfoFinal, dedicatedBufferImageUsage, &memTypeIndex); // Can't find any single memory type matching requirements. res is VK_ERROR_FEATURE_NOT_PRESENT. - if (res != VK_SUCCESS) + if(res != VK_SUCCESS) return res; do { @@ -13995,14 +14006,14 @@ VkResult VmaAllocator_T::AllocateMemory( allocationCount, pAllocations); // Allocation succeeded - if (res == VK_SUCCESS) + if(res == VK_SUCCESS) return VK_SUCCESS; // Remove old memTypeIndex from list of possibilities. memoryTypeBits &= ~(1u << memTypeIndex); // Find alternative memTypeIndex. res = FindMemoryTypeIndex(memoryTypeBits, &createInfoFinal, dedicatedBufferImageUsage, &memTypeIndex); - } while (res == VK_SUCCESS); + } while(res == VK_SUCCESS); // No other matching memory type index could be found. // Not returning res, which is VK_ERROR_FEATURE_NOT_PRESENT, because we already failed to allocate once. @@ -14016,38 +14027,38 @@ void VmaAllocator_T::FreeMemory( { VMA_ASSERT(pAllocations); - for (size_t allocIndex = allocationCount; allocIndex--; ) + for(size_t allocIndex = allocationCount; allocIndex--; ) { VmaAllocation allocation = pAllocations[allocIndex]; - if (allocation != VK_NULL_HANDLE) + if(allocation != VK_NULL_HANDLE) { - if (VMA_DEBUG_INITIALIZE_ALLOCATIONS) + if(VMA_DEBUG_INITIALIZE_ALLOCATIONS) { FillAllocation(allocation, VMA_ALLOCATION_FILL_PATTERN_DESTROYED); } allocation->FreeName(this); - switch (allocation->GetType()) + switch(allocation->GetType()) { case VmaAllocation_T::ALLOCATION_TYPE_BLOCK: - { - VmaBlockVector* pBlockVector = VMA_NULL; - VmaPool hPool = allocation->GetParentPool(); - if (hPool != VK_NULL_HANDLE) { - pBlockVector = &hPool->m_BlockVector; + VmaBlockVector* pBlockVector = VMA_NULL; + VmaPool hPool = allocation->GetParentPool(); + if(hPool != VK_NULL_HANDLE) + { + pBlockVector = &hPool->m_BlockVector; + } + else + { + const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex(); + pBlockVector = m_pBlockVectors[memTypeIndex]; + VMA_ASSERT(pBlockVector && "Trying to free memory of unsupported type!"); + } + pBlockVector->Free(allocation); } - else - { - const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex(); - pBlockVector = m_pBlockVectors[memTypeIndex]; - VMA_ASSERT(pBlockVector && "Trying to free memory of unsupported type!"); - } - pBlockVector->Free(allocation); - } - break; + break; case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: FreeDedicatedMemory(allocation); break; @@ -14062,13 +14073,13 @@ void VmaAllocator_T::CalculateStatistics(VmaTotalStatistics* pStats) { // Initialize. VmaClearDetailedStatistics(pStats->total); - for (uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; ++i) + for(uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; ++i) VmaClearDetailedStatistics(pStats->memoryType[i]); - for (uint32_t i = 0; i < VK_MAX_MEMORY_HEAPS; ++i) + for(uint32_t i = 0; i < VK_MAX_MEMORY_HEAPS; ++i) VmaClearDetailedStatistics(pStats->memoryHeap[i]); // Process default pools. - for (uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) + for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) { VmaBlockVector* const pBlockVector = m_pBlockVectors[memTypeIndex]; if (pBlockVector != VMA_NULL) @@ -14078,7 +14089,7 @@ void VmaAllocator_T::CalculateStatistics(VmaTotalStatistics* pStats) // Process custom pools. { VmaMutexLockRead lock(m_PoolsMutex, m_UseMutex); - for (VmaPool pool = m_Pools.Front(); pool != VMA_NULL; pool = m_Pools.GetNext(pool)) + for(VmaPool pool = m_Pools.Front(); pool != VMA_NULL; pool = m_Pools.GetNext(pool)) { VmaBlockVector& blockVector = pool->m_BlockVector; const uint32_t memTypeIndex = blockVector.GetMemoryTypeIndex(); @@ -14088,20 +14099,20 @@ void VmaAllocator_T::CalculateStatistics(VmaTotalStatistics* pStats) } // Process dedicated allocations. - for (uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) + for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) { m_DedicatedAllocations[memTypeIndex].AddDetailedStatistics(pStats->memoryType[memTypeIndex]); } // Sum from memory types to memory heaps. - for (uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) + for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) { const uint32_t memHeapIndex = m_MemProps.memoryTypes[memTypeIndex].heapIndex; VmaAddDetailedStatistics(pStats->memoryHeap[memHeapIndex], pStats->memoryType[memTypeIndex]); } // Sum from memory heaps to total. - for (uint32_t memHeapIndex = 0; memHeapIndex < GetMemoryHeapCount(); ++memHeapIndex) + for(uint32_t memHeapIndex = 0; memHeapIndex < GetMemoryHeapCount(); ++memHeapIndex) VmaAddDetailedStatistics(pStats->total, pStats->memoryHeap[memHeapIndex]); VMA_ASSERT(pStats->total.statistics.allocationCount == 0 || @@ -14113,12 +14124,12 @@ void VmaAllocator_T::CalculateStatistics(VmaTotalStatistics* pStats) void VmaAllocator_T::GetHeapBudgets(VmaBudget* outBudgets, uint32_t firstHeap, uint32_t heapCount) { #if VMA_MEMORY_BUDGET - if (m_UseExtMemoryBudget) + if(m_UseExtMemoryBudget) { - if (m_Budget.m_OperationsSinceBudgetFetch < 30) + if(m_Budget.m_OperationsSinceBudgetFetch < 30) { VmaMutexLockRead lockRead(m_Budget.m_BudgetMutex, m_UseMutex); - for (uint32_t i = 0; i < heapCount; ++i, ++outBudgets) + for(uint32_t i = 0; i < heapCount; ++i, ++outBudgets) { const uint32_t heapIndex = firstHeap + i; @@ -14127,7 +14138,7 @@ void VmaAllocator_T::GetHeapBudgets(VmaBudget* outBudgets, uint32_t firstHeap, u outBudgets->statistics.blockBytes = m_Budget.m_BlockBytes[heapIndex]; outBudgets->statistics.allocationBytes = m_Budget.m_AllocationBytes[heapIndex]; - if (m_Budget.m_VulkanUsage[heapIndex] + outBudgets->statistics.blockBytes > m_Budget.m_BlockBytesAtBudgetFetch[heapIndex]) + if(m_Budget.m_VulkanUsage[heapIndex] + outBudgets->statistics.blockBytes > m_Budget.m_BlockBytesAtBudgetFetch[heapIndex]) { outBudgets->usage = m_Budget.m_VulkanUsage[heapIndex] + outBudgets->statistics.blockBytes - m_Budget.m_BlockBytesAtBudgetFetch[heapIndex]; @@ -14151,7 +14162,7 @@ void VmaAllocator_T::GetHeapBudgets(VmaBudget* outBudgets, uint32_t firstHeap, u else #endif { - for (uint32_t i = 0; i < heapCount; ++i, ++outBudgets) + for(uint32_t i = 0; i < heapCount; ++i, ++outBudgets) { const uint32_t heapIndex = firstHeap + i; @@ -14203,26 +14214,26 @@ VkResult VmaAllocator_T::CreatePool(const VmaPoolCreateInfo* pCreateInfo, VmaPoo VmaPoolCreateInfo newCreateInfo = *pCreateInfo; // Protection against uninitialized new structure member. If garbage data are left there, this pointer dereference would crash. - if (pCreateInfo->pMemoryAllocateNext) + if(pCreateInfo->pMemoryAllocateNext) { VMA_ASSERT(((const VkBaseInStructure*)pCreateInfo->pMemoryAllocateNext)->sType != 0); } - if (newCreateInfo.maxBlockCount == 0) + if(newCreateInfo.maxBlockCount == 0) { newCreateInfo.maxBlockCount = SIZE_MAX; } - if (newCreateInfo.minBlockCount > newCreateInfo.maxBlockCount) + if(newCreateInfo.minBlockCount > newCreateInfo.maxBlockCount) { return VK_ERROR_INITIALIZATION_FAILED; } // Memory type index out of range or forbidden. - if (pCreateInfo->memoryTypeIndex >= GetMemoryTypeCount() || + if(pCreateInfo->memoryTypeIndex >= GetMemoryTypeCount() || ((1u << pCreateInfo->memoryTypeIndex) & m_GlobalMemoryTypeBits) == 0) { return VK_ERROR_FEATURE_NOT_PRESENT; } - if (newCreateInfo.minAllocationAlignment > 0) + if(newCreateInfo.minAllocationAlignment > 0) { VMA_ASSERT(VmaIsPow2(newCreateInfo.minAllocationAlignment)); } @@ -14232,7 +14243,7 @@ VkResult VmaAllocator_T::CreatePool(const VmaPoolCreateInfo* pCreateInfo, VmaPoo *pPool = vma_new(this, VmaPool_T)(this, newCreateInfo, preferredBlockSize); VkResult res = (*pPool)->m_BlockVector.CreateMinBlocks(); - if (res != VK_SUCCESS) + if(res != VK_SUCCESS) { vma_delete(this, *pPool); *pPool = VMA_NULL; @@ -14279,7 +14290,7 @@ void VmaAllocator_T::SetCurrentFrameIndex(uint32_t frameIndex) m_CurrentFrameIndex.store(frameIndex); #if VMA_MEMORY_BUDGET - if (m_UseExtMemoryBudget) + if(m_UseExtMemoryBudget) { UpdateVulkanBudget(); } @@ -14296,13 +14307,13 @@ VkResult VmaAllocator_T::CheckCorruption(uint32_t memoryTypeBits) VkResult finalRes = VK_ERROR_FEATURE_NOT_PRESENT; // Process default pools. - for (uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) + for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) { VmaBlockVector* const pBlockVector = m_pBlockVectors[memTypeIndex]; - if (pBlockVector != VMA_NULL) + if(pBlockVector != VMA_NULL) { VkResult localRes = pBlockVector->CheckCorruption(); - switch (localRes) + switch(localRes) { case VK_ERROR_FEATURE_NOT_PRESENT: break; @@ -14318,12 +14329,12 @@ VkResult VmaAllocator_T::CheckCorruption(uint32_t memoryTypeBits) // Process custom pools. { VmaMutexLockRead lock(m_PoolsMutex, m_UseMutex); - for (VmaPool pool = m_Pools.Front(); pool != VMA_NULL; pool = m_Pools.GetNext(pool)) + for(VmaPool pool = m_Pools.Front(); pool != VMA_NULL; pool = m_Pools.GetNext(pool)) { - if (((1u << pool->m_BlockVector.GetMemoryTypeIndex()) & memoryTypeBits) != 0) + if(((1u << pool->m_BlockVector.GetMemoryTypeIndex()) & memoryTypeBits) != 0) { VkResult localRes = pool->m_BlockVector.CheckCorruption(); - switch (localRes) + switch(localRes) { case VK_ERROR_FEATURE_NOT_PRESENT: break; @@ -14345,7 +14356,7 @@ VkResult VmaAllocator_T::AllocateVulkanMemory(const VkMemoryAllocateInfo* pAlloc AtomicTransactionalIncrement deviceMemoryCountIncrement; const uint64_t prevDeviceMemoryCount = deviceMemoryCountIncrement.Increment(&m_DeviceMemoryCount); #if VMA_DEBUG_DONT_EXCEED_MAX_MEMORY_ALLOCATION_COUNT - if (prevDeviceMemoryCount >= m_PhysicalDeviceProperties.limits.maxMemoryAllocationCount) + if(prevDeviceMemoryCount >= m_PhysicalDeviceProperties.limits.maxMemoryAllocationCount) { return VK_ERROR_TOO_MANY_OBJECTS; } @@ -14354,22 +14365,22 @@ VkResult VmaAllocator_T::AllocateVulkanMemory(const VkMemoryAllocateInfo* pAlloc const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(pAllocateInfo->memoryTypeIndex); // HeapSizeLimit is in effect for this heap. - if ((m_HeapSizeLimitMask & (1u << heapIndex)) != 0) + if((m_HeapSizeLimitMask & (1u << heapIndex)) != 0) { const VkDeviceSize heapSize = m_MemProps.memoryHeaps[heapIndex].size; VkDeviceSize blockBytes = m_Budget.m_BlockBytes[heapIndex]; - for (;;) + for(;;) { const VkDeviceSize blockBytesAfterAllocation = blockBytes + pAllocateInfo->allocationSize; - if (blockBytesAfterAllocation > heapSize) + if(blockBytesAfterAllocation > heapSize) { return VK_ERROR_OUT_OF_DEVICE_MEMORY; - } - if (m_Budget.m_BlockBytes[heapIndex].compare_exchange_strong(blockBytes, blockBytesAfterAllocation)) + } + if(m_Budget.m_BlockBytes[heapIndex].compare_exchange_strong(blockBytes, blockBytesAfterAllocation)) { break; } -} + } } else { @@ -14380,14 +14391,14 @@ VkResult VmaAllocator_T::AllocateVulkanMemory(const VkMemoryAllocateInfo* pAlloc // VULKAN CALL vkAllocateMemory. VkResult res = (*m_VulkanFunctions.vkAllocateMemory)(m_hDevice, pAllocateInfo, GetAllocationCallbacks(), pMemory); - if (res == VK_SUCCESS) + if(res == VK_SUCCESS) { #if VMA_MEMORY_BUDGET ++m_Budget.m_OperationsSinceBudgetFetch; #endif // Informative callback. - if (m_DeviceMemoryCallbacks.pfnAllocate != VMA_NULL) + if(m_DeviceMemoryCallbacks.pfnAllocate != VMA_NULL) { (*m_DeviceMemoryCallbacks.pfnAllocate)(this, pAllocateInfo->memoryTypeIndex, *pMemory, pAllocateInfo->allocationSize, m_DeviceMemoryCallbacks.pUserData); } @@ -14401,12 +14412,12 @@ VkResult VmaAllocator_T::AllocateVulkanMemory(const VkMemoryAllocateInfo* pAlloc } return res; - } +} void VmaAllocator_T::FreeVulkanMemory(uint32_t memoryType, VkDeviceSize size, VkDeviceMemory hMemory) { // Informative callback. - if (m_DeviceMemoryCallbacks.pfnFree != VMA_NULL) + if(m_DeviceMemoryCallbacks.pfnFree != VMA_NULL) { (*m_DeviceMemoryCallbacks.pfnFree)(this, memoryType, hMemory, size, m_DeviceMemoryCallbacks.pUserData); } @@ -14427,10 +14438,10 @@ VkResult VmaAllocator_T::BindVulkanBuffer( VkBuffer buffer, const void* pNext) { - if (pNext != VMA_NULL) + if(pNext != VMA_NULL) { #if VMA_VULKAN_VERSION >= 1001000 || VMA_BIND_MEMORY2 - if ((m_UseKhrBindMemory2 || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) && + if((m_UseKhrBindMemory2 || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) && m_VulkanFunctions.vkBindBufferMemory2KHR != VMA_NULL) { VkBindBufferMemoryInfoKHR bindBufferMemoryInfo = { VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHR }; @@ -14458,10 +14469,10 @@ VkResult VmaAllocator_T::BindVulkanImage( VkImage image, const void* pNext) { - if (pNext != VMA_NULL) + if(pNext != VMA_NULL) { #if VMA_VULKAN_VERSION >= 1001000 || VMA_BIND_MEMORY2 - if ((m_UseKhrBindMemory2 || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) && + if((m_UseKhrBindMemory2 || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) && m_VulkanFunctions.vkBindImageMemory2KHR != VMA_NULL) { VkBindImageMemoryInfoKHR bindBufferMemoryInfo = { VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHR }; @@ -14485,20 +14496,20 @@ VkResult VmaAllocator_T::BindVulkanImage( VkResult VmaAllocator_T::Map(VmaAllocation hAllocation, void** ppData) { - switch (hAllocation->GetType()) + switch(hAllocation->GetType()) { case VmaAllocation_T::ALLOCATION_TYPE_BLOCK: - { - VmaDeviceMemoryBlock* const pBlock = hAllocation->GetBlock(); - char* pBytes = VMA_NULL; - VkResult res = pBlock->Map(this, 1, (void**)&pBytes); - if (res == VK_SUCCESS) { - *ppData = pBytes + (ptrdiff_t)hAllocation->GetOffset(); - hAllocation->BlockAllocMap(); + VmaDeviceMemoryBlock* const pBlock = hAllocation->GetBlock(); + char *pBytes = VMA_NULL; + VkResult res = pBlock->Map(this, 1, (void**)&pBytes); + if(res == VK_SUCCESS) + { + *ppData = pBytes + (ptrdiff_t)hAllocation->GetOffset(); + hAllocation->BlockAllocMap(); + } + return res; } - return res; - } case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: return hAllocation->DedicatedAllocMap(this, ppData); default: @@ -14509,15 +14520,15 @@ VkResult VmaAllocator_T::Map(VmaAllocation hAllocation, void** ppData) void VmaAllocator_T::Unmap(VmaAllocation hAllocation) { - switch (hAllocation->GetType()) + switch(hAllocation->GetType()) { case VmaAllocation_T::ALLOCATION_TYPE_BLOCK: - { - VmaDeviceMemoryBlock* const pBlock = hAllocation->GetBlock(); - hAllocation->BlockAllocUnmap(); - pBlock->Unmap(this, 1); - } - break; + { + VmaDeviceMemoryBlock* const pBlock = hAllocation->GetBlock(); + hAllocation->BlockAllocUnmap(); + pBlock->Unmap(this, 1); + } + break; case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: hAllocation->DedicatedAllocUnmap(this); break; @@ -14533,7 +14544,7 @@ VkResult VmaAllocator_T::BindBufferMemory( const void* pNext) { VkResult res = VK_ERROR_UNKNOWN_COPY; - switch (hAllocation->GetType()) + switch(hAllocation->GetType()) { case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: res = BindVulkanBuffer(hAllocation->GetMemory(), allocationLocalOffset, hBuffer, pNext); @@ -14558,7 +14569,7 @@ VkResult VmaAllocator_T::BindImageMemory( const void* pNext) { VkResult res = VK_ERROR_UNKNOWN_COPY; - switch (hAllocation->GetType()) + switch(hAllocation->GetType()) { case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: res = BindVulkanImage(hAllocation->GetMemory(), allocationLocalOffset, hImage, pNext); @@ -14584,9 +14595,9 @@ VkResult VmaAllocator_T::FlushOrInvalidateAllocation( VkResult res = VK_SUCCESS; VkMappedMemoryRange memRange = {}; - if (GetFlushOrInvalidateRange(hAllocation, offset, size, memRange)) + if(GetFlushOrInvalidateRange(hAllocation, offset, size, memRange)) { - switch (op) + switch(op) { case VMA_CACHE_FLUSH: res = (*GetVulkanFunctions().vkFlushMappedMemoryRanges)(m_hDevice, 1, &memRange); @@ -14612,22 +14623,22 @@ VkResult VmaAllocator_T::FlushOrInvalidateAllocations( typedef VmaSmallVector RangeVector; RangeVector ranges = RangeVector(RangeAllocator(GetAllocationCallbacks())); - for (uint32_t allocIndex = 0; allocIndex < allocationCount; ++allocIndex) + for(uint32_t allocIndex = 0; allocIndex < allocationCount; ++allocIndex) { const VmaAllocation alloc = allocations[allocIndex]; const VkDeviceSize offset = offsets != VMA_NULL ? offsets[allocIndex] : 0; const VkDeviceSize size = sizes != VMA_NULL ? sizes[allocIndex] : VK_WHOLE_SIZE; VkMappedMemoryRange newRange; - if (GetFlushOrInvalidateRange(alloc, offset, size, newRange)) + if(GetFlushOrInvalidateRange(alloc, offset, size, newRange)) { ranges.push_back(newRange); } } VkResult res = VK_SUCCESS; - if (!ranges.empty()) + if(!ranges.empty()) { - switch (op) + switch(op) { case VMA_CACHE_FLUSH: res = (*GetVulkanFunctions().vkFlushMappedMemoryRanges)(m_hDevice, (uint32_t)ranges.size(), ranges.data()); @@ -14651,7 +14662,7 @@ VkResult VmaAllocator_T::CopyMemoryToAllocation( { void* dstMappedData = VMA_NULL; VkResult res = Map(dstAllocation, &dstMappedData); - if (res == VK_SUCCESS) + if(res == VK_SUCCESS) { memcpy((char*)dstMappedData + dstAllocationLocalOffset, pSrcHostPointer, (size_t)size); Unmap(dstAllocation); @@ -14668,10 +14679,10 @@ VkResult VmaAllocator_T::CopyAllocationToMemory( { void* srcMappedData = VMA_NULL; VkResult res = Map(srcAllocation, &srcMappedData); - if (res == VK_SUCCESS) + if(res == VK_SUCCESS) { res = FlushOrInvalidateAllocation(srcAllocation, srcAllocationLocalOffset, size, VMA_CACHE_INVALIDATE); - if (res == VK_SUCCESS) + if(res == VK_SUCCESS) { memcpy(pDstHostPointer, (const char*)srcMappedData + srcAllocationLocalOffset, (size_t)size); Unmap(srcAllocation); @@ -14686,7 +14697,7 @@ void VmaAllocator_T::FreeDedicatedMemory(const VmaAllocation allocation) const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex(); VmaPool parentPool = allocation->GetParentPool(); - if (parentPool == VK_NULL_HANDLE) + if(parentPool == VK_NULL_HANDLE) { // Default pool m_DedicatedAllocations[memTypeIndex].Unregister(allocation); @@ -14728,7 +14739,7 @@ uint32_t VmaAllocator_T::CalculateGpuDefragmentationMemoryTypeBits() const VkBuffer buf = VK_NULL_HANDLE; VkResult res = (*GetVulkanFunctions().vkCreateBuffer)( m_hDevice, &dummyBufCreateInfo, GetAllocationCallbacks(), &buf); - if (res == VK_SUCCESS) + if(res == VK_SUCCESS) { // Query for supported memory types. VkMemoryRequirements memReq; @@ -14749,12 +14760,12 @@ uint32_t VmaAllocator_T::CalculateGlobalMemoryTypeBits() const uint32_t memoryTypeBits = UINT32_MAX; - if (!m_UseAmdDeviceCoherentMemory) + if(!m_UseAmdDeviceCoherentMemory) { // Exclude memory types that have VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD. - for (uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) + for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex) { - if ((m_MemProps.memoryTypes[memTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY) != 0) + if((m_MemProps.memoryTypes[memTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY) != 0) { memoryTypeBits &= ~(1u << memTypeIndex); } @@ -14770,7 +14781,7 @@ bool VmaAllocator_T::GetFlushOrInvalidateRange( VkMappedMemoryRange& outRange) const { const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex(); - if (size > 0 && IsMemoryTypeNonCoherent(memTypeIndex)) + if(size > 0 && IsMemoryTypeNonCoherent(memTypeIndex)) { const VkDeviceSize nonCoherentAtomSize = m_PhysicalDeviceProperties.limits.nonCoherentAtomSize; const VkDeviceSize allocationSize = allocation->GetSize(); @@ -14780,11 +14791,11 @@ bool VmaAllocator_T::GetFlushOrInvalidateRange( outRange.pNext = VMA_NULL; outRange.memory = allocation->GetMemory(); - switch (allocation->GetType()) + switch(allocation->GetType()) { case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED: outRange.offset = VmaAlignDown(offset, nonCoherentAtomSize); - if (size == VK_WHOLE_SIZE) + if(size == VK_WHOLE_SIZE) { outRange.size = allocationSize - outRange.offset; } @@ -14800,7 +14811,7 @@ bool VmaAllocator_T::GetFlushOrInvalidateRange( { // 1. Still within this allocation. outRange.offset = VmaAlignDown(offset, nonCoherentAtomSize); - if (size == VK_WHOLE_SIZE) + if(size == VK_WHOLE_SIZE) { size = allocationSize - offset; } @@ -14842,22 +14853,22 @@ void VmaAllocator_T::UpdateVulkanBudget() { VmaMutexLockWrite lockWrite(m_Budget.m_BudgetMutex, m_UseMutex); - for (uint32_t heapIndex = 0; heapIndex < GetMemoryHeapCount(); ++heapIndex) + for(uint32_t heapIndex = 0; heapIndex < GetMemoryHeapCount(); ++heapIndex) { m_Budget.m_VulkanUsage[heapIndex] = budgetProps.heapUsage[heapIndex]; m_Budget.m_VulkanBudget[heapIndex] = budgetProps.heapBudget[heapIndex]; m_Budget.m_BlockBytesAtBudgetFetch[heapIndex] = m_Budget.m_BlockBytes[heapIndex].load(); // Some bugged drivers return the budget incorrectly, e.g. 0 or much bigger than heap size. - if (m_Budget.m_VulkanBudget[heapIndex] == 0) + if(m_Budget.m_VulkanBudget[heapIndex] == 0) { m_Budget.m_VulkanBudget[heapIndex] = m_MemProps.memoryHeaps[heapIndex].size * 8 / 10; // 80% heuristics. } - else if (m_Budget.m_VulkanBudget[heapIndex] > m_MemProps.memoryHeaps[heapIndex].size) + else if(m_Budget.m_VulkanBudget[heapIndex] > m_MemProps.memoryHeaps[heapIndex].size) { m_Budget.m_VulkanBudget[heapIndex] = m_MemProps.memoryHeaps[heapIndex].size; } - if (m_Budget.m_VulkanUsage[heapIndex] == 0 && m_Budget.m_BlockBytesAtBudgetFetch[heapIndex] > 0) + if(m_Budget.m_VulkanUsage[heapIndex] == 0 && m_Budget.m_BlockBytesAtBudgetFetch[heapIndex] > 0) { m_Budget.m_VulkanUsage[heapIndex] = m_Budget.m_BlockBytesAtBudgetFetch[heapIndex]; } @@ -14869,13 +14880,13 @@ void VmaAllocator_T::UpdateVulkanBudget() void VmaAllocator_T::FillAllocation(const VmaAllocation hAllocation, uint8_t pattern) { - if (VMA_DEBUG_INITIALIZE_ALLOCATIONS && + if(VMA_DEBUG_INITIALIZE_ALLOCATIONS && hAllocation->IsMappingAllowed() && (m_MemProps.memoryTypes[hAllocation->GetMemoryTypeIndex()].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0) { void* pData = VMA_NULL; VkResult res = Map(hAllocation, &pData); - if (res == VK_SUCCESS) + if(res == VK_SUCCESS) { memset(pData, (int)pattern, (size_t)hAllocation->GetSize()); FlushOrInvalidateAllocation(hAllocation, 0, VK_WHOLE_SIZE, VMA_CACHE_FLUSH); @@ -14891,7 +14902,7 @@ void VmaAllocator_T::FillAllocation(const VmaAllocation hAllocation, uint8_t pat uint32_t VmaAllocator_T::GetGpuDefragmentationMemoryTypeBits() { uint32_t memoryTypeBits = m_GpuDefragmentationMemoryTypeBits.load(); - if (memoryTypeBits == UINT32_MAX) + if(memoryTypeBits == UINT32_MAX) { memoryTypeBits = CalculateGpuDefragmentationMemoryTypeBits(); m_GpuDefragmentationMemoryTypeBits.store(memoryTypeBits); @@ -15002,7 +15013,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAllocator( VMA_DEBUG_LOG("vmaCreateAllocator"); *pAllocator = vma_new(pCreateInfo->pAllocationCallbacks, VmaAllocator_T)(pCreateInfo); VkResult result = (*pAllocator)->Init(pCreateInfo); - if (result < 0) + if(result < 0) { vma_delete(pCreateInfo->pAllocationCallbacks, *pAllocator); *pAllocator = VK_NULL_HANDLE; @@ -15013,7 +15024,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAllocator( VMA_CALL_PRE void VMA_CALL_POST vmaDestroyAllocator( VmaAllocator allocator) { - if (allocator != VK_NULL_HANDLE) + if(allocator != VK_NULL_HANDLE) { VMA_DEBUG_LOG("vmaDestroyAllocator"); VkAllocationCallbacks allocationCallbacks = allocator->m_AllocationCallbacks; // Have to copy the callbacks when destroying. @@ -15031,7 +15042,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocatorInfo(VmaAllocator allocator, VmaA VMA_CALL_PRE void VMA_CALL_POST vmaGetPhysicalDeviceProperties( VmaAllocator allocator, - const VkPhysicalDeviceProperties** ppPhysicalDeviceProperties) + const VkPhysicalDeviceProperties **ppPhysicalDeviceProperties) { VMA_ASSERT(allocator && ppPhysicalDeviceProperties); *ppPhysicalDeviceProperties = &allocator->m_PhysicalDeviceProperties; @@ -15063,7 +15074,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaSetCurrentFrameIndex( VMA_DEBUG_GLOBAL_MUTEX_LOCK - allocator->SetCurrentFrameIndex(frameIndex); + allocator->SetCurrentFrameIndex(frameIndex); } VMA_CALL_PRE void VMA_CALL_POST vmaCalculateStatistics( @@ -15072,7 +15083,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaCalculateStatistics( { VMA_ASSERT(allocator && pStats); VMA_DEBUG_GLOBAL_MUTEX_LOCK - allocator->CalculateStatistics(pStats); + allocator->CalculateStatistics(pStats); } VMA_CALL_PRE void VMA_CALL_POST vmaGetHeapBudgets( @@ -15081,7 +15092,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaGetHeapBudgets( { VMA_ASSERT(allocator && pBudgets); VMA_DEBUG_GLOBAL_MUTEX_LOCK - allocator->GetHeapBudgets(pBudgets, 0, allocator->GetMemoryHeapCount()); + allocator->GetHeapBudgets(pBudgets, 0, allocator->GetMemoryHeapCount()); } #if VMA_STATS_STRING_ENABLED @@ -15094,7 +15105,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaBuildStatsString( VMA_ASSERT(allocator && ppStatsString); VMA_DEBUG_GLOBAL_MUTEX_LOCK - VmaStringBuilder sb(allocator->GetAllocationCallbacks()); + VmaStringBuilder sb(allocator->GetAllocationCallbacks()); { VmaBudget budgets[VK_MAX_MEMORY_HEAPS]; allocator->GetHeapBudgets(budgets, 0, allocator->GetMemoryHeapCount()); @@ -15163,16 +15174,16 @@ VMA_CALL_PRE void VMA_CALL_POST vmaBuildStatsString( { if (heapInfo.flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) json.WriteString("DEVICE_LOCAL"); -#if VMA_VULKAN_VERSION >= 1001000 + #if VMA_VULKAN_VERSION >= 1001000 if (heapInfo.flags & VK_MEMORY_HEAP_MULTI_INSTANCE_BIT) json.WriteString("MULTI_INSTANCE"); -#endif + #endif VkMemoryHeapFlags flags = heapInfo.flags & ~(VK_MEMORY_HEAP_DEVICE_LOCAL_BIT -#if VMA_VULKAN_VERSION >= 1001000 + #if VMA_VULKAN_VERSION >= 1001000 | VK_MEMORY_HEAP_MULTI_INSTANCE_BIT -#endif + #endif ); if (flags != 0) json.WriteNumber(flags); @@ -15221,25 +15232,25 @@ VMA_CALL_PRE void VMA_CALL_POST vmaBuildStatsString( json.WriteString("HOST_CACHED"); if (flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) json.WriteString("LAZILY_ALLOCATED"); -#if VMA_VULKAN_VERSION >= 1001000 + #if VMA_VULKAN_VERSION >= 1001000 if (flags & VK_MEMORY_PROPERTY_PROTECTED_BIT) json.WriteString("PROTECTED"); -#endif -#if VK_AMD_device_coherent_memory + #endif + #if VK_AMD_device_coherent_memory if (flags & VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY) json.WriteString("DEVICE_COHERENT_AMD"); if (flags & VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD_COPY) json.WriteString("DEVICE_UNCACHED_AMD"); -#endif + #endif flags &= ~(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT -#if VMA_VULKAN_VERSION >= 1001000 + #if VMA_VULKAN_VERSION >= 1001000 | VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT -#endif -#if VK_AMD_device_coherent_memory + #endif + #if VK_AMD_device_coherent_memory | VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD_COPY | VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD_COPY -#endif + #endif | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT); @@ -15277,7 +15288,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaFreeStatsString( VmaAllocator allocator, char* pStatsString) { - if (pStatsString != VMA_NULL) + if(pStatsString != VMA_NULL) { VMA_ASSERT(allocator); VmaFreeString(allocator->GetAllocationCallbacks(), pStatsString); @@ -15318,13 +15329,13 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForBufferInfo( VkResult res; #if VMA_KHR_MAINTENANCE4 || VMA_VULKAN_VERSION >= 1003000 - if (funcs->vkGetDeviceBufferMemoryRequirements) + if(funcs->vkGetDeviceBufferMemoryRequirements) { // Can query straight from VkBufferCreateInfo :) - VkDeviceBufferMemoryRequirementsKHR devBufMemReq = { VK_STRUCTURE_TYPE_DEVICE_BUFFER_MEMORY_REQUIREMENTS_KHR }; + VkDeviceBufferMemoryRequirementsKHR devBufMemReq = {VK_STRUCTURE_TYPE_DEVICE_BUFFER_MEMORY_REQUIREMENTS_KHR}; devBufMemReq.pCreateInfo = pBufferCreateInfo; - VkMemoryRequirements2 memReq = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2 }; + VkMemoryRequirements2 memReq = {VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2}; (*funcs->vkGetDeviceBufferMemoryRequirements)(hDev, &devBufMemReq, &memReq); res = allocator->FindMemoryTypeIndex( @@ -15338,7 +15349,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForBufferInfo( VkBuffer hBuffer = VK_NULL_HANDLE; res = funcs->vkCreateBuffer( hDev, pBufferCreateInfo, allocator->GetAllocationCallbacks(), &hBuffer); - if (res == VK_SUCCESS) + if(res == VK_SUCCESS) { VkMemoryRequirements memReq = {}; funcs->vkGetBufferMemoryRequirements(hDev, hBuffer, &memReq); @@ -15370,15 +15381,15 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForImageInfo( VkResult res; #if VMA_KHR_MAINTENANCE4 || VMA_VULKAN_VERSION >= 1003000 - if (funcs->vkGetDeviceImageMemoryRequirements) + if(funcs->vkGetDeviceImageMemoryRequirements) { // Can query straight from VkImageCreateInfo :) - VkDeviceImageMemoryRequirementsKHR devImgMemReq = { VK_STRUCTURE_TYPE_DEVICE_IMAGE_MEMORY_REQUIREMENTS_KHR }; + VkDeviceImageMemoryRequirementsKHR devImgMemReq = {VK_STRUCTURE_TYPE_DEVICE_IMAGE_MEMORY_REQUIREMENTS_KHR}; devImgMemReq.pCreateInfo = pImageCreateInfo; VMA_ASSERT(pImageCreateInfo->tiling != VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT_COPY && (pImageCreateInfo->flags & VK_IMAGE_CREATE_DISJOINT_BIT_COPY) == 0 && "Cannot use this VkImageCreateInfo with vmaFindMemoryTypeIndexForImageInfo as I don't know what to pass as VkDeviceImageMemoryRequirements::planeAspect."); - VkMemoryRequirements2 memReq = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2 }; + VkMemoryRequirements2 memReq = {VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2}; (*funcs->vkGetDeviceImageMemoryRequirements)(hDev, &devImgMemReq, &memReq); res = allocator->FindMemoryTypeIndex( @@ -15392,7 +15403,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaFindMemoryTypeIndexForImageInfo( VkImage hImage = VK_NULL_HANDLE; res = funcs->vkCreateImage( hDev, pImageCreateInfo, allocator->GetAllocationCallbacks(), &hImage); - if (res == VK_SUCCESS) + if(res == VK_SUCCESS) { VkMemoryRequirements memReq = {}; funcs->vkGetImageMemoryRequirements(hDev, hImage, &memReq); @@ -15419,7 +15430,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreatePool( VMA_DEBUG_GLOBAL_MUTEX_LOCK - return allocator->CreatePool(pCreateInfo, pPool); + return allocator->CreatePool(pCreateInfo, pPool); } VMA_CALL_PRE void VMA_CALL_POST vmaDestroyPool( @@ -15428,7 +15439,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaDestroyPool( { VMA_ASSERT(allocator); - if (pool == VK_NULL_HANDLE) + if(pool == VK_NULL_HANDLE) { return; } @@ -15437,7 +15448,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaDestroyPool( VMA_DEBUG_GLOBAL_MUTEX_LOCK - allocator->DestroyPool(pool); + allocator->DestroyPool(pool); } VMA_CALL_PRE void VMA_CALL_POST vmaGetPoolStatistics( @@ -15449,7 +15460,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaGetPoolStatistics( VMA_DEBUG_GLOBAL_MUTEX_LOCK - allocator->GetPoolStatistics(pool, pPoolStats); + allocator->GetPoolStatistics(pool, pPoolStats); } VMA_CALL_PRE void VMA_CALL_POST vmaCalculatePoolStatistics( @@ -15461,7 +15472,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaCalculatePoolStatistics( VMA_DEBUG_GLOBAL_MUTEX_LOCK - allocator->CalculatePoolStatistics(pool, pPoolStats); + allocator->CalculatePoolStatistics(pool, pPoolStats); } VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckPoolCorruption(VmaAllocator allocator, VmaPool pool) @@ -15470,7 +15481,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckPoolCorruption(VmaAllocator allocato VMA_DEBUG_GLOBAL_MUTEX_LOCK - VMA_DEBUG_LOG("vmaCheckPoolCorruption"); + VMA_DEBUG_LOG("vmaCheckPoolCorruption"); return allocator->CheckPoolCorruption(pool); } @@ -15486,7 +15497,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaGetPoolName( VMA_DEBUG_GLOBAL_MUTEX_LOCK - * ppName = pool->GetName(); + *ppName = pool->GetName(); } VMA_CALL_PRE void VMA_CALL_POST vmaSetPoolName( @@ -15500,7 +15511,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaSetPoolName( VMA_DEBUG_GLOBAL_MUTEX_LOCK - pool->SetName(pName); + pool->SetName(pName); } VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemory( @@ -15516,19 +15527,19 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemory( VMA_DEBUG_GLOBAL_MUTEX_LOCK - VkResult result = allocator->AllocateMemory( - *pVkMemoryRequirements, - false, // requiresDedicatedAllocation - false, // prefersDedicatedAllocation - VK_NULL_HANDLE, // dedicatedBuffer - VK_NULL_HANDLE, // dedicatedImage - VmaBufferImageUsage::UNKNOWN, // dedicatedBufferImageUsage - *pCreateInfo, - VMA_SUBALLOCATION_TYPE_UNKNOWN, - 1, // allocationCount - pAllocation); + VkResult result = allocator->AllocateMemory( + *pVkMemoryRequirements, + false, // requiresDedicatedAllocation + false, // prefersDedicatedAllocation + VK_NULL_HANDLE, // dedicatedBuffer + VK_NULL_HANDLE, // dedicatedImage + VmaBufferImageUsage::UNKNOWN, // dedicatedBufferImageUsage + *pCreateInfo, + VMA_SUBALLOCATION_TYPE_UNKNOWN, + 1, // allocationCount + pAllocation); - if (pAllocationInfo != VMA_NULL && result == VK_SUCCESS) + if(pAllocationInfo != VMA_NULL && result == VK_SUCCESS) { allocator->GetAllocationInfo(*pAllocation, pAllocationInfo); } @@ -15544,7 +15555,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryPages( VmaAllocation* pAllocations, VmaAllocationInfo* pAllocationInfo) { - if (allocationCount == 0) + if(allocationCount == 0) { return VK_SUCCESS; } @@ -15555,21 +15566,21 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryPages( VMA_DEBUG_GLOBAL_MUTEX_LOCK - VkResult result = allocator->AllocateMemory( - *pVkMemoryRequirements, - false, // requiresDedicatedAllocation - false, // prefersDedicatedAllocation - VK_NULL_HANDLE, // dedicatedBuffer - VK_NULL_HANDLE, // dedicatedImage - VmaBufferImageUsage::UNKNOWN, // dedicatedBufferImageUsage - *pCreateInfo, - VMA_SUBALLOCATION_TYPE_UNKNOWN, - allocationCount, - pAllocations); + VkResult result = allocator->AllocateMemory( + *pVkMemoryRequirements, + false, // requiresDedicatedAllocation + false, // prefersDedicatedAllocation + VK_NULL_HANDLE, // dedicatedBuffer + VK_NULL_HANDLE, // dedicatedImage + VmaBufferImageUsage::UNKNOWN, // dedicatedBufferImageUsage + *pCreateInfo, + VMA_SUBALLOCATION_TYPE_UNKNOWN, + allocationCount, + pAllocations); - if (pAllocationInfo != VMA_NULL && result == VK_SUCCESS) + if(pAllocationInfo != VMA_NULL && result == VK_SUCCESS) { - for (size_t i = 0; i < allocationCount; ++i) + for(size_t i = 0; i < allocationCount; ++i) { allocator->GetAllocationInfo(pAllocations[i], pAllocationInfo + i); } @@ -15591,7 +15602,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForBuffer( VMA_DEBUG_GLOBAL_MUTEX_LOCK - VkMemoryRequirements vkMemReq = {}; + VkMemoryRequirements vkMemReq = {}; bool requiresDedicatedAllocation = false; bool prefersDedicatedAllocation = false; allocator->GetBufferMemoryRequirements(buffer, vkMemReq, @@ -15610,7 +15621,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForBuffer( 1, // allocationCount pAllocation); - if (pAllocationInfo && result == VK_SUCCESS) + if(pAllocationInfo && result == VK_SUCCESS) { allocator->GetAllocationInfo(*pAllocation, pAllocationInfo); } @@ -15631,9 +15642,9 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForImage( VMA_DEBUG_GLOBAL_MUTEX_LOCK - VkMemoryRequirements vkMemReq = {}; + VkMemoryRequirements vkMemReq = {}; bool requiresDedicatedAllocation = false; - bool prefersDedicatedAllocation = false; + bool prefersDedicatedAllocation = false; allocator->GetImageMemoryRequirements(image, vkMemReq, requiresDedicatedAllocation, prefersDedicatedAllocation); @@ -15649,7 +15660,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateMemoryForImage( 1, // allocationCount pAllocation); - if (pAllocationInfo && result == VK_SUCCESS) + if(pAllocationInfo && result == VK_SUCCESS) { allocator->GetAllocationInfo(*pAllocation, pAllocationInfo); } @@ -15663,7 +15674,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemory( { VMA_ASSERT(allocator); - if (allocation == VK_NULL_HANDLE) + if(allocation == VK_NULL_HANDLE) { return; } @@ -15672,9 +15683,9 @@ VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemory( VMA_DEBUG_GLOBAL_MUTEX_LOCK - allocator->FreeMemory( - 1, // allocationCount - &allocation); + allocator->FreeMemory( + 1, // allocationCount + &allocation); } VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemoryPages( @@ -15682,7 +15693,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemoryPages( size_t allocationCount, const VmaAllocation* pAllocations) { - if (allocationCount == 0) + if(allocationCount == 0) { return; } @@ -15693,7 +15704,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaFreeMemoryPages( VMA_DEBUG_GLOBAL_MUTEX_LOCK - allocator->FreeMemory(allocationCount, pAllocations); + allocator->FreeMemory(allocationCount, pAllocations); } VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationInfo( @@ -15705,7 +15716,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationInfo( VMA_DEBUG_GLOBAL_MUTEX_LOCK - allocator->GetAllocationInfo(allocation, pAllocationInfo); + allocator->GetAllocationInfo(allocation, pAllocationInfo); } VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationInfo2( @@ -15717,7 +15728,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationInfo2( VMA_DEBUG_GLOBAL_MUTEX_LOCK - allocator->GetAllocationInfo2(allocation, pAllocationInfo); + allocator->GetAllocationInfo2(allocation, pAllocationInfo); } VMA_CALL_PRE void VMA_CALL_POST vmaSetAllocationUserData( @@ -15729,7 +15740,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaSetAllocationUserData( VMA_DEBUG_GLOBAL_MUTEX_LOCK - allocation->SetUserData(allocator, pUserData); + allocation->SetUserData(allocator, pUserData); } VMA_CALL_PRE void VMA_CALL_POST vmaSetAllocationName( @@ -15759,7 +15770,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaMapMemory( VMA_DEBUG_GLOBAL_MUTEX_LOCK - return allocator->Map(allocation, ppData); + return allocator->Map(allocation, ppData); } VMA_CALL_PRE void VMA_CALL_POST vmaUnmapMemory( @@ -15770,7 +15781,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaUnmapMemory( VMA_DEBUG_GLOBAL_MUTEX_LOCK - allocator->Unmap(allocation); + allocator->Unmap(allocation); } VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocation( @@ -15785,7 +15796,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocation( VMA_DEBUG_GLOBAL_MUTEX_LOCK - return allocator->FlushOrInvalidateAllocation(allocation, offset, size, VMA_CACHE_FLUSH); + return allocator->FlushOrInvalidateAllocation(allocation, offset, size, VMA_CACHE_FLUSH); } VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocation( @@ -15800,7 +15811,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocation( VMA_DEBUG_GLOBAL_MUTEX_LOCK - return allocator->FlushOrInvalidateAllocation(allocation, offset, size, VMA_CACHE_INVALIDATE); + return allocator->FlushOrInvalidateAllocation(allocation, offset, size, VMA_CACHE_INVALIDATE); } VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocations( @@ -15812,7 +15823,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocations( { VMA_ASSERT(allocator); - if (allocationCount == 0) + if(allocationCount == 0) { return VK_SUCCESS; } @@ -15823,7 +15834,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaFlushAllocations( VMA_DEBUG_GLOBAL_MUTEX_LOCK - return allocator->FlushOrInvalidateAllocations(allocationCount, allocations, offsets, sizes, VMA_CACHE_FLUSH); + return allocator->FlushOrInvalidateAllocations(allocationCount, allocations, offsets, sizes, VMA_CACHE_FLUSH); } VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocations( @@ -15835,7 +15846,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocations( { VMA_ASSERT(allocator); - if (allocationCount == 0) + if(allocationCount == 0) { return VK_SUCCESS; } @@ -15846,7 +15857,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaInvalidateAllocations( VMA_DEBUG_GLOBAL_MUTEX_LOCK - return allocator->FlushOrInvalidateAllocations(allocationCount, allocations, offsets, sizes, VMA_CACHE_INVALIDATE); + return allocator->FlushOrInvalidateAllocations(allocationCount, allocations, offsets, sizes, VMA_CACHE_INVALIDATE); } VMA_CALL_PRE VkResult VMA_CALL_POST vmaCopyMemoryToAllocation( @@ -15858,7 +15869,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCopyMemoryToAllocation( { VMA_ASSERT(allocator && pSrcHostPointer && dstAllocation); - if (size == 0) + if(size == 0) { return VK_SUCCESS; } @@ -15867,7 +15878,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCopyMemoryToAllocation( VMA_DEBUG_GLOBAL_MUTEX_LOCK - return allocator->CopyMemoryToAllocation(pSrcHostPointer, dstAllocation, dstAllocationLocalOffset, size); + return allocator->CopyMemoryToAllocation(pSrcHostPointer, dstAllocation, dstAllocationLocalOffset, size); } VMA_CALL_PRE VkResult VMA_CALL_POST vmaCopyAllocationToMemory( @@ -15879,7 +15890,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCopyAllocationToMemory( { VMA_ASSERT(allocator && srcAllocation && pDstHostPointer); - if (size == 0) + if(size == 0) { return VK_SUCCESS; } @@ -15888,7 +15899,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCopyAllocationToMemory( VMA_DEBUG_GLOBAL_MUTEX_LOCK - return allocator->CopyAllocationToMemory(srcAllocation, srcAllocationLocalOffset, pDstHostPointer, size); + return allocator->CopyAllocationToMemory(srcAllocation, srcAllocationLocalOffset, pDstHostPointer, size); } VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckCorruption( @@ -15901,7 +15912,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCheckCorruption( VMA_DEBUG_GLOBAL_MUTEX_LOCK - return allocator->CheckCorruption(memoryTypeBits); + return allocator->CheckCorruption(memoryTypeBits); } VMA_CALL_PRE VkResult VMA_CALL_POST vmaBeginDefragmentation( @@ -15922,7 +15933,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaBeginDefragmentation( VMA_DEBUG_GLOBAL_MUTEX_LOCK - * pContext = vma_new(allocator, VmaDefragmentationContext_T)(allocator, *pInfo); + *pContext = vma_new(allocator, VmaDefragmentationContext_T)(allocator, *pInfo); return VK_SUCCESS; } @@ -15937,8 +15948,8 @@ VMA_CALL_PRE void VMA_CALL_POST vmaEndDefragmentation( VMA_DEBUG_GLOBAL_MUTEX_LOCK - if (pStats) - context->GetStats(*pStats); + if (pStats) + context->GetStats(*pStats); vma_delete(allocator, context); } @@ -15953,7 +15964,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaBeginDefragmentationPass( VMA_DEBUG_GLOBAL_MUTEX_LOCK - return context->DefragmentPassBegin(*pPassInfo); + return context->DefragmentPassBegin(*pPassInfo); } VMA_CALL_PRE VkResult VMA_CALL_POST vmaEndDefragmentationPass( @@ -15967,7 +15978,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaEndDefragmentationPass( VMA_DEBUG_GLOBAL_MUTEX_LOCK - return context->DefragmentPassEnd(*pPassInfo); + return context->DefragmentPassEnd(*pPassInfo); } VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory( @@ -15981,7 +15992,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory( VMA_DEBUG_GLOBAL_MUTEX_LOCK - return allocator->BindBufferMemory(allocation, 0, buffer, VMA_NULL); + return allocator->BindBufferMemory(allocation, 0, buffer, VMA_NULL); } VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory2( @@ -15997,7 +16008,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindBufferMemory2( VMA_DEBUG_GLOBAL_MUTEX_LOCK - return allocator->BindBufferMemory(allocation, allocationLocalOffset, buffer, pNext); + return allocator->BindBufferMemory(allocation, allocationLocalOffset, buffer, pNext); } VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory( @@ -16011,7 +16022,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory( VMA_DEBUG_GLOBAL_MUTEX_LOCK - return allocator->BindImageMemory(allocation, 0, image, VMA_NULL); + return allocator->BindImageMemory(allocation, 0, image, VMA_NULL); } VMA_CALL_PRE VkResult VMA_CALL_POST vmaBindImageMemory2( @@ -16040,11 +16051,11 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBuffer( { VMA_ASSERT(allocator && pBufferCreateInfo && pAllocationCreateInfo && pBuffer && pAllocation); - if (pBufferCreateInfo->size == 0) + if(pBufferCreateInfo->size == 0) { return VK_ERROR_INITIALIZATION_FAILED; } - if ((pBufferCreateInfo->usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_COPY) != 0 && + if((pBufferCreateInfo->usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_COPY) != 0 && !allocator->m_UseKhrBufferDeviceAddress) { VMA_ASSERT(0 && "Creating a buffer with VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT is not valid if VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT was not used."); @@ -16055,7 +16066,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBuffer( VMA_DEBUG_GLOBAL_MUTEX_LOCK - * pBuffer = VK_NULL_HANDLE; + *pBuffer = VK_NULL_HANDLE; *pAllocation = VK_NULL_HANDLE; // 1. Create VkBuffer. @@ -16064,12 +16075,12 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBuffer( pBufferCreateInfo, allocator->GetAllocationCallbacks(), pBuffer); - if (res >= 0) + if(res >= 0) { // 2. vkGetBufferMemoryRequirements. VkMemoryRequirements vkMemReq = {}; bool requiresDedicatedAllocation = false; - bool prefersDedicatedAllocation = false; + bool prefersDedicatedAllocation = false; allocator->GetBufferMemoryRequirements(*pBuffer, vkMemReq, requiresDedicatedAllocation, prefersDedicatedAllocation); @@ -16086,20 +16097,20 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBuffer( 1, // allocationCount pAllocation); - if (res >= 0) + if(res >= 0) { // 3. Bind buffer with memory. - if ((pAllocationCreateInfo->flags & VMA_ALLOCATION_CREATE_DONT_BIND_BIT) == 0) + if((pAllocationCreateInfo->flags & VMA_ALLOCATION_CREATE_DONT_BIND_BIT) == 0) { res = allocator->BindBufferMemory(*pAllocation, 0, *pBuffer, VMA_NULL); } - if (res >= 0) + if(res >= 0) { // All steps succeeded. -#if VMA_STATS_STRING_ENABLED - (*pAllocation)->InitBufferUsage(*pBufferCreateInfo, allocator->m_UseKhrMaintenance5); -#endif - if (pAllocationInfo != VMA_NULL) + #if VMA_STATS_STRING_ENABLED + (*pAllocation)->InitBufferUsage(*pBufferCreateInfo, allocator->m_UseKhrMaintenance5); + #endif + if(pAllocationInfo != VMA_NULL) { allocator->GetAllocationInfo(*pAllocation, pAllocationInfo); } @@ -16132,11 +16143,11 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBufferWithAlignment( { VMA_ASSERT(allocator && pBufferCreateInfo && pAllocationCreateInfo && VmaIsPow2(minAlignment) && pBuffer && pAllocation); - if (pBufferCreateInfo->size == 0) + if(pBufferCreateInfo->size == 0) { return VK_ERROR_INITIALIZATION_FAILED; } - if ((pBufferCreateInfo->usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_COPY) != 0 && + if((pBufferCreateInfo->usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_COPY) != 0 && !allocator->m_UseKhrBufferDeviceAddress) { VMA_ASSERT(0 && "Creating a buffer with VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT is not valid if VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT was not used."); @@ -16147,7 +16158,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBufferWithAlignment( VMA_DEBUG_GLOBAL_MUTEX_LOCK - * pBuffer = VK_NULL_HANDLE; + *pBuffer = VK_NULL_HANDLE; *pAllocation = VK_NULL_HANDLE; // 1. Create VkBuffer. @@ -16156,12 +16167,12 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBufferWithAlignment( pBufferCreateInfo, allocator->GetAllocationCallbacks(), pBuffer); - if (res >= 0) + if(res >= 0) { // 2. vkGetBufferMemoryRequirements. VkMemoryRequirements vkMemReq = {}; bool requiresDedicatedAllocation = false; - bool prefersDedicatedAllocation = false; + bool prefersDedicatedAllocation = false; allocator->GetBufferMemoryRequirements(*pBuffer, vkMemReq, requiresDedicatedAllocation, prefersDedicatedAllocation); @@ -16181,20 +16192,20 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateBufferWithAlignment( 1, // allocationCount pAllocation); - if (res >= 0) + if(res >= 0) { // 3. Bind buffer with memory. - if ((pAllocationCreateInfo->flags & VMA_ALLOCATION_CREATE_DONT_BIND_BIT) == 0) + if((pAllocationCreateInfo->flags & VMA_ALLOCATION_CREATE_DONT_BIND_BIT) == 0) { res = allocator->BindBufferMemory(*pAllocation, 0, *pBuffer, VMA_NULL); } - if (res >= 0) + if(res >= 0) { // All steps succeeded. -#if VMA_STATS_STRING_ENABLED - (*pAllocation)->InitBufferUsage(*pBufferCreateInfo, allocator->m_UseKhrMaintenance5); -#endif - if (pAllocationInfo != VMA_NULL) + #if VMA_STATS_STRING_ENABLED + (*pAllocation)->InitBufferUsage(*pBufferCreateInfo, allocator->m_UseKhrMaintenance5); + #endif + if(pAllocationInfo != VMA_NULL) { allocator->GetAllocationInfo(*pAllocation, pAllocationInfo); } @@ -16252,12 +16263,12 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAliasingBuffer2( VMA_DEBUG_GLOBAL_MUTEX_LOCK - // 1. Create VkBuffer. - VkResult res = (*allocator->GetVulkanFunctions().vkCreateBuffer)( - allocator->m_hDevice, - pBufferCreateInfo, - allocator->GetAllocationCallbacks(), - pBuffer); + // 1. Create VkBuffer. + VkResult res = (*allocator->GetVulkanFunctions().vkCreateBuffer)( + allocator->m_hDevice, + pBufferCreateInfo, + allocator->GetAllocationCallbacks(), + pBuffer); if (res >= 0) { // 2. Bind buffer with memory. @@ -16278,7 +16289,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaDestroyBuffer( { VMA_ASSERT(allocator); - if (buffer == VK_NULL_HANDLE && allocation == VK_NULL_HANDLE) + if(buffer == VK_NULL_HANDLE && allocation == VK_NULL_HANDLE) { return; } @@ -16287,12 +16298,12 @@ VMA_CALL_PRE void VMA_CALL_POST vmaDestroyBuffer( VMA_DEBUG_GLOBAL_MUTEX_LOCK - if (buffer != VK_NULL_HANDLE) - { - (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, buffer, allocator->GetAllocationCallbacks()); - } + if(buffer != VK_NULL_HANDLE) + { + (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, buffer, allocator->GetAllocationCallbacks()); + } - if (allocation != VK_NULL_HANDLE) + if(allocation != VK_NULL_HANDLE) { allocator->FreeMemory( 1, // allocationCount @@ -16310,7 +16321,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateImage( { VMA_ASSERT(allocator && pImageCreateInfo && pAllocationCreateInfo && pImage && pAllocation); - if (pImageCreateInfo->extent.width == 0 || + if(pImageCreateInfo->extent.width == 0 || pImageCreateInfo->extent.height == 0 || pImageCreateInfo->extent.depth == 0 || pImageCreateInfo->mipLevels == 0 || @@ -16323,7 +16334,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateImage( VMA_DEBUG_GLOBAL_MUTEX_LOCK - * pImage = VK_NULL_HANDLE; + *pImage = VK_NULL_HANDLE; *pAllocation = VK_NULL_HANDLE; // 1. Create VkImage. @@ -16332,7 +16343,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateImage( pImageCreateInfo, allocator->GetAllocationCallbacks(), pImage); - if (res >= 0) + if(res >= 0) { VmaSuballocationType suballocType = pImageCreateInfo->tiling == VK_IMAGE_TILING_OPTIMAL ? VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL : @@ -16341,7 +16352,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateImage( // 2. Allocate memory using allocator. VkMemoryRequirements vkMemReq = {}; bool requiresDedicatedAllocation = false; - bool prefersDedicatedAllocation = false; + bool prefersDedicatedAllocation = false; allocator->GetImageMemoryRequirements(*pImage, vkMemReq, requiresDedicatedAllocation, prefersDedicatedAllocation); @@ -16357,20 +16368,20 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateImage( 1, // allocationCount pAllocation); - if (res >= 0) + if(res >= 0) { // 3. Bind image with memory. - if ((pAllocationCreateInfo->flags & VMA_ALLOCATION_CREATE_DONT_BIND_BIT) == 0) + if((pAllocationCreateInfo->flags & VMA_ALLOCATION_CREATE_DONT_BIND_BIT) == 0) { res = allocator->BindImageMemory(*pAllocation, 0, *pImage, VMA_NULL); } - if (res >= 0) + if(res >= 0) { // All steps succeeded. -#if VMA_STATS_STRING_ENABLED - (*pAllocation)->InitImageUsage(*pImageCreateInfo); -#endif - if (pAllocationInfo != VMA_NULL) + #if VMA_STATS_STRING_ENABLED + (*pAllocation)->InitImageUsage(*pImageCreateInfo); + #endif + if(pAllocationInfo != VMA_NULL) { allocator->GetAllocationInfo(*pAllocation, pAllocationInfo); } @@ -16425,12 +16436,12 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateAliasingImage2( VMA_DEBUG_GLOBAL_MUTEX_LOCK - // 1. Create VkImage. - VkResult res = (*allocator->GetVulkanFunctions().vkCreateImage)( - allocator->m_hDevice, - pImageCreateInfo, - allocator->GetAllocationCallbacks(), - pImage); + // 1. Create VkImage. + VkResult res = (*allocator->GetVulkanFunctions().vkCreateImage)( + allocator->m_hDevice, + pImageCreateInfo, + allocator->GetAllocationCallbacks(), + pImage); if (res >= 0) { // 2. Bind image with memory. @@ -16451,7 +16462,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaDestroyImage( { VMA_ASSERT(allocator); - if (image == VK_NULL_HANDLE && allocation == VK_NULL_HANDLE) + if(image == VK_NULL_HANDLE && allocation == VK_NULL_HANDLE) { return; } @@ -16460,11 +16471,11 @@ VMA_CALL_PRE void VMA_CALL_POST vmaDestroyImage( VMA_DEBUG_GLOBAL_MUTEX_LOCK - if (image != VK_NULL_HANDLE) - { - (*allocator->GetVulkanFunctions().vkDestroyImage)(allocator->m_hDevice, image, allocator->GetAllocationCallbacks()); - } - if (allocation != VK_NULL_HANDLE) + if(image != VK_NULL_HANDLE) + { + (*allocator->GetVulkanFunctions().vkDestroyImage)(allocator->m_hDevice, image, allocator->GetAllocationCallbacks()); + } + if(allocation != VK_NULL_HANDLE) { allocator->FreeMemory( 1, // allocationCount @@ -16474,7 +16485,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaDestroyImage( VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateVirtualBlock( const VmaVirtualBlockCreateInfo* VMA_NOT_NULL pCreateInfo, - VmaVirtualBlock VMA_NULLABLE* VMA_NOT_NULL pVirtualBlock) + VmaVirtualBlock VMA_NULLABLE * VMA_NOT_NULL pVirtualBlock) { VMA_ASSERT(pCreateInfo && pVirtualBlock); VMA_ASSERT(pCreateInfo->size > 0); @@ -16482,7 +16493,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateVirtualBlock( VMA_DEBUG_GLOBAL_MUTEX_LOCK; *pVirtualBlock = vma_new(pCreateInfo->pAllocationCallbacks, VmaVirtualBlock_T)(*pCreateInfo); VkResult res = (*pVirtualBlock)->Init(); - if (res < 0) + if(res < 0) { vma_delete(pCreateInfo->pAllocationCallbacks, *pVirtualBlock); *pVirtualBlock = VK_NULL_HANDLE; @@ -16492,7 +16503,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateVirtualBlock( VMA_CALL_PRE void VMA_CALL_POST vmaDestroyVirtualBlock(VmaVirtualBlock VMA_NULLABLE virtualBlock) { - if (virtualBlock != VK_NULL_HANDLE) + if(virtualBlock != VK_NULL_HANDLE) { VMA_DEBUG_LOG("vmaDestroyVirtualBlock"); VMA_DEBUG_GLOBAL_MUTEX_LOCK; @@ -16530,7 +16541,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaVirtualAllocate(VmaVirtualBlock VMA_NOT_N VMA_CALL_PRE void VMA_CALL_POST vmaVirtualFree(VmaVirtualBlock VMA_NOT_NULL virtualBlock, VmaVirtualAllocation VMA_NULLABLE_NON_DISPATCHABLE allocation) { - if (allocation != VK_NULL_HANDLE) + if(allocation != VK_NULL_HANDLE) { VMA_ASSERT(virtualBlock != VK_NULL_HANDLE); VMA_DEBUG_LOG("vmaVirtualFree"); @@ -16577,7 +16588,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaCalculateVirtualBlockStatistics(VmaVirtualBlo #if VMA_STATS_STRING_ENABLED VMA_CALL_PRE void VMA_CALL_POST vmaBuildVirtualBlockStatsString(VmaVirtualBlock VMA_NOT_NULL virtualBlock, - char* VMA_NULLABLE* VMA_NOT_NULL ppStatsString, VkBool32 detailedMap) + char* VMA_NULLABLE * VMA_NOT_NULL ppStatsString, VkBool32 detailedMap) { VMA_ASSERT(virtualBlock != VK_NULL_HANDLE && ppStatsString != VMA_NULL); VMA_DEBUG_GLOBAL_MUTEX_LOCK; @@ -16590,14 +16601,14 @@ VMA_CALL_PRE void VMA_CALL_POST vmaBuildVirtualBlockStatsString(VmaVirtualBlock VMA_CALL_PRE void VMA_CALL_POST vmaFreeVirtualBlockStatsString(VmaVirtualBlock VMA_NOT_NULL virtualBlock, char* VMA_NULLABLE pStatsString) { - if (pStatsString != VMA_NULL) + if(pStatsString != VMA_NULL) { VMA_ASSERT(virtualBlock != VK_NULL_HANDLE); VMA_DEBUG_GLOBAL_MUTEX_LOCK; VmaFreeString(virtualBlock->GetAllocationCallbacks(), pStatsString); } } -#ifdef VK_USE_PLATFORM_WIN32_KHR +#if VMA_EXTERNAL_MEMORY_WIN32 VMA_CALL_PRE VkResult VMA_CALL_POST vmaGetMemoryWin32HandleKHR(VmaAllocator VMA_NOT_NULL allocator, VmaAllocation VMA_NOT_NULL allocation, HANDLE hTargetProcess, HANDLE* pHandle) { @@ -16605,7 +16616,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaGetMemoryWin32HandleKHR(VmaAllocator VMA_ VMA_DEBUG_GLOBAL_MUTEX_LOCK; return allocation->GetWin32Handle(allocator, hTargetProcess, pHandle); } -#endif // VK_USE_PLATFORM_WIN32_KHR +#endif // VMA_EXTERNAL_MEMORY_WIN32 #endif // VMA_STATS_STRING_ENABLED #endif // _VMA_PUBLIC_INTERFACE #endif // VMA_IMPLEMENTATION From 65afd9e98b1b0de79b19ee4c63f546d670016755 Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Tue, 27 Aug 2024 10:39:54 +0200 Subject: [PATCH 06/10] documentation --- Doxyfile | 1 + include/vk_mem_alloc.h | 31 ++++++++++++------------------- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/Doxyfile b/Doxyfile index 99b96fe..2b6bcc9 100644 --- a/Doxyfile +++ b/Doxyfile @@ -2466,6 +2466,7 @@ PREDEFINED = VMA_CALL_PRE= \ VMA_MEMORY_PRIORITY=1 \ VMA_KHR_MAINTENANCE4=1 \ VMA_KHR_MAINTENANCE5=1 \ + VMA_EXTERNAL_MEMORY_WIN32=1 \ VMA_EXTERNAL_MEMORY=1 \ VMA_EXTENDS_VK_STRUCT= \ VMA_STATS_STRING_ENABLED=1 diff --git a/include/vk_mem_alloc.h b/include/vk_mem_alloc.h index d3a9871..4b31afb 100644 --- a/include/vk_mem_alloc.h +++ b/include/vk_mem_alloc.h @@ -242,7 +242,7 @@ extern "C" { #endif #endif -// Defined to 1 when VK_KHR_external_memory device extension is defined in Vulkan headers. +// Defined to 1 when VK_KHR_external_memory_win32 device extension is defined in Vulkan headers. #if !defined(VMA_EXTERNAL_MEMORY_WIN32) #if VK_KHR_external_memory_win32 #define VMA_EXTERNAL_MEMORY_WIN32 1 @@ -1052,7 +1052,7 @@ typedef struct VmaVulkanFunctions /// Fetch from "vkGetDeviceImageMemoryRequirements" on Vulkan >= 1.3, but you can also fetch it from "vkGetDeviceImageMemoryRequirementsKHR" if you enabled extension VK_KHR_maintenance4. PFN_vkGetDeviceImageMemoryRequirementsKHR VMA_NULLABLE vkGetDeviceImageMemoryRequirements; #endif -#ifdef VK_USE_PLATFORM_WIN32_KHR +#ifdef VMA_EXTERNAL_MEMORY_WIN32 PFN_vkGetMemoryWin32HandleKHR VMA_NULLABLE vkGetMemoryWin32HandleKHR; #else void* VMA_NULLABLE vkGetMemoryWin32HandleKHR; @@ -6096,7 +6096,7 @@ class VmaWin32Handle { public: VmaWin32Handle() noexcept : m_hHandle(VMA_NULL) { } - VmaWin32Handle(HANDLE hHandle) noexcept : m_hHandle(hHandle) { } + explicit VmaWin32Handle(HANDLE hHandle) noexcept : m_hHandle(hHandle) { } ~VmaWin32Handle() noexcept { if (m_hHandle != VMA_NULL) { ::CloseHandle(m_hHandle); } } VMA_CLASS_NO_COPY_NO_MOVE(VmaWin32Handle) @@ -6105,32 +6105,26 @@ public: VkResult GetHandle(VkDevice device, VkDeviceMemory memory, decltype(&vkGetMemoryWin32HandleKHR) pvkGetMemoryWin32HandleKHR, HANDLE hTargetProcess, bool useMutex, HANDLE* pHandle) noexcept { *pHandle = VMA_NULL; - // We only care about atomicity of handle retrieval, not about memory order. - HANDLE handle = m_hHandle.load(std::memory_order_relaxed); - // Try to get handle first. - if (handle != VMA_NULL) + if (m_hHandle != VMA_NULL) { *pHandle = Duplicate(hTargetProcess); return VK_SUCCESS; } - HANDLE hCreatedHandle = VMA_NULL; - VkResult res = VK_SUCCESS; // If failed, try to create it. { VmaMutexLockWrite lock(m_Mutex, useMutex); - if (m_hHandle.load(std::memory_order_relaxed) == VMA_NULL) + if (m_hHandle == VMA_NULL) { - VkResult res = Create(device, memory, pvkGetMemoryWin32HandleKHR, &hCreatedHandle); - m_hHandle.store(hCreatedHandle, std::memory_order_relaxed); + res = Create(device, memory, pvkGetMemoryWin32HandleKHR, &m_hHandle); } } *pHandle = Duplicate(hTargetProcess); return res; -} + } operator bool() const noexcept { return m_hHandle != VMA_NULL; } private: @@ -6150,20 +6144,19 @@ private: } HANDLE Duplicate(HANDLE hTargetProcess = VMA_NULL) const noexcept { - HANDLE handle = m_hHandle.load(std::memory_order_relaxed); - if (!handle) - return handle; + if (!m_hHandle) + return m_hHandle; HANDLE hCurrentProcess = ::GetCurrentProcess(); HANDLE hDupHandle = VMA_NULL; - if (!::DuplicateHandle(hCurrentProcess, handle, hTargetProcess ? hTargetProcess : hCurrentProcess, &hDupHandle, 0, FALSE, DUPLICATE_SAME_ACCESS)) + if (!::DuplicateHandle(hCurrentProcess, m_hHandle, hTargetProcess ? hTargetProcess : hCurrentProcess, &hDupHandle, 0, FALSE, DUPLICATE_SAME_ACCESS)) { VMA_ASSERT(0 && "Failed to duplicate handle."); } return hDupHandle; } private: - std::atomic m_hHandle; + HANDLE m_hHandle; VMA_RW_MUTEX m_Mutex; // Protects access m_Handle }; #else @@ -10804,7 +10797,7 @@ VkResult VmaDeviceMemoryBlock::BindImageMemory( VkResult VmaDeviceMemoryBlock::CreateWin32Handle(const VmaAllocator hAllocator, decltype(&vkGetMemoryWin32HandleKHR) pvkGetMemoryWin32HandleKHR, HANDLE hTargetProcess, HANDLE* pHandle) noexcept { VMA_ASSERT(pHandle); - return m_Handle.GetHandle(hAllocator->m_hDevice, m_hMemory, &vkGetMemoryWin32HandleKHR, hTargetProcess, hAllocator->m_UseMutex, pHandle); + return m_Handle.GetHandle(hAllocator->m_hDevice, m_hMemory, pvkGetMemoryWin32HandleKHR, hTargetProcess, hAllocator->m_UseMutex, pHandle); } #endif // VMA_EXTERNAL_MEMORY_WIN32 #endif // _VMA_DEVICE_MEMORY_BLOCK_FUNCTIONS From 0c8feb29ff7a9e384207db4f9053554a05e70772 Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Tue, 27 Aug 2024 10:49:16 +0200 Subject: [PATCH 07/10] dynamic fetching of function --- include/vk_mem_alloc.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/vk_mem_alloc.h b/include/vk_mem_alloc.h index 4b31afb..9947c21 100644 --- a/include/vk_mem_alloc.h +++ b/include/vk_mem_alloc.h @@ -13128,7 +13128,8 @@ void VmaAllocator_T::ImportVulkanFunctions_Static() } #endif #if VMA_EXTERNAL_MEMORY_WIN32 - m_VulkanFunctions.vkGetMemoryWin32HandleKHR = (PFN_vkGetMemoryWin32HandleKHR)vkGetMemoryWin32HandleKHR; + // Can only be fetched dynamically + m_VulkanFunctions.vkGetMemoryWin32HandleKHR = (PFN_vkGetMemoryWin32HandleKHR)m_VulkanFunctions.vkGetDeviceProcAddr(m_hDevice, "vkGetMemoryWin32HandleKHR"); #else m_VulkanFunctions.vkGetMemoryWin32HandleKHR = VMA_NULL; #endif From c9b2a6a4654301eeed098892d1fbb119e2f1ad75 Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Tue, 27 Aug 2024 11:23:46 +0200 Subject: [PATCH 08/10] Tests, documentation and fix --- include/vk_mem_alloc.h | 29 +++++++++++++++++++---------- src/Tests.cpp | 29 +++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/include/vk_mem_alloc.h b/include/vk_mem_alloc.h index 9947c21..808eefc 100644 --- a/include/vk_mem_alloc.h +++ b/include/vk_mem_alloc.h @@ -2074,6 +2074,21 @@ VMA_CALL_PRE void VMA_CALL_POST vmaGetAllocationMemoryProperties( VmaAllocation VMA_NOT_NULL allocation, VkMemoryPropertyFlags* VMA_NOT_NULL pFlags); + +#if VMA_EXTERNAL_MEMORY_WIN32 +/** +\brief Given an allocation, returns Win32 Handle, that may be imported by other processes or APIs. + +`hTargetProcess` must be a valid handle to target process or NULL. If it's `NULL`, the function returns +handle for the current process. + +If the allocation was created with `VMA_ALLOCATION_CREATE_EXPORT_WIN32_HANDLE_BIT` flag, +the function fills `pHandle` with handle that can be used in target process. +*/ +VMA_CALL_PRE VkResult VMA_CALL_POST vmaGetMemoryWin32HandleKHR(VmaAllocator VMA_NOT_NULL allocator, + VmaAllocation VMA_NOT_NULL allocation, HANDLE hTargetProcess, HANDLE* VMA_NOT_NULL pHandle); +#endif // VMA_EXTERNAL_MEMORY_WIN32 + /** \brief Maps memory represented by given allocation and returns pointer to it. Maps memory represented by given allocation to make it accessible to CPU code. @@ -6345,7 +6360,7 @@ public: #endif #if VMA_EXTERNAL_MEMORY_WIN32 - VkResult GetWin32Handle(VmaAllocator hAllocator, HANDLE hTargetProcess, HANDLE* hHandle) const noexcept; + VkResult GetWin32Handle(VmaAllocator hAllocator, HANDLE hTargetProcess, HANDLE* hHandle) noexcept; #endif // VMA_EXTERNAL_MEMORY_WIN32 private: @@ -6363,7 +6378,7 @@ private: void* m_pMappedData; // Not null means memory is mapped. VmaAllocation_T* m_Prev; VmaAllocation_T* m_Next; - mutable VmaWin32Handle m_Handle; // Win32 handle + VmaWin32Handle m_Handle; // Win32 handle }; union { @@ -11101,7 +11116,7 @@ void VmaAllocation_T::PrintParameters(class VmaJsonWriter& json) const } } #if VMA_EXTERNAL_MEMORY_WIN32 -VkResult VmaAllocation_T::GetWin32Handle(VmaAllocator hAllocator, HANDLE hTargetProcess, HANDLE* pHandle) const noexcept +VkResult VmaAllocation_T::GetWin32Handle(VmaAllocator hAllocator, HANDLE hTargetProcess, HANDLE* pHandle) noexcept { // Where do we get this function from? auto pvkGetMemoryWin32HandleKHR = hAllocator->GetVulkanFunctions().vkGetMemoryWin32HandleKHR; @@ -13127,12 +13142,6 @@ void VmaAllocator_T::ImportVulkanFunctions_Static() m_VulkanFunctions.vkGetDeviceImageMemoryRequirements = (PFN_vkGetDeviceImageMemoryRequirements)vkGetDeviceImageMemoryRequirements; } #endif -#if VMA_EXTERNAL_MEMORY_WIN32 - // Can only be fetched dynamically - m_VulkanFunctions.vkGetMemoryWin32HandleKHR = (PFN_vkGetMemoryWin32HandleKHR)m_VulkanFunctions.vkGetDeviceProcAddr(m_hDevice, "vkGetMemoryWin32HandleKHR"); -#else - m_VulkanFunctions.vkGetMemoryWin32HandleKHR = VMA_NULL; -#endif } #endif // VMA_STATIC_VULKAN_FUNCTIONS == 1 @@ -16604,7 +16613,7 @@ VMA_CALL_PRE void VMA_CALL_POST vmaFreeVirtualBlockStatsString(VmaVirtualBlock V } #if VMA_EXTERNAL_MEMORY_WIN32 VMA_CALL_PRE VkResult VMA_CALL_POST vmaGetMemoryWin32HandleKHR(VmaAllocator VMA_NOT_NULL allocator, - VmaAllocation VMA_NOT_NULL allocation, HANDLE hTargetProcess, HANDLE* pHandle) + VmaAllocation VMA_NOT_NULL allocation, HANDLE hTargetProcess, HANDLE* VMA_NOT_NULL pHandle) { VMA_ASSERT(allocator && allocation); VMA_DEBUG_GLOBAL_MUTEX_LOCK; diff --git a/src/Tests.cpp b/src/Tests.cpp index 796b84d..4703672 100644 --- a/src/Tests.cpp +++ b/src/Tests.cpp @@ -8253,6 +8253,34 @@ static void TestMappingHysteresis() } } + +static void TestWin32Handles() +{ +#if VMA_EXTERNAL_MEMORY_WIN32 + wprintf(L"Test Win32 handles\n"); + VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; + bufCreateInfo.size = 1024; + bufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + VmaAllocationCreateInfo allocCreateInfo = {}; + allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; + VkBuffer buf; + VmaAllocation alloc; + VmaAllocationInfo allocInfo; + TEST(vmaCreateBuffer(g_hAllocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, &allocInfo) == VK_SUCCESS); + HANDLE handle; + HANDLE handle2; + TEST(vmaGetMemoryWin32HandleKHR(g_hAllocator, alloc, nullptr, &handle) == VK_SUCCESS); + TEST(handle != nullptr); + TEST(vmaGetMemoryWin32HandleKHR(g_hAllocator, alloc, nullptr, &handle2) == VK_SUCCESS); + TEST(handle2 != nullptr); + TEST(handle2 != handle); + + vmaDestroyBuffer(g_hAllocator, buf, alloc); + TEST(CloseHandle(handle)); + TEST(CloseHandle(handle2)); +#endif +} + void Test() { wprintf(L"TESTING:\n"); @@ -8295,6 +8323,7 @@ void Test() TestMappingHysteresis(); TestDeviceLocalMapped(); TestMaintenance5(); + TestWin32Handles(); TestMappingMultithreaded(); TestLinearAllocator(); ManuallyTestLinearAllocator(); From 2683cfedc57423ec53d1477df13284479020263b Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Tue, 27 Aug 2024 12:33:38 +0200 Subject: [PATCH 09/10] extension enabled --- src/Tests.cpp | 47 ++++++++++++++++++++++++++++++++++++++------ src/VulkanSample.cpp | 11 +++++++++++ 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/src/Tests.cpp b/src/Tests.cpp index 4703672..bb6650f 100644 --- a/src/Tests.cpp +++ b/src/Tests.cpp @@ -8258,15 +8258,50 @@ static void TestWin32Handles() { #if VMA_EXTERNAL_MEMORY_WIN32 wprintf(L"Test Win32 handles\n"); - VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; - bufCreateInfo.size = 1024; - bufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - VmaAllocationCreateInfo allocCreateInfo = {}; - allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; + constexpr static VkExportMemoryAllocateInfoKHR exportInfo{ + VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR, + nullptr, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT + }; + constexpr static VkExternalMemoryBufferCreateInfoKHR externalInfo{ + VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHR, + nullptr, + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT + }; + + VkBufferCreateInfo sampleBufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; + sampleBufCreateInfo.size = 0x1000; // Doesn't matter. + sampleBufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + sampleBufCreateInfo.pNext = &externalInfo; + + VmaAllocationCreateInfo sampleAllocCreateInfo = {}; + sampleAllocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; + sampleAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT; + + uint32_t memTypeIndex; + TEST(vmaFindMemoryTypeIndexForBufferInfo(g_hAllocator, + &sampleBufCreateInfo, &sampleAllocCreateInfo, &memTypeIndex) == VK_SUCCESS); + // Check res... + + + // Create a pool that can have at most 2 blocks, 128 MiB each. + VmaPoolCreateInfo poolCreateInfo = {}; + poolCreateInfo.memoryTypeIndex = memTypeIndex; + poolCreateInfo.blockSize = 128ull * 1024 * 1024; + poolCreateInfo.maxBlockCount = 2; + poolCreateInfo.pMemoryAllocateNext = (void*)&exportInfo; + + + VmaPool pool; + TEST(vmaCreatePool(g_hAllocator, &poolCreateInfo, &pool) == VK_SUCCESS); + + + sampleAllocCreateInfo.pool = pool; + VkBuffer buf; VmaAllocation alloc; VmaAllocationInfo allocInfo; - TEST(vmaCreateBuffer(g_hAllocator, &bufCreateInfo, &allocCreateInfo, &buf, &alloc, &allocInfo) == VK_SUCCESS); + TEST(vmaCreateBuffer(g_hAllocator, &sampleBufCreateInfo, &sampleAllocCreateInfo, &buf, &alloc, &allocInfo) == VK_SUCCESS); HANDLE handle; HANDLE handle2; TEST(vmaGetMemoryWin32HandleKHR(g_hAllocator, alloc, nullptr, &handle) == VK_SUCCESS); diff --git a/src/VulkanSample.cpp b/src/VulkanSample.cpp index 1a2ebf1..480b325 100644 --- a/src/VulkanSample.cpp +++ b/src/VulkanSample.cpp @@ -69,6 +69,7 @@ bool VK_KHR_buffer_device_address_enabled = false; bool VK_EXT_memory_priority_enabled = false; bool VK_EXT_debug_utils_enabled = false; bool VK_KHR_maintenance5_enabled = false; +bool VK_KHR_external_memory_win32_enabled = false; bool g_SparseBindingEnabled = false; // # Pointers to functions from extensions @@ -1449,6 +1450,7 @@ static void PrintEnabledFeatures() } wprintf(L"VK_EXT_memory_priority: %d\n", VK_EXT_memory_priority_enabled ? 1 : 0); wprintf(L"VK_KHR_maintenance5: %d\n", VK_KHR_maintenance5_enabled? 1 : 0); + wprintf(L"VK_KHR_external_memory_win32: %d\n", VK_KHR_external_memory_win32_enabled ? 1 : 0); } void SetAllocatorCreateInfo(VmaAllocatorCreateInfo& outInfo) @@ -1494,6 +1496,11 @@ void SetAllocatorCreateInfo(VmaAllocatorCreateInfo& outInfo) outInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE5_BIT; } + if(VK_KHR_external_memory_win32_enabled) + { + outInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_EXTERNAL_MEMORY_WIN32_BIT; + } + if(USE_CUSTOM_CPU_ALLOCATION_CALLBACKS) { outInfo.pAllocationCallbacks = &g_CpuAllocationCallbacks; @@ -1876,6 +1883,8 @@ static void InitializeApplication() VK_EXT_memory_priority_enabled = true; else if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_KHR_MAINTENANCE_5_EXTENSION_NAME) == 0) VK_KHR_maintenance5_enabled = true; + else if (strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME) == 0) + VK_KHR_external_memory_win32_enabled = true; } if(GetVulkanApiVersion() >= VK_API_VERSION_1_2) @@ -2036,6 +2045,8 @@ static void InitializeApplication() enabledDeviceExtensions.push_back(VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME); if(VK_KHR_maintenance5_enabled) enabledDeviceExtensions.push_back(VK_KHR_MAINTENANCE_5_EXTENSION_NAME); + if (VK_KHR_external_memory_win32_enabled) + enabledDeviceExtensions.push_back(VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME); VkPhysicalDeviceFeatures2 deviceFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 }; deviceFeatures.features.samplerAnisotropy = VK_TRUE; From e962c8c83e3e4f4b905f0bbc82cd4d4bffb86799 Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Tue, 27 Aug 2024 12:44:15 +0200 Subject: [PATCH 10/10] Fixed test not compiling shaders --- src/Shaders/CMakeLists.txt | 8 ++++++++ src/Tests.cpp | 2 ++ src/VulkanSample.cpp | 4 ++-- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/Shaders/CMakeLists.txt b/src/Shaders/CMakeLists.txt index f85ab78..0998924 100644 --- a/src/Shaders/CMakeLists.txt +++ b/src/Shaders/CMakeLists.txt @@ -17,14 +17,22 @@ foreach(SHADER ${SHADERS}) get_filename_component(FILE_NAME ${SHADER} NAME) # Put the .spv files into the bin folder + set(SPIRV_BIN ${CMAKE_CURRENT_BINARY_DIR}/${FILE_NAME}.spv) set(SPIRV ${PROJECT_SOURCE_DIR}/bin/${FILE_NAME}.spv) + add_custom_command( OUTPUT ${SPIRV} # Use the same file name and append .spv to the compiled shader COMMAND ${GLSL_VALIDATOR} -V ${CMAKE_CURRENT_SOURCE_DIR}/${SHADER} -o ${SPIRV} DEPENDS ${SHADER} ) + add_custom_command( + OUTPUT ${SPIRV_BIN} + # Use the same file name and append .spv to the compiled shader + COMMAND ${GLSL_VALIDATOR} -V ${CMAKE_CURRENT_SOURCE_DIR}/${SHADER} -o ${SPIRV_BIN} + DEPENDS ${SHADER} + ) list(APPEND SPIRV_FILES ${SPIRV}) endforeach() diff --git a/src/Tests.cpp b/src/Tests.cpp index bb6650f..853b56a 100644 --- a/src/Tests.cpp +++ b/src/Tests.cpp @@ -8313,6 +8313,8 @@ static void TestWin32Handles() vmaDestroyBuffer(g_hAllocator, buf, alloc); TEST(CloseHandle(handle)); TEST(CloseHandle(handle2)); + + vmaDestroyPool(g_hAllocator, pool); #endif } diff --git a/src/VulkanSample.cpp b/src/VulkanSample.cpp index 480b325..b3df053 100644 --- a/src/VulkanSample.cpp +++ b/src/VulkanSample.cpp @@ -32,7 +32,7 @@ #pragma comment(lib, "shlwapi.lib") -static const char* const SHADER_PATH1 = "./"; +static const char* const SHADER_PATH1 = "./Shaders/"; static const char* const SHADER_PATH2 = "../bin/"; static const wchar_t* const WINDOW_CLASS_NAME = L"VULKAN_MEMORY_ALLOCATOR_SAMPLE"; static const char* const VALIDATION_LAYER_NAME = "VK_LAYER_KHRONOS_validation"; @@ -1884,7 +1884,7 @@ static void InitializeApplication() else if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_KHR_MAINTENANCE_5_EXTENSION_NAME) == 0) VK_KHR_maintenance5_enabled = true; else if (strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME) == 0) - VK_KHR_external_memory_win32_enabled = true; + VK_KHR_external_memory_win32_enabled = VMA_DYNAMIC_VULKAN_FUNCTIONS; } if(GetVulkanApiVersion() >= VK_API_VERSION_1_2)