Fix for case when a large allocation is made with ALLOCATION_FLAG_CAN_ALIAS

Code by @medranSolus
This commit is contained in:
Adam Sawicki 2022-03-24 13:58:50 +01:00
parent 98218850d6
commit 10bff5ec74
3 changed files with 105 additions and 16 deletions

View File

@ -635,7 +635,7 @@ private:
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)

View File

@ -5906,6 +5906,7 @@ struct CommittedAllocationParameters
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 @@ HRESULT AllocatorPimpl::AllocateCommittedResource(
{
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,7 +7532,6 @@ HRESULT AllocatorPimpl::AllocateCommittedResource(
*
* [ STATE_CREATION ERROR #640: CREATERESOURCEANDHEAP_INVALIDHEAPMISCFLAGS]
*/
HRESULT hr;
#ifdef __ID3D12Device4_INTERFACE_DEFINED__
if (m_Device4)
{
@ -7538,7 +7567,7 @@ HRESULT AllocatorPimpl::AllocateCommittedResource(
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 @@ HRESULT AllocatorPimpl::AllocateCommittedResource2(
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 @@ HRESULT AllocatorPimpl::AllocateCommittedResource2(
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 @@ HRESULT AllocatorPimpl::CalcAllocationParams(const ALLOCATION_DESC& allocDesc, U
{
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 @@ HRESULT BlockVector::CreateResource(
}
if (SUCCEEDED(hr))
{
(*ppAllocation)->SetResource(res, &resourceDesc);
(*ppAllocation)->SetResourcePointer(res, &resourceDesc);
}
else
{
@ -8393,7 +8452,7 @@ HRESULT BlockVector::CreateResource2(
}
if (SUCCEEDED(hr))
{
(*ppAllocation)->SetResource(res, &resourceDesc);
(*ppAllocation)->SetResourcePointer(res, &resourceDesc);
}
else
{
@ -9701,7 +9760,7 @@ NormalBlock* Allocation::GetBlock()
}
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;

View File

@ -1457,6 +1457,35 @@ static void TestAliasingMemory(const TestContext& ctx)
// 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 @@ static void TestGroupBasics(const TestContext& ctx)
TestCustomHeaps(ctx);
TestStandardCustomCommittedPlaced(ctx);
TestAliasingMemory(ctx);
TestAliasingImplicitCommitted(ctx);
TestMapping(ctx);
TestStats(ctx);
TestTransfer(ctx);