From 9bb37321a031bb928b2130ee04238d28763a11f4 Mon Sep 17 00:00:00 2001 From: JordanTheToaster Date: Thu, 1 Oct 2026 12:55:16 +0100 Subject: [PATCH] 3rdparty: Update VMA to version v3.4.0 --- 3rdparty/vulkan/include/CHANGELOG.md | 9 +- 3rdparty/vulkan/include/vk_mem_alloc.h | 258 ++++++++++++------ 3rdparty/vulkan/include/vulkan/vk_mem_alloc.h | 258 ++++++++++++------ 3 files changed, 365 insertions(+), 160 deletions(-) diff --git a/3rdparty/vulkan/include/CHANGELOG.md b/3rdparty/vulkan/include/CHANGELOG.md index 26f4e9b686..a51c1505d8 100644 --- a/3rdparty/vulkan/include/CHANGELOG.md +++ b/3rdparty/vulkan/include/CHANGELOG.md @@ -1,14 +1,19 @@ -# 3.4.0 (2026-??-??) +# 3.4.0 (2026-06-05) +- Added file `AGENTS.md` for agentic AI. - Added member `VmaAllocationCreateInfo::minAlignment` (#523). - Remember to always fully initialize structures with zeros and don't rely on their specific `sizeof` to ensure backward compatibility! - Function `vmaCreateBufferWithAlignment` is now deprecated. - Improvements for external memory export & import (#503): - Added functions `vmaCreateDedicatedBuffer`, `vmaCreateDedicatedImage`, `vmaAllocateDedicatedMemory` offering extra parameter `void* pMemoryAllocateNext`. - Added function `vmaGetMemoryWin32Handle2` offering extra parameter `VkExternalMemoryHandleTypeFlagBits handleType`. +- Added member `VmaVulkanFunctions::vkGetPhysicalDeviceProperties2KHR` and macro `VMA_GET_PHYSICAL_DEVICE_PROPERTIES2` to fix validation layer warnings about the usage of legacy commands on Vulkan >= 1.1 (#530, #531). - Added `VMA_VERSION` macro with library version number (#507). +- Added support for `VMA_VULKAN_HEADERS_ALREADY_INCLUDED`. When defined, VMA does not include ``. - Improvements in the algorithm choosing memory type when `VMA_MEMORY_USAGE_AUTO*` is used (#520). -- Fixes for compatibility with C++20 modules on Clang 21 and GCC15 (#513, #514). +- Fixed compatibility with C++20 modules on Clang 21 and GCC15 (#513, #514). +- Fixed a bug in buffer-image granularity handling (#517). +- Fixed race conditions in defragmentation (#529, #313) and other places (#525). - Other fixes and improvements, including compatibility with various platforms and compilers, improvements in documentation, sample application, and tests. # 3.3.0 (2025-05-12) diff --git a/3rdparty/vulkan/include/vk_mem_alloc.h b/3rdparty/vulkan/include/vk_mem_alloc.h index 24792855e2..f2b58bf620 100644 --- a/3rdparty/vulkan/include/vk_mem_alloc.h +++ b/3rdparty/vulkan/include/vk_mem_alloc.h @@ -25,7 +25,7 @@ /** \mainpage Vulkan Memory Allocator -Version 3.4.0-development +Version 3.4.0 Copyright (c) 2017-2026 Advanced Micro Devices, Inc. All rights reserved. \n License: MIT \n @@ -129,8 +129,10 @@ See documentation chapter: \ref statistics. extern "C" { #endif -#if !defined(VULKAN_H_) -#include +#ifndef VMA_VULKAN_HEADERS_ALREADY_INCLUDED + #if !defined(VULKAN_H_) + #include + #endif #endif #define VMA_VERSION (VK_MAKE_VERSION(3, 4, 0)) @@ -194,8 +196,16 @@ extern "C" { #endif #endif +#if !defined(VMA_GET_PHYSICAL_DEVICE_PROPERTIES2) + #if VK_KHR_get_physical_device_properties2 || VMA_VULKAN_VERSION >= 1001000 + #define VMA_GET_PHYSICAL_DEVICE_PROPERTIES2 1 + #else + #define VMA_GET_PHYSICAL_DEVICE_PROPERTIES2 0 + #endif +#endif + #if !defined(VMA_MEMORY_BUDGET) - #if VK_EXT_memory_budget && (VK_KHR_get_physical_device_properties2 || VMA_VULKAN_VERSION >= 1001000) + #if VK_EXT_memory_budget && VMA_GET_PHYSICAL_DEVICE_PROPERTIES2 #define VMA_MEMORY_BUDGET 1 #else #define VMA_MEMORY_BUDGET 0 @@ -1049,7 +1059,7 @@ typedef struct VmaVulkanFunctions /// 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 +#if VMA_GET_PHYSICAL_DEVICE_PROPERTIES2 /// 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 @@ -1064,6 +1074,10 @@ typedef struct VmaVulkanFunctions #else void* VMA_NULLABLE vkGetMemoryWin32HandleKHR; #endif +#if VMA_GET_PHYSICAL_DEVICE_PROPERTIES2 + /// Fetch from "vkGetPhysicalDeviceProperties2" on Vulkan >= 1.1, but you can also fetch it from "vkGetPhysicalDeviceProperties2KHR" if you enabled extension VK_KHR_get_physical_device_properties2. + PFN_vkGetPhysicalDeviceProperties2KHR VMA_NULLABLE vkGetPhysicalDeviceProperties2KHR; +#endif } VmaVulkanFunctions; /// Description of a Allocator to be created. @@ -3125,7 +3139,7 @@ remove them if not needed. */ #if !defined(VMA_CONFIGURATION_USER_INCLUDES_H) #include // for assert - #include // for min, max, swap + #include // for min, max, swap, sort #include #else #include VMA_CONFIGURATION_USER_INCLUDES_H @@ -3442,6 +3456,11 @@ If providing your own implementation, you need to implement a subset of std::ato #define VMA_ATOMIC_UINT64 std::atomic #endif +#ifndef VMA_ATOMIC_BOOL + #include + #define VMA_ATOMIC_BOOL std::atomic +#endif + #ifndef VMA_DEBUG_ALWAYS_DEDICATED_MEMORY /** Every allocation will have its own memory block. @@ -6549,6 +6568,7 @@ public: uint32_t GetMemoryTypeIndex() const { return m_MemoryTypeIndex; } uint32_t GetId() const { return m_Id; } void* GetMappedData() const { return m_pMappedData; } + bool IsMapped() const { return m_IsMapped.load(); } uint32_t GetMapRefCount() const { return m_MapCount; } // Call when allocation/free was made from m_pMetadata. @@ -6596,12 +6616,18 @@ private: /* Protects access to m_hMemory so it is not used by multiple threads simultaneously, e.g. vkMapMemory, vkBindBufferMemory. Also protects m_MapCount, m_pMappedData. + m_IsMapped mirrors whether m_pMappedData is non-null and can be read without this mutex in allocation heuristics. Allocations, deallocations, any change in m_pMetadata is protected by parent's VmaBlockVector::m_Mutex. */ VMA_MUTEX m_MapAndBindMutex; VmaMappingHysteresis m_MappingHysteresis; uint32_t m_MapCount; void* m_pMappedData; + /* + Mirrors `m_pMappedData != VMA_NULL` for allocation heuristics that only need mapped/unmapped state. + This is atomic so allocation scans don't race with Map/Unmap while the actual mapped pointer remains protected by m_MapAndBindMutex. + */ + VMA_ATOMIC_BOOL m_IsMapped; VmaWin32Handle m_Handle; }; @@ -7166,6 +7192,14 @@ void VmaBlockMetadata::PrintDetailedMap_End(class VmaJsonWriter& json) #ifndef _VMA_BLOCK_BUFFER_IMAGE_GRANULARITY // Before deleting object of this class remember to call 'Destroy()' +/* +Tracks block occupancy at VkPhysicalDeviceLimits::bufferImageGranularity page boundaries. +For each granularity-sized page in a memory block, m_RegionInfo stores: +- allocCount: how many allocations touch this page as their first or last page. +- allocType: the remembered VmaSuballocationType for that page while allocCount > 0. +Only boundary pages are tracked because buffer-image granularity conflicts matter when +adjacent allocations share the same granularity page at the start or end of an allocation. +*/ class VmaBlockBufferImageGranularity final { public: @@ -7188,6 +7222,21 @@ public: VkDeviceSize& inOutAllocSize, VkDeviceSize& inOutAllocAlignment) const; + /* + Checks whether an allocation placed in a free block would conflict with existing + allocations due to buffer-image granularity requirements and, if needed, aligns the + allocation start to the next granularity page. + + Parameters: + - inOutAllocOffset: candidate allocation offset inside the block; may be increased. + - allocSize: size of the allocation being placed. + - blockOffset: start offset of the free block being considered. + - blockSize: size of the free block being considered. + - allocType: VmaSuballocationType of the allocation being placed. + + Returns true when the placement conflicts or no longer fits in the free block after alignment. + Returns false when the placement is valid, possibly after updating inOutAllocOffset. + */ bool CheckConflictAndAlignUp(VkDeviceSize& inOutAllocOffset, VkDeviceSize allocSize, VkDeviceSize blockOffset, @@ -7276,56 +7325,62 @@ bool VmaBlockBufferImageGranularity::CheckConflictAndAlignUp(VkDeviceSize& inOut VkDeviceSize blockSize, VmaSuballocationType allocType) const { - if (IsEnabled()) + if (!IsEnabled()) + return false; + + uint32_t startPage = GetStartPage(inOutAllocOffset); + if (m_RegionInfo[startPage].allocCount > 0 && + VmaIsBufferImageGranularityConflict(static_cast(m_RegionInfo[startPage].allocType), allocType)) { - uint32_t startPage = GetStartPage(inOutAllocOffset); + inOutAllocOffset = VmaAlignUp(inOutAllocOffset, m_BufferImageGranularity); + if (blockSize < allocSize + inOutAllocOffset - blockOffset) + return true; + startPage = GetStartPage(inOutAllocOffset); if (m_RegionInfo[startPage].allocCount > 0 && VmaIsBufferImageGranularityConflict(static_cast(m_RegionInfo[startPage].allocType), allocType)) - { - inOutAllocOffset = VmaAlignUp(inOutAllocOffset, m_BufferImageGranularity); - if (blockSize < allocSize + inOutAllocOffset - blockOffset) - return true; - ++startPage; - } - uint32_t endPage = GetEndPage(inOutAllocOffset, allocSize); - if (endPage != startPage && - m_RegionInfo[endPage].allocCount > 0 && - VmaIsBufferImageGranularityConflict(static_cast(m_RegionInfo[endPage].allocType), allocType)) { return true; } } + uint32_t endPage = GetEndPage(inOutAllocOffset, allocSize); + if (endPage != startPage && + m_RegionInfo[endPage].allocCount > 0 && + VmaIsBufferImageGranularityConflict(static_cast(m_RegionInfo[endPage].allocType), allocType)) + { + return true; + } + return false; } void VmaBlockBufferImageGranularity::AllocPages(uint8_t allocType, VkDeviceSize offset, VkDeviceSize size) { - if (IsEnabled()) - { - uint32_t startPage = GetStartPage(offset); - AllocPage(m_RegionInfo[startPage], allocType); + if (!IsEnabled()) + return; - uint32_t endPage = GetEndPage(offset, size); - if (startPage != endPage) - AllocPage(m_RegionInfo[endPage], allocType); - } + uint32_t startPage = GetStartPage(offset); + AllocPage(m_RegionInfo[startPage], allocType); + + uint32_t endPage = GetEndPage(offset, size); + if (startPage != endPage) + AllocPage(m_RegionInfo[endPage], allocType); } void VmaBlockBufferImageGranularity::FreePages(VkDeviceSize offset, VkDeviceSize size) { - if (IsEnabled()) + if (!IsEnabled()) + return; + + uint32_t startPage = GetStartPage(offset); + --m_RegionInfo[startPage].allocCount; + if (m_RegionInfo[startPage].allocCount == 0) + m_RegionInfo[startPage].allocType = VMA_SUBALLOCATION_TYPE_FREE; + uint32_t endPage = GetEndPage(offset, size); + if (startPage != endPage) { - uint32_t startPage = GetStartPage(offset); - --m_RegionInfo[startPage].allocCount; - if (m_RegionInfo[startPage].allocCount == 0) - m_RegionInfo[startPage].allocType = VMA_SUBALLOCATION_TYPE_FREE; - uint32_t endPage = GetEndPage(offset, size); - if (startPage != endPage) - { - --m_RegionInfo[endPage].allocCount; - if (m_RegionInfo[endPage].allocCount == 0) - m_RegionInfo[endPage].allocType = VMA_SUBALLOCATION_TYPE_FREE; - } + --m_RegionInfo[endPage].allocCount; + if (m_RegionInfo[endPage].allocCount == 0) + m_RegionInfo[endPage].allocType = VMA_SUBALLOCATION_TYPE_FREE; } } @@ -7350,36 +7405,38 @@ VmaBlockBufferImageGranularity::ValidationContext VmaBlockBufferImageGranularity bool VmaBlockBufferImageGranularity::Validate(ValidationContext& ctx, VkDeviceSize offset, VkDeviceSize size) const { - if (IsEnabled()) - { - uint32_t start = GetStartPage(offset); - ++ctx.pageAllocs[start]; - VMA_VALIDATE(m_RegionInfo[start].allocCount > 0); + if (!IsEnabled()) + return true; - uint32_t end = GetEndPage(offset, size); - if (start != end) - { - ++ctx.pageAllocs[end]; - VMA_VALIDATE(m_RegionInfo[end].allocCount > 0); - } + uint32_t start = GetStartPage(offset); + ++ctx.pageAllocs[start]; + VMA_VALIDATE(m_RegionInfo[start].allocCount > 0); + + uint32_t end = GetEndPage(offset, size); + if (start != end) + { + ++ctx.pageAllocs[end]; + VMA_VALIDATE(m_RegionInfo[end].allocCount > 0); } + return true; } bool VmaBlockBufferImageGranularity::FinishValidation(ValidationContext& ctx) const { - // Check proper page structure - if (IsEnabled()) - { - VMA_ASSERT(ctx.pageAllocs != VMA_NULL && "Validation context not initialized!"); + if (!IsEnabled()) + return true; - for (uint32_t page = 0; page < m_RegionCount; ++page) - { - VMA_VALIDATE(ctx.pageAllocs[page] == m_RegionInfo[page].allocCount); - } - vma_delete_array(ctx.allocCallbacks, ctx.pageAllocs, m_RegionCount); - ctx.pageAllocs = VMA_NULL; + // Check proper page structure + VMA_ASSERT(ctx.pageAllocs != VMA_NULL && "Validation context not initialized!"); + + for (uint32_t page = 0; page < m_RegionCount; ++page) + { + VMA_VALIDATE(ctx.pageAllocs[page] == m_RegionInfo[page].allocCount); } + vma_delete_array(ctx.allocCallbacks, ctx.pageAllocs, m_RegionCount); + ctx.pageAllocs = VMA_NULL; + return true; } @@ -10921,7 +10978,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_IsMapped(false){} VmaDeviceMemoryBlock::~VmaDeviceMemoryBlock() { @@ -10977,6 +11035,8 @@ void VmaDeviceMemoryBlock::Destroy(VmaAllocator allocator) VMA_ASSERT_LEAK(m_hMemory != VK_NULL_HANDLE); allocator->FreeVulkanMemory(m_MemoryTypeIndex, m_pMetadata->GetSize(), m_hMemory); m_hMemory = VK_NULL_HANDLE; + m_pMappedData = VMA_NULL; + m_IsMapped.store(false); vma_delete(allocator, m_pMetadata); m_pMetadata = VMA_NULL; @@ -10997,6 +11057,7 @@ void VmaDeviceMemoryBlock::PostFree(VmaAllocator hAllocator) if (m_MapCount == 0) { m_pMappedData = VMA_NULL; + m_IsMapped.store(false); (*hAllocator->GetVulkanFunctions().vkUnmapMemory)(hAllocator->m_hDevice, m_hMemory); } } @@ -11057,6 +11118,7 @@ VkResult VmaDeviceMemoryBlock::Map(VmaAllocator hAllocator, uint32_t count, void if (result == VK_SUCCESS) { VMA_ASSERT(m_pMappedData != VMA_NULL); + m_IsMapped.store(true); m_MappingHysteresis.PostMap(); m_MapCount = count; if (ppData != VMA_NULL) @@ -11082,6 +11144,7 @@ void VmaDeviceMemoryBlock::Unmap(VmaAllocator hAllocator, uint32_t count) if (totalMapCount == 0) { m_pMappedData = VMA_NULL; + m_IsMapped.store(false); (*hAllocator->GetVulkanFunctions().vkUnmapMemory)(hAllocator->m_hDevice, m_hMemory); } m_MappingHysteresis.PostUnmap(); @@ -11743,7 +11806,7 @@ VkResult VmaBlockVector::AllocatePage( { VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex]; VMA_ASSERT(pCurrBlock); - const bool isBlockMapped = pCurrBlock->GetMappedData() != VMA_NULL; + const bool isBlockMapped = pCurrBlock->IsMapped(); if((mappingI == 0) == (isMappingAllowed == isBlockMapped)) { VkResult res = AllocateFromBlock( @@ -12221,6 +12284,8 @@ VmaDefragmentationContext_T::VmaDefragmentationContext_T( m_BlockVectorCount = 1; m_PoolBlockVector = &info.pool->m_BlockVector; m_pBlockVectors = &m_PoolBlockVector; + + VmaMutexLockWrite lock(m_PoolBlockVector->m_Mutex, hAllocator->m_UseMutex); m_PoolBlockVector->SetIncrementalSort(false); m_PoolBlockVector->SortByFreeSize(); } @@ -12234,6 +12299,7 @@ VmaDefragmentationContext_T::VmaDefragmentationContext_T( VmaBlockVector* vector = m_pBlockVectors[i]; if (vector != VMA_NULL) { + VmaMutexLockWrite lock(vector->m_Mutex, hAllocator->m_UseMutex); vector->SetIncrementalSort(false); vector->SortByFreeSize(); } @@ -12264,6 +12330,7 @@ VmaDefragmentationContext_T::~VmaDefragmentationContext_T() { if (m_PoolBlockVector != VMA_NULL) { + VmaMutexLockWrite lock(m_PoolBlockVector->m_Mutex, m_PoolBlockVector->m_hAllocator->m_UseMutex); m_PoolBlockVector->SetIncrementalSort(true); } else @@ -12272,7 +12339,10 @@ VmaDefragmentationContext_T::~VmaDefragmentationContext_T() { VmaBlockVector* vector = m_pBlockVectors[i]; if (vector != VMA_NULL) + { + VmaMutexLockWrite lock(vector->m_Mutex, vector->m_hAllocator->m_UseMutex); vector->SetIncrementalSort(true); + } } } @@ -12370,7 +12440,11 @@ VkResult VmaDefragmentationContext_T::DefragmentPassEnd(VmaDefragmentationPassMo { case VMA_DEFRAGMENTATION_MOVE_OPERATION_COPY: { - uint8_t mapCount = move.srcAllocation->SwapBlockAllocation(vector->m_hAllocator, move.dstTmpAllocation); + uint8_t mapCount = 0; + { + VmaMutexLockWrite swapLock(vector->GetMutex(), vector->GetAllocator()->m_UseMutex); + mapCount = move.srcAllocation->SwapBlockAllocation(vector->m_hAllocator, move.dstTmpAllocation); + } if (mapCount > 0) { allocator = vector->m_hAllocator; @@ -13287,7 +13361,7 @@ VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) : } #endif } -#if !(VMA_MEMORY_BUDGET) +#if !(VMA_MEMORY_BUDGET) || !(VMA_GET_PHYSICAL_DEVICE_PROPERTIES2) 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."); @@ -13363,8 +13437,35 @@ VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) : ImportVulkanFunctions(pCreateInfo->pVulkanFunctions); - (*m_VulkanFunctions.vkGetPhysicalDeviceProperties)(m_PhysicalDevice, &m_PhysicalDeviceProperties); - (*m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties)(m_PhysicalDevice, &m_MemProps); + // Call vkGetPhysicalDeviceProperties[2][KHR]. +#if VMA_GET_PHYSICAL_DEVICE_PROPERTIES2 + if(m_VulkanFunctions.vkGetPhysicalDeviceProperties2KHR) + { + VkPhysicalDeviceProperties2KHR props2 = { + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR }; + (*m_VulkanFunctions.vkGetPhysicalDeviceProperties2KHR)(m_PhysicalDevice, &props2); + memcpy(&m_PhysicalDeviceProperties, &props2.properties, sizeof(m_PhysicalDeviceProperties)); + } + else +#endif + { + (*m_VulkanFunctions.vkGetPhysicalDeviceProperties)(m_PhysicalDevice, &m_PhysicalDeviceProperties); + } + + // Call vkGetPhysicalDeviceMemoryProperties[2][KHR]. +#if VMA_GET_PHYSICAL_DEVICE_PROPERTIES2 + if(m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties2KHR) + { + VkPhysicalDeviceMemoryProperties2KHR memProps2 = { + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR }; + (*m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties2KHR)(m_PhysicalDevice, &memProps2); + memcpy(&m_MemProps, &memProps2.memoryProperties, sizeof(m_MemProps)); + } + else +#endif + { + (*m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties)(m_PhysicalDevice, &m_MemProps); + } VMA_ASSERT(VmaIsPow2(VMA_MIN_ALIGNMENT)); VMA_ASSERT(VmaIsPow2(VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY)); @@ -13507,6 +13608,7 @@ void VmaAllocator_T::ImportVulkanFunctions_Static() if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) { m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties2KHR = (PFN_vkGetPhysicalDeviceMemoryProperties2)vkGetPhysicalDeviceMemoryProperties2; + m_VulkanFunctions.vkGetPhysicalDeviceProperties2KHR = (PFN_vkGetPhysicalDeviceProperties2)vkGetPhysicalDeviceProperties2; } #endif @@ -13558,8 +13660,9 @@ void VmaAllocator_T::ImportVulkanFunctions_Custom(const VmaVulkanFunctions* pVul VMA_COPY_IF_NOT_NULL(vkBindImageMemory2KHR); #endif -#if VMA_MEMORY_BUDGET || VMA_VULKAN_VERSION >= 1001000 +#if VMA_GET_PHYSICAL_DEVICE_PROPERTIES2 VMA_COPY_IF_NOT_NULL(vkGetPhysicalDeviceMemoryProperties2KHR); + VMA_COPY_IF_NOT_NULL(vkGetPhysicalDeviceProperties2KHR); #endif #if VMA_KHR_MAINTENANCE4 || VMA_VULKAN_VERSION >= 1003000 @@ -13618,18 +13721,22 @@ void VmaAllocator_T::ImportVulkanFunctions_Dynamic() } #endif -#if VMA_MEMORY_BUDGET || VMA_VULKAN_VERSION >= 1001000 +#if VMA_GET_PHYSICAL_DEVICE_PROPERTIES2 if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) { VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, PFN_vkGetPhysicalDeviceMemoryProperties2KHR, "vkGetPhysicalDeviceMemoryProperties2"); + VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceProperties2KHR, PFN_vkGetPhysicalDeviceProperties2KHR, "vkGetPhysicalDeviceProperties2"); // Try to fetch the pointer from the other name, based on suspected driver bug - see issue #410. VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, PFN_vkGetPhysicalDeviceMemoryProperties2KHR, "vkGetPhysicalDeviceMemoryProperties2KHR"); + VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceProperties2KHR, PFN_vkGetPhysicalDeviceProperties2KHR, "vkGetPhysicalDeviceProperties2KHR"); } else if(m_UseExtMemoryBudget) { VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, PFN_vkGetPhysicalDeviceMemoryProperties2KHR, "vkGetPhysicalDeviceMemoryProperties2KHR"); + VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceProperties2KHR, PFN_vkGetPhysicalDeviceProperties2KHR, "vkGetPhysicalDeviceProperties2KHR"); // Try to fetch the pointer from the other name, based on suspected driver bug - see issue #410. VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, PFN_vkGetPhysicalDeviceMemoryProperties2KHR, "vkGetPhysicalDeviceMemoryProperties2"); + VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceProperties2KHR, PFN_vkGetPhysicalDeviceProperties2KHR, "vkGetPhysicalDeviceProperties2"); } #endif @@ -13649,17 +13756,6 @@ 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)) - { - VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, PFN_vkGetPhysicalDeviceMemoryProperties2KHR, "vkGetPhysicalDeviceMemoryProperties2"); - } - 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)) { @@ -13722,12 +13818,14 @@ void VmaAllocator_T::ValidateVulkanFunctions() const } #endif -#if VMA_MEMORY_BUDGET || VMA_VULKAN_VERSION >= 1001000 +#if VMA_GET_PHYSICAL_DEVICE_PROPERTIES2 if(m_UseExtMemoryBudget || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) { VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties2KHR != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceProperties2KHR != VMA_NULL); } #endif + #if VMA_EXTERNAL_MEMORY_WIN32 if (m_UseKhrExternalMemoryWin32) { @@ -15608,6 +15706,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaImportVulkanFunctionsFromVolk( if (pAllocatorCreateInfo->vulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) { COPY_GLOBAL_TO_VMA_FUNC(vkGetPhysicalDeviceMemoryProperties2, vkGetPhysicalDeviceMemoryProperties2KHR) + COPY_GLOBAL_TO_VMA_FUNC(vkGetPhysicalDeviceProperties2, vkGetPhysicalDeviceProperties2KHR) COPY_DEVICE_TO_VMA_FUNC(vkGetBufferMemoryRequirements2, vkGetBufferMemoryRequirements2KHR) COPY_DEVICE_TO_VMA_FUNC(vkGetImageMemoryRequirements2, vkGetImageMemoryRequirements2KHR) COPY_DEVICE_TO_VMA_FUNC(vkBindBufferMemory2, vkBindBufferMemory2KHR) @@ -15646,6 +15745,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaImportVulkanFunctionsFromVolk( if ((pAllocatorCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT) != 0) { COPY_GLOBAL_TO_VMA_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, vkGetPhysicalDeviceMemoryProperties2KHR) + COPY_GLOBAL_TO_VMA_FUNC(vkGetPhysicalDeviceProperties2KHR, vkGetPhysicalDeviceProperties2KHR) } #endif #if VMA_EXTERNAL_MEMORY_WIN32 diff --git a/3rdparty/vulkan/include/vulkan/vk_mem_alloc.h b/3rdparty/vulkan/include/vulkan/vk_mem_alloc.h index 24792855e2..f2b58bf620 100644 --- a/3rdparty/vulkan/include/vulkan/vk_mem_alloc.h +++ b/3rdparty/vulkan/include/vulkan/vk_mem_alloc.h @@ -25,7 +25,7 @@ /** \mainpage Vulkan Memory Allocator -Version 3.4.0-development +Version 3.4.0 Copyright (c) 2017-2026 Advanced Micro Devices, Inc. All rights reserved. \n License: MIT \n @@ -129,8 +129,10 @@ See documentation chapter: \ref statistics. extern "C" { #endif -#if !defined(VULKAN_H_) -#include +#ifndef VMA_VULKAN_HEADERS_ALREADY_INCLUDED + #if !defined(VULKAN_H_) + #include + #endif #endif #define VMA_VERSION (VK_MAKE_VERSION(3, 4, 0)) @@ -194,8 +196,16 @@ extern "C" { #endif #endif +#if !defined(VMA_GET_PHYSICAL_DEVICE_PROPERTIES2) + #if VK_KHR_get_physical_device_properties2 || VMA_VULKAN_VERSION >= 1001000 + #define VMA_GET_PHYSICAL_DEVICE_PROPERTIES2 1 + #else + #define VMA_GET_PHYSICAL_DEVICE_PROPERTIES2 0 + #endif +#endif + #if !defined(VMA_MEMORY_BUDGET) - #if VK_EXT_memory_budget && (VK_KHR_get_physical_device_properties2 || VMA_VULKAN_VERSION >= 1001000) + #if VK_EXT_memory_budget && VMA_GET_PHYSICAL_DEVICE_PROPERTIES2 #define VMA_MEMORY_BUDGET 1 #else #define VMA_MEMORY_BUDGET 0 @@ -1049,7 +1059,7 @@ typedef struct VmaVulkanFunctions /// 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 +#if VMA_GET_PHYSICAL_DEVICE_PROPERTIES2 /// 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 @@ -1064,6 +1074,10 @@ typedef struct VmaVulkanFunctions #else void* VMA_NULLABLE vkGetMemoryWin32HandleKHR; #endif +#if VMA_GET_PHYSICAL_DEVICE_PROPERTIES2 + /// Fetch from "vkGetPhysicalDeviceProperties2" on Vulkan >= 1.1, but you can also fetch it from "vkGetPhysicalDeviceProperties2KHR" if you enabled extension VK_KHR_get_physical_device_properties2. + PFN_vkGetPhysicalDeviceProperties2KHR VMA_NULLABLE vkGetPhysicalDeviceProperties2KHR; +#endif } VmaVulkanFunctions; /// Description of a Allocator to be created. @@ -3125,7 +3139,7 @@ remove them if not needed. */ #if !defined(VMA_CONFIGURATION_USER_INCLUDES_H) #include // for assert - #include // for min, max, swap + #include // for min, max, swap, sort #include #else #include VMA_CONFIGURATION_USER_INCLUDES_H @@ -3442,6 +3456,11 @@ If providing your own implementation, you need to implement a subset of std::ato #define VMA_ATOMIC_UINT64 std::atomic #endif +#ifndef VMA_ATOMIC_BOOL + #include + #define VMA_ATOMIC_BOOL std::atomic +#endif + #ifndef VMA_DEBUG_ALWAYS_DEDICATED_MEMORY /** Every allocation will have its own memory block. @@ -6549,6 +6568,7 @@ public: uint32_t GetMemoryTypeIndex() const { return m_MemoryTypeIndex; } uint32_t GetId() const { return m_Id; } void* GetMappedData() const { return m_pMappedData; } + bool IsMapped() const { return m_IsMapped.load(); } uint32_t GetMapRefCount() const { return m_MapCount; } // Call when allocation/free was made from m_pMetadata. @@ -6596,12 +6616,18 @@ private: /* Protects access to m_hMemory so it is not used by multiple threads simultaneously, e.g. vkMapMemory, vkBindBufferMemory. Also protects m_MapCount, m_pMappedData. + m_IsMapped mirrors whether m_pMappedData is non-null and can be read without this mutex in allocation heuristics. Allocations, deallocations, any change in m_pMetadata is protected by parent's VmaBlockVector::m_Mutex. */ VMA_MUTEX m_MapAndBindMutex; VmaMappingHysteresis m_MappingHysteresis; uint32_t m_MapCount; void* m_pMappedData; + /* + Mirrors `m_pMappedData != VMA_NULL` for allocation heuristics that only need mapped/unmapped state. + This is atomic so allocation scans don't race with Map/Unmap while the actual mapped pointer remains protected by m_MapAndBindMutex. + */ + VMA_ATOMIC_BOOL m_IsMapped; VmaWin32Handle m_Handle; }; @@ -7166,6 +7192,14 @@ void VmaBlockMetadata::PrintDetailedMap_End(class VmaJsonWriter& json) #ifndef _VMA_BLOCK_BUFFER_IMAGE_GRANULARITY // Before deleting object of this class remember to call 'Destroy()' +/* +Tracks block occupancy at VkPhysicalDeviceLimits::bufferImageGranularity page boundaries. +For each granularity-sized page in a memory block, m_RegionInfo stores: +- allocCount: how many allocations touch this page as their first or last page. +- allocType: the remembered VmaSuballocationType for that page while allocCount > 0. +Only boundary pages are tracked because buffer-image granularity conflicts matter when +adjacent allocations share the same granularity page at the start or end of an allocation. +*/ class VmaBlockBufferImageGranularity final { public: @@ -7188,6 +7222,21 @@ public: VkDeviceSize& inOutAllocSize, VkDeviceSize& inOutAllocAlignment) const; + /* + Checks whether an allocation placed in a free block would conflict with existing + allocations due to buffer-image granularity requirements and, if needed, aligns the + allocation start to the next granularity page. + + Parameters: + - inOutAllocOffset: candidate allocation offset inside the block; may be increased. + - allocSize: size of the allocation being placed. + - blockOffset: start offset of the free block being considered. + - blockSize: size of the free block being considered. + - allocType: VmaSuballocationType of the allocation being placed. + + Returns true when the placement conflicts or no longer fits in the free block after alignment. + Returns false when the placement is valid, possibly after updating inOutAllocOffset. + */ bool CheckConflictAndAlignUp(VkDeviceSize& inOutAllocOffset, VkDeviceSize allocSize, VkDeviceSize blockOffset, @@ -7276,56 +7325,62 @@ bool VmaBlockBufferImageGranularity::CheckConflictAndAlignUp(VkDeviceSize& inOut VkDeviceSize blockSize, VmaSuballocationType allocType) const { - if (IsEnabled()) + if (!IsEnabled()) + return false; + + uint32_t startPage = GetStartPage(inOutAllocOffset); + if (m_RegionInfo[startPage].allocCount > 0 && + VmaIsBufferImageGranularityConflict(static_cast(m_RegionInfo[startPage].allocType), allocType)) { - uint32_t startPage = GetStartPage(inOutAllocOffset); + inOutAllocOffset = VmaAlignUp(inOutAllocOffset, m_BufferImageGranularity); + if (blockSize < allocSize + inOutAllocOffset - blockOffset) + return true; + startPage = GetStartPage(inOutAllocOffset); if (m_RegionInfo[startPage].allocCount > 0 && VmaIsBufferImageGranularityConflict(static_cast(m_RegionInfo[startPage].allocType), allocType)) - { - inOutAllocOffset = VmaAlignUp(inOutAllocOffset, m_BufferImageGranularity); - if (blockSize < allocSize + inOutAllocOffset - blockOffset) - return true; - ++startPage; - } - uint32_t endPage = GetEndPage(inOutAllocOffset, allocSize); - if (endPage != startPage && - m_RegionInfo[endPage].allocCount > 0 && - VmaIsBufferImageGranularityConflict(static_cast(m_RegionInfo[endPage].allocType), allocType)) { return true; } } + uint32_t endPage = GetEndPage(inOutAllocOffset, allocSize); + if (endPage != startPage && + m_RegionInfo[endPage].allocCount > 0 && + VmaIsBufferImageGranularityConflict(static_cast(m_RegionInfo[endPage].allocType), allocType)) + { + return true; + } + return false; } void VmaBlockBufferImageGranularity::AllocPages(uint8_t allocType, VkDeviceSize offset, VkDeviceSize size) { - if (IsEnabled()) - { - uint32_t startPage = GetStartPage(offset); - AllocPage(m_RegionInfo[startPage], allocType); + if (!IsEnabled()) + return; - uint32_t endPage = GetEndPage(offset, size); - if (startPage != endPage) - AllocPage(m_RegionInfo[endPage], allocType); - } + uint32_t startPage = GetStartPage(offset); + AllocPage(m_RegionInfo[startPage], allocType); + + uint32_t endPage = GetEndPage(offset, size); + if (startPage != endPage) + AllocPage(m_RegionInfo[endPage], allocType); } void VmaBlockBufferImageGranularity::FreePages(VkDeviceSize offset, VkDeviceSize size) { - if (IsEnabled()) + if (!IsEnabled()) + return; + + uint32_t startPage = GetStartPage(offset); + --m_RegionInfo[startPage].allocCount; + if (m_RegionInfo[startPage].allocCount == 0) + m_RegionInfo[startPage].allocType = VMA_SUBALLOCATION_TYPE_FREE; + uint32_t endPage = GetEndPage(offset, size); + if (startPage != endPage) { - uint32_t startPage = GetStartPage(offset); - --m_RegionInfo[startPage].allocCount; - if (m_RegionInfo[startPage].allocCount == 0) - m_RegionInfo[startPage].allocType = VMA_SUBALLOCATION_TYPE_FREE; - uint32_t endPage = GetEndPage(offset, size); - if (startPage != endPage) - { - --m_RegionInfo[endPage].allocCount; - if (m_RegionInfo[endPage].allocCount == 0) - m_RegionInfo[endPage].allocType = VMA_SUBALLOCATION_TYPE_FREE; - } + --m_RegionInfo[endPage].allocCount; + if (m_RegionInfo[endPage].allocCount == 0) + m_RegionInfo[endPage].allocType = VMA_SUBALLOCATION_TYPE_FREE; } } @@ -7350,36 +7405,38 @@ VmaBlockBufferImageGranularity::ValidationContext VmaBlockBufferImageGranularity bool VmaBlockBufferImageGranularity::Validate(ValidationContext& ctx, VkDeviceSize offset, VkDeviceSize size) const { - if (IsEnabled()) - { - uint32_t start = GetStartPage(offset); - ++ctx.pageAllocs[start]; - VMA_VALIDATE(m_RegionInfo[start].allocCount > 0); + if (!IsEnabled()) + return true; - uint32_t end = GetEndPage(offset, size); - if (start != end) - { - ++ctx.pageAllocs[end]; - VMA_VALIDATE(m_RegionInfo[end].allocCount > 0); - } + uint32_t start = GetStartPage(offset); + ++ctx.pageAllocs[start]; + VMA_VALIDATE(m_RegionInfo[start].allocCount > 0); + + uint32_t end = GetEndPage(offset, size); + if (start != end) + { + ++ctx.pageAllocs[end]; + VMA_VALIDATE(m_RegionInfo[end].allocCount > 0); } + return true; } bool VmaBlockBufferImageGranularity::FinishValidation(ValidationContext& ctx) const { - // Check proper page structure - if (IsEnabled()) - { - VMA_ASSERT(ctx.pageAllocs != VMA_NULL && "Validation context not initialized!"); + if (!IsEnabled()) + return true; - for (uint32_t page = 0; page < m_RegionCount; ++page) - { - VMA_VALIDATE(ctx.pageAllocs[page] == m_RegionInfo[page].allocCount); - } - vma_delete_array(ctx.allocCallbacks, ctx.pageAllocs, m_RegionCount); - ctx.pageAllocs = VMA_NULL; + // Check proper page structure + VMA_ASSERT(ctx.pageAllocs != VMA_NULL && "Validation context not initialized!"); + + for (uint32_t page = 0; page < m_RegionCount; ++page) + { + VMA_VALIDATE(ctx.pageAllocs[page] == m_RegionInfo[page].allocCount); } + vma_delete_array(ctx.allocCallbacks, ctx.pageAllocs, m_RegionCount); + ctx.pageAllocs = VMA_NULL; + return true; } @@ -10921,7 +10978,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_IsMapped(false){} VmaDeviceMemoryBlock::~VmaDeviceMemoryBlock() { @@ -10977,6 +11035,8 @@ void VmaDeviceMemoryBlock::Destroy(VmaAllocator allocator) VMA_ASSERT_LEAK(m_hMemory != VK_NULL_HANDLE); allocator->FreeVulkanMemory(m_MemoryTypeIndex, m_pMetadata->GetSize(), m_hMemory); m_hMemory = VK_NULL_HANDLE; + m_pMappedData = VMA_NULL; + m_IsMapped.store(false); vma_delete(allocator, m_pMetadata); m_pMetadata = VMA_NULL; @@ -10997,6 +11057,7 @@ void VmaDeviceMemoryBlock::PostFree(VmaAllocator hAllocator) if (m_MapCount == 0) { m_pMappedData = VMA_NULL; + m_IsMapped.store(false); (*hAllocator->GetVulkanFunctions().vkUnmapMemory)(hAllocator->m_hDevice, m_hMemory); } } @@ -11057,6 +11118,7 @@ VkResult VmaDeviceMemoryBlock::Map(VmaAllocator hAllocator, uint32_t count, void if (result == VK_SUCCESS) { VMA_ASSERT(m_pMappedData != VMA_NULL); + m_IsMapped.store(true); m_MappingHysteresis.PostMap(); m_MapCount = count; if (ppData != VMA_NULL) @@ -11082,6 +11144,7 @@ void VmaDeviceMemoryBlock::Unmap(VmaAllocator hAllocator, uint32_t count) if (totalMapCount == 0) { m_pMappedData = VMA_NULL; + m_IsMapped.store(false); (*hAllocator->GetVulkanFunctions().vkUnmapMemory)(hAllocator->m_hDevice, m_hMemory); } m_MappingHysteresis.PostUnmap(); @@ -11743,7 +11806,7 @@ VkResult VmaBlockVector::AllocatePage( { VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex]; VMA_ASSERT(pCurrBlock); - const bool isBlockMapped = pCurrBlock->GetMappedData() != VMA_NULL; + const bool isBlockMapped = pCurrBlock->IsMapped(); if((mappingI == 0) == (isMappingAllowed == isBlockMapped)) { VkResult res = AllocateFromBlock( @@ -12221,6 +12284,8 @@ VmaDefragmentationContext_T::VmaDefragmentationContext_T( m_BlockVectorCount = 1; m_PoolBlockVector = &info.pool->m_BlockVector; m_pBlockVectors = &m_PoolBlockVector; + + VmaMutexLockWrite lock(m_PoolBlockVector->m_Mutex, hAllocator->m_UseMutex); m_PoolBlockVector->SetIncrementalSort(false); m_PoolBlockVector->SortByFreeSize(); } @@ -12234,6 +12299,7 @@ VmaDefragmentationContext_T::VmaDefragmentationContext_T( VmaBlockVector* vector = m_pBlockVectors[i]; if (vector != VMA_NULL) { + VmaMutexLockWrite lock(vector->m_Mutex, hAllocator->m_UseMutex); vector->SetIncrementalSort(false); vector->SortByFreeSize(); } @@ -12264,6 +12330,7 @@ VmaDefragmentationContext_T::~VmaDefragmentationContext_T() { if (m_PoolBlockVector != VMA_NULL) { + VmaMutexLockWrite lock(m_PoolBlockVector->m_Mutex, m_PoolBlockVector->m_hAllocator->m_UseMutex); m_PoolBlockVector->SetIncrementalSort(true); } else @@ -12272,7 +12339,10 @@ VmaDefragmentationContext_T::~VmaDefragmentationContext_T() { VmaBlockVector* vector = m_pBlockVectors[i]; if (vector != VMA_NULL) + { + VmaMutexLockWrite lock(vector->m_Mutex, vector->m_hAllocator->m_UseMutex); vector->SetIncrementalSort(true); + } } } @@ -12370,7 +12440,11 @@ VkResult VmaDefragmentationContext_T::DefragmentPassEnd(VmaDefragmentationPassMo { case VMA_DEFRAGMENTATION_MOVE_OPERATION_COPY: { - uint8_t mapCount = move.srcAllocation->SwapBlockAllocation(vector->m_hAllocator, move.dstTmpAllocation); + uint8_t mapCount = 0; + { + VmaMutexLockWrite swapLock(vector->GetMutex(), vector->GetAllocator()->m_UseMutex); + mapCount = move.srcAllocation->SwapBlockAllocation(vector->m_hAllocator, move.dstTmpAllocation); + } if (mapCount > 0) { allocator = vector->m_hAllocator; @@ -13287,7 +13361,7 @@ VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) : } #endif } -#if !(VMA_MEMORY_BUDGET) +#if !(VMA_MEMORY_BUDGET) || !(VMA_GET_PHYSICAL_DEVICE_PROPERTIES2) 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."); @@ -13363,8 +13437,35 @@ VmaAllocator_T::VmaAllocator_T(const VmaAllocatorCreateInfo* pCreateInfo) : ImportVulkanFunctions(pCreateInfo->pVulkanFunctions); - (*m_VulkanFunctions.vkGetPhysicalDeviceProperties)(m_PhysicalDevice, &m_PhysicalDeviceProperties); - (*m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties)(m_PhysicalDevice, &m_MemProps); + // Call vkGetPhysicalDeviceProperties[2][KHR]. +#if VMA_GET_PHYSICAL_DEVICE_PROPERTIES2 + if(m_VulkanFunctions.vkGetPhysicalDeviceProperties2KHR) + { + VkPhysicalDeviceProperties2KHR props2 = { + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR }; + (*m_VulkanFunctions.vkGetPhysicalDeviceProperties2KHR)(m_PhysicalDevice, &props2); + memcpy(&m_PhysicalDeviceProperties, &props2.properties, sizeof(m_PhysicalDeviceProperties)); + } + else +#endif + { + (*m_VulkanFunctions.vkGetPhysicalDeviceProperties)(m_PhysicalDevice, &m_PhysicalDeviceProperties); + } + + // Call vkGetPhysicalDeviceMemoryProperties[2][KHR]. +#if VMA_GET_PHYSICAL_DEVICE_PROPERTIES2 + if(m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties2KHR) + { + VkPhysicalDeviceMemoryProperties2KHR memProps2 = { + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR }; + (*m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties2KHR)(m_PhysicalDevice, &memProps2); + memcpy(&m_MemProps, &memProps2.memoryProperties, sizeof(m_MemProps)); + } + else +#endif + { + (*m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties)(m_PhysicalDevice, &m_MemProps); + } VMA_ASSERT(VmaIsPow2(VMA_MIN_ALIGNMENT)); VMA_ASSERT(VmaIsPow2(VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY)); @@ -13507,6 +13608,7 @@ void VmaAllocator_T::ImportVulkanFunctions_Static() if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) { m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties2KHR = (PFN_vkGetPhysicalDeviceMemoryProperties2)vkGetPhysicalDeviceMemoryProperties2; + m_VulkanFunctions.vkGetPhysicalDeviceProperties2KHR = (PFN_vkGetPhysicalDeviceProperties2)vkGetPhysicalDeviceProperties2; } #endif @@ -13558,8 +13660,9 @@ void VmaAllocator_T::ImportVulkanFunctions_Custom(const VmaVulkanFunctions* pVul VMA_COPY_IF_NOT_NULL(vkBindImageMemory2KHR); #endif -#if VMA_MEMORY_BUDGET || VMA_VULKAN_VERSION >= 1001000 +#if VMA_GET_PHYSICAL_DEVICE_PROPERTIES2 VMA_COPY_IF_NOT_NULL(vkGetPhysicalDeviceMemoryProperties2KHR); + VMA_COPY_IF_NOT_NULL(vkGetPhysicalDeviceProperties2KHR); #endif #if VMA_KHR_MAINTENANCE4 || VMA_VULKAN_VERSION >= 1003000 @@ -13618,18 +13721,22 @@ void VmaAllocator_T::ImportVulkanFunctions_Dynamic() } #endif -#if VMA_MEMORY_BUDGET || VMA_VULKAN_VERSION >= 1001000 +#if VMA_GET_PHYSICAL_DEVICE_PROPERTIES2 if(m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) { VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, PFN_vkGetPhysicalDeviceMemoryProperties2KHR, "vkGetPhysicalDeviceMemoryProperties2"); + VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceProperties2KHR, PFN_vkGetPhysicalDeviceProperties2KHR, "vkGetPhysicalDeviceProperties2"); // Try to fetch the pointer from the other name, based on suspected driver bug - see issue #410. VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, PFN_vkGetPhysicalDeviceMemoryProperties2KHR, "vkGetPhysicalDeviceMemoryProperties2KHR"); + VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceProperties2KHR, PFN_vkGetPhysicalDeviceProperties2KHR, "vkGetPhysicalDeviceProperties2KHR"); } else if(m_UseExtMemoryBudget) { VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, PFN_vkGetPhysicalDeviceMemoryProperties2KHR, "vkGetPhysicalDeviceMemoryProperties2KHR"); + VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceProperties2KHR, PFN_vkGetPhysicalDeviceProperties2KHR, "vkGetPhysicalDeviceProperties2KHR"); // Try to fetch the pointer from the other name, based on suspected driver bug - see issue #410. VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, PFN_vkGetPhysicalDeviceMemoryProperties2KHR, "vkGetPhysicalDeviceMemoryProperties2"); + VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceProperties2KHR, PFN_vkGetPhysicalDeviceProperties2KHR, "vkGetPhysicalDeviceProperties2"); } #endif @@ -13649,17 +13756,6 @@ 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)) - { - VMA_FETCH_INSTANCE_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, PFN_vkGetPhysicalDeviceMemoryProperties2KHR, "vkGetPhysicalDeviceMemoryProperties2"); - } - 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)) { @@ -13722,12 +13818,14 @@ void VmaAllocator_T::ValidateVulkanFunctions() const } #endif -#if VMA_MEMORY_BUDGET || VMA_VULKAN_VERSION >= 1001000 +#if VMA_GET_PHYSICAL_DEVICE_PROPERTIES2 if(m_UseExtMemoryBudget || m_VulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) { VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties2KHR != VMA_NULL); + VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceProperties2KHR != VMA_NULL); } #endif + #if VMA_EXTERNAL_MEMORY_WIN32 if (m_UseKhrExternalMemoryWin32) { @@ -15608,6 +15706,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaImportVulkanFunctionsFromVolk( if (pAllocatorCreateInfo->vulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) { COPY_GLOBAL_TO_VMA_FUNC(vkGetPhysicalDeviceMemoryProperties2, vkGetPhysicalDeviceMemoryProperties2KHR) + COPY_GLOBAL_TO_VMA_FUNC(vkGetPhysicalDeviceProperties2, vkGetPhysicalDeviceProperties2KHR) COPY_DEVICE_TO_VMA_FUNC(vkGetBufferMemoryRequirements2, vkGetBufferMemoryRequirements2KHR) COPY_DEVICE_TO_VMA_FUNC(vkGetImageMemoryRequirements2, vkGetImageMemoryRequirements2KHR) COPY_DEVICE_TO_VMA_FUNC(vkBindBufferMemory2, vkBindBufferMemory2KHR) @@ -15646,6 +15745,7 @@ VMA_CALL_PRE VkResult VMA_CALL_POST vmaImportVulkanFunctionsFromVolk( if ((pAllocatorCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT) != 0) { COPY_GLOBAL_TO_VMA_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, vkGetPhysicalDeviceMemoryProperties2KHR) + COPY_GLOBAL_TO_VMA_FUNC(vkGetPhysicalDeviceProperties2KHR, vkGetPhysicalDeviceProperties2KHR) } #endif #if VMA_EXTERNAL_MEMORY_WIN32