- Added Allocation::GetResource. Allocation now remembers associated ID3D12Resource and keeps reference to it.

- Added Allocator::BuildStatsString, FreeStatsString for generation of a dump of internal library state, including list of all allocations and their parameters, in a JSON format.
- Added Allocator::AllocateMemory to allocate a piece of heap without any associated resource. Useful for aliasing.
This commit is contained in:
Adam Sawicki 2019-10-11 11:11:28 +02:00
parent 40a205aee1
commit 5855a7ffd1
4 changed files with 1132 additions and 178 deletions

5
src/.editorconfig Normal file
View File

@ -0,0 +1,5 @@
root = true
[**.{cpp,h}]
indent_style = space
indent_size = 4

File diff suppressed because it is too large Load Diff

View File

@ -24,7 +24,7 @@
/** \mainpage D3D12 Memory Allocator
<b>Version 1.0.0-development</b> (2019-09-30)
<b>Version 1.0.0-development</b> (2019-10-09)
Copyright (c) 2019 Advanced Micro Devices, Inc. All rights reserved. \n
License: MIT
@ -320,7 +320,11 @@ Features deliberately excluded from the scope of this library:
*/
#include <d3d12.h>
// If using this library on a platform different than Windows PC, you should
// include D3D12-compatible header before this library on your own.
#ifdef _WIN32
#include <d3d12.h>
#endif
/// \cond INTERNAL
@ -341,7 +345,7 @@ namespace D3D12MA
/// \cond INTERNAL
class AllocatorPimpl;
class DeviceMemoryBlock;
class NormalBlock;
class BlockVector;
/// \endcond
@ -412,6 +416,9 @@ Allocator::CreateResource.
The object remembers size and some other information.
To retrieve this information, use methods of this class.
The object also remembers `ID3D12Resource` and "owns" a reference to it,
so it calls `Release()` on the resource when destroyed.
*/
class Allocation
{
@ -435,6 +442,12 @@ public:
*/
UINT64 GetSize() const { return m_Size; }
/** \brief Returns D3D12 resource associated with this object.
Calling this method doesn't increment resource's reference counter.
*/
ID3D12Resource* GetResource() const { return m_Resource; }
/** \brief Returns memory heap that the resource is created in.
If the Allocation represents committed resource with implicit heap, returns NULL.
@ -468,9 +481,11 @@ private:
{
TYPE_COMMITTED,
TYPE_PLACED,
TYPE_HEAP,
TYPE_COUNT
} m_Type;
UINT64 m_Size;
ID3D12Resource* m_Resource;
wchar_t* m_Name;
union
@ -483,15 +498,22 @@ private:
struct
{
UINT64 offset;
DeviceMemoryBlock* block;
NormalBlock* block;
} m_Placed;
struct
{
D3D12_HEAP_TYPE heapType;
ID3D12Heap* heap;
} m_Heap;
};
Allocation();
~Allocation();
void InitCommitted(AllocatorPimpl* allocator, UINT64 size, D3D12_HEAP_TYPE heapType);
void InitPlaced(AllocatorPimpl* allocator, UINT64 size, UINT64 offset, UINT64 alignment, DeviceMemoryBlock* block);
DeviceMemoryBlock* GetBlock();
void InitPlaced(AllocatorPimpl* allocator, UINT64 size, UINT64 offset, UINT64 alignment, NormalBlock* block);
void InitHeap(AllocatorPimpl* allocator, UINT64 size, D3D12_HEAP_TYPE heapType, ID3D12Heap* heap);
void SetResource(ID3D12Resource* resource);
void FreeName();
D3D12MA_CLASS_NO_COPY(Allocation)
@ -606,8 +628,22 @@ public:
existing memory heap to the new resource, which is the main purpose of this
whole library.
Two objects are created and returned: allocation and resource. You need to
destroy them both.
If `ppvResource` is null, you receive only `ppAllocation` object from this function.
It holds pointer to `ID3D12Resource` that can be queried using function D3D12::Allocation::GetResource().
Reference count of the resource object is 1.
It is automatically destroyed when you destroy the allocation object.
If 'ppvResource` is not null, you receive pointer to the resource next to allocation object.
Reference count of the resource object is then 2, so you need to manually `Release` it
along with the allocation.
\param pAllocDesc Parameters of the allocation.
\param pResourceDesc Description of created resource.
\param InitialResourceState Initial resource state.
\param pOptimizedClearValue Optional. Either null or optimized clear value.
\param[out] ppAllocation Filled with pointer to new allocation object created.
\param riidResource IID of a resource to be created. Must be `__uuidof(ID3D12Resource)`.
\param[out] ppvResource Optional. If not null, filled with pointer to new resouce created.
*/
HRESULT CreateResource(
const ALLOCATION_DESC* pAllocDesc,
@ -618,10 +654,39 @@ public:
REFIID riidResource,
void** ppvResource);
/* \brief Allocates memory without creating any resource placed in it.
This function is similar to `ID3D12Device::CreateHeap`, but it may really assign
part of a larger, existing heap to the allocation.
If ResourceHeapTier = 1, `heapFlags` must be one of these values, depending on type
of resources you are going to create in this memory:
`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, `heapFlags` may be `D3D12_HEAP_FLAG_ALLOW_ALL_BUFFERS_AND_TEXTURES`.
`pAllocInfo->SizeInBytes` must be multiply of 64KB.
`pAllocInfo->Alignment` must be one of the legal values as described in documentation of `D3D12_HEAP_DESC`.
*/
HRESULT AllocateMemory(
const ALLOCATION_DESC* pAllocDesc,
D3D12_HEAP_FLAGS heapFlags,
const D3D12_RESOURCE_ALLOCATION_INFO* pAllocInfo,
Allocation** ppAllocation);
/** \brief Retrieves statistics from the current state of the allocator.
*/
void CalculateStats(Stats* pStats);
/// Builds and returns statistics as a string in JSON format.
/** @param[out] ppStatsString Must be freed using Allocator::FreeStatsString.
*/
void BuildStatsString(WCHAR** ppStatsString, BOOL DetailedMap);
/// Frees memory of a string returned from Allocator::BuildStatsString.
void FreeStatsString(WCHAR* pStatsString);
private:
friend HRESULT CreateAllocator(const ALLOCATOR_DESC*, Allocator**);
template<typename T> friend void D3D12MA_DELETE(const ALLOCATION_CALLBACKS&, T*);

View File

@ -91,9 +91,9 @@ static bool ValidateData(const void* ptr, const UINT64 sizeInBytes, UINT seed)
return true;
}
static void TestCommittedResources(const TestContext& ctx)
static void TestCommittedResourcesAndJson(const TestContext& ctx)
{
wprintf(L"Test committed resources\n");
wprintf(L"Test committed resources and JSON\n");
const UINT count = 4;
const UINT64 bufSize = 32ull * 1024;
@ -115,6 +115,8 @@ static void TestCommittedResources(const TestContext& ctx)
for(UINT i = 0; i < count; ++i)
{
const bool receiveExplicitResource = i < 2;
D3D12MA::Allocation* alloc = nullptr;
CHECK_HR( ctx.allocator->CreateResource(
&allocDesc,
@ -122,8 +124,18 @@ static void TestCommittedResources(const TestContext& ctx)
D3D12_RESOURCE_STATE_GENERIC_READ,
NULL,
&alloc,
IID_PPV_ARGS(&resources[i].resource)) );
__uuidof(ID3D12Resource),
receiveExplicitResource ? (void**)&resources[i].resource : NULL));
resources[i].allocation.reset(alloc);
if(receiveExplicitResource)
{
ID3D12Resource* res = resources[i].resource.p;
CHECK_BOOL(res && res == resources[i].allocation->GetResource());
const ULONG refCountAfterAdd = res->AddRef();
CHECK_BOOL(refCountAfterAdd == 3);
res->Release();
}
// Make sure it has implicit heap.
CHECK_BOOL( resources[i].allocation->GetHeap() == NULL && resources[i].allocation->GetOffset() == 0 );
@ -144,6 +156,13 @@ static void TestCommittedResources(const TestContext& ctx)
CHECK_BOOL(names[i] == NULL);
}
}
WCHAR* jsonString;
ctx.allocator->BuildStatsString(&jsonString, TRUE);
CHECK_BOOL(wcsstr(jsonString, L"\"Resource\\nFoo\\r\\nBar\"") != NULL);
CHECK_BOOL(wcsstr(jsonString, L"\"Resource \\\"'&<>?#@!&-=_+[]{};:,.\\/\\\\\"") != NULL);
CHECK_BOOL(wcsstr(jsonString, L"\"\"") != NULL);
ctx.allocator->FreeStatsString(jsonString);
}
static void TestPlacedResources(const TestContext& ctx)
@ -501,7 +520,7 @@ static void TestMultithreading(const TestContext& ctx)
resources.reserve(256);
// Create starting number of buffers.
const UINT bufToCreateCount = 64;
const UINT bufToCreateCount = 32;
for(UINT bufIndex = 0; bufIndex < bufToCreateCount; ++bufIndex)
{
ResourceWithAllocation res = {};
@ -613,7 +632,7 @@ static void TestMultithreading(const TestContext& ctx)
static void TestGroupBasics(const TestContext& ctx)
{
TestCommittedResources(ctx);
TestCommittedResourcesAndJson(ctx);
TestPlacedResources(ctx);
TestMapping(ctx);
TestStats(ctx);