mirror of
https://github.com/GPUOpen-LibrariesAndSDKs/D3D12MemoryAllocator.git
synced 2024-11-25 05:20:04 +00:00
Add big feature of budget management - struct Budget, Allocator::GetBudget, ALLOCATION_FLAG_WITHIN_BUDGET, ALLOCATOR_DESC::pAdapter.
Added macro D3D12MA_DXGI_1_4, D3D12MA_D3D12_HEADERS_ALREADY_INCLUDED. Some bug fixes and improvements.
This commit is contained in:
parent
87528d084a
commit
0db8cd41e4
@ -22,6 +22,13 @@
|
|||||||
|
|
||||||
#include "D3D12MemAlloc.h"
|
#include "D3D12MemAlloc.h"
|
||||||
|
|
||||||
|
#ifndef D3D12MA_D3D12_HEADERS_ALREADY_INCLUDED
|
||||||
|
#include <dxgi.h>
|
||||||
|
#if D3D12MA_DXGI_1_4
|
||||||
|
#include <dxgi1_4.h>
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@ -165,6 +172,8 @@ static void SetupAllocationCallbacks(ALLOCATION_CALLBACKS& outAllocs, const ALLO
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Private globals - basic facilities
|
// Private globals - basic facilities
|
||||||
|
|
||||||
|
#define SAFE_RELEASE(ptr) do { if(ptr) { (ptr)->Release(); (ptr) = NULL; } } while(false)
|
||||||
|
|
||||||
#define D3D12MA_VALIDATE(cond) do { if(!(cond)) { \
|
#define D3D12MA_VALIDATE(cond) do { if(!(cond)) { \
|
||||||
D3D12MA_ASSERT(0 && "Validation failed: " #cond); \
|
D3D12MA_ASSERT(0 && "Validation failed: " #cond); \
|
||||||
return false; \
|
return false; \
|
||||||
@ -225,6 +234,10 @@ If providing your own implementation, you need to implement a subset of std::ato
|
|||||||
#define D3D12MA_ATOMIC_UINT32 std::atomic<UINT>
|
#define D3D12MA_ATOMIC_UINT32 std::atomic<UINT>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef D3D12MA_ATOMIC_UINT64
|
||||||
|
#define D3D12MA_ATOMIC_UINT64 std::atomic<UINT64>
|
||||||
|
#endif
|
||||||
|
|
||||||
// Aligns given value up to nearest multiply of align value. For example: AlignUp(11, 8) = 16.
|
// Aligns given value up to nearest multiply of align value. For example: AlignUp(11, 8) = 16.
|
||||||
// Use types like UINT, uint64_t as T.
|
// Use types like UINT, uint64_t as T.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -2073,11 +2086,53 @@ private:
|
|||||||
|
|
||||||
static const UINT DEFAULT_POOL_MAX_COUNT = 9;
|
static const UINT DEFAULT_POOL_MAX_COUNT = 9;
|
||||||
|
|
||||||
|
struct CurrentBudgetData
|
||||||
|
{
|
||||||
|
D3D12MA_ATOMIC_UINT64 m_BlockBytes[HEAP_TYPE_COUNT];
|
||||||
|
D3D12MA_ATOMIC_UINT64 m_AllocationBytes[HEAP_TYPE_COUNT];
|
||||||
|
|
||||||
|
D3D12MA_ATOMIC_UINT32 m_OperationsSinceBudgetFetch;
|
||||||
|
D3D12MA_RW_MUTEX m_BudgetMutex;
|
||||||
|
UINT64 m_D3D12UsageLocal, m_D3D12UsageNonLocal;
|
||||||
|
UINT64 m_D3D12BudgetLocal, m_D3D12BudgetNonLocal;
|
||||||
|
UINT64 m_BlockBytesAtBudgetFetch[HEAP_TYPE_COUNT];
|
||||||
|
|
||||||
|
CurrentBudgetData()
|
||||||
|
{
|
||||||
|
for(UINT i = 0; i < HEAP_TYPE_COUNT; ++i)
|
||||||
|
{
|
||||||
|
m_BlockBytes[i] = 0;
|
||||||
|
m_AllocationBytes[i] = 0;
|
||||||
|
m_BlockBytesAtBudgetFetch[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_D3D12UsageLocal = 0;
|
||||||
|
m_D3D12UsageNonLocal = 0;
|
||||||
|
m_D3D12BudgetLocal = 0;
|
||||||
|
m_D3D12BudgetNonLocal = 0;
|
||||||
|
m_OperationsSinceBudgetFetch = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddAllocation(UINT heapTypeIndex, UINT64 allocationSize)
|
||||||
|
{
|
||||||
|
m_AllocationBytes[heapTypeIndex] += allocationSize;
|
||||||
|
++m_OperationsSinceBudgetFetch;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoveAllocation(UINT heapTypeIndex, UINT64 allocationSize)
|
||||||
|
{
|
||||||
|
m_AllocationBytes[heapTypeIndex] -= allocationSize;
|
||||||
|
++m_OperationsSinceBudgetFetch;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class AllocatorPimpl
|
class AllocatorPimpl
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
CurrentBudgetData m_Budget;
|
||||||
|
|
||||||
AllocatorPimpl(const ALLOCATION_CALLBACKS& allocationCallbacks, const ALLOCATOR_DESC& desc);
|
AllocatorPimpl(const ALLOCATION_CALLBACKS& allocationCallbacks, const ALLOCATOR_DESC& desc);
|
||||||
HRESULT Init();
|
HRESULT Init(const ALLOCATOR_DESC& desc);
|
||||||
~AllocatorPimpl();
|
~AllocatorPimpl();
|
||||||
|
|
||||||
ID3D12Device* GetDevice() const { return m_Device; }
|
ID3D12Device* GetDevice() const { return m_Device; }
|
||||||
@ -2118,6 +2173,9 @@ public:
|
|||||||
|
|
||||||
void CalculateStats(Stats& outStats);
|
void CalculateStats(Stats& outStats);
|
||||||
|
|
||||||
|
void GetBudget(Budget* outGpuBudget, Budget* outCpuBudget);
|
||||||
|
void GetBudgetForHeapType(Budget& outBudget, D3D12_HEAP_TYPE heapType);
|
||||||
|
|
||||||
void BuildStatsString(WCHAR** ppStatsString, BOOL DetailedMap);
|
void BuildStatsString(WCHAR** ppStatsString, BOOL DetailedMap);
|
||||||
|
|
||||||
void FreeStatsString(WCHAR* pStatsString);
|
void FreeStatsString(WCHAR* pStatsString);
|
||||||
@ -2133,11 +2191,15 @@ private:
|
|||||||
|
|
||||||
const bool m_UseMutex;
|
const bool m_UseMutex;
|
||||||
const bool m_AlwaysCommitted;
|
const bool m_AlwaysCommitted;
|
||||||
ID3D12Device* m_Device;
|
ID3D12Device* m_Device; // AddRef
|
||||||
|
IDXGIAdapter* m_Adapter; // AddRef
|
||||||
|
#if D3D12MA_DXGI_1_4
|
||||||
|
IDXGIAdapter3* m_Adapter3; // AddRef, optional
|
||||||
|
#endif
|
||||||
UINT64 m_PreferredBlockSize;
|
UINT64 m_PreferredBlockSize;
|
||||||
ALLOCATION_CALLBACKS m_AllocationCallbacks;
|
ALLOCATION_CALLBACKS m_AllocationCallbacks;
|
||||||
D3D12MA_ATOMIC_UINT32 m_CurrentFrameIndex;
|
D3D12MA_ATOMIC_UINT32 m_CurrentFrameIndex;
|
||||||
|
DXGI_ADAPTER_DESC m_AdapterDesc;
|
||||||
D3D12_FEATURE_DATA_D3D12_OPTIONS m_D3D12Options;
|
D3D12_FEATURE_DATA_D3D12_OPTIONS m_D3D12Options;
|
||||||
|
|
||||||
typedef Vector<Allocation*> AllocationVectorType;
|
typedef Vector<Allocation*> AllocationVectorType;
|
||||||
@ -2193,6 +2255,11 @@ private:
|
|||||||
void RegisterCommittedAllocation(Allocation* alloc, D3D12_HEAP_TYPE heapType);
|
void RegisterCommittedAllocation(Allocation* alloc, D3D12_HEAP_TYPE heapType);
|
||||||
// Unregisters Allocation object from m_pCommittedAllocations.
|
// Unregisters Allocation object from m_pCommittedAllocations.
|
||||||
void UnregisterCommittedAllocation(Allocation* alloc, D3D12_HEAP_TYPE heapType);
|
void UnregisterCommittedAllocation(Allocation* alloc, D3D12_HEAP_TYPE heapType);
|
||||||
|
|
||||||
|
HRESULT UpdateD3D12Budget();
|
||||||
|
|
||||||
|
// Writes object { } with data of given budget.
|
||||||
|
static void WriteBudgetToJson(JsonWriter& json, const Budget& budget);
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -2761,18 +2828,21 @@ NormalBlock::NormalBlock(
|
|||||||
UINT64 size,
|
UINT64 size,
|
||||||
UINT id) :
|
UINT id) :
|
||||||
MemoryBlock(allocator, heapType, heapFlags, size, id),
|
MemoryBlock(allocator, heapType, heapFlags, size, id),
|
||||||
|
m_pMetadata(NULL),
|
||||||
m_BlockVector(blockVector)
|
m_BlockVector(blockVector)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
NormalBlock::~NormalBlock()
|
NormalBlock::~NormalBlock()
|
||||||
{
|
{
|
||||||
// THIS IS THE MOST IMPORTANT ASSERT IN THE ENTIRE LIBRARY!
|
if(m_pMetadata != NULL)
|
||||||
// Hitting it means you have some memory leak - unreleased Allocation objects.
|
{
|
||||||
D3D12MA_ASSERT(m_pMetadata->IsEmpty() && "Some allocations were not freed before destruction of this memory block!");
|
// THIS IS THE MOST IMPORTANT ASSERT IN THE ENTIRE LIBRARY!
|
||||||
|
// Hitting it means you have some memory leak - unreleased Allocation objects.
|
||||||
|
D3D12MA_ASSERT(m_pMetadata->IsEmpty() && "Some allocations were not freed before destruction of this memory block!");
|
||||||
|
|
||||||
D3D12MA_DELETE(m_Allocator->GetAllocs(), m_pMetadata);
|
D3D12MA_DELETE(m_Allocator->GetAllocs(), m_pMetadata);
|
||||||
m_pMetadata = NULL;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT NormalBlock::Init()
|
HRESULT NormalBlock::Init()
|
||||||
@ -2819,6 +2889,7 @@ MemoryBlock::~MemoryBlock()
|
|||||||
{
|
{
|
||||||
if(m_Heap)
|
if(m_Heap)
|
||||||
{
|
{
|
||||||
|
m_Allocator->m_Budget.m_BlockBytes[HeapTypeToIndex(m_HeapType)] -= m_Size;
|
||||||
m_Heap->Release();
|
m_Heap->Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2833,7 +2904,12 @@ HRESULT MemoryBlock::Init()
|
|||||||
heapDesc.Alignment = HeapFlagsToAlignment(m_HeapFlags);
|
heapDesc.Alignment = HeapFlagsToAlignment(m_HeapFlags);
|
||||||
heapDesc.Flags = m_HeapFlags;
|
heapDesc.Flags = m_HeapFlags;
|
||||||
|
|
||||||
return m_Allocator->GetDevice()->CreateHeap(&heapDesc, __uuidof(*m_Heap), (void**)&m_Heap);
|
HRESULT hr = m_Allocator->GetDevice()->CreateHeap(&heapDesc, __uuidof(*m_Heap), (void**)&m_Heap);
|
||||||
|
if(SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
m_Allocator->m_Budget.m_BlockBytes[HeapTypeToIndex(m_HeapType)] += m_Size;
|
||||||
|
}
|
||||||
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -2932,9 +3008,17 @@ HRESULT BlockVector::AllocatePage(
|
|||||||
return E_OUTOFMEMORY;
|
return E_OUTOFMEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UINT64 freeMemory;
|
||||||
|
{
|
||||||
|
Budget budget = {};
|
||||||
|
m_hAllocator->GetBudgetForHeapType(budget, m_HeapType);
|
||||||
|
freeMemory = (budget.Usage < budget.Budget) ? (budget.Budget - budget.Usage) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
const bool canCreateNewBlock =
|
const bool canCreateNewBlock =
|
||||||
((createInfo.Flags & ALLOCATION_FLAG_NEVER_ALLOCATE) == 0) &&
|
((createInfo.Flags & ALLOCATION_FLAG_NEVER_ALLOCATE) == 0) &&
|
||||||
(m_Blocks.size() < m_MaxBlockCount);
|
(m_Blocks.size() < m_MaxBlockCount) &&
|
||||||
|
freeMemory >= size;
|
||||||
|
|
||||||
if(canCreateNewBlock)
|
if(canCreateNewBlock)
|
||||||
{
|
{
|
||||||
@ -2990,7 +3074,8 @@ HRESULT BlockVector::AllocatePage(
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t newBlockIndex = 0;
|
size_t newBlockIndex = 0;
|
||||||
HRESULT hr = CreateBlock(newBlockSize, &newBlockIndex);
|
HRESULT hr = newBlockSize <= freeMemory ?
|
||||||
|
CreateBlock(newBlockSize, &newBlockIndex) : E_OUTOFMEMORY;
|
||||||
// Allocation of this size failed? Try 1/2, 1/4, 1/8 of m_PreferredBlockSize.
|
// Allocation of this size failed? Try 1/2, 1/4, 1/8 of m_PreferredBlockSize.
|
||||||
if(!m_ExplicitBlockSize)
|
if(!m_ExplicitBlockSize)
|
||||||
{
|
{
|
||||||
@ -3001,7 +3086,8 @@ HRESULT BlockVector::AllocatePage(
|
|||||||
{
|
{
|
||||||
newBlockSize = smallerNewBlockSize;
|
newBlockSize = smallerNewBlockSize;
|
||||||
++newBlockSizeShift;
|
++newBlockSizeShift;
|
||||||
hr = CreateBlock(newBlockSize, &newBlockIndex);
|
hr = newBlockSize <= freeMemory ?
|
||||||
|
CreateBlock(newBlockSize, &newBlockIndex) : E_OUTOFMEMORY;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -3041,6 +3127,13 @@ void BlockVector::Free(Allocation* hAllocation)
|
|||||||
{
|
{
|
||||||
NormalBlock* pBlockToDelete = NULL;
|
NormalBlock* pBlockToDelete = NULL;
|
||||||
|
|
||||||
|
bool budgetExceeded = false;
|
||||||
|
{
|
||||||
|
Budget budget = {};
|
||||||
|
m_hAllocator->GetBudgetForHeapType(budget, m_HeapType);
|
||||||
|
budgetExceeded = budget.Usage >= budget.Budget;
|
||||||
|
}
|
||||||
|
|
||||||
// Scope for lock.
|
// Scope for lock.
|
||||||
{
|
{
|
||||||
MutexLockWrite lock(m_Mutex, m_hAllocator->UseMutex());
|
MutexLockWrite lock(m_Mutex, m_hAllocator->UseMutex());
|
||||||
@ -3050,11 +3143,12 @@ void BlockVector::Free(Allocation* hAllocation)
|
|||||||
pBlock->m_pMetadata->Free(hAllocation);
|
pBlock->m_pMetadata->Free(hAllocation);
|
||||||
D3D12MA_HEAVY_ASSERT(pBlock->Validate());
|
D3D12MA_HEAVY_ASSERT(pBlock->Validate());
|
||||||
|
|
||||||
|
const bool canDeleteBlock = m_Blocks.size() > m_MinBlockCount;
|
||||||
// pBlock became empty after this deallocation.
|
// pBlock became empty after this deallocation.
|
||||||
if(pBlock->m_pMetadata->IsEmpty())
|
if(pBlock->m_pMetadata->IsEmpty())
|
||||||
{
|
{
|
||||||
// Already has empty Allocation. We don't want to have two, so delete this one.
|
// Already has empty Allocation. We don't want to have two, so delete this one.
|
||||||
if(m_HasEmptyBlock && m_Blocks.size() > m_MinBlockCount)
|
if((m_HasEmptyBlock || budgetExceeded) && canDeleteBlock)
|
||||||
{
|
{
|
||||||
pBlockToDelete = pBlock;
|
pBlockToDelete = pBlock;
|
||||||
Remove(pBlock);
|
Remove(pBlock);
|
||||||
@ -3067,7 +3161,7 @@ void BlockVector::Free(Allocation* hAllocation)
|
|||||||
}
|
}
|
||||||
// pBlock didn't become empty, but we have another empty block - find and free that one.
|
// pBlock didn't become empty, but we have another empty block - find and free that one.
|
||||||
// (This is optional, heuristics.)
|
// (This is optional, heuristics.)
|
||||||
else if(m_HasEmptyBlock)
|
else if(m_HasEmptyBlock && canDeleteBlock)
|
||||||
{
|
{
|
||||||
NormalBlock* pLastBlock = m_Blocks.back();
|
NormalBlock* pLastBlock = m_Blocks.back();
|
||||||
if(pLastBlock->m_pMetadata->IsEmpty() && m_Blocks.size() > m_MinBlockCount)
|
if(pLastBlock->m_pMetadata->IsEmpty() && m_Blocks.size() > m_MinBlockCount)
|
||||||
@ -3157,6 +3251,7 @@ HRESULT BlockVector::AllocateFromBlock(
|
|||||||
alignment,
|
alignment,
|
||||||
pBlock);
|
pBlock);
|
||||||
D3D12MA_HEAVY_ASSERT(pBlock->Validate());
|
D3D12MA_HEAVY_ASSERT(pBlock->Validate());
|
||||||
|
m_hAllocator->m_Budget.AddAllocation(HeapTypeToIndex(m_HeapType), size);
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
return E_OUTOFMEMORY;
|
return E_OUTOFMEMORY;
|
||||||
@ -3234,6 +3329,10 @@ AllocatorPimpl::AllocatorPimpl(const ALLOCATION_CALLBACKS& allocationCallbacks,
|
|||||||
m_UseMutex((desc.Flags & ALLOCATOR_FLAG_SINGLETHREADED) == 0),
|
m_UseMutex((desc.Flags & ALLOCATOR_FLAG_SINGLETHREADED) == 0),
|
||||||
m_AlwaysCommitted((desc.Flags & ALLOCATOR_FLAG_ALWAYS_COMMITTED) != 0),
|
m_AlwaysCommitted((desc.Flags & ALLOCATOR_FLAG_ALWAYS_COMMITTED) != 0),
|
||||||
m_Device(desc.pDevice),
|
m_Device(desc.pDevice),
|
||||||
|
m_Adapter(desc.pAdapter),
|
||||||
|
#if D3D12MA_DXGI_1_4
|
||||||
|
m_Adapter3(NULL),
|
||||||
|
#endif
|
||||||
m_PreferredBlockSize(desc.PreferredBlockSize != 0 ? desc.PreferredBlockSize : D3D12MA_DEFAULT_BLOCK_SIZE),
|
m_PreferredBlockSize(desc.PreferredBlockSize != 0 ? desc.PreferredBlockSize : D3D12MA_DEFAULT_BLOCK_SIZE),
|
||||||
m_AllocationCallbacks(allocationCallbacks),
|
m_AllocationCallbacks(allocationCallbacks),
|
||||||
m_CurrentFrameIndex(0)
|
m_CurrentFrameIndex(0)
|
||||||
@ -3249,11 +3348,24 @@ AllocatorPimpl::AllocatorPimpl(const ALLOCATION_CALLBACKS& allocationCallbacks,
|
|||||||
{
|
{
|
||||||
m_pCommittedAllocations[heapTypeIndex] = D3D12MA_NEW(GetAllocs(), AllocationVectorType)(GetAllocs());
|
m_pCommittedAllocations[heapTypeIndex] = D3D12MA_NEW(GetAllocs(), AllocationVectorType)(GetAllocs());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_Device->AddRef();
|
||||||
|
m_Adapter->AddRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT AllocatorPimpl::Init()
|
HRESULT AllocatorPimpl::Init(const ALLOCATOR_DESC& desc)
|
||||||
{
|
{
|
||||||
HRESULT hr = m_Device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &m_D3D12Options, sizeof(m_D3D12Options));
|
#if D3D12MA_DXGI_1_4
|
||||||
|
desc.pAdapter->QueryInterface<IDXGIAdapter3>(&m_Adapter3);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
HRESULT hr = m_Adapter->GetDesc(&m_AdapterDesc);
|
||||||
|
if(FAILED(hr))
|
||||||
|
{
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = m_Device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &m_D3D12Options, sizeof(m_D3D12Options));
|
||||||
if(FAILED(hr))
|
if(FAILED(hr))
|
||||||
{
|
{
|
||||||
return hr;
|
return hr;
|
||||||
@ -3277,11 +3389,24 @@ HRESULT AllocatorPimpl::Init()
|
|||||||
// No need to call m_pBlockVectors[i]->CreateMinBlocks here, becase minBlockCount is 0.
|
// No need to call m_pBlockVectors[i]->CreateMinBlocks here, becase minBlockCount is 0.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if D3D12MA_DXGI_1_4
|
||||||
|
if(m_Adapter3)
|
||||||
|
{
|
||||||
|
UpdateD3D12Budget();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
AllocatorPimpl::~AllocatorPimpl()
|
AllocatorPimpl::~AllocatorPimpl()
|
||||||
{
|
{
|
||||||
|
#if D3D12MA_DXGI_1_4
|
||||||
|
SAFE_RELEASE(m_Adapter3);
|
||||||
|
#endif
|
||||||
|
SAFE_RELEASE(m_Adapter);
|
||||||
|
SAFE_RELEASE(m_Device);
|
||||||
|
|
||||||
for(UINT i = DEFAULT_POOL_MAX_COUNT; i--; )
|
for(UINT i = DEFAULT_POOL_MAX_COUNT; i--; )
|
||||||
{
|
{
|
||||||
D3D12MA_DELETE(GetAllocs(), m_BlockVectors[i]);
|
D3D12MA_DELETE(GetAllocs(), m_BlockVectors[i]);
|
||||||
@ -3385,8 +3510,7 @@ HRESULT AllocatorPimpl::CreateResource(
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
(*ppAllocation)->Release();
|
SAFE_RELEASE(*ppAllocation);
|
||||||
*ppAllocation = NULL;
|
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3479,6 +3603,16 @@ HRESULT AllocatorPimpl::AllocateCommittedResource(
|
|||||||
return E_OUTOFMEMORY;
|
return E_OUTOFMEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if((pAllocDesc->Flags & ALLOCATION_FLAG_WITHIN_BUDGET) != 0)
|
||||||
|
{
|
||||||
|
Budget budget = {};
|
||||||
|
GetBudgetForHeapType(budget, pAllocDesc->HeapType);
|
||||||
|
if(budget.Usage + resAllocInfo.SizeInBytes > budget.Budget)
|
||||||
|
{
|
||||||
|
return E_OUTOFMEMORY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
D3D12_HEAP_PROPERTIES heapProps = {};
|
D3D12_HEAP_PROPERTIES heapProps = {};
|
||||||
heapProps.Type = pAllocDesc->HeapType;
|
heapProps.Type = pAllocDesc->HeapType;
|
||||||
ID3D12Resource* res = NULL;
|
ID3D12Resource* res = NULL;
|
||||||
@ -3499,6 +3633,10 @@ HRESULT AllocatorPimpl::AllocateCommittedResource(
|
|||||||
}
|
}
|
||||||
|
|
||||||
RegisterCommittedAllocation(*ppAllocation, pAllocDesc->HeapType);
|
RegisterCommittedAllocation(*ppAllocation, pAllocDesc->HeapType);
|
||||||
|
|
||||||
|
const UINT heapTypeIndex = HeapTypeToIndex(pAllocDesc->HeapType);
|
||||||
|
m_Budget.AddAllocation(heapTypeIndex, resAllocInfo.SizeInBytes);
|
||||||
|
m_Budget.m_BlockBytes[heapTypeIndex] += resAllocInfo.SizeInBytes;
|
||||||
}
|
}
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
@ -3516,6 +3654,16 @@ HRESULT AllocatorPimpl::AllocateHeap(
|
|||||||
return E_OUTOFMEMORY;
|
return E_OUTOFMEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if((pAllocDesc->Flags & ALLOCATION_FLAG_WITHIN_BUDGET) != 0)
|
||||||
|
{
|
||||||
|
Budget budget = {};
|
||||||
|
GetBudgetForHeapType(budget, pAllocDesc->HeapType);
|
||||||
|
if(budget.Usage + allocInfo.SizeInBytes > budget.Budget)
|
||||||
|
{
|
||||||
|
return E_OUTOFMEMORY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
D3D12_HEAP_DESC heapDesc = {};
|
D3D12_HEAP_DESC heapDesc = {};
|
||||||
heapDesc.SizeInBytes = allocInfo.SizeInBytes;
|
heapDesc.SizeInBytes = allocInfo.SizeInBytes;
|
||||||
heapDesc.Properties.Type = pAllocDesc->HeapType;
|
heapDesc.Properties.Type = pAllocDesc->HeapType;
|
||||||
@ -3529,6 +3677,10 @@ HRESULT AllocatorPimpl::AllocateHeap(
|
|||||||
(*ppAllocation) = D3D12MA_NEW(m_AllocationCallbacks, Allocation)();
|
(*ppAllocation) = D3D12MA_NEW(m_AllocationCallbacks, Allocation)();
|
||||||
(*ppAllocation)->InitHeap(this, allocInfo.SizeInBytes, pAllocDesc->HeapType, heap);
|
(*ppAllocation)->InitHeap(this, allocInfo.SizeInBytes, pAllocDesc->HeapType, heap);
|
||||||
RegisterCommittedAllocation(*ppAllocation, pAllocDesc->HeapType);
|
RegisterCommittedAllocation(*ppAllocation, pAllocDesc->HeapType);
|
||||||
|
|
||||||
|
const UINT heapTypeIndex = HeapTypeToIndex(pAllocDesc->HeapType);
|
||||||
|
m_Budget.AddAllocation(heapTypeIndex, allocInfo.SizeInBytes);
|
||||||
|
m_Budget.m_BlockBytes[heapTypeIndex] += allocInfo.SizeInBytes;
|
||||||
}
|
}
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
@ -3676,6 +3828,11 @@ void AllocatorPimpl::FreeCommittedMemory(Allocation* allocation)
|
|||||||
{
|
{
|
||||||
D3D12MA_ASSERT(allocation && allocation->m_Type == Allocation::TYPE_COMMITTED);
|
D3D12MA_ASSERT(allocation && allocation->m_Type == Allocation::TYPE_COMMITTED);
|
||||||
UnregisterCommittedAllocation(allocation, allocation->m_Committed.heapType);
|
UnregisterCommittedAllocation(allocation, allocation->m_Committed.heapType);
|
||||||
|
|
||||||
|
const UINT64 allocationSize = allocation->GetSize();
|
||||||
|
const UINT heapTypeIndex = HeapTypeToIndex(allocation->m_Committed.heapType);
|
||||||
|
m_Budget.RemoveAllocation(heapTypeIndex, allocationSize);
|
||||||
|
m_Budget.m_BlockBytes[heapTypeIndex] -= allocationSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AllocatorPimpl::FreePlacedMemory(Allocation* allocation)
|
void AllocatorPimpl::FreePlacedMemory(Allocation* allocation)
|
||||||
@ -3686,6 +3843,7 @@ void AllocatorPimpl::FreePlacedMemory(Allocation* allocation)
|
|||||||
D3D12MA_ASSERT(block);
|
D3D12MA_ASSERT(block);
|
||||||
BlockVector* const blockVector = block->GetBlockVector();
|
BlockVector* const blockVector = block->GetBlockVector();
|
||||||
D3D12MA_ASSERT(blockVector);
|
D3D12MA_ASSERT(blockVector);
|
||||||
|
m_Budget.RemoveAllocation(HeapTypeToIndex(block->GetHeapType()), allocation->GetSize());
|
||||||
blockVector->Free(allocation);
|
blockVector->Free(allocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3693,12 +3851,24 @@ void AllocatorPimpl::FreeHeapMemory(Allocation* allocation)
|
|||||||
{
|
{
|
||||||
D3D12MA_ASSERT(allocation && allocation->m_Type == Allocation::TYPE_HEAP);
|
D3D12MA_ASSERT(allocation && allocation->m_Type == Allocation::TYPE_HEAP);
|
||||||
UnregisterCommittedAllocation(allocation, allocation->m_Heap.heapType);
|
UnregisterCommittedAllocation(allocation, allocation->m_Heap.heapType);
|
||||||
allocation->m_Heap.heap->Release();
|
SAFE_RELEASE(allocation->m_Heap.heap);
|
||||||
|
|
||||||
|
const UINT heapTypeIndex = HeapTypeToIndex(allocation->m_Heap.heapType);
|
||||||
|
const UINT64 allocationSize = allocation->GetSize();
|
||||||
|
m_Budget.m_BlockBytes[heapTypeIndex] -= allocationSize;
|
||||||
|
m_Budget.RemoveAllocation(heapTypeIndex, allocationSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AllocatorPimpl::SetCurrentFrameIndex(UINT frameIndex)
|
void AllocatorPimpl::SetCurrentFrameIndex(UINT frameIndex)
|
||||||
{
|
{
|
||||||
m_CurrentFrameIndex.store(frameIndex);
|
m_CurrentFrameIndex.store(frameIndex);
|
||||||
|
|
||||||
|
#if D3D12MA_DXGI_1_4
|
||||||
|
if(m_Adapter3)
|
||||||
|
{
|
||||||
|
UpdateD3D12Budget();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void AllocatorPimpl::CalculateStats(Stats& outStats)
|
void AllocatorPimpl::CalculateStats(Stats& outStats)
|
||||||
@ -3739,7 +3909,7 @@ void AllocatorPimpl::CalculateStats(Stats& outStats)
|
|||||||
statInfo.UnusedBytes = 0;
|
statInfo.UnusedBytes = 0;
|
||||||
statInfo.AllocationSizeMin = size;
|
statInfo.AllocationSizeMin = size;
|
||||||
statInfo.AllocationSizeMax = size;
|
statInfo.AllocationSizeMax = size;
|
||||||
statInfo.UnusedRangeSizeMin = 0;
|
statInfo.UnusedRangeSizeMin = UINT64_MAX;
|
||||||
statInfo.UnusedRangeSizeMax = 0;
|
statInfo.UnusedRangeSizeMax = 0;
|
||||||
AddStatInfo(outStats.Total, statInfo);
|
AddStatInfo(outStats.Total, statInfo);
|
||||||
AddStatInfo(heapStatInfo, statInfo);
|
AddStatInfo(heapStatInfo, statInfo);
|
||||||
@ -3752,6 +3922,94 @@ void AllocatorPimpl::CalculateStats(Stats& outStats)
|
|||||||
PostProcessStatInfo(outStats.HeapType[i]);
|
PostProcessStatInfo(outStats.HeapType[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AllocatorPimpl::GetBudget(Budget* outGpuBudget, Budget* outCpuBudget)
|
||||||
|
{
|
||||||
|
if(outGpuBudget)
|
||||||
|
{
|
||||||
|
// Taking DEFAULT.
|
||||||
|
outGpuBudget->BlockBytes = m_Budget.m_BlockBytes[0];
|
||||||
|
outGpuBudget->AllocationBytes = m_Budget.m_AllocationBytes[0];
|
||||||
|
}
|
||||||
|
if(outCpuBudget)
|
||||||
|
{
|
||||||
|
// Taking UPLOAD + READBACK.
|
||||||
|
outCpuBudget->BlockBytes = m_Budget.m_BlockBytes[1] + m_Budget.m_BlockBytes[2];
|
||||||
|
outCpuBudget->AllocationBytes = m_Budget.m_AllocationBytes[1] + m_Budget.m_AllocationBytes[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
#if D3D12MA_DXGI_1_4
|
||||||
|
if(m_Adapter3)
|
||||||
|
{
|
||||||
|
if(m_Budget.m_OperationsSinceBudgetFetch < 30)
|
||||||
|
{
|
||||||
|
MutexLockRead lockRead(m_Budget.m_BudgetMutex, m_UseMutex);
|
||||||
|
if(outGpuBudget)
|
||||||
|
{
|
||||||
|
|
||||||
|
if(m_Budget.m_D3D12UsageLocal + outGpuBudget->BlockBytes > m_Budget.m_BlockBytesAtBudgetFetch[0])
|
||||||
|
{
|
||||||
|
outGpuBudget->Usage = m_Budget.m_D3D12UsageLocal +
|
||||||
|
outGpuBudget->BlockBytes - m_Budget.m_BlockBytesAtBudgetFetch[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
outGpuBudget->Usage = 0;
|
||||||
|
}
|
||||||
|
outGpuBudget->Budget = m_Budget.m_D3D12BudgetLocal;
|
||||||
|
}
|
||||||
|
if(outCpuBudget)
|
||||||
|
{
|
||||||
|
if(m_Budget.m_D3D12UsageNonLocal + outCpuBudget->BlockBytes > m_Budget.m_BlockBytesAtBudgetFetch[1] + m_Budget.m_BlockBytesAtBudgetFetch[2])
|
||||||
|
{
|
||||||
|
outCpuBudget->Usage = m_Budget.m_D3D12UsageNonLocal +
|
||||||
|
outCpuBudget->BlockBytes - (m_Budget.m_BlockBytesAtBudgetFetch[1] + m_Budget.m_BlockBytesAtBudgetFetch[2]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
outCpuBudget->Usage = 0;
|
||||||
|
}
|
||||||
|
outCpuBudget->Budget = m_Budget.m_D3D12BudgetNonLocal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UpdateD3D12Budget(); // Outside of mutex lock
|
||||||
|
GetBudget(outGpuBudget, outCpuBudget); // Recursion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if(outGpuBudget)
|
||||||
|
{
|
||||||
|
const UINT64 gpuMemorySize = m_AdapterDesc.DedicatedVideoMemory + m_AdapterDesc.DedicatedSystemMemory; // TODO: Is this right?
|
||||||
|
outGpuBudget->Usage = outGpuBudget->BlockBytes;
|
||||||
|
outGpuBudget->Budget = gpuMemorySize * 8 / 10; // 80% heuristics.
|
||||||
|
}
|
||||||
|
if(outCpuBudget)
|
||||||
|
{
|
||||||
|
const UINT64 cpuMemorySize = m_AdapterDesc.SharedSystemMemory; // TODO: Is this right?
|
||||||
|
outCpuBudget->Usage = outCpuBudget->BlockBytes;
|
||||||
|
outCpuBudget->Budget = cpuMemorySize * 8 / 10; // 80% heuristics.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AllocatorPimpl::GetBudgetForHeapType(Budget& outBudget, D3D12_HEAP_TYPE heapType)
|
||||||
|
{
|
||||||
|
switch(heapType)
|
||||||
|
{
|
||||||
|
case D3D12_HEAP_TYPE_DEFAULT:
|
||||||
|
GetBudget(&outBudget, NULL);
|
||||||
|
break;
|
||||||
|
case D3D12_HEAP_TYPE_UPLOAD:
|
||||||
|
case D3D12_HEAP_TYPE_READBACK:
|
||||||
|
GetBudget(NULL, &outBudget);
|
||||||
|
break;
|
||||||
|
default: D3D12MA_ASSERT(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void AddStatInfoToJson(JsonWriter& json, const StatInfo& statInfo)
|
static void AddStatInfoToJson(JsonWriter& json, const StatInfo& statInfo)
|
||||||
{
|
{
|
||||||
json.BeginObject();
|
json.BeginObject();
|
||||||
@ -3795,10 +4053,14 @@ void AllocatorPimpl::BuildStatsString(WCHAR** ppStatsString, BOOL DetailedMap)
|
|||||||
{
|
{
|
||||||
JsonWriter json(GetAllocs(), sb);
|
JsonWriter json(GetAllocs(), sb);
|
||||||
|
|
||||||
|
Budget gpuBudget = {}, cpuBudget = {};
|
||||||
|
GetBudget(&gpuBudget, &cpuBudget);
|
||||||
|
|
||||||
Stats stats;
|
Stats stats;
|
||||||
CalculateStats(stats);
|
CalculateStats(stats);
|
||||||
|
|
||||||
json.BeginObject();
|
json.BeginObject();
|
||||||
|
|
||||||
json.WriteString(L"Total");
|
json.WriteString(L"Total");
|
||||||
AddStatInfoToJson(json, stats.Total);
|
AddStatInfoToJson(json, stats.Total);
|
||||||
for (size_t heapType = 0; heapType < HEAP_TYPE_COUNT; ++heapType)
|
for (size_t heapType = 0; heapType < HEAP_TYPE_COUNT; ++heapType)
|
||||||
@ -3807,6 +4069,16 @@ void AllocatorPimpl::BuildStatsString(WCHAR** ppStatsString, BOOL DetailedMap)
|
|||||||
AddStatInfoToJson(json, stats.HeapType[heapType]);
|
AddStatInfoToJson(json, stats.HeapType[heapType]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
json.WriteString(L"Budget");
|
||||||
|
json.BeginObject();
|
||||||
|
{
|
||||||
|
json.WriteString(L"GPU");
|
||||||
|
WriteBudgetToJson(json, gpuBudget);
|
||||||
|
json.WriteString(L"CPU");
|
||||||
|
WriteBudgetToJson(json, cpuBudget);
|
||||||
|
}
|
||||||
|
json.EndObject();
|
||||||
|
|
||||||
if (DetailedMap)
|
if (DetailedMap)
|
||||||
{
|
{
|
||||||
json.WriteString(L"DetailedMap");
|
json.WriteString(L"DetailedMap");
|
||||||
@ -3905,6 +4177,60 @@ void AllocatorPimpl::FreeStatsString(WCHAR* pStatsString)
|
|||||||
Free(GetAllocs(), pStatsString);
|
Free(GetAllocs(), pStatsString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HRESULT AllocatorPimpl::UpdateD3D12Budget()
|
||||||
|
{
|
||||||
|
#if D3D12MA_DXGI_1_4
|
||||||
|
D3D12MA_ASSERT(m_Adapter3);
|
||||||
|
|
||||||
|
DXGI_QUERY_VIDEO_MEMORY_INFO infoLocal = {};
|
||||||
|
DXGI_QUERY_VIDEO_MEMORY_INFO infoNonLocal = {};
|
||||||
|
HRESULT hrLocal = m_Adapter3->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &infoLocal);
|
||||||
|
HRESULT hrNonLocal = m_Adapter3->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL, &infoNonLocal);
|
||||||
|
|
||||||
|
{
|
||||||
|
MutexLockWrite lockWrite(m_Budget.m_BudgetMutex, m_UseMutex);
|
||||||
|
|
||||||
|
if(SUCCEEDED(hrLocal))
|
||||||
|
{
|
||||||
|
m_Budget.m_D3D12UsageLocal = infoLocal.CurrentUsage;
|
||||||
|
m_Budget.m_D3D12BudgetLocal = infoLocal.Budget;
|
||||||
|
}
|
||||||
|
if(SUCCEEDED(hrNonLocal))
|
||||||
|
{
|
||||||
|
m_Budget.m_D3D12UsageNonLocal = infoNonLocal.CurrentUsage;
|
||||||
|
m_Budget.m_D3D12BudgetNonLocal = infoNonLocal.Budget;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(UINT i = 0; i < HEAP_TYPE_COUNT; ++i)
|
||||||
|
{
|
||||||
|
m_Budget.m_BlockBytesAtBudgetFetch[i] = m_Budget.m_BlockBytes[i].load();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Budget.m_OperationsSinceBudgetFetch = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FAILED(hrLocal) ? hrLocal : hrNonLocal;
|
||||||
|
#else
|
||||||
|
return S_OK;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void AllocatorPimpl::WriteBudgetToJson(JsonWriter& json, const Budget& budget)
|
||||||
|
{
|
||||||
|
json.BeginObject();
|
||||||
|
{
|
||||||
|
json.WriteString(L"BlockBytes");
|
||||||
|
json.WriteNumber(budget.BlockBytes);
|
||||||
|
json.WriteString(L"AllocationBytes");
|
||||||
|
json.WriteNumber(budget.AllocationBytes);
|
||||||
|
json.WriteString(L"Usage");
|
||||||
|
json.WriteNumber(budget.Usage);
|
||||||
|
json.WriteString(L"Budget");
|
||||||
|
json.WriteNumber(budget.Budget);
|
||||||
|
}
|
||||||
|
json.EndObject();
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Public class Allocation implementation
|
// Public class Allocation implementation
|
||||||
|
|
||||||
@ -3917,10 +4243,7 @@ void Allocation::Release()
|
|||||||
|
|
||||||
D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
|
D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
|
||||||
|
|
||||||
if(m_Resource)
|
SAFE_RELEASE(m_Resource);
|
||||||
{
|
|
||||||
m_Resource->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(m_Type)
|
switch(m_Type)
|
||||||
{
|
{
|
||||||
@ -4147,6 +4470,16 @@ void Allocator::CalculateStats(Stats* pStats)
|
|||||||
m_Pimpl->CalculateStats(*pStats);
|
m_Pimpl->CalculateStats(*pStats);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Allocator::GetBudget(Budget* pGpuBudget, Budget* pCpuBudget)
|
||||||
|
{
|
||||||
|
if(pGpuBudget == NULL && pCpuBudget == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
|
||||||
|
m_Pimpl->GetBudget(pGpuBudget, pCpuBudget);
|
||||||
|
}
|
||||||
|
|
||||||
void Allocator::BuildStatsString(WCHAR** ppStatsString, BOOL DetailedMap)
|
void Allocator::BuildStatsString(WCHAR** ppStatsString, BOOL DetailedMap)
|
||||||
{
|
{
|
||||||
D3D12MA_ASSERT(ppStatsString);
|
D3D12MA_ASSERT(ppStatsString);
|
||||||
@ -4168,7 +4501,7 @@ void Allocator::FreeStatsString(WCHAR* pStatsString)
|
|||||||
|
|
||||||
HRESULT CreateAllocator(const ALLOCATOR_DESC* pDesc, Allocator** ppAllocator)
|
HRESULT CreateAllocator(const ALLOCATOR_DESC* pDesc, Allocator** ppAllocator)
|
||||||
{
|
{
|
||||||
if(!pDesc || !ppAllocator || !pDesc->pDevice ||
|
if(!pDesc || !ppAllocator || !pDesc->pDevice || !pDesc->pAdapter ||
|
||||||
!(pDesc->PreferredBlockSize == 0 || (pDesc->PreferredBlockSize >= 16 && pDesc->PreferredBlockSize < 0x10000000000ull)))
|
!(pDesc->PreferredBlockSize == 0 || (pDesc->PreferredBlockSize >= 16 && pDesc->PreferredBlockSize < 0x10000000000ull)))
|
||||||
{
|
{
|
||||||
D3D12MA_ASSERT(0 && "Invalid arguments passed to CreateAllocator.");
|
D3D12MA_ASSERT(0 && "Invalid arguments passed to CreateAllocator.");
|
||||||
@ -4181,7 +4514,7 @@ HRESULT CreateAllocator(const ALLOCATOR_DESC* pDesc, Allocator** ppAllocator)
|
|||||||
SetupAllocationCallbacks(allocationCallbacks, *pDesc);
|
SetupAllocationCallbacks(allocationCallbacks, *pDesc);
|
||||||
|
|
||||||
*ppAllocator = D3D12MA_NEW(allocationCallbacks, Allocator)(allocationCallbacks, *pDesc);
|
*ppAllocator = D3D12MA_NEW(allocationCallbacks, Allocator)(allocationCallbacks, *pDesc);
|
||||||
HRESULT hr = (*ppAllocator)->m_Pimpl->Init();
|
HRESULT hr = (*ppAllocator)->m_Pimpl->Init(*pDesc);
|
||||||
if(FAILED(hr))
|
if(FAILED(hr))
|
||||||
{
|
{
|
||||||
D3D12MA_DELETE(allocationCallbacks, *ppAllocator);
|
D3D12MA_DELETE(allocationCallbacks, *ppAllocator);
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
/** \mainpage D3D12 Memory Allocator
|
/** \mainpage D3D12 Memory Allocator
|
||||||
|
|
||||||
<b>Version 1.0.0-development</b> (2019-10-09)
|
<b>Version 2.0.0-development</b> (2019-11-20)
|
||||||
|
|
||||||
Copyright (c) 2019 Advanced Micro Devices, Inc. All rights reserved. \n
|
Copyright (c) 2019 Advanced Micro Devices, Inc. All rights reserved. \n
|
||||||
License: MIT
|
License: MIT
|
||||||
@ -307,8 +307,6 @@ Near future: feature parity with [Vulkan Memory Allocator](https://github.com/GP
|
|||||||
Later:
|
Later:
|
||||||
|
|
||||||
- Memory defragmentation
|
- Memory defragmentation
|
||||||
- Query for memory budget using `IDXGIAdapter3::QueryVideoMemoryInfo` and
|
|
||||||
sticking to this budget with allocations
|
|
||||||
- Support for resource aliasing (overlap)
|
- Support for resource aliasing (overlap)
|
||||||
- Support for multi-GPU (multi-adapter)
|
- Support for multi-GPU (multi-adapter)
|
||||||
|
|
||||||
@ -325,10 +323,16 @@ Features deliberately excluded from the scope of this library:
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Define this macro to 0 to disable usage of DXGI 1.4 (needed for IDXGIAdapter3 and query for memory budget).
|
||||||
|
#ifndef D3D12MA_DXGI_1_4
|
||||||
|
#define D3D12MA_DXGI_1_4 1
|
||||||
|
#endif
|
||||||
|
|
||||||
// If using this library on a platform different than Windows PC, you should
|
// If using this library on a platform different than Windows PC, you should
|
||||||
// include D3D12-compatible header before this library on your own.
|
// include D3D12-compatible header before this library on your own and define this macro.
|
||||||
#ifdef _WIN32
|
#ifndef D3D12MA_D3D12_HEADERS_ALREADY_INCLUDED
|
||||||
#include <d3d12.h>
|
#include <d3d12.h>
|
||||||
|
#include <dxgi.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// \cond INTERNAL
|
/// \cond INTERNAL
|
||||||
@ -398,6 +402,10 @@ typedef enum ALLOCATION_FLAGS
|
|||||||
#ALLOCATION_FLAG_NEVER_ALLOCATE at the same time. It makes no sense.
|
#ALLOCATION_FLAG_NEVER_ALLOCATE at the same time. It makes no sense.
|
||||||
*/
|
*/
|
||||||
ALLOCATION_FLAG_NEVER_ALLOCATE = 0x2,
|
ALLOCATION_FLAG_NEVER_ALLOCATE = 0x2,
|
||||||
|
|
||||||
|
/** TODO
|
||||||
|
*/
|
||||||
|
ALLOCATION_FLAG_WITHIN_BUDGET = 0x4,
|
||||||
} ALLOCATION_FLAGS;
|
} ALLOCATION_FLAGS;
|
||||||
|
|
||||||
/// \brief Parameters of created Allocation object. To be used with Allocator::CreateResource.
|
/// \brief Parameters of created Allocation object. To be used with Allocator::CreateResource.
|
||||||
@ -558,7 +566,10 @@ struct ALLOCATOR_DESC
|
|||||||
/// Flags.
|
/// Flags.
|
||||||
ALLOCATOR_FLAGS Flags;
|
ALLOCATOR_FLAGS Flags;
|
||||||
|
|
||||||
/// Direct3D device object that the allocator should be attached to.
|
/** Direct3D device object that the allocator should be attached to.
|
||||||
|
|
||||||
|
Allocator is doing AddRef/Release on this object.
|
||||||
|
*/
|
||||||
ID3D12Device* pDevice;
|
ID3D12Device* pDevice;
|
||||||
|
|
||||||
/** \brief Preferred size of a single `ID3D12Heap` block to be allocated.
|
/** \brief Preferred size of a single `ID3D12Heap` block to be allocated.
|
||||||
@ -572,6 +583,12 @@ struct ALLOCATOR_DESC
|
|||||||
Optional, can be null. When specified, will be used for all CPU-side memory allocations.
|
Optional, can be null. When specified, will be used for all CPU-side memory allocations.
|
||||||
*/
|
*/
|
||||||
const ALLOCATION_CALLBACKS* pAllocationCallbacks;
|
const ALLOCATION_CALLBACKS* pAllocationCallbacks;
|
||||||
|
|
||||||
|
/** TODO
|
||||||
|
|
||||||
|
Allocator is doing AddRef/Release on this object.
|
||||||
|
*/
|
||||||
|
IDXGIAdapter* pAdapter;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -616,6 +633,44 @@ struct Stats
|
|||||||
StatInfo HeapType[HEAP_TYPE_COUNT];
|
StatInfo HeapType[HEAP_TYPE_COUNT];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** \brief Statistics of current memory usage and available budget, in bytes, for GPU or CPU memory.
|
||||||
|
*/
|
||||||
|
struct Budget
|
||||||
|
{
|
||||||
|
/** \brief Sum size of all memory blocks allocated from particular heap type, in bytes.
|
||||||
|
*/
|
||||||
|
UINT64 BlockBytes;
|
||||||
|
|
||||||
|
/** \brief Sum size of all allocations created in particular heap type, in bytes.
|
||||||
|
|
||||||
|
Always less or equal than `BlockBytes`.
|
||||||
|
Difference `BlockBytes - AllocationBytes` is the amount of memory allocated but unused -
|
||||||
|
available for new allocations or wasted due to fragmentation.
|
||||||
|
*/
|
||||||
|
UINT64 AllocationBytes;
|
||||||
|
|
||||||
|
/** \brief Estimated current memory usage of the program, in bytes.
|
||||||
|
|
||||||
|
Fetched from system using TODO if enabled.
|
||||||
|
|
||||||
|
It might be different than `BlockBytes` (usually higher) due to additional implicit objects
|
||||||
|
also occupying the memory, like swapchain, pipeline state objects, descriptor heaps, command lists, or
|
||||||
|
memory blocks allocated outside of this library, if any.
|
||||||
|
*/
|
||||||
|
UINT64 Usage;
|
||||||
|
|
||||||
|
/** \brief Estimated amount of memory available to the program, in bytes.
|
||||||
|
|
||||||
|
Fetched from system using TODO if enabled.
|
||||||
|
|
||||||
|
It might be different (most probably smaller) than TODO due to factors
|
||||||
|
external to the program, like other programs also consuming system resources.
|
||||||
|
Difference `Budget - Usage` is the amount of additional memory that can probably
|
||||||
|
be allocated without problems. Exceeding the budget may result in various problems.
|
||||||
|
*/
|
||||||
|
UINT64 Budget;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Represents main object of this library initialized for particular `ID3D12Device`.
|
\brief Represents main object of this library initialized for particular `ID3D12Device`.
|
||||||
|
|
||||||
@ -702,6 +757,19 @@ public:
|
|||||||
*/
|
*/
|
||||||
void CalculateStats(Stats* pStats);
|
void CalculateStats(Stats* pStats);
|
||||||
|
|
||||||
|
/** \brief Retrieves information about current memory budget.
|
||||||
|
|
||||||
|
\param[out] pGpuBudget Optional, can be null.
|
||||||
|
\param[out] pCpuBudget Optional, can be null.
|
||||||
|
|
||||||
|
This function is called "get" not "calculate" because it is very fast, suitable to be called
|
||||||
|
every frame or every allocation. For more detailed statistics use CalculateStats().
|
||||||
|
|
||||||
|
Note that when using allocator from multiple threads, returned information may immediately
|
||||||
|
become outdated.
|
||||||
|
*/
|
||||||
|
void GetBudget(Budget* pGpuBudget, Budget* pCpuBudget);
|
||||||
|
|
||||||
/// Builds and returns statistics as a string in JSON format.
|
/// Builds and returns statistics as a string in JSON format.
|
||||||
/** @param[out] ppStatsString Must be freed using Allocator::FreeStatsString.
|
/** @param[out] ppStatsString Must be freed using Allocator::FreeStatsString.
|
||||||
*/
|
*/
|
||||||
|
@ -420,6 +420,7 @@ void InitD3D() // initializes direct3d 12
|
|||||||
D3D12MA::ALLOCATOR_DESC desc = {};
|
D3D12MA::ALLOCATOR_DESC desc = {};
|
||||||
desc.Flags = g_AllocatorFlags;
|
desc.Flags = g_AllocatorFlags;
|
||||||
desc.pDevice = device;
|
desc.pDevice = device;
|
||||||
|
desc.pAdapter = adapter;
|
||||||
|
|
||||||
D3D12MA::ALLOCATION_CALLBACKS allocationCallbacks = {};
|
D3D12MA::ALLOCATION_CALLBACKS allocationCallbacks = {};
|
||||||
if(ENABLE_CPU_ALLOCATION_CALLBACKS)
|
if(ENABLE_CPU_ALLOCATION_CALLBACKS)
|
||||||
|
@ -481,6 +481,8 @@ static void TestStats(const TestContext& ctx)
|
|||||||
|
|
||||||
for(UINT i = 0; i < count; ++i)
|
for(UINT i = 0; i < count; ++i)
|
||||||
{
|
{
|
||||||
|
if(i == count / 2)
|
||||||
|
allocDesc.Flags |= D3D12MA::ALLOCATION_FLAG_COMMITTED;
|
||||||
D3D12MA::Allocation* alloc = nullptr;
|
D3D12MA::Allocation* alloc = nullptr;
|
||||||
CHECK_HR( ctx.allocator->CreateResource(
|
CHECK_HR( ctx.allocator->CreateResource(
|
||||||
&allocDesc,
|
&allocDesc,
|
||||||
@ -514,6 +516,18 @@ static void TestStats(const TestContext& ctx)
|
|||||||
CheckStatInfo(endStats.HeapType[0]);
|
CheckStatInfo(endStats.HeapType[0]);
|
||||||
CheckStatInfo(endStats.HeapType[1]);
|
CheckStatInfo(endStats.HeapType[1]);
|
||||||
CheckStatInfo(endStats.HeapType[2]);
|
CheckStatInfo(endStats.HeapType[2]);
|
||||||
|
|
||||||
|
D3D12MA::Budget gpuBudget = {}, cpuBudget = {};
|
||||||
|
ctx.allocator->GetBudget(&gpuBudget, &cpuBudget);
|
||||||
|
|
||||||
|
CHECK_BOOL(gpuBudget.AllocationBytes <= gpuBudget.BlockBytes);
|
||||||
|
CHECK_BOOL(gpuBudget.AllocationBytes == endStats.HeapType[0].UsedBytes);
|
||||||
|
CHECK_BOOL(gpuBudget.BlockBytes == endStats.HeapType[0].UsedBytes + endStats.HeapType[0].UnusedBytes);
|
||||||
|
|
||||||
|
CHECK_BOOL(cpuBudget.AllocationBytes <= cpuBudget.BlockBytes);
|
||||||
|
CHECK_BOOL(cpuBudget.AllocationBytes == endStats.HeapType[1].UsedBytes + endStats.HeapType[2].UsedBytes);
|
||||||
|
CHECK_BOOL(cpuBudget.BlockBytes == endStats.HeapType[1].UsedBytes + endStats.HeapType[1].UnusedBytes +
|
||||||
|
endStats.HeapType[2].UsedBytes + endStats.HeapType[2].UnusedBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void TestTransfer(const TestContext& ctx)
|
static void TestTransfer(const TestContext& ctx)
|
||||||
|
Loading…
Reference in New Issue
Block a user