Add custom pools
Added struct POOL_DESC, class Pool, function Allocator::CreatePool, member ALLOCATION_DESC::CustomPool.
diff --git a/src/D3D12MemAlloc.cpp b/src/D3D12MemAlloc.cpp
index 682acca..b78fa6f 100644
--- a/src/D3D12MemAlloc.cpp
+++ b/src/D3D12MemAlloc.cpp
@@ -741,6 +741,13 @@
return result;
}
+static inline bool IsHeapTypeValid(D3D12_HEAP_TYPE type)
+{
+ return type == D3D12_HEAP_TYPE_DEFAULT ||
+ type == D3D12_HEAP_TYPE_UPLOAD ||
+ type == D3D12_HEAP_TYPE_READBACK;
+}
+
////////////////////////////////////////////////////////////////////////////////
// Private class Vector
@@ -2334,6 +2341,17 @@
void Free(
Allocation* hAllocation);
+ HRESULT CreateResource(
+ UINT64 size,
+ UINT64 alignment,
+ const ALLOCATION_DESC& allocDesc,
+ const D3D12_RESOURCE_DESC& resourceDesc,
+ D3D12_RESOURCE_STATES InitialResourceState,
+ const D3D12_CLEAR_VALUE *pOptimizedClearValue,
+ Allocation** ppAllocation,
+ REFIID riidResource,
+ void** ppvResource);
+
void AddStats(Stats& outpStats);
void WriteBlockInfoToJson(JsonWriter& json);
@@ -2441,6 +2459,7 @@
bool SupportsResourceHeapTier2() const { return m_D3D12Options.ResourceHeapTier >= D3D12_RESOURCE_HEAP_TIER_2; }
bool UseMutex() const { return m_UseMutex; }
AllocationObjectAllocator& GetAllocationObjectAllocator() { return m_AllocationObjectAllocator; }
+ bool HeapFlagsFulfillResourceHeapTier(D3D12_HEAP_FLAGS flags) const;
HRESULT CreateResource(
const ALLOCATION_DESC* pAllocDesc,
@@ -3502,6 +3521,46 @@
}
}
+HRESULT BlockVector::CreateResource(
+ UINT64 size,
+ UINT64 alignment,
+ const ALLOCATION_DESC& allocDesc,
+ const D3D12_RESOURCE_DESC& resourceDesc,
+ D3D12_RESOURCE_STATES InitialResourceState,
+ const D3D12_CLEAR_VALUE *pOptimizedClearValue,
+ Allocation** ppAllocation,
+ REFIID riidResource,
+ void** ppvResource)
+{
+ HRESULT hr = Allocate(size, alignment, allocDesc, 1, ppAllocation);
+ if(SUCCEEDED(hr))
+ {
+ ID3D12Resource* res = NULL;
+ hr = m_hAllocator->GetDevice()->CreatePlacedResource(
+ (*ppAllocation)->m_Placed.block->GetHeap(),
+ (*ppAllocation)->GetOffset(),
+ &resourceDesc,
+ InitialResourceState,
+ pOptimizedClearValue,
+ riidResource,
+ (void**)&res);
+ if(SUCCEEDED(hr))
+ {
+ (*ppAllocation)->SetResource(res, &resourceDesc);
+ if(ppvResource != NULL)
+ {
+ res->AddRef();
+ *ppvResource = res;
+ }
+ }
+ else
+ {
+ SAFE_RELEASE(*ppAllocation);
+ }
+ }
+ return hr;
+}
+
UINT64 BlockVector::CalcMaxBlockSize() const
{
UINT64 result = 0;
@@ -3637,6 +3696,75 @@
}
////////////////////////////////////////////////////////////////////////////////
+// Private class PoolPimpl
+
+class PoolPimpl
+{
+public:
+ PoolPimpl(AllocatorPimpl* allocator, const POOL_DESC& desc) :
+ m_Allocator(allocator),
+ m_Desc(desc),
+ m_BlockVector(D3D12MA_NEW(allocator->GetAllocs(), BlockVector)(
+ allocator, desc.HeapType, desc.HeapFlags,
+ desc.BlockSize != 0 ? desc.BlockSize : D3D12MA_DEFAULT_BLOCK_SIZE, // preferredBlockSize
+ desc.MinBlockCount, desc.MaxBlockCount,
+ desc.BlockSize != 0)) // explicitBlockSize
+ {
+ }
+ ~PoolPimpl()
+ {
+ D3D12MA_DELETE(m_Allocator->GetAllocs(), m_BlockVector);
+ }
+ HRESULT Init();
+
+ AllocatorPimpl* GetAllocator() const { return m_Allocator; }
+ const POOL_DESC& GetDesc() const { return m_Desc; }
+ BlockVector* GetBlockVector() { return m_BlockVector; }
+
+private:
+ friend class Allocator;
+
+ AllocatorPimpl* m_Allocator; // Externally owned object.
+ POOL_DESC m_Desc;
+ BlockVector* m_BlockVector; // Owned object.
+};
+
+HRESULT PoolPimpl::Init()
+{
+ return m_BlockVector->CreateMinBlocks();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Public class Pool implementation
+
+void Pool::Release()
+{
+ if(this == NULL)
+ {
+ return;
+ }
+
+ D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
+
+ D3D12MA_DELETE(m_Pimpl->GetAllocator()->GetAllocs(), this);
+}
+
+POOL_DESC Pool::GetDesc()
+{
+ return m_Pimpl->GetDesc();
+}
+
+Pool::Pool(Allocator* allocator, const POOL_DESC &desc) :
+ m_Pimpl(D3D12MA_NEW(allocator->m_Pimpl->GetAllocs(), PoolPimpl)(allocator->m_Pimpl, desc))
+{
+}
+
+Pool::~Pool()
+{
+ D3D12MA_DELETE(m_Pimpl->GetAllocator()->GetAllocs(), m_Pimpl);
+}
+
+////////////////////////////////////////////////////////////////////////////////
// Private class AllocatorPimpl implementation
AllocatorPimpl::AllocatorPimpl(const ALLOCATION_CALLBACKS& allocationCallbacks, const ALLOCATOR_DESC& desc) :
@@ -3738,6 +3866,22 @@
}
}
+bool AllocatorPimpl::HeapFlagsFulfillResourceHeapTier(D3D12_HEAP_FLAGS flags) const
+{
+ if(SupportsResourceHeapTier2())
+ {
+ return true;
+ }
+ else
+ {
+ const bool allowBuffers = (flags & D3D12_HEAP_FLAG_DENY_BUFFERS ) == 0;
+ const bool allowRtDsTextures = (flags & D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES ) == 0;
+ const bool allowNonRtDsTextures = (flags & D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES) == 0;
+ const uint8_t allowedGroupCount = (allowBuffers ? 1 : 0) + (allowRtDsTextures ? 1 : 0) + (allowNonRtDsTextures ? 1 : 0);
+ return allowedGroupCount == 1;
+ }
+}
+
HRESULT AllocatorPimpl::CreateResource(
const ALLOCATION_DESC* pAllocDesc,
const D3D12_RESOURCE_DESC* pResourceDesc,
@@ -3753,57 +3897,36 @@
*ppvResource = NULL;
}
- if(pAllocDesc->HeapType != D3D12_HEAP_TYPE_DEFAULT &&
- pAllocDesc->HeapType != D3D12_HEAP_TYPE_UPLOAD &&
- pAllocDesc->HeapType != D3D12_HEAP_TYPE_READBACK)
+ if(pAllocDesc->CustomPool == NULL)
{
- return E_INVALIDARG;
+ if(!IsHeapTypeValid(pAllocDesc->HeapType))
+ {
+ return E_INVALIDARG;
+ }
}
ALLOCATION_DESC finalAllocDesc = *pAllocDesc;
- D3D12_RESOURCE_DESC resourceDesc2 = *pResourceDesc;
- D3D12_RESOURCE_ALLOCATION_INFO resAllocInfo = GetResourceAllocationInfo(resourceDesc2);
+ 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);
- const UINT defaultPoolIndex = CalcDefaultPoolIndex(*pAllocDesc, resourceDesc2);
- const bool requireCommittedMemory = defaultPoolIndex == UINT32_MAX;
- if(requireCommittedMemory)
+ if(pAllocDesc->CustomPool != NULL)
{
- return AllocateCommittedResource(
- &finalAllocDesc,
- &resourceDesc2,
- resAllocInfo,
- InitialResourceState,
- pOptimizedClearValue,
- ppAllocation,
- riidResource,
- ppvResource);
- }
+ if((finalAllocDesc.Flags & ALLOCATION_FLAG_COMMITTED) != 0)
+ {
+ return E_INVALIDARG;
+ }
- BlockVector* blockVector = m_BlockVectors[defaultPoolIndex];
- D3D12MA_ASSERT(blockVector);
-
- const UINT64 preferredBlockSize = blockVector->GetPreferredBlockSize();
- bool preferCommittedMemory =
- m_AlwaysCommitted ||
- PrefersCommittedAllocation(resourceDesc2) ||
- // Heuristics: Allocate committed memory if requested size if greater than half of preferred block size.
- resAllocInfo.SizeInBytes > preferredBlockSize / 2;
- if(preferCommittedMemory &&
- (finalAllocDesc.Flags & ALLOCATION_FLAG_NEVER_ALLOCATE) == 0)
- {
- finalAllocDesc.Flags |= ALLOCATION_FLAG_COMMITTED;
- }
-
- if((finalAllocDesc.Flags & ALLOCATION_FLAG_COMMITTED) != 0)
- {
- return AllocateCommittedResource(
- &finalAllocDesc,
- &resourceDesc2,
- resAllocInfo,
+ BlockVector* blockVector = pAllocDesc->CustomPool->m_Pimpl->GetBlockVector();
+ D3D12MA_ASSERT(blockVector);
+ return blockVector->CreateResource(
+ resAllocInfo.SizeInBytes,
+ resAllocInfo.Alignment,
+ finalAllocDesc,
+ finalResourceDesc,
InitialResourceState,
pOptimizedClearValue,
ppAllocation,
@@ -3812,49 +3935,75 @@
}
else
{
- HRESULT hr = blockVector->Allocate(
- resAllocInfo.SizeInBytes,
- resAllocInfo.Alignment,
- finalAllocDesc,
- 1,
- (Allocation**)ppAllocation);
- if(SUCCEEDED(hr))
+ const UINT defaultPoolIndex = CalcDefaultPoolIndex(*pAllocDesc, finalResourceDesc);
+ const bool requireCommittedMemory = defaultPoolIndex == UINT32_MAX;
+ if(requireCommittedMemory)
{
- ID3D12Resource* res = NULL;
- hr = m_Device->CreatePlacedResource(
- (*ppAllocation)->m_Placed.block->GetHeap(),
- (*ppAllocation)->GetOffset(),
- &resourceDesc2,
+ return AllocateCommittedResource(
+ &finalAllocDesc,
+ &finalResourceDesc,
+ resAllocInfo,
InitialResourceState,
pOptimizedClearValue,
+ ppAllocation,
riidResource,
- (void**)&res);
- if(SUCCEEDED(hr))
- {
- (*ppAllocation)->SetResource(res, &resourceDesc2);
- if(ppvResource != NULL)
- {
- res->AddRef();
- *ppvResource = res;
- }
- return hr;
- }
- else
- {
- SAFE_RELEASE(*ppAllocation);
- return hr;
- }
+ ppvResource);
}
- return AllocateCommittedResource(
- &finalAllocDesc,
- &resourceDesc2,
- resAllocInfo,
- InitialResourceState,
- pOptimizedClearValue,
- ppAllocation,
- riidResource,
- ppvResource);
+ BlockVector* blockVector = m_BlockVectors[defaultPoolIndex];
+ D3D12MA_ASSERT(blockVector);
+
+ const UINT64 preferredBlockSize = blockVector->GetPreferredBlockSize();
+ bool preferCommittedMemory =
+ m_AlwaysCommitted ||
+ PrefersCommittedAllocation(finalResourceDesc) ||
+ // Heuristics: Allocate committed memory if requested size if greater than half of preferred block size.
+ resAllocInfo.SizeInBytes > preferredBlockSize / 2;
+ if(preferCommittedMemory &&
+ (finalAllocDesc.Flags & ALLOCATION_FLAG_NEVER_ALLOCATE) == 0)
+ {
+ finalAllocDesc.Flags |= ALLOCATION_FLAG_COMMITTED;
+ }
+
+ if((finalAllocDesc.Flags & ALLOCATION_FLAG_COMMITTED) != 0)
+ {
+ return AllocateCommittedResource(
+ &finalAllocDesc,
+ &finalResourceDesc,
+ resAllocInfo,
+ InitialResourceState,
+ pOptimizedClearValue,
+ ppAllocation,
+ riidResource,
+ ppvResource);
+ }
+ else
+ {
+ HRESULT hr = blockVector->CreateResource(
+ resAllocInfo.SizeInBytes,
+ resAllocInfo.Alignment,
+ finalAllocDesc,
+ finalResourceDesc,
+ InitialResourceState,
+ pOptimizedClearValue,
+ ppAllocation,
+ riidResource,
+ ppvResource);
+ if(SUCCEEDED(hr))
+ {
+ return hr;
+ }
+
+ return AllocateCommittedResource(
+ &finalAllocDesc,
+ &finalResourceDesc,
+ resAllocInfo,
+ InitialResourceState,
+ pOptimizedClearValue,
+ ppAllocation,
+ riidResource,
+ ppvResource);
+ }
}
}
@@ -3865,9 +4014,7 @@
{
*ppAllocation = NULL;
- if(pAllocDesc->HeapType != D3D12_HEAP_TYPE_DEFAULT &&
- pAllocDesc->HeapType != D3D12_HEAP_TYPE_UPLOAD &&
- pAllocDesc->HeapType != D3D12_HEAP_TYPE_READBACK)
+ if(!IsHeapTypeValid(pAllocDesc->HeapType))
{
return E_INVALIDARG;
}
@@ -4944,6 +5091,33 @@
return m_Pimpl->CreateAliasingResource(pAllocation, AllocationLocalOffset, pResourceDesc, InitialResourceState, pOptimizedClearValue, riidResource, ppvResource);
}
+HRESULT Allocator::CreatePool(
+ const POOL_DESC* pPoolDesc,
+ Pool** ppPool)
+{
+ if(!pPoolDesc || !ppPool ||
+ !IsHeapTypeValid(pPoolDesc->HeapType) ||
+ pPoolDesc->MinBlockCount > pPoolDesc->MaxBlockCount)
+ {
+ D3D12MA_ASSERT(0 && "Invalid arguments passed to Allocator::CreatePool.");
+ return E_INVALIDARG;
+ }
+ if(!m_Pimpl->HeapFlagsFulfillResourceHeapTier(pPoolDesc->HeapFlags))
+ {
+ D3D12MA_ASSERT(0 && "Invalid pPoolDesc->HeapFlags passed to Allocator::CreatePool. Did you forget to handle ResourceHeapTier=1?");
+ return E_INVALIDARG;
+ }
+ D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
+ *ppPool = D3D12MA_NEW(m_Pimpl->GetAllocs(), Pool)(this, *pPoolDesc);
+ HRESULT hr = (*ppPool)->m_Pimpl->Init();
+ if(FAILED(hr))
+ {
+ D3D12MA_DELETE(m_Pimpl->GetAllocs(), *ppPool);
+ *ppPool = NULL;
+ }
+ return hr;
+}
+
void Allocator::SetCurrentFrameIndex(UINT frameIndex)
{
D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
diff --git a/src/D3D12MemAlloc.h b/src/D3D12MemAlloc.h
index 9bdcd5d..3466397 100644
--- a/src/D3D12MemAlloc.h
+++ b/src/D3D12MemAlloc.h
@@ -375,11 +375,15 @@
/// \cond INTERNAL
class AllocatorPimpl;
+class PoolPimpl;
class NormalBlock;
class BlockVector;
class JsonWriter;
/// \endcond
+class Pool;
+class Allocator;
+
/// Pointer to custom callback function that allocates CPU memory.
typedef void* (*ALLOCATE_FUNC_PTR)(size_t Size, size_t Alignment, void* pUserData);
/**
@@ -438,6 +442,8 @@
/** \brief The type of memory heap where the new allocation should be placed.
It must be one of: `D3D12_HEAP_TYPE_DEFAULT`, `D3D12_HEAP_TYPE_UPLOAD`, `D3D12_HEAP_TYPE_READBACK`.
+
+ When D3D12MA::ALLOCATION_DESC::CustomPool != NULL this member is ignored.
*/
D3D12_HEAP_TYPE HeapType;
/** \brief Additional heap flags to be used when allocating memory.
@@ -455,8 +461,16 @@
`D3D12_HEAP_FLAG_ALLOW_SHADER_ATOMICS` is added automatically wherever it might be needed.
- You can specify additional flags if needed. Then the memory will always be allocated as
separate block using `D3D12Device::CreateCommittedResource` or `CreateHeap`, not as part of an existing larget block.
+
+ When D3D12MA::ALLOCATION_DESC::CustomPool != NULL this member is ignored.
*/
D3D12_HEAP_FLAGS ExtraHeapFlags;
+ /** \brief Custom pool to place the new resource in. Optional.
+
+ When not NULL, the resource will be created inside specified custom pool.
+ It will then never be created as committed.
+ */
+ Pool* CustomPool;
};
/** \brief Represents single memory allocation.
@@ -621,6 +635,69 @@
D3D12MA_CLASS_NO_COPY(Allocation)
};
+struct POOL_DESC
+{
+ /** \brief The type of memory heap where allocations of this pool should be placed.
+
+ It must be one of: `D3D12_HEAP_TYPE_DEFAULT`, `D3D12_HEAP_TYPE_UPLOAD`, `D3D12_HEAP_TYPE_READBACK`.
+ */
+ D3D12_HEAP_TYPE HeapType;
+ /** \brief Heap flags to be used when allocating heaps of this pool.
+
+ If ResourceHeapTier = 1, it must contain one of these values, depending on type
+ of resources you are going to create in this heap:
+ `D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS`,
+ `D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES`,
+ `D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES`.
+ If ResourceHeapTier = 2, it may be `D3D12_HEAP_FLAG_ALLOW_ALL_BUFFERS_AND_TEXTURES` = 0.
+
+ If configuration macro `D3D12MA_ALLOW_SHADER_ATOMICS` is set to 1 (which is the default),
+ `D3D12_HEAP_FLAG_ALLOW_SHADER_ATOMICS` is added automatically wherever it might be needed.
+
+ You can specify additional flags if needed.
+ */
+ D3D12_HEAP_FLAGS HeapFlags;
+ /** \brief Size of a single heap (memory block) to be allocated as part of this pool, in bytes. Optional.
+
+ Specify nonzero to set explicit, constant size of memory blocks used by this pool.
+ Leave 0 to use default and let the library manage block sizes automatically.
+ Then sizes of particular blocks may vary.
+ */
+ UINT64 BlockSize;
+ /** \brief Minimum number of heaps (memory blocks) to be always allocated in this pool, even if they stay empty.
+
+ Set to 0 to have no preallocated blocks and allow the pool be completely empty.
+ */
+ UINT MinBlockCount;
+ /** \brief Maximum number of heaps (memory blocks) that can be allocated in this pool. Optional.
+
+ Set to 0 to use default, which is `UINT64_MAX`, which means no limit.
+
+ Set to same value as D3D12MA::POOL_DESC::MinBlockCount to have fixed amount of memory allocated
+ throughout whole lifetime of this pool.
+ */
+ UINT MaxBlockCount;
+};
+
+class Pool
+{
+public:
+ void Release();
+ POOL_DESC GetDesc();
+
+private:
+ friend class Allocator;
+ friend class AllocatorPimpl;
+ template<typename T> friend void D3D12MA_DELETE(const ALLOCATION_CALLBACKS&, T*);
+
+ PoolPimpl* m_Pimpl;
+
+ Pool(Allocator* allocator, const POOL_DESC &desc);
+ ~Pool();
+
+ D3D12MA_CLASS_NO_COPY(Pool)
+};
+
/// \brief Bit flags to be used with ALLOCATOR_DESC::Flags.
typedef enum ALLOCATOR_FLAGS
{
@@ -864,6 +941,10 @@
REFIID riidResource,
void** ppvResource);
+ HRESULT CreatePool(
+ const POOL_DESC* pPoolDesc,
+ Pool** ppPool);
+
/** \brief Sets the index of the current frame.
This function is used to set the frame index in the allocator when a new game frame begins.
@@ -899,6 +980,7 @@
private:
friend HRESULT CreateAllocator(const ALLOCATOR_DESC*, Allocator**);
template<typename T> friend void D3D12MA_DELETE(const ALLOCATION_CALLBACKS&, T*);
+ friend class Pool;
Allocator(const ALLOCATION_CALLBACKS& allocationCallbacks, const ALLOCATOR_DESC& desc);
~Allocator();
diff --git a/src/Tests.cpp b/src/Tests.cpp
index 954caed..7cfda89 100644
--- a/src/Tests.cpp
+++ b/src/Tests.cpp
@@ -27,9 +27,12 @@
extern ID3D12GraphicsCommandList* BeginCommandList();
extern void EndCommandList(ID3D12GraphicsCommandList* cmdList);
-struct AllocationDeleter
+static constexpr UINT64 MEGABYTE = 1024 * 1024;
+
+template<typename T>
+struct D3d12maObjDeleter
{
- void operator()(D3D12MA::Allocation* obj) const
+ void operator()(T* obj) const
{
if(obj)
{
@@ -38,7 +41,8 @@
}
};
-typedef std::unique_ptr<D3D12MA::Allocation, AllocationDeleter> AllocationUniquePtr;
+typedef std::unique_ptr<D3D12MA::Allocation, D3d12maObjDeleter<D3D12MA::Allocation>> AllocationUniquePtr;
+typedef std::unique_ptr<D3D12MA::Pool, D3d12maObjDeleter<D3D12MA::Pool>> PoolUniquePtr;
struct ResourceWithAllocation
{
@@ -399,6 +403,84 @@
renderTargetRes.allocation.reset(alloc);
}
+static void TestCustomPools(const TestContext& ctx)
+{
+ wprintf(L"Test custom pools\n");
+
+ // # Create pool, 1..2 blocks of 11 MB
+
+ D3D12MA::POOL_DESC poolDesc = {};
+ poolDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT;
+ poolDesc.HeapFlags = D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS;
+ poolDesc.BlockSize = 11 * MEGABYTE;
+ poolDesc.MinBlockCount = 1;
+ poolDesc.MaxBlockCount = 2;
+
+ D3D12MA::Pool* poolPtr;
+ CHECK_HR( ctx.allocator->CreatePool(&poolDesc, &poolPtr) );
+ PoolUniquePtr pool{poolPtr};
+
+ // # Create buffers 2x 5 MB
+
+ D3D12MA::ALLOCATION_DESC allocDesc = {};
+ allocDesc.CustomPool = pool.get();
+ allocDesc.ExtraHeapFlags = (D3D12_HEAP_FLAGS)0xCDCDCDCD; // Should be ignored.
+ allocDesc.HeapType = (D3D12_HEAP_TYPE)0xCDCDCDCD; // Should be ignored.
+
+ D3D12_RESOURCE_DESC resDesc;
+ FillResourceDescForBuffer(resDesc, 5 * MEGABYTE);
+
+ AllocationUniquePtr allocs[4];
+ for(uint32_t i = 0; i < 2; ++i)
+ {
+ D3D12MA::Allocation* allocPtr;
+ CHECK_HR( ctx.allocator->CreateResource(&allocDesc, &resDesc,
+ D3D12_RESOURCE_STATE_GENERIC_READ,
+ NULL, // pOptimizedClearValue
+ &allocPtr,
+ __uuidof(ID3D12Resource), NULL) ); // riidResource, ppvResource
+ allocs[i].reset(allocPtr);
+ }
+
+ // # NEVER_ALLOCATE and COMMITTED should fail
+
+ for(uint32_t i = 0; i < 2; ++i)
+ {
+ allocDesc.Flags = i == 0 ?
+ D3D12MA::ALLOCATION_FLAG_NEVER_ALLOCATE:
+ D3D12MA::ALLOCATION_FLAG_COMMITTED;
+ D3D12MA::Allocation* allocPtr;
+ const HRESULT hr = ctx.allocator->CreateResource(&allocDesc, &resDesc,
+ D3D12_RESOURCE_STATE_GENERIC_READ,
+ NULL, // pOptimizedClearValue
+ &allocPtr,
+ __uuidof(ID3D12Resource), NULL); // riidResource, ppvResource
+ CHECK_BOOL( FAILED(hr) );
+ }
+
+ // # 3 more buffers. 3rd should fail.
+
+ allocDesc.Flags = D3D12MA::ALLOCATION_FLAG_NONE;
+ for(uint32_t i = 2; i < 5; ++i)
+ {
+ D3D12MA::Allocation* allocPtr;
+ HRESULT hr = ctx.allocator->CreateResource(&allocDesc, &resDesc,
+ D3D12_RESOURCE_STATE_GENERIC_READ,
+ NULL, // pOptimizedClearValue
+ &allocPtr,
+ __uuidof(ID3D12Resource), NULL); // riidResource, ppvResource
+ if(i < 4)
+ {
+ CHECK_HR( hr );
+ allocs[i].reset(allocPtr);
+ }
+ else
+ {
+ CHECK_BOOL( FAILED(hr) );
+ }
+ }
+}
+
static void TestAliasingMemory(const TestContext& ctx)
{
wprintf(L"Test aliasing memory\n");
@@ -1002,6 +1084,7 @@
TestCommittedResourcesAndJson(ctx);
TestCustomHeapFlags(ctx);
TestPlacedResources(ctx);
+ TestCustomPools(ctx);
TestAliasingMemory(ctx);
TestMapping(ctx);
TestStats(ctx);