VulkanMemoryAllocator 0.5.1 → 0.6
raw patch · 5 files changed
+142/−48 lines, 5 filesdep ~vulkanPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: vulkan
API changes (from Hackage documentation)
- VulkanMemoryAllocator: instance GHC.Classes.Eq VulkanMemoryAllocator.PoolCreateInfo
+ VulkanMemoryAllocator: [$sel:memoryAllocateNext:PoolCreateInfo] :: PoolCreateInfo -> Ptr ()
+ VulkanMemoryAllocator: [$sel:minAllocationAlignment:PoolCreateInfo] :: PoolCreateInfo -> DeviceSize
- VulkanMemoryAllocator: PoolCreateInfo :: Word32 -> PoolCreateFlags -> DeviceSize -> Word64 -> Word64 -> Word32 -> Float -> PoolCreateInfo
+ VulkanMemoryAllocator: PoolCreateInfo :: Word32 -> PoolCreateFlags -> DeviceSize -> Word64 -> Word64 -> Word32 -> Float -> DeviceSize -> Ptr () -> PoolCreateInfo
Files
- VulkanMemoryAllocator.cabal +2/−2
- VulkanMemoryAllocator/include/vk_mem_alloc.h +101/−39
- changelog.md +3/−0
- package.yaml +2/−2
- src/VulkanMemoryAllocator.hs +34/−5
VulkanMemoryAllocator.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: VulkanMemoryAllocator-version: 0.5.1+version: 0.6 synopsis: Bindings to the VulkanMemoryAllocator library category: Graphics homepage: https://github.com/expipiplus1/vulkan#readme@@ -96,7 +96,7 @@ , bytestring , transformers , vector- , vulkan >=3.6 && <3.11+ , vulkan >=3.6 && <3.12 if flag(safe-foreign-calls) cpp-options: -DSAFE_FOREIGN_CALLS if flag(vma-ndebug)
VulkanMemoryAllocator/include/vk_mem_alloc.h view
@@ -25,7 +25,7 @@ /** \mainpage Vulkan Memory Allocator -<b>Version 3.0.0-development</b> (2021-02-16) +<b>Version 3.0.0-development</b> (2021-06-21) Copyright (c) 2017-2021 Advanced Micro Devices, Inc. All rights reserved. \n License: MIT @@ -3093,6 +3093,23 @@ 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 pMemoryAllocateNext; } VmaPoolCreateInfo; /** \brief Describes parameter of existing #VmaPool. @@ -4346,12 +4363,16 @@ #define VMA_DEBUG_ALWAYS_DEDICATED_MEMORY (0) #endif -#ifndef VMA_DEBUG_ALIGNMENT +#ifndef VMA_MIN_ALIGNMENT /** Minimum alignment of all allocations, in bytes. - Set to more than 1 for debugging purposes only. Must be power of two. + Set to more than 1 for debugging purposes. Must be power of two. */ - #define VMA_DEBUG_ALIGNMENT (1) + #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 @@ -4963,6 +4984,7 @@ } VmaStlAllocator& operator=(const VmaStlAllocator& x) = delete; + VmaStlAllocator(const VmaStlAllocator&) = default; }; #if VMA_USE_STL_VECTOR @@ -5102,17 +5124,13 @@ } } - void resize(size_t newCount, bool freeMemory = false) + void resize(size_t newCount) { size_t newCapacity = m_Capacity; if(newCount > m_Capacity) { newCapacity = VMA_MAX(newCount, VMA_MAX(m_Capacity * 3 / 2, (size_t)8)); } - else if(freeMemory) - { - newCapacity = newCount; - } if(newCapacity != m_Capacity) { @@ -5130,11 +5148,27 @@ m_Count = newCount; } - void clear(bool freeMemory = false) + void clear() { - resize(0, freeMemory); + resize(0); } + void shrink_to_fit() + { + if(m_Capacity > m_Count) + { + T* newArray = VMA_NULL; + if(m_Count > 0) + { + newArray = VmaAllocateArray<T>(m_Allocator.m_pCallbacks, m_Count); + memcpy(newArray, m_pArray, m_Count * sizeof(T)); + } + VmaFree(m_Allocator.m_pCallbacks, m_pArray); + m_Capacity = m_Count; + m_pArray = newArray; + } + } + void insert(size_t index, const T& src) { VMA_HEAVY_ASSERT(index <= m_Count); @@ -5312,12 +5346,16 @@ if(newCount > N && m_Count > N) { // Any direction, staying in m_DynamicArray - m_DynamicArray.resize(newCount, freeMemory); + m_DynamicArray.resize(newCount); + if(freeMemory) + { + m_DynamicArray.shrink_to_fit(); + } } else if(newCount > N && m_Count <= N) { // Growing, moving from m_StaticArray to m_DynamicArray - m_DynamicArray.resize(newCount, freeMemory); + m_DynamicArray.resize(newCount); if(m_Count > 0) { memcpy(m_DynamicArray.data(), m_StaticArray, m_Count * sizeof(T)); @@ -5330,7 +5368,11 @@ { memcpy(m_StaticArray, m_DynamicArray.data(), newCount * sizeof(T)); } - m_DynamicArray.resize(0, freeMemory); + m_DynamicArray.resize(0); + if(freeMemory) + { + m_DynamicArray.shrink_to_fit(); + } } else { @@ -5341,7 +5383,11 @@ void clear(bool freeMemory = false) { - m_DynamicArray.clear(freeMemory); + m_DynamicArray.clear(); + if(freeMemory) + { + m_DynamicArray.shrink_to_fit(); + } m_Count = 0; } @@ -7301,7 +7347,9 @@ uint32_t frameInUseCount, bool explicitBlockSize, uint32_t algorithm, - float priority); + float priority, + VkDeviceSize minAllocationAlignment, + void* pMemoryAllocateNext); ~VmaBlockVector(); VkResult CreateMinBlocks(); @@ -7385,6 +7433,8 @@ const bool m_ExplicitBlockSize; const uint32_t m_Algorithm; const float m_Priority; + const VkDeviceSize m_MinAllocationAlignment; + void* const m_pMemoryAllocateNext; VMA_RW_MUTEX m_Mutex; /* There can be at most one allocation that is completely empty (except when minBlockCount > 0) - @@ -8204,8 +8254,8 @@ VkDeviceSize GetMemoryTypeMinAlignment(uint32_t memTypeIndex) const { return IsMemoryTypeNonCoherent(memTypeIndex) ? - VMA_MAX((VkDeviceSize)VMA_DEBUG_ALIGNMENT, m_PhysicalDeviceProperties.limits.nonCoherentAtomSize) : - (VkDeviceSize)VMA_DEBUG_ALIGNMENT; + VMA_MAX((VkDeviceSize)VMA_MIN_ALIGNMENT, m_PhysicalDeviceProperties.limits.nonCoherentAtomSize) : + (VkDeviceSize)VMA_MIN_ALIGNMENT; } bool IsIntegratedGpu() const @@ -8337,6 +8387,7 @@ */ uint32_t GetGpuDefragmentationMemoryTypeBits(); + private: VkDeviceSize m_PreferredLargeHeapBlockSize; @@ -12846,8 +12897,10 @@ (createInfo.flags & VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT) != 0 ? 1 : hAllocator->GetBufferImageGranularity(), createInfo.frameInUseCount, createInfo.blockSize != 0, // explicitBlockSize - createInfo.flags & VMA_POOL_CREATE_ALGORITHM_MASK, - createInfo.priority), // algorithm + createInfo.flags & VMA_POOL_CREATE_ALGORITHM_MASK, // algorithm + createInfo.priority, + VMA_MAX(hAllocator->GetMemoryTypeMinAlignment(createInfo.memoryTypeIndex), createInfo.minAllocationAlignment), + createInfo.pMemoryAllocateNext), m_Id(0), m_Name(VMA_NULL) { @@ -12888,7 +12941,9 @@ uint32_t frameInUseCount, bool explicitBlockSize, uint32_t algorithm, - float priority) : + float priority, + VkDeviceSize minAllocationAlignment, + void* pMemoryAllocateNext) : m_hAllocator(hAllocator), m_hParentPool(hParentPool), m_MemoryTypeIndex(memoryTypeIndex), @@ -12900,6 +12955,8 @@ m_ExplicitBlockSize(explicitBlockSize), m_Algorithm(algorithm), m_Priority(priority), + m_MinAllocationAlignment(minAllocationAlignment), + m_pMemoryAllocateNext(pMemoryAllocateNext), m_HasEmptyBlock(false), m_Blocks(VmaStlAllocator<VmaDeviceMemoryBlock*>(hAllocator->GetAllocationCallbacks())), m_NextBlockId(0) @@ -12979,6 +13036,8 @@ size_t allocIndex; VkResult res = VK_SUCCESS; + alignment = VMA_MAX(alignment, m_MinAllocationAlignment); + if(IsCorruptionDetectionEnabled()) { size = VmaAlignUp<VkDeviceSize>(size, sizeof(VMA_CORRUPTION_DETECTION_MAGIC_VALUE)); @@ -13587,6 +13646,7 @@ VkResult VmaBlockVector::CreateBlock(VkDeviceSize blockSize, size_t* pNewBlockIndex) { VkMemoryAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; + allocInfo.pNext = m_pMemoryAllocateNext; allocInfo.memoryTypeIndex = m_MemoryTypeIndex; allocInfo.allocationSize = blockSize; @@ -15882,7 +15942,7 @@ fprintf(m_File, "Extension,VK_AMD_device_coherent_memory,%u\n", deviceCoherentMemoryExtensionEnabled ? 1 : 0); fprintf(m_File, "Macro,VMA_DEBUG_ALWAYS_DEDICATED_MEMORY,%u\n", VMA_DEBUG_ALWAYS_DEDICATED_MEMORY ? 1 : 0); - fprintf(m_File, "Macro,VMA_DEBUG_ALIGNMENT,%llu\n", (VkDeviceSize)VMA_DEBUG_ALIGNMENT); + fprintf(m_File, "Macro,VMA_MIN_ALIGNMENT,%llu\n", (VkDeviceSize)VMA_MIN_ALIGNMENT); fprintf(m_File, "Macro,VMA_DEBUG_MARGIN,%llu\n", (VkDeviceSize)VMA_DEBUG_MARGIN); fprintf(m_File, "Macro,VMA_DEBUG_INITIALIZE_ALLOCATIONS,%u\n", VMA_DEBUG_INITIALIZE_ALLOCATIONS ? 1 : 0); fprintf(m_File, "Macro,VMA_DEBUG_DETECT_CORRUPTION,%u\n", VMA_DEBUG_DETECT_CORRUPTION ? 1 : 0); @@ -16053,6 +16113,7 @@ memset(&m_pBlockVectors, 0, sizeof(m_pBlockVectors)); memset(&m_VulkanFunctions, 0, sizeof(m_VulkanFunctions)); + if(pCreateInfo->pDeviceMemoryCallbacks != VMA_NULL) { m_DeviceMemoryCallbacks.pUserData = pCreateInfo->pDeviceMemoryCallbacks->pUserData; @@ -16065,7 +16126,7 @@ (*m_VulkanFunctions.vkGetPhysicalDeviceProperties)(m_PhysicalDevice, &m_PhysicalDeviceProperties); (*m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties)(m_PhysicalDevice, &m_MemProps); - VMA_ASSERT(VmaIsPow2(VMA_DEBUG_ALIGNMENT)); + VMA_ASSERT(VmaIsPow2(VMA_MIN_ALIGNMENT)); VMA_ASSERT(VmaIsPow2(VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY)); VMA_ASSERT(VmaIsPow2(m_PhysicalDeviceProperties.limits.bufferImageGranularity)); VMA_ASSERT(VmaIsPow2(m_PhysicalDeviceProperties.limits.nonCoherentAtomSize)); @@ -16075,6 +16136,7 @@ m_GlobalMemoryTypeBits = CalculateGlobalMemoryTypeBits(); + if(pCreateInfo->pHeapSizeLimit != VMA_NULL) { for(uint32_t heapIndex = 0; heapIndex < GetMemoryHeapCount(); ++heapIndex) @@ -16106,7 +16168,9 @@ pCreateInfo->frameInUseCount, false, // explicitBlockSize false, // linearAlgorithm - 0.5f); // priority (0.5 is the default per Vulkan spec) + 0.5f, // priority (0.5 is the default per Vulkan spec) + GetMemoryTypeMinAlignment(memTypeIndex), // minAllocationAlignment + VMA_NULL); // // pMemoryAllocateNext // No need to call m_pBlockVectors[memTypeIndex][blockVectorTypeIndex]->CreateMinBlocks here, // becase minBlockCount is 0. } @@ -16834,10 +16898,6 @@ if(createInfo.pool != VK_NULL_HANDLE) { - const VkDeviceSize alignmentForPool = VMA_MAX( - vkMemReq.alignment, - GetMemoryTypeMinAlignment(createInfo.pool->m_BlockVector.GetMemoryTypeIndex())); - VmaAllocationCreateInfo createInfoForPool = createInfo; // If memory type is not HOST_VISIBLE, disable MAPPED. if((createInfoForPool.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0 && @@ -16849,7 +16909,7 @@ return createInfo.pool->m_BlockVector.Allocate( m_CurrentFrameIndex.load(), vkMemReq.size, - alignmentForPool, + vkMemReq.alignment, createInfoForPool, suballocType, allocationCount, @@ -16863,13 +16923,9 @@ VkResult res = vmaFindMemoryTypeIndex(this, memoryTypeBits, &createInfo, &memTypeIndex); if(res == VK_SUCCESS) { - VkDeviceSize alignmentForMemType = VMA_MAX( - vkMemReq.alignment, - GetMemoryTypeMinAlignment(memTypeIndex)); - res = AllocateMemoryOfType( vkMemReq.size, - alignmentForMemType, + vkMemReq.alignment, requiresDedicatedAllocation || prefersDedicatedAllocation, dedicatedBuffer, dedicatedBufferUsage, @@ -16895,13 +16951,9 @@ res = vmaFindMemoryTypeIndex(this, memoryTypeBits, &createInfo, &memTypeIndex); if(res == VK_SUCCESS) { - alignmentForMemType = VMA_MAX( - vkMemReq.alignment, - GetMemoryTypeMinAlignment(memTypeIndex)); - res = AllocateMemoryOfType( vkMemReq.size, - alignmentForMemType, + vkMemReq.alignment, requiresDedicatedAllocation || prefersDedicatedAllocation, dedicatedBuffer, dedicatedBufferUsage, @@ -17272,6 +17324,12 @@ VmaPoolCreateInfo newCreateInfo = *pCreateInfo; + // Protection against uninitialized new structure member. If garbage data are left there, this pointer dereference would crash. + if(pCreateInfo->pMemoryAllocateNext) + { + VMA_ASSERT(((const VkBaseInStructure*)pCreateInfo->pMemoryAllocateNext)->sType != 0); + } + if(newCreateInfo.maxBlockCount == 0) { newCreateInfo.maxBlockCount = SIZE_MAX; @@ -17285,6 +17343,10 @@ ((1u << pCreateInfo->memoryTypeIndex) & m_GlobalMemoryTypeBits) == 0) { return VK_ERROR_FEATURE_NOT_PRESENT; + } + if(newCreateInfo.minAllocationAlignment > 0) + { + VMA_ASSERT(VmaIsPow2(newCreateInfo.minAllocationAlignment)); } const VkDeviceSize preferredBlockSize = CalcPreferredBlockSize(newCreateInfo.memoryTypeIndex);
changelog.md view
@@ -2,6 +2,9 @@ ## WIP +## [0.6] - 2021-06-22+- Bump VMA, adding alignment info to PoolCreateInfo+ ## [0.5.1] - 2021-06-05 - Bump VMA, documentation changes
package.yaml view
@@ -1,5 +1,5 @@ name: VulkanMemoryAllocator-version: "0.5.1"+version: "0.6" synopsis: Bindings to the VulkanMemoryAllocator library category: Graphics maintainer: Joe Hermaszewski <live.long.and.prosper@monoid.al>@@ -20,7 +20,7 @@ src/lib.cpp dependencies: - base <5- - vulkan >= 3.6 && < 3.11+ - vulkan >= 3.6 && < 3.12 - bytestring - transformers - vector
src/VulkanMemoryAllocator.hs view
@@ -3987,15 +3987,37 @@ -- used during creation of the 'Allocator' object. Otherwise, this variable -- is ignored. priority :: Float+ , -- | 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.+ minAllocationAlignment :: DeviceSize+ , -- | 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.+ memoryAllocateNext :: Ptr () }- deriving (Typeable, Eq)+ deriving (Typeable) #if defined(GENERIC_INSTANCES) deriving instance Generic (PoolCreateInfo) #endif deriving instance Show PoolCreateInfo instance ToCStruct PoolCreateInfo where- withCStruct x f = allocaBytesAligned 40 8 $ \p -> pokeCStruct p x (f p)+ withCStruct x f = allocaBytesAligned 56 8 $ \p -> pokeCStruct p x (f p) pokeCStruct p PoolCreateInfo{..} f = do poke ((p `plusPtr` 0 :: Ptr Word32)) (memoryTypeIndex) poke ((p `plusPtr` 4 :: Ptr PoolCreateFlags)) (flags)@@ -4004,8 +4026,10 @@ poke ((p `plusPtr` 24 :: Ptr CSize)) (CSize (maxBlockCount)) poke ((p `plusPtr` 32 :: Ptr Word32)) (frameInUseCount) poke ((p `plusPtr` 36 :: Ptr CFloat)) (CFloat (priority))+ poke ((p `plusPtr` 40 :: Ptr DeviceSize)) (minAllocationAlignment)+ poke ((p `plusPtr` 48 :: Ptr (Ptr ()))) (memoryAllocateNext) f- cStructSize = 40+ cStructSize = 56 cStructAlignment = 8 pokeZeroCStruct p f = do poke ((p `plusPtr` 0 :: Ptr Word32)) (zero)@@ -4015,6 +4039,7 @@ poke ((p `plusPtr` 24 :: Ptr CSize)) (CSize (zero)) poke ((p `plusPtr` 32 :: Ptr Word32)) (zero) poke ((p `plusPtr` 36 :: Ptr CFloat)) (CFloat (zero))+ poke ((p `plusPtr` 40 :: Ptr DeviceSize)) (zero) f instance FromCStruct PoolCreateInfo where@@ -4026,17 +4051,21 @@ maxBlockCount <- peek @CSize ((p `plusPtr` 24 :: Ptr CSize)) frameInUseCount <- peek @Word32 ((p `plusPtr` 32 :: Ptr Word32)) priority <- peek @CFloat ((p `plusPtr` 36 :: Ptr CFloat))+ minAllocationAlignment <- peek @DeviceSize ((p `plusPtr` 40 :: Ptr DeviceSize))+ pMemoryAllocateNext <- peek @(Ptr ()) ((p `plusPtr` 48 :: Ptr (Ptr ()))) pure $ PoolCreateInfo- memoryTypeIndex flags blockSize (coerce @CSize @Word64 minBlockCount) (coerce @CSize @Word64 maxBlockCount) frameInUseCount (coerce @CFloat @Float priority)+ memoryTypeIndex flags blockSize (coerce @CSize @Word64 minBlockCount) (coerce @CSize @Word64 maxBlockCount) frameInUseCount (coerce @CFloat @Float priority) minAllocationAlignment pMemoryAllocateNext instance Storable PoolCreateInfo where- sizeOf ~_ = 40+ sizeOf ~_ = 56 alignment ~_ = 8 peek = peekCStruct poke ptr poked = pokeCStruct ptr poked (pure ()) instance Zero PoolCreateInfo where zero = PoolCreateInfo+ zero+ zero zero zero zero