Added POOL_DESC::MinAllocationAlignment
diff --git a/src/D3D12MemAlloc.cpp b/src/D3D12MemAlloc.cpp
index 9706e31..f38e597 100644
--- a/src/D3D12MemAlloc.cpp
+++ b/src/D3D12MemAlloc.cpp
@@ -2637,7 +2637,8 @@
         UINT64 preferredBlockSize,

         size_t minBlockCount,

         size_t maxBlockCount,

-        bool explicitBlockSize);

+        bool explicitBlockSize,

+        UINT64 minAllocationAlignment);

     ~BlockVector();

 

     HRESULT CreateMinBlocks();

@@ -2695,6 +2696,7 @@
     const size_t m_MinBlockCount;

     const size_t m_MaxBlockCount;

     const bool m_ExplicitBlockSize;

+    const UINT64 m_MinAllocationAlignment;

     /* There can be at most one allocation that is completely empty - a

     hysteresis to avoid pessimistic case of alternating creation and destruction

     of a VkDeviceMemory. */

@@ -3864,7 +3866,8 @@
     UINT64 preferredBlockSize,

     size_t minBlockCount,

     size_t maxBlockCount,

-    bool explicitBlockSize) :

+    bool explicitBlockSize,

+    UINT64 minAllocationAlignment) :

     m_hAllocator(hAllocator),

     m_HeapProps(heapProps),

     m_HeapFlags(heapFlags),

@@ -3872,6 +3875,7 @@
     m_MinBlockCount(minBlockCount),

     m_MaxBlockCount(maxBlockCount),

     m_ExplicitBlockSize(explicitBlockSize),

+    m_MinAllocationAlignment(minAllocationAlignment),

     m_HasEmptyBlock(false),

     m_Blocks(hAllocator->GetAllocs()),

     m_NextBlockId(0)

@@ -4290,6 +4294,8 @@
     ALLOCATION_FLAGS allocFlags,

     Allocation** pAllocation)

 {

+    alignment = D3D12MA_MAX(alignment, m_MinAllocationAlignment);

+

     AllocationRequest currRequest = {};

     if(pBlock->m_pMetadata->CreateAllocationRequest(

         size,

@@ -4412,7 +4418,8 @@
         allocator, desc.HeapProperties, heapFlags,

         preferredBlockSize,

         desc.MinBlockCount, maxBlockCount,

-        explicitBlockSize);

+        explicitBlockSize,

+        D3D12MA_MAX(desc.MinAllocationAlignment, (UINT64)D3D12MA_DEBUG_ALIGNMENT));

 }

 

 HRESULT PoolPimpl::Init()

@@ -4608,7 +4615,8 @@
             m_PreferredBlockSize,

             0, // minBlockCount

             SIZE_MAX, // maxBlockCount

-            false); // explicitBlockSize

+            false, // explicitBlockSize

+            D3D12MA_DEBUG_ALIGNMENT); // minAllocationAlignment

         // No need to call m_pBlockVectors[i]->CreateMinBlocks here, becase minBlockCount is 0.

     }

 

@@ -4685,7 +4693,6 @@
 

     D3D12_RESOURCE_DESC finalResourceDesc = *pResourceDesc;

     D3D12_RESOURCE_ALLOCATION_INFO resAllocInfo = GetResourceAllocationInfo(finalResourceDesc);

-    resAllocInfo.Alignment = D3D12MA_MAX<UINT64>(resAllocInfo.Alignment, D3D12MA_DEBUG_ALIGNMENT);

     D3D12MA_ASSERT(IsPow2(resAllocInfo.Alignment));

     D3D12MA_ASSERT(resAllocInfo.SizeInBytes > 0);

 

@@ -4755,7 +4762,6 @@
 

     D3D12_RESOURCE_DESC finalResourceDesc = *pResourceDesc;

     D3D12_RESOURCE_ALLOCATION_INFO resAllocInfo = GetResourceAllocationInfo(finalResourceDesc);

-    resAllocInfo.Alignment = D3D12MA_MAX<UINT64>(resAllocInfo.Alignment, D3D12MA_DEBUG_ALIGNMENT);

     D3D12MA_ASSERT(IsPow2(resAllocInfo.Alignment));

     D3D12MA_ASSERT(resAllocInfo.SizeInBytes > 0);

 

@@ -4807,7 +4813,6 @@
 

     D3D12_RESOURCE_DESC1 finalResourceDesc = *pResourceDesc;

     D3D12_RESOURCE_ALLOCATION_INFO resAllocInfo = GetResourceAllocationInfo(finalResourceDesc);

-    resAllocInfo.Alignment = D3D12MA_MAX<UINT64>(resAllocInfo.Alignment, D3D12MA_DEBUG_ALIGNMENT);

     D3D12MA_ASSERT(IsPow2(resAllocInfo.Alignment));

     D3D12MA_ASSERT(resAllocInfo.SizeInBytes > 0);

 

@@ -4945,7 +4950,6 @@
 

     D3D12_RESOURCE_DESC resourceDesc2 = *pResourceDesc;

     D3D12_RESOURCE_ALLOCATION_INFO resAllocInfo = GetResourceAllocationInfo(resourceDesc2);

-    resAllocInfo.Alignment = D3D12MA_MAX<UINT64>(resAllocInfo.Alignment, D3D12MA_DEBUG_ALIGNMENT);

     D3D12MA_ASSERT(IsPow2(resAllocInfo.Alignment));

     D3D12MA_ASSERT(resAllocInfo.SizeInBytes > 0);

 

@@ -6225,7 +6229,8 @@
     Pool** ppPool)

 {

     if(!pPoolDesc || !ppPool ||

-        (pPoolDesc->MaxBlockCount > 0 && pPoolDesc->MaxBlockCount < pPoolDesc->MinBlockCount))

+        (pPoolDesc->MaxBlockCount > 0 && pPoolDesc->MaxBlockCount < pPoolDesc->MinBlockCount) ||

+        (pPoolDesc->MinAllocationAlignment > 0 && !IsPow2(pPoolDesc->MinAllocationAlignment)))

     {

         D3D12MA_ASSERT(0 && "Invalid arguments passed to Allocator::CreatePool.");

         return E_INVALIDARG;

diff --git a/src/D3D12MemAlloc.h b/src/D3D12MemAlloc.h
index ded69c3..8b8674a 100644
--- a/src/D3D12MemAlloc.h
+++ b/src/D3D12MemAlloc.h
@@ -1053,6 +1053,11 @@
     throughout whole lifetime of this pool.

     */

     UINT MaxBlockCount;

+    /** \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.

+    */

+    UINT64 MinAllocationAlignment;

 };

 

 /** \brief Custom memory pool

diff --git a/src/Tests.cpp b/src/Tests.cpp
index f3784be..4bd44df 100644
--- a/src/Tests.cpp
+++ b/src/Tests.cpp
@@ -711,6 +711,43 @@
         IID_PPV_ARGS(&res)) );

 }

 

+static void TestCustomPool_MinAllocationAlignment(const TestContext& ctx)

+{

+    wprintf(L"Test custom pool MinAllocationAlignment\n");

+

+    const UINT64 BUFFER_SIZE = 32;

+    constexpr size_t BUFFER_COUNT = 4;

+    const UINT64 MIN_ALIGNMENT = 128 * 1024;

+

+    D3D12MA::POOL_DESC poolDesc = {};

+    poolDesc.HeapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;

+    poolDesc.HeapFlags = D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS;

+    poolDesc.MinAllocationAlignment = MIN_ALIGNMENT;

+

+    D3D12MA::Pool* poolPtr;

+    CHECK_HR( ctx.allocator->CreatePool(&poolDesc, &poolPtr) );

+    PoolUniquePtr pool{poolPtr};

+

+    D3D12MA::Allocation* allocPtr;

+    D3D12MA::ALLOCATION_DESC allocDesc = {};

+    allocDesc.CustomPool = pool.get();

+

+    D3D12_RESOURCE_DESC resDesc;

+    FillResourceDescForBuffer(resDesc, BUFFER_SIZE);

+

+    AllocationUniquePtr allocs[BUFFER_COUNT];

+    for(size_t i = 0; i < BUFFER_COUNT; ++i)

+    {

+        CHECK_HR( ctx.allocator->CreateResource(&allocDesc, &resDesc,

+            D3D12_RESOURCE_STATE_GENERIC_READ,

+            NULL, // pOptimizedClearValue

+            &allocPtr,

+            IID_NULL, NULL) ); // riidResource, ppvResource

+        allocs[i].reset(allocPtr);

+        CHECK_BOOL(allocPtr->GetOffset() % MIN_ALIGNMENT == 0);

+    }

+}

+

 static HRESULT TestCustomHeap(const TestContext& ctx, const D3D12_HEAP_PROPERTIES& heapProps)

 {

     D3D12MA::Stats globalStatsBeg = {};

@@ -1589,6 +1626,7 @@
     TestPlacedResources(ctx);

     TestOtherComInterface(ctx);

     TestCustomPools(ctx);

+    TestCustomPool_MinAllocationAlignment(ctx);

     TestCustomHeaps(ctx);

     TestStandardCustomCommittedPlaced(ctx);

     TestAliasingMemory(ctx);