Fix for case when a large allocation is made with ALLOCATION_FLAG_CAN_ALIAS

Code by @medranSolus
diff --git a/include/D3D12MemAlloc.h b/include/D3D12MemAlloc.h
index 6e3ecf7..a9d2612 100644
--- a/include/D3D12MemAlloc.h
+++ b/include/D3D12MemAlloc.h
@@ -635,7 +635,7 @@
     AllocHandle GetAllocHandle() const;

     NormalBlock* GetBlock();

     template<typename D3D12_RESOURCE_DESC_T>

-    void SetResource(ID3D12Resource* resource, const D3D12_RESOURCE_DESC_T* pResourceDesc);

+    void SetResourcePointer(ID3D12Resource* resource, const D3D12_RESOURCE_DESC_T* pResourceDesc);

     void FreeName();

 

     D3D12MA_CLASS_NO_COPY(Allocation)

diff --git a/src/D3D12MemAlloc.cpp b/src/D3D12MemAlloc.cpp
index 6939696..82b824b 100644
--- a/src/D3D12MemAlloc.cpp
+++ b/src/D3D12MemAlloc.cpp
@@ -5906,6 +5906,7 @@
     D3D12_HEAP_PROPERTIES m_HeapProperties = {};

     D3D12_HEAP_FLAGS m_HeapFlags = D3D12_HEAP_FLAG_NONE;

     ID3D12ProtectedResourceSession* m_ProtectedSession = NULL;

+    bool m_CanAlias = false;

 

     bool IsValid() const { return m_List != NULL; }

 };

@@ -7485,13 +7486,42 @@
 {

     D3D12MA_ASSERT(committedAllocParams.IsValid());

 

+    HRESULT hr;

+    ID3D12Resource* res = NULL;

+    // Allocate aliasing memory with explicit heap

+    if (committedAllocParams.m_CanAlias)

+    {

+        D3D12_RESOURCE_ALLOCATION_INFO heapAllocInfo = {};

+        heapAllocInfo.SizeInBytes = resourceSize;

+        heapAllocInfo.Alignment = HeapFlagsToAlignment(committedAllocParams.m_HeapFlags);

+        hr = AllocateHeap(committedAllocParams, heapAllocInfo, withinBudget, pPrivateData, ppAllocation);

+        if (SUCCEEDED(hr))

+        {

+            hr = m_Device->CreatePlacedResource((*ppAllocation)->GetHeap(), 0,

+                pResourceDesc, InitialResourceState,

+                pOptimizedClearValue, D3D12MA_IID_PPV_ARGS(&res));

+            if (SUCCEEDED(hr))

+            {

+                if (ppvResource != NULL)

+                    hr = res->QueryInterface(riidResource, ppvResource);

+                if (SUCCEEDED(hr))

+                {

+                    (*ppAllocation)->SetResourcePointer(res, pResourceDesc);

+                    return hr;

+                }

+                res->Release();

+            }

+            FreeHeapMemory(*ppAllocation);

+        }

+        return hr;

+    }

+

     if (withinBudget &&

         !NewAllocationWithinBudget(committedAllocParams.m_HeapProperties.Type, resourceSize))

     {

         return E_OUTOFMEMORY;

     }

 

-    ID3D12Resource* res = NULL;

     /* D3D12 ERROR:

      * ID3D12Device::CreateCommittedResource:

      * When creating a committed resource, D3D12_HEAP_FLAGS must not have either

@@ -7502,15 +7532,14 @@
      *

      * [ STATE_CREATION ERROR #640: CREATERESOURCEANDHEAP_INVALIDHEAPMISCFLAGS]

     */

-    HRESULT hr;

 #ifdef __ID3D12Device4_INTERFACE_DEFINED__

     if (m_Device4)

     {

-        hr = m_Device4->CreateCommittedResource1(

-            &committedAllocParams.m_HeapProperties,

-            committedAllocParams.m_HeapFlags & ~RESOURCE_CLASS_HEAP_FLAGS,

-            pResourceDesc, InitialResourceState,

-            pOptimizedClearValue, committedAllocParams.m_ProtectedSession, D3D12MA_IID_PPV_ARGS(&res));

+            hr = m_Device4->CreateCommittedResource1(

+                &committedAllocParams.m_HeapProperties,

+                committedAllocParams.m_HeapFlags & ~RESOURCE_CLASS_HEAP_FLAGS,

+                pResourceDesc, InitialResourceState,

+                pOptimizedClearValue, committedAllocParams.m_ProtectedSession, D3D12MA_IID_PPV_ARGS(&res));

     }

     else

 #endif

@@ -7538,7 +7567,7 @@
             const BOOL wasZeroInitialized = TRUE;

             Allocation* alloc = m_AllocationObjectAllocator.Allocate(this, resourceSize, pResourceDesc->Alignment, wasZeroInitialized);

             alloc->InitCommitted(committedAllocParams.m_List);

-            alloc->SetResource(res, pResourceDesc);

+            alloc->SetResourcePointer(res, pResourceDesc);

             alloc->SetPrivateData(pPrivateData);

 

             *ppAllocation = alloc;

@@ -7572,14 +7601,43 @@
         return E_NOINTERFACE;

     }

 

+    HRESULT hr;

+    ID3D12Resource* res = NULL;

+    // Allocate aliasing memory with explicit heap

+    if (committedAllocParams.m_CanAlias)

+    {

+        D3D12_RESOURCE_ALLOCATION_INFO heapAllocInfo = {};

+        heapAllocInfo.SizeInBytes = resourceSize;

+        heapAllocInfo.Alignment = HeapFlagsToAlignment(committedAllocParams.m_HeapFlags);

+        hr = AllocateHeap(committedAllocParams, heapAllocInfo, withinBudget, pPrivateData, ppAllocation);

+        if (SUCCEEDED(hr))

+        {

+            hr = m_Device8->CreatePlacedResource1((*ppAllocation)->GetHeap(), 0,

+                pResourceDesc, InitialResourceState,

+                pOptimizedClearValue, D3D12MA_IID_PPV_ARGS(&res));

+            if (SUCCEEDED(hr))

+            {

+                if (ppvResource != NULL)

+                    hr = res->QueryInterface(riidResource, ppvResource);

+                if (SUCCEEDED(hr))

+                {

+                    (*ppAllocation)->SetResourcePointer(res, pResourceDesc);

+                    return hr;

+                }

+                res->Release();

+            }

+            FreeHeapMemory(*ppAllocation);

+        }

+        return hr;

+    }

+

     if (withinBudget &&

         !NewAllocationWithinBudget(committedAllocParams.m_HeapProperties.Type, resourceSize))

     {

         return E_OUTOFMEMORY;

     }

 

-    ID3D12Resource* res = NULL;

-    HRESULT hr = m_Device8->CreateCommittedResource2(

+    hr = m_Device8->CreateCommittedResource2(

         &committedAllocParams.m_HeapProperties,

         committedAllocParams.m_HeapFlags & ~RESOURCE_CLASS_HEAP_FLAGS, // D3D12 ERROR: ID3D12Device::CreateCommittedResource: When creating a committed resource, D3D12_HEAP_FLAGS must not have either D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES, D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES, nor D3D12_HEAP_FLAG_DENY_BUFFERS set. These flags will be set automatically to correspond with the committed resource type. [ STATE_CREATION ERROR #640: CREATERESOURCEANDHEAP_INVALIDHEAPMISCFLAGS]

         pResourceDesc, InitialResourceState,

@@ -7595,7 +7653,7 @@
             const BOOL wasZeroInitialized = TRUE;

             Allocation* alloc = m_AllocationObjectAllocator.Allocate(this, resourceSize, pResourceDesc->Alignment, wasZeroInitialized);

             alloc->InitCommitted(committedAllocParams.m_List);

-            alloc->SetResource(res, pResourceDesc);

+            alloc->SetResourcePointer(res, pResourceDesc);

             alloc->SetPrivateData(pPrivateData);

 

             *ppAllocation = alloc;

@@ -7726,10 +7784,11 @@
     {

         outBlockVector = NULL;

     }

-    if ((allocDesc.Flags & (ALLOCATION_FLAG_NEVER_ALLOCATE | ALLOCATION_FLAG_CAN_ALIAS)) != 0)

+    if ((allocDesc.Flags & ALLOCATION_FLAG_NEVER_ALLOCATE) != 0)

     {

         outCommittedAllocationParams.m_List = NULL;

     }

+    outCommittedAllocationParams.m_CanAlias = allocDesc.Flags & ALLOCATION_FLAG_CAN_ALIAS;

 

     if (resDesc != NULL && !outPreferCommitted && PrefersCommittedAllocation(*resDesc))

     {

@@ -8340,7 +8399,7 @@
             }

             if (SUCCEEDED(hr))

             {

-                (*ppAllocation)->SetResource(res, &resourceDesc);

+                (*ppAllocation)->SetResourcePointer(res, &resourceDesc);

             }

             else

             {

@@ -8393,7 +8452,7 @@
             }

             if (SUCCEEDED(hr))

             {

-                (*ppAllocation)->SetResource(res, &resourceDesc);

+                (*ppAllocation)->SetResourcePointer(res, &resourceDesc);

             }

             else

             {

@@ -9701,7 +9760,7 @@
 }

 

 template<typename D3D12_RESOURCE_DESC_T>

-void Allocation::SetResource(ID3D12Resource* resource, const D3D12_RESOURCE_DESC_T* pResourceDesc)

+void Allocation::SetResourcePointer(ID3D12Resource* resource, const D3D12_RESOURCE_DESC_T* pResourceDesc)

 {

     D3D12MA_ASSERT(m_Resource == NULL && pResourceDesc);

     m_Resource = resource;

diff --git a/src/Tests.cpp b/src/Tests.cpp
index 9d8755a..1423b5a 100644
--- a/src/Tests.cpp
+++ b/src/Tests.cpp
@@ -1457,6 +1457,35 @@
     // You can use res1 and res2, but not at the same time!

 }

 

+static void TestAliasingImplicitCommitted(const TestContext& ctx)

+{

+    wprintf(L"Test aliasing implicit dedicated\n");

+

+    // The buffer will be large enough to be allocated as committed.

+    // We still need it to have an explicit heap to be able to alias.

+

+    D3D12_RESOURCE_DESC resDesc = {};

+    FillResourceDescForBuffer(resDesc, 300 * MEGABYTE);

+

+    D3D12MA::ALLOCATION_DESC allocDesc = {};

+    allocDesc.HeapType = D3D12_HEAP_TYPE_UPLOAD;

+    allocDesc.Flags = D3D12MA::ALLOCATION_FLAG_CAN_ALIAS;

+

+    ComPtr<D3D12MA::Allocation> alloc;

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

+        D3D12_RESOURCE_STATE_GENERIC_READ, NULL,

+        &alloc, IID_NULL, NULL));

+    CHECK_BOOL(alloc != NULL && alloc->GetHeap() != NULL);

+

+    resDesc.Width = 200 * MEGABYTE;

+    ComPtr<ID3D12Resource> aliasingRes;

+    CHECK_HR(ctx.allocator->CreateAliasingResource(alloc.Get(),

+        0, // AllocationLocalOffset

+        &resDesc,

+        D3D12_RESOURCE_STATE_GENERIC_READ, NULL, IID_PPV_ARGS(&aliasingRes)));

+    CHECK_BOOL(aliasingRes != NULL);

+}

+

 static void TestMapping(const TestContext& ctx)

 {

     wprintf(L"Test mapping\n");

@@ -3994,6 +4023,7 @@
     TestCustomHeaps(ctx);

     TestStandardCustomCommittedPlaced(ctx);

     TestAliasingMemory(ctx);

+    TestAliasingImplicitCommitted(ctx);

     TestMapping(ctx);

     TestStats(ctx);

     TestTransfer(ctx);