packages feed

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 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