Refactored internal code structure similary to VMA.
Code by @medranSolus
diff --git a/src/D3D12MemAlloc.cpp b/src/D3D12MemAlloc.cpp
index 92b9008..46c44b2 100644
--- a/src/D3D12MemAlloc.cpp
+++ b/src/D3D12MemAlloc.cpp
@@ -22,20 +22,12 @@
#include "D3D12MemAlloc.h"
-#ifndef D3D12MA_D3D12_HEADERS_ALREADY_INCLUDED
- #include <dxgi.h>
- #if D3D12MA_DXGI_1_4
- #include <dxgi1_4.h>
- #endif
-#endif
-
#include <combaseapi.h>
#include <mutex>
#include <algorithm>
#include <utility>
#include <cstdlib>
#include <malloc.h> // for _aligned_malloc, _aligned_free
-
#ifndef _WIN32
#include <shared_mutex>
#endif
@@ -47,6 +39,20 @@
//
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
+#ifndef _D3D12MA_CONFIGURATION
+
+#ifdef _WIN32
+ #if !defined(WINVER) || WINVER < 0x0600
+ #error Required at least WinAPI version supporting: client = Windows Vista, server = Windows Server 2008.
+ #endif
+#endif
+
+#ifndef D3D12MA_D3D12_HEADERS_ALREADY_INCLUDED
+ #include <dxgi.h>
+ #if D3D12MA_DXGI_1_4
+ #include <dxgi1_4.h>
+ #endif
+#endif
#ifndef D3D12MA_ASSERT
#include <cassert>
@@ -96,6 +102,7 @@
#define D3D12MA_DEFAULT_BLOCK_SIZE (64ull * 1024 * 1024)
#endif
+#endif // _D3D12MA_CONFIGURATION
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
@@ -108,9 +115,49 @@
namespace D3D12MA
{
+static constexpr UINT HEAP_TYPE_COUNT = 4;
+static constexpr UINT STANDARD_HEAP_TYPE_COUNT = 3; // Only DEFAULT, UPLOAD, READBACK.
+static constexpr UINT DEFAULT_POOL_MAX_COUNT = 9;
+static const UINT NEW_BLOCK_SIZE_SHIFT_MAX = 3;
+// Minimum size of a free suballocation to register it in the free suballocation collection.
+static const UINT64 MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER = 16;
-////////////////////////////////////////////////////////////////////////////////
-// Private globals - CPU memory allocation
+static const WCHAR* const HeapTypeNames[] =
+{
+ L"DEFAULT",
+ L"UPLOAD",
+ L"READBACK",
+ L"CUSTOM",
+};
+
+static const D3D12_HEAP_FLAGS RESOURCE_CLASS_HEAP_FLAGS =
+ D3D12_HEAP_FLAG_DENY_BUFFERS | D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES | D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES;
+
+#ifndef _D3D12MA_ENUM_DECLARATIONS
+
+// Local copy of this enum, as it is provided only by <dxgi1_4.h>, so it may not be available.
+enum DXGI_MEMORY_SEGMENT_GROUP_COPY
+{
+ DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY = 0,
+ DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL_COPY = 1,
+ DXGI_MEMORY_SEGMENT_GROUP_COUNT
+};
+
+enum class ResourceClass
+{
+ Unknown, Buffer, Non_RT_DS_Texture, RT_DS_Texture
+};
+
+enum SuballocationType
+{
+ SUBALLOCATION_TYPE_FREE = 0,
+ SUBALLOCATION_TYPE_ALLOCATION = 1,
+};
+
+#endif // _D3D12MA_ENUM_DECLARATIONS
+
+
+#ifndef _D3D12MA_FUNCTIONS
static void* DefaultAllocate(size_t Size, size_t Alignment, void* /*pUserData*/)
{
@@ -157,7 +204,7 @@
template<typename T>
void D3D12MA_DELETE(const ALLOCATION_CALLBACKS& allocs, T* memory)
{
- if(memory)
+ if (memory)
{
memory->~T();
Free(allocs, memory);
@@ -166,9 +213,9 @@
template<typename T>
void D3D12MA_DELETE_ARRAY(const ALLOCATION_CALLBACKS& allocs, T* memory, size_t count)
{
- if(memory)
+ if (memory)
{
- for(size_t i = count; i--; )
+ for (size_t i = count; i--; )
{
memory[i].~T();
}
@@ -178,7 +225,7 @@
static void SetupAllocationCallbacks(ALLOCATION_CALLBACKS& outAllocs, const ALLOCATION_CALLBACKS* allocationCallbacks)
{
- if(allocationCallbacks)
+ if (allocationCallbacks)
{
outAllocs = *allocationCallbacks;
D3D12MA_ASSERT(outAllocs.pAllocate != NULL && outAllocs.pFree != NULL);
@@ -191,84 +238,23 @@
}
}
-////////////////////////////////////////////////////////////////////////////////
-// Private globals - basic facilities
-
#define SAFE_RELEASE(ptr) do { if(ptr) { (ptr)->Release(); (ptr) = NULL; } } while(false)
#define D3D12MA_VALIDATE(cond) do { if(!(cond)) { \
- D3D12MA_ASSERT(0 && "Validation failed: " #cond); \
- return false; \
- } } while(false)
-
-const UINT NEW_BLOCK_SIZE_SHIFT_MAX = 3;
+ D3D12MA_ASSERT(0 && "Validation failed: " #cond); \
+ return false; \
+} } while(false)
template<typename T>
-static inline T D3D12MA_MIN(const T& a, const T& b)
-{
- return a <= b ? a : b;
-}
+static T D3D12MA_MIN(const T& a, const T& b) { return a <= b ? a : b; }
template<typename T>
-static inline T D3D12MA_MAX(const T& a, const T& b)
-{
- return a <= b ? b : a;
-}
+static T D3D12MA_MAX(const T& a, const T& b) { return a <= b ? b : a; }
template<typename T>
-static inline void D3D12MA_SWAP(T& a, T& b)
-{
- T tmp = a; a = b; b = tmp;
-}
-
-#ifndef D3D12MA_MUTEX
- class Mutex
- {
- public:
- void Lock() { m_Mutex.lock(); }
- void Unlock() { m_Mutex.unlock(); }
- private:
- std::mutex m_Mutex;
- };
- #define D3D12MA_MUTEX Mutex
-#endif
-
-#ifdef _WIN32
- #if !defined(WINVER) || WINVER < 0x0600
- #error Required at least WinAPI version supporting: client = Windows Vista, server = Windows Server 2008.
- #endif
-#endif // #ifdef _WIN32
-
-#ifndef D3D12MA_RW_MUTEX
-#ifdef _WIN32
- class RWMutex
- {
- public:
- RWMutex() { InitializeSRWLock(&m_Lock); }
- void LockRead() { AcquireSRWLockShared(&m_Lock); }
- void UnlockRead() { ReleaseSRWLockShared(&m_Lock); }
- void LockWrite() { AcquireSRWLockExclusive(&m_Lock); }
- void UnlockWrite() { ReleaseSRWLockExclusive(&m_Lock); }
- private:
- SRWLOCK m_Lock;
- };
-#else // #ifdef _WIN32
- class RWMutex
- {
- public:
- RWMutex() {}
- void LockRead() { m_Mutex.lock_shared(); }
- void UnlockRead() { m_Mutex.unlock_shared(); }
- void LockWrite() { m_Mutex.lock(); }
- void UnlockWrite() { m_Mutex.unlock(); }
- private:
- std::shared_timed_mutex m_Mutex;
- };
-#endif // #ifdef _WIN32
- #define D3D12MA_RW_MUTEX RWMutex
-#endif // #ifndef D3D12MA_RW_MUTEX
+static void D3D12MA_SWAP(T& a, T& b) { T tmp = a; a = b; b = tmp; }
// Scans integer for index of first nonzero bit from the Least Significant Bit (LSB). If mask is 0 then returns UINT8_MAX
-static inline UINT8 BitScanLSB(UINT64 mask)
+static UINT8 BitScanLSB(UINT64 mask)
{
#if defined(_MSC_VER) && defined(_WIN64)
unsigned long pos;
@@ -289,9 +275,8 @@
return UINT8_MAX;
#endif
}
-
// Scans integer for index of first nonzero bit from the Least Significant Bit (LSB). If mask is 0 then returns UINT8_MAX
-static inline UINT8 BitScanLSB(UINT32 mask)
+static UINT8 BitScanLSB(UINT32 mask)
{
#ifdef _MSC_VER
unsigned long pos;
@@ -314,7 +299,7 @@
}
// Scans integer for index of first nonzero bit from the Most Significant Bit (MSB). If mask is 0 then returns UINT8_MAX
-static inline UINT8 BitScanMSB(UINT64 mask)
+static UINT8 BitScanMSB(UINT64 mask)
{
#if defined(_MSC_VER) && defined(_WIN64)
unsigned long pos;
@@ -335,9 +320,8 @@
#endif
return UINT8_MAX;
}
-
// Scans integer for index of first nonzero bit from the Most Significant Bit (MSB). If mask is 0 then returns UINT8_MAX
-static inline UINT8 BitScanMSB(UINT32 mask)
+static UINT8 BitScanMSB(UINT32 mask)
{
#ifdef _MSC_VER
unsigned long pos;
@@ -365,23 +349,20 @@
For 0 returns true.
*/
template <typename T>
-inline bool IsPow2(T x)
-{
- return (x & (x-1)) == 0;
-}
+static bool IsPow2(T x) { return (x & (x - 1)) == 0; }
// Aligns given value up to nearest multiply of align value. For example: AlignUp(11, 8) = 16.
// Use types like UINT, uint64_t as T.
template <typename T>
-static inline T AlignUp(T val, T alignment)
+static T AlignUp(T val, T alignment)
{
D3D12MA_HEAVY_ASSERT(IsPow2(alignment));
- return (val + alignment - 1) & ~(alignment - 1);
+ return (val + alignment - 1) & ~(alignment - 1);
}
// Aligns given value down to nearest multiply of align value. For example: AlignUp(11, 8) = 8.
// Use types like UINT, uint64_t as T.
template <typename T>
-static inline T AlignDown(T val, T alignment)
+static T AlignDown(T val, T alignment)
{
D3D12MA_HEAVY_ASSERT(IsPow2(alignment));
return val & ~(alignment - 1);
@@ -389,109 +370,10 @@
// Division with mathematical rounding to nearest number.
template <typename T>
-static inline T RoundDiv(T x, T y)
-{
- return (x + (y / (T)2)) / y;
-}
+static T RoundDiv(T x, T y) { return (x + (y / (T)2)) / y; }
template <typename T>
-static inline T DivideRoundingUp(T x, T y)
-{
- return (x + y - 1) / y;
-}
-
-// Helper RAII class to lock a mutex in constructor and unlock it in destructor (at the end of scope).
-struct MutexLock
-{
-public:
- MutexLock(D3D12MA_MUTEX& mutex, bool useMutex = true) :
- m_pMutex(useMutex ? &mutex : NULL)
- {
- if(m_pMutex)
- {
- m_pMutex->Lock();
- }
- }
- ~MutexLock()
- {
- if(m_pMutex)
- {
- m_pMutex->Unlock();
- }
- }
-private:
- D3D12MA_MUTEX* m_pMutex;
-
- D3D12MA_CLASS_NO_COPY(MutexLock)
-};
-
-// Helper RAII class to lock a RW mutex in constructor and unlock it in destructor (at the end of scope), for reading.
-struct MutexLockRead
-{
-public:
- MutexLockRead(D3D12MA_RW_MUTEX& mutex, bool useMutex) :
- m_pMutex(useMutex ? &mutex : NULL)
- {
- if(m_pMutex)
- {
- m_pMutex->LockRead();
- }
- }
- ~MutexLockRead()
- {
- if(m_pMutex)
- {
- m_pMutex->UnlockRead();
- }
- }
-private:
- D3D12MA_RW_MUTEX* m_pMutex;
-
- D3D12MA_CLASS_NO_COPY(MutexLockRead)
-};
-
-// Helper RAII class to lock a RW mutex in constructor and unlock it in destructor (at the end of scope), for writing.
-struct MutexLockWrite
-{
-public:
- MutexLockWrite(D3D12MA_RW_MUTEX& mutex, bool useMutex) :
- m_pMutex(useMutex ? &mutex : NULL)
- {
- if(m_pMutex)
- {
- m_pMutex->LockWrite();
- }
- }
- ~MutexLockWrite()
- {
- if(m_pMutex)
- {
- m_pMutex->UnlockWrite();
- }
- }
-private:
- D3D12MA_RW_MUTEX* m_pMutex;
-
- D3D12MA_CLASS_NO_COPY(MutexLockWrite)
-};
-
-#if D3D12MA_DEBUG_GLOBAL_MUTEX
- static D3D12MA_MUTEX g_DebugGlobalMutex;
- #define D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK MutexLock debugGlobalMutexLock(g_DebugGlobalMutex, true);
-#else
- #define D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
-#endif
-
-// Minimum size of a free suballocation to register it in the free suballocation collection.
-static const UINT64 MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER = 16;
-
-// Local copy of this enum, as it is provided only by <dxgi1_4.h>, so it may not be available.
-enum DXGI_MEMORY_SEGMENT_GROUP_COPY
-{
- DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY = 0,
- DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL_COPY = 1,
- DXGI_MEMORY_SEGMENT_GROUP_COUNT
-};
-
+static T DivideRoundingUp(T x, T y) { return (x + y - 1) / y; }
+
/*
Performs binary search and returns iterator to first element that is greater or
equal to `key`, according to comparison `cmp`.
@@ -502,13 +384,13 @@
new element with value (key) should be inserted.
*/
template <typename CmpLess, typename IterT, typename KeyT>
-static IterT BinaryFindFirstNotLess(IterT beg, IterT end, const KeyT &key, const CmpLess& cmp)
+static IterT BinaryFindFirstNotLess(IterT beg, IterT end, const KeyT& key, const CmpLess& cmp)
{
size_t down = 0, up = (end - beg);
- while(down < up)
+ while (down < up)
{
const size_t mid = (down + up) / 2;
- if(cmp(*(beg+mid), key))
+ if (cmp(*(beg + mid), key))
{
down = mid + 1;
}
@@ -530,10 +412,10 @@
found.
*/
template<typename CmpLess, typename IterT, typename KeyT>
-IterT BinaryFindSorted(const IterT& beg, const IterT& end, const KeyT& value, const CmpLess& cmp)
+static IterT BinaryFindSorted(const IterT& beg, const IterT& end, const KeyT& value, const CmpLess& cmp)
{
IterT it = BinaryFindFirstNotLess<CmpLess, IterT, KeyT>(beg, end, value, cmp);
- if(it == end ||
+ if (it == end ||
(!cmp(*it, value) && !cmp(value, *it)))
{
return it;
@@ -543,7 +425,7 @@
static UINT HeapTypeToIndex(D3D12_HEAP_TYPE type)
{
- switch(type)
+ switch (type)
{
case D3D12_HEAP_TYPE_DEFAULT: return 0;
case D3D12_HEAP_TYPE_UPLOAD: return 1;
@@ -560,66 +442,6 @@
return (D3D12_HEAP_TYPE)(heapTypeIndex + 1);
}
-static const WCHAR* const HeapTypeNames[] = {
- L"DEFAULT",
- L"UPLOAD",
- L"READBACK",
- L"CUSTOM",
-};
-
-// Stat helper functions
-
-static void ClearStatistics(Statistics& outStats)
-{
- outStats.BlockCount = 0;
- outStats.AllocationCount = 0;
- outStats.BlockBytes = 0;
- outStats.AllocationBytes = 0;
-}
-
-static void ClearDetailedStatistics(DetailedStatistics& outStats)
-{
- ClearStatistics(outStats.Stats);
- outStats.UnusedRangeCount = 0;
- outStats.AllocationSizeMin = UINT64_MAX;
- outStats.AllocationSizeMax = 0;
- outStats.UnusedRangeSizeMin = UINT64_MAX;
- outStats.UnusedRangeSizeMax = 0;
-}
-
-static void AddStatistics(Statistics& inoutStats, const Statistics& src)
-{
- inoutStats.BlockCount += src.BlockCount;
- inoutStats.AllocationCount += src.AllocationCount;
- inoutStats.BlockBytes += src.BlockBytes;
- inoutStats.AllocationBytes += src.AllocationBytes;
-}
-
-static void AddDetailedStatistics(DetailedStatistics& inoutStats, const DetailedStatistics& src)
-{
- AddStatistics(inoutStats.Stats, src.Stats);
- inoutStats.UnusedRangeCount += src.UnusedRangeCount;
- inoutStats.AllocationSizeMin = D3D12MA_MIN(inoutStats.AllocationSizeMin, src.AllocationSizeMin);
- inoutStats.AllocationSizeMax = D3D12MA_MAX(inoutStats.AllocationSizeMax, src.AllocationSizeMax);
- inoutStats.UnusedRangeSizeMin = D3D12MA_MIN(inoutStats.UnusedRangeSizeMin, src.UnusedRangeSizeMin);
- inoutStats.UnusedRangeSizeMax = D3D12MA_MAX(inoutStats.UnusedRangeSizeMax, src.UnusedRangeSizeMax);
-}
-
-static void AddDetailedStatisticsAllocation(DetailedStatistics& inoutStats, UINT64 size)
-{
- inoutStats.Stats.AllocationCount++;
- inoutStats.Stats.AllocationBytes += size;
- inoutStats.AllocationSizeMin = D3D12MA_MIN(inoutStats.AllocationSizeMin, size);
- inoutStats.AllocationSizeMax = D3D12MA_MAX(inoutStats.AllocationSizeMax, size);
-}
-
-static void AddDetailedStatisticsUnusedRange(DetailedStatistics& inoutStats, UINT64 size)
-{
- inoutStats.UnusedRangeCount++;
- inoutStats.UnusedRangeSizeMin = D3D12MA_MIN(inoutStats.UnusedRangeSizeMin, size);
- inoutStats.UnusedRangeSizeMax = D3D12MA_MAX(inoutStats.UnusedRangeSizeMax, size);
-}
-
static UINT64 HeapFlagsToAlignment(D3D12_HEAP_FLAGS flags)
{
/*
@@ -641,9 +463,41 @@
D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT : D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
}
+static ResourceClass HeapFlagsToResourceClass(D3D12_HEAP_FLAGS heapFlags)
+{
+ const bool allowBuffers = (heapFlags & D3D12_HEAP_FLAG_DENY_BUFFERS) == 0;
+ const bool allowRtDsTextures = (heapFlags & D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES) == 0;
+ const bool allowNonRtDsTextures = (heapFlags & D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES) == 0;
+
+ const uint8_t allowedGroupCount = (allowBuffers ? 1 : 0) + (allowRtDsTextures ? 1 : 0) + (allowNonRtDsTextures ? 1 : 0);
+ if (allowedGroupCount != 1)
+ return ResourceClass::Unknown;
+
+ if (allowRtDsTextures)
+ return ResourceClass::RT_DS_Texture;
+ if (allowNonRtDsTextures)
+ return ResourceClass::Non_RT_DS_Texture;
+ return ResourceClass::Buffer;
+}
+
+static bool IsHeapTypeStandard(D3D12_HEAP_TYPE type)
+{
+ return type == D3D12_HEAP_TYPE_DEFAULT ||
+ type == D3D12_HEAP_TYPE_UPLOAD ||
+ type == D3D12_HEAP_TYPE_READBACK;
+}
+
+static D3D12_HEAP_PROPERTIES StandardHeapTypeToHeapProperties(D3D12_HEAP_TYPE type)
+{
+ D3D12MA_ASSERT(IsHeapTypeStandard(type));
+ D3D12_HEAP_PROPERTIES result = {};
+ result.Type = type;
+ return result;
+}
+
static bool IsFormatCompressed(DXGI_FORMAT format)
{
- switch(format)
+ switch (format)
{
case DXGI_FORMAT_BC1_TYPELESS:
case DXGI_FORMAT_BC1_UNORM:
@@ -675,7 +529,7 @@
// Only some formats are supported. For others it returns 0.
static UINT GetBitsPerPixel(DXGI_FORMAT format)
{
- switch(format)
+ switch (format)
{
case DXGI_FORMAT_R32G32B32A32_TYPELESS:
case DXGI_FORMAT_R32G32B32A32_FLOAT:
@@ -787,63 +641,38 @@
return 0;
}
}
-
-static const D3D12_HEAP_FLAGS RESOURCE_CLASS_HEAP_FLAGS =
- D3D12_HEAP_FLAG_DENY_BUFFERS | D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES | D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES;
-
-enum class ResourceClass
-{
- Unknown, Buffer, Non_RT_DS_Texture, RT_DS_Texture
-};
-
+
template<typename D3D12_RESOURCE_DESC_T>
-static inline ResourceClass ResourceDescToResourceClass(const D3D12_RESOURCE_DESC_T& resDesc)
+static ResourceClass ResourceDescToResourceClass(const D3D12_RESOURCE_DESC_T& resDesc)
{
- if(resDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
+ if (resDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
return ResourceClass::Buffer;
// Else: it's surely a texture.
const bool isRenderTargetOrDepthStencil =
(resDesc.Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) != 0;
return isRenderTargetOrDepthStencil ? ResourceClass::RT_DS_Texture : ResourceClass::Non_RT_DS_Texture;
}
-
-static inline ResourceClass HeapFlagsToResourceClass(D3D12_HEAP_FLAGS heapFlags)
-{
- const bool allowBuffers = (heapFlags & D3D12_HEAP_FLAG_DENY_BUFFERS ) == 0;
- const bool allowRtDsTextures = (heapFlags & D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES ) == 0;
- const bool allowNonRtDsTextures = (heapFlags & D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES) == 0;
-
- const uint8_t allowedGroupCount = (allowBuffers ? 1 : 0) + (allowRtDsTextures ? 1 : 0) + (allowNonRtDsTextures ? 1 : 0);
- if(allowedGroupCount != 1)
- return ResourceClass::Unknown;
- if(allowRtDsTextures)
- return ResourceClass::RT_DS_Texture;
- if(allowNonRtDsTextures)
- return ResourceClass::Non_RT_DS_Texture;
- return ResourceClass::Buffer;
-}
-
// This algorithm is overly conservative.
template<typename D3D12_RESOURCE_DESC_T>
static bool CanUseSmallAlignment(const D3D12_RESOURCE_DESC_T& resourceDesc)
{
- if(resourceDesc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE2D)
+ if (resourceDesc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE2D)
return false;
- if((resourceDesc.Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) != 0)
+ if ((resourceDesc.Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) != 0)
return false;
- if(resourceDesc.SampleDesc.Count > 1)
+ if (resourceDesc.SampleDesc.Count > 1)
return false;
- if(resourceDesc.DepthOrArraySize != 1)
+ if (resourceDesc.DepthOrArraySize != 1)
return false;
UINT sizeX = (UINT)resourceDesc.Width;
UINT sizeY = resourceDesc.Height;
UINT bitsPerPixel = GetBitsPerPixel(resourceDesc.Format);
- if(bitsPerPixel == 0)
+ if (bitsPerPixel == 0)
return false;
- if(IsFormatCompressed(resourceDesc.Format))
+ if (IsFormatCompressed(resourceDesc.Format))
{
sizeX = DivideRoundingUp(sizeX, 4u);
sizeY = DivideRoundingUp(sizeY, 4u);
@@ -851,7 +680,7 @@
}
UINT tileSizeX = 0, tileSizeY = 0;
- switch(bitsPerPixel)
+ switch (bitsPerPixel)
{
case 8: tileSizeX = 64; tileSizeY = 64; break;
case 16: tileSizeX = 64; tileSizeY = 32; break;
@@ -864,25 +693,186 @@
const UINT tileCount = DivideRoundingUp(sizeX, tileSizeX) * DivideRoundingUp(sizeY, tileSizeY);
return tileCount <= 16;
}
-
-static inline bool IsHeapTypeStandard(D3D12_HEAP_TYPE type)
+
+static bool ValidateAllocateMemoryParameters(
+ const ALLOCATION_DESC* pAllocDesc,
+ const D3D12_RESOURCE_ALLOCATION_INFO* pAllocInfo,
+ Allocation** ppAllocation)
{
- return type == D3D12_HEAP_TYPE_DEFAULT ||
- type == D3D12_HEAP_TYPE_UPLOAD ||
- type == D3D12_HEAP_TYPE_READBACK;
+ return pAllocDesc &&
+ pAllocInfo &&
+ ppAllocation &&
+ (pAllocInfo->Alignment == 0 ||
+ pAllocInfo->Alignment == D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT ||
+ pAllocInfo->Alignment == D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT) &&
+ pAllocInfo->SizeInBytes != 0 &&
+ pAllocInfo->SizeInBytes % (64ull * 1024) == 0;
}
-static inline D3D12_HEAP_PROPERTIES StandardHeapTypeToHeapProperties(D3D12_HEAP_TYPE type)
+#endif // _D3D12MA_FUNCTIONS
+
+#ifndef _D3D12MA_STATISTICS_FUNCTIONS
+
+static void ClearStatistics(Statistics& outStats)
{
- D3D12MA_ASSERT(IsHeapTypeStandard(type));
- D3D12_HEAP_PROPERTIES result = {};
- result.Type = type;
- return result;
+ outStats.BlockCount = 0;
+ outStats.AllocationCount = 0;
+ outStats.BlockBytes = 0;
+ outStats.AllocationBytes = 0;
}
-////////////////////////////////////////////////////////////////////////////////
-// Private class Vector
+static void ClearDetailedStatistics(DetailedStatistics& outStats)
+{
+ ClearStatistics(outStats.Stats);
+ outStats.UnusedRangeCount = 0;
+ outStats.AllocationSizeMin = UINT64_MAX;
+ outStats.AllocationSizeMax = 0;
+ outStats.UnusedRangeSizeMin = UINT64_MAX;
+ outStats.UnusedRangeSizeMax = 0;
+}
+static void AddStatistics(Statistics& inoutStats, const Statistics& src)
+{
+ inoutStats.BlockCount += src.BlockCount;
+ inoutStats.AllocationCount += src.AllocationCount;
+ inoutStats.BlockBytes += src.BlockBytes;
+ inoutStats.AllocationBytes += src.AllocationBytes;
+}
+
+static void AddDetailedStatistics(DetailedStatistics& inoutStats, const DetailedStatistics& src)
+{
+ AddStatistics(inoutStats.Stats, src.Stats);
+ inoutStats.UnusedRangeCount += src.UnusedRangeCount;
+ inoutStats.AllocationSizeMin = D3D12MA_MIN(inoutStats.AllocationSizeMin, src.AllocationSizeMin);
+ inoutStats.AllocationSizeMax = D3D12MA_MAX(inoutStats.AllocationSizeMax, src.AllocationSizeMax);
+ inoutStats.UnusedRangeSizeMin = D3D12MA_MIN(inoutStats.UnusedRangeSizeMin, src.UnusedRangeSizeMin);
+ inoutStats.UnusedRangeSizeMax = D3D12MA_MAX(inoutStats.UnusedRangeSizeMax, src.UnusedRangeSizeMax);
+}
+
+static void AddDetailedStatisticsAllocation(DetailedStatistics& inoutStats, UINT64 size)
+{
+ inoutStats.Stats.AllocationCount++;
+ inoutStats.Stats.AllocationBytes += size;
+ inoutStats.AllocationSizeMin = D3D12MA_MIN(inoutStats.AllocationSizeMin, size);
+ inoutStats.AllocationSizeMax = D3D12MA_MAX(inoutStats.AllocationSizeMax, size);
+}
+
+static void AddDetailedStatisticsUnusedRange(DetailedStatistics& inoutStats, UINT64 size)
+{
+ inoutStats.UnusedRangeCount++;
+ inoutStats.UnusedRangeSizeMin = D3D12MA_MIN(inoutStats.UnusedRangeSizeMin, size);
+ inoutStats.UnusedRangeSizeMax = D3D12MA_MAX(inoutStats.UnusedRangeSizeMax, size);
+}
+
+#endif // _D3D12MA_STATISTICS_FUNCTIONS
+
+
+#ifndef _D3D12MA_MUTEX
+
+#ifndef D3D12MA_MUTEX
+ class Mutex
+ {
+ public:
+ void Lock() { m_Mutex.lock(); }
+ void Unlock() { m_Mutex.unlock(); }
+
+ private:
+ std::mutex m_Mutex;
+ };
+ #define D3D12MA_MUTEX Mutex
+#endif
+
+#ifndef D3D12MA_RW_MUTEX
+#ifdef _WIN32
+ class RWMutex
+ {
+ public:
+ RWMutex() { InitializeSRWLock(&m_Lock); }
+ void LockRead() { AcquireSRWLockShared(&m_Lock); }
+ void UnlockRead() { ReleaseSRWLockShared(&m_Lock); }
+ void LockWrite() { AcquireSRWLockExclusive(&m_Lock); }
+ void UnlockWrite() { ReleaseSRWLockExclusive(&m_Lock); }
+
+ private:
+ SRWLOCK m_Lock;
+ };
+#else // #ifdef _WIN32
+ class RWMutex
+ {
+ public:
+ RWMutex() {}
+ void LockRead() { m_Mutex.lock_shared(); }
+ void UnlockRead() { m_Mutex.unlock_shared(); }
+ void LockWrite() { m_Mutex.lock(); }
+ void UnlockWrite() { m_Mutex.unlock(); }
+
+ private:
+ std::shared_timed_mutex m_Mutex;
+ };
+#endif // #ifdef _WIN32
+ #define D3D12MA_RW_MUTEX RWMutex
+#endif // #ifndef D3D12MA_RW_MUTEX
+
+// Helper RAII class to lock a mutex in constructor and unlock it in destructor (at the end of scope).
+struct MutexLock
+{
+ D3D12MA_CLASS_NO_COPY(MutexLock);
+public:
+ MutexLock(D3D12MA_MUTEX& mutex, bool useMutex = true) :
+ m_pMutex(useMutex ? &mutex : NULL)
+ {
+ if (m_pMutex) m_pMutex->Lock();
+ }
+ ~MutexLock() { if (m_pMutex) m_pMutex->Unlock(); }
+
+private:
+ D3D12MA_MUTEX* m_pMutex;
+};
+
+// Helper RAII class to lock a RW mutex in constructor and unlock it in destructor (at the end of scope), for reading.
+struct MutexLockRead
+{
+ D3D12MA_CLASS_NO_COPY(MutexLockRead);
+public:
+ MutexLockRead(D3D12MA_RW_MUTEX& mutex, bool useMutex)
+ : m_pMutex(useMutex ? &mutex : NULL)
+ {
+ if(m_pMutex)
+ {
+ m_pMutex->LockRead();
+ }
+ }
+ ~MutexLockRead() { if (m_pMutex) m_pMutex->UnlockRead(); }
+
+private:
+ D3D12MA_RW_MUTEX* m_pMutex;
+};
+
+// Helper RAII class to lock a RW mutex in constructor and unlock it in destructor (at the end of scope), for writing.
+struct MutexLockWrite
+{
+ D3D12MA_CLASS_NO_COPY(MutexLockWrite);
+public:
+ MutexLockWrite(D3D12MA_RW_MUTEX& mutex, bool useMutex)
+ : m_pMutex(useMutex ? &mutex : NULL)
+ {
+ if (m_pMutex) m_pMutex->LockWrite();
+ }
+ ~MutexLockWrite() { if (m_pMutex) m_pMutex->UnlockWrite(); }
+
+private:
+ D3D12MA_RW_MUTEX* m_pMutex;
+};
+
+#if D3D12MA_DEBUG_GLOBAL_MUTEX
+ static D3D12MA_MUTEX g_DebugGlobalMutex;
+ #define D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK MutexLock debugGlobalMutexLock(g_DebugGlobalMutex, true);
+#else
+ #define D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
+#endif
+#endif // _D3D12MA_MUTEX
+
+#ifndef _D3D12MA_VECTOR
/*
Dynamically resizing continuous array. Class with interface similar to std::vector.
T must be POD because constructors and destructors are not called and memcpy is
@@ -893,235 +883,53 @@
{
public:
using value_type = T;
+ using iterator = T*;
// allocationCallbacks externally owned, must outlive this object.
- Vector(const ALLOCATION_CALLBACKS& allocationCallbacks) :
- m_AllocationCallbacks(allocationCallbacks),
- m_pArray(NULL),
- m_Count(0),
- m_Capacity(0)
- {
- }
-
- Vector(size_t count, const ALLOCATION_CALLBACKS& allocationCallbacks) :
- m_AllocationCallbacks(allocationCallbacks),
- m_pArray(count ? AllocateArray<T>(allocationCallbacks, count) : NULL),
- m_Count(count),
- m_Capacity(count)
- {
- }
-
- Vector(const Vector<T>& src) :
- m_AllocationCallbacks(src.m_AllocationCallbacks),
- m_pArray(src.m_Count ? AllocateArray<T>(src.m_AllocationCallbacks, src.m_Count) : NULL),
- m_Count(src.m_Count),
- m_Capacity(src.m_Count)
- {
- if(m_Count > 0)
- {
- memcpy(m_pArray, src.m_pArray, m_Count * sizeof(T));
- }
- }
-
- ~Vector()
- {
- Free(m_AllocationCallbacks, m_pArray);
- }
-
- Vector& operator=(const Vector<T>& rhs)
- {
- if(&rhs != this)
- {
- resize(rhs.m_Count);
- if(m_Count != 0)
- {
- memcpy(m_pArray, rhs.m_pArray, m_Count * sizeof(T));
- }
- }
- return *this;
- }
+ Vector(const ALLOCATION_CALLBACKS& allocationCallbacks);
+ Vector(size_t count, const ALLOCATION_CALLBACKS& allocationCallbacks);
+ Vector(const Vector<T>& src);
+ ~Vector();
bool empty() const { return m_Count == 0; }
size_t size() const { return m_Count; }
T* data() { return m_pArray; }
const T* data() const { return m_pArray; }
-
- T& operator[](size_t index)
- {
- D3D12MA_HEAVY_ASSERT(index < m_Count);
- return m_pArray[index];
- }
- const T& operator[](size_t index) const
- {
- D3D12MA_HEAVY_ASSERT(index < m_Count);
- return m_pArray[index];
- }
-
- T& front()
- {
- D3D12MA_HEAVY_ASSERT(m_Count > 0);
- return m_pArray[0];
- }
- const T& front() const
- {
- D3D12MA_HEAVY_ASSERT(m_Count > 0);
- return m_pArray[0];
- }
- T& back()
- {
- D3D12MA_HEAVY_ASSERT(m_Count > 0);
- return m_pArray[m_Count - 1];
- }
- const T& back() const
- {
- D3D12MA_HEAVY_ASSERT(m_Count > 0);
- return m_pArray[m_Count - 1];
- }
-
- void reserve(size_t newCapacity, bool freeMemory = false)
- {
- newCapacity = D3D12MA_MAX(newCapacity, m_Count);
-
- if((newCapacity < m_Capacity) && !freeMemory)
- {
- newCapacity = m_Capacity;
- }
-
- if(newCapacity != m_Capacity)
- {
- T* const newArray = newCapacity ? AllocateArray<T>(m_AllocationCallbacks, newCapacity) : NULL;
- if(m_Count != 0)
- {
- memcpy(newArray, m_pArray, m_Count * sizeof(T));
- }
- Free(m_AllocationCallbacks, m_pArray);
- m_Capacity = newCapacity;
- m_pArray = newArray;
- }
- }
-
- void resize(size_t newCount, bool freeMemory = false)
- {
- size_t newCapacity = m_Capacity;
- if(newCount > m_Capacity)
- {
- newCapacity = D3D12MA_MAX(newCount, D3D12MA_MAX(m_Capacity * 3 / 2, (size_t)8));
- }
- else if(freeMemory)
- {
- newCapacity = newCount;
- }
-
- if(newCapacity != m_Capacity)
- {
- T* const newArray = newCapacity ? AllocateArray<T>(m_AllocationCallbacks, newCapacity) : NULL;
- const size_t elementsToCopy = D3D12MA_MIN(m_Count, newCount);
- if(elementsToCopy != 0)
- {
- memcpy(newArray, m_pArray, elementsToCopy * sizeof(T));
- }
- Free(m_AllocationCallbacks, m_pArray);
- m_Capacity = newCapacity;
- m_pArray = newArray;
- }
-
- m_Count = newCount;
- }
-
- void clear(bool freeMemory = false)
- {
- resize(0, freeMemory);
- }
-
- void insert(size_t index, const T& src)
- {
- D3D12MA_HEAVY_ASSERT(index <= m_Count);
- const size_t oldCount = size();
- resize(oldCount + 1);
- if(index < oldCount)
- {
- memmove(m_pArray + (index + 1), m_pArray + index, (oldCount - index) * sizeof(T));
- }
- m_pArray[index] = src;
- }
-
- void remove(size_t index)
- {
- D3D12MA_HEAVY_ASSERT(index < m_Count);
- const size_t oldCount = size();
- if(index < oldCount - 1)
- {
- memmove(m_pArray + index, m_pArray + (index + 1), (oldCount - index - 1) * sizeof(T));
- }
- resize(oldCount - 1);
- }
-
- void push_back(const T& src)
- {
- const size_t newIndex = size();
- resize(newIndex + 1);
- m_pArray[newIndex] = src;
- }
-
- void pop_back()
- {
- D3D12MA_HEAVY_ASSERT(m_Count > 0);
- resize(size() - 1);
- }
-
- void push_front(const T& src)
- {
- insert(0, src);
- }
-
- void pop_front()
- {
- D3D12MA_HEAVY_ASSERT(m_Count > 0);
- remove(0);
- }
-
- using iterator = T*;
+ void clear(bool freeMemory = false) { resize(0, freeMemory); }
iterator begin() { return m_pArray; }
- const iterator cbegin() const { return m_pArray; }
-
- iterator rbegin() { return end() - 1; }
- const iterator crbegin() const { return cend() - 1; }
-
iterator end() { return m_pArray + m_Count; }
- const iterator cend() const { return m_pArray + m_Count; }
-
iterator rend() { return begin() - 1; }
+ iterator rbegin() { return end() - 1; }
+
+ const iterator cbegin() const { return m_pArray; }
+ const iterator cend() const { return m_pArray + m_Count; }
+ const iterator crbegin() const { return cend() - 1; }
const iterator crend() const { return cbegin() - 1; }
- template<typename CmpLess>
- size_t InsertSorted(const T& value, const CmpLess& cmp)
- {
- const size_t indexToInsert = BinaryFindFirstNotLess<CmpLess, iterator, T>(
- m_pArray,
- m_pArray + m_Count,
- value,
- cmp) - m_pArray;
- insert(indexToInsert, value);
- return indexToInsert;
- }
+ void push_front(const T& src) { insert(0, src); }
+ void push_back(const T& src);
+ void pop_front();
+ void pop_back();
+
+ T& front();
+ T& back();
+ const T& front() const;
+ const T& back() const;
+
+ void reserve(size_t newCapacity, bool freeMemory = false);
+ void resize(size_t newCount, bool freeMemory = false);
+ void insert(size_t index, const T& src);
+ void remove(size_t index);
template<typename CmpLess>
- bool RemoveSorted(const T& value, const CmpLess& cmp)
- {
- const iterator it = BinaryFindFirstNotLess(
- m_pArray,
- m_pArray + m_Count,
- value,
- cmp);
- if((it != end()) && !cmp(*it, value) && !cmp(value, *it))
- {
- size_t indexToRemove = it - begin();
- remove(indexToRemove);
- return true;
- }
- return false;
- }
+ size_t InsertSorted(const T& value, const CmpLess& cmp);
+ template<typename CmpLess>
+ bool RemoveSorted(const T& value, const CmpLess& cmp);
+
+ Vector& operator=(const Vector<T>& rhs);
+ T& operator[](size_t index);
+ const T& operator[](size_t index) const;
private:
const ALLOCATION_CALLBACKS& m_AllocationCallbacks;
@@ -1130,13 +938,231 @@
size_t m_Capacity;
};
-////////////////////////////////////////////////////////////////////////////////
-// Private class StringBuilder
+#ifndef _D3D12MA_VECTOR_FUNCTIONS
+template<typename T>
+Vector<T>::Vector(const ALLOCATION_CALLBACKS& allocationCallbacks)
+ : m_AllocationCallbacks(allocationCallbacks),
+ m_pArray(NULL),
+ m_Count(0),
+ m_Capacity(0) {}
+template<typename T>
+Vector<T>::Vector(size_t count, const ALLOCATION_CALLBACKS& allocationCallbacks)
+ : m_AllocationCallbacks(allocationCallbacks),
+ m_pArray(count ? AllocateArray<T>(allocationCallbacks, count) : NULL),
+ m_Count(count),
+ m_Capacity(count) {}
+
+template<typename T>
+Vector<T>::Vector(const Vector<T>& src)
+ : m_AllocationCallbacks(src.m_AllocationCallbacks),
+ m_pArray(src.m_Count ? AllocateArray<T>(src.m_AllocationCallbacks, src.m_Count) : NULL),
+ m_Count(src.m_Count),
+ m_Capacity(src.m_Count)
+{
+ if (m_Count > 0)
+ {
+ memcpy(m_pArray, src.m_pArray, m_Count * sizeof(T));
+ }
+}
+
+template<typename T>
+Vector<T>::~Vector()
+{
+ Free(m_AllocationCallbacks, m_pArray);
+}
+
+template<typename T>
+void Vector<T>::push_back(const T& src)
+{
+ const size_t newIndex = size();
+ resize(newIndex + 1);
+ m_pArray[newIndex] = src;
+}
+
+template<typename T>
+void Vector<T>::pop_front()
+{
+ D3D12MA_HEAVY_ASSERT(m_Count > 0);
+ remove(0);
+}
+
+template<typename T>
+void Vector<T>::pop_back()
+{
+ D3D12MA_HEAVY_ASSERT(m_Count > 0);
+ resize(size() - 1);
+}
+
+template<typename T>
+T& Vector<T>::front()
+{
+ D3D12MA_HEAVY_ASSERT(m_Count > 0);
+ return m_pArray[0];
+}
+
+template<typename T>
+T& Vector<T>::back()
+{
+ D3D12MA_HEAVY_ASSERT(m_Count > 0);
+ return m_pArray[m_Count - 1];
+}
+
+template<typename T>
+const T& Vector<T>::front() const
+{
+ D3D12MA_HEAVY_ASSERT(m_Count > 0);
+ return m_pArray[0];
+}
+
+template<typename T>
+const T& Vector<T>::back() const
+{
+ D3D12MA_HEAVY_ASSERT(m_Count > 0);
+ return m_pArray[m_Count - 1];
+}
+
+template<typename T>
+void Vector<T>::reserve(size_t newCapacity, bool freeMemory)
+{
+ newCapacity = D3D12MA_MAX(newCapacity, m_Count);
+
+ if ((newCapacity < m_Capacity) && !freeMemory)
+ {
+ newCapacity = m_Capacity;
+ }
+
+ if (newCapacity != m_Capacity)
+ {
+ T* const newArray = newCapacity ? AllocateArray<T>(m_AllocationCallbacks, newCapacity) : NULL;
+ if (m_Count != 0)
+ {
+ memcpy(newArray, m_pArray, m_Count * sizeof(T));
+ }
+ Free(m_AllocationCallbacks, m_pArray);
+ m_Capacity = newCapacity;
+ m_pArray = newArray;
+ }
+}
+
+template<typename T>
+void Vector<T>::resize(size_t newCount, bool freeMemory)
+{
+ size_t newCapacity = m_Capacity;
+ if (newCount > m_Capacity)
+ {
+ newCapacity = D3D12MA_MAX(newCount, D3D12MA_MAX(m_Capacity * 3 / 2, (size_t)8));
+ }
+ else if (freeMemory)
+ {
+ newCapacity = newCount;
+ }
+
+ if (newCapacity != m_Capacity)
+ {
+ T* const newArray = newCapacity ? AllocateArray<T>(m_AllocationCallbacks, newCapacity) : NULL;
+ const size_t elementsToCopy = D3D12MA_MIN(m_Count, newCount);
+ if (elementsToCopy != 0)
+ {
+ memcpy(newArray, m_pArray, elementsToCopy * sizeof(T));
+ }
+ Free(m_AllocationCallbacks, m_pArray);
+ m_Capacity = newCapacity;
+ m_pArray = newArray;
+ }
+
+ m_Count = newCount;
+}
+
+template<typename T>
+void Vector<T>::insert(size_t index, const T& src)
+{
+ D3D12MA_HEAVY_ASSERT(index <= m_Count);
+ const size_t oldCount = size();
+ resize(oldCount + 1);
+ if (index < oldCount)
+ {
+ memmove(m_pArray + (index + 1), m_pArray + index, (oldCount - index) * sizeof(T));
+ }
+ m_pArray[index] = src;
+}
+
+template<typename T>
+void Vector<T>::remove(size_t index)
+{
+ D3D12MA_HEAVY_ASSERT(index < m_Count);
+ const size_t oldCount = size();
+ if (index < oldCount - 1)
+ {
+ memmove(m_pArray + index, m_pArray + (index + 1), (oldCount - index - 1) * sizeof(T));
+ }
+ resize(oldCount - 1);
+}
+
+template<typename T> template<typename CmpLess>
+size_t Vector<T>::InsertSorted(const T& value, const CmpLess& cmp)
+{
+ const size_t indexToInsert = BinaryFindFirstNotLess<CmpLess, iterator, T>(
+ m_pArray,
+ m_pArray + m_Count,
+ value,
+ cmp) - m_pArray;
+ insert(indexToInsert, value);
+ return indexToInsert;
+}
+
+template<typename T> template<typename CmpLess>
+bool Vector<T>::RemoveSorted(const T& value, const CmpLess& cmp)
+{
+ const iterator it = BinaryFindFirstNotLess(
+ m_pArray,
+ m_pArray + m_Count,
+ value,
+ cmp);
+ if ((it != end()) && !cmp(*it, value) && !cmp(value, *it))
+ {
+ size_t indexToRemove = it - begin();
+ remove(indexToRemove);
+ return true;
+ }
+ return false;
+}
+
+template<typename T>
+Vector<T>& Vector<T>::operator=(const Vector<T>& rhs)
+{
+ if (&rhs != this)
+ {
+ resize(rhs.m_Count);
+ if (m_Count != 0)
+ {
+ memcpy(m_pArray, rhs.m_pArray, m_Count * sizeof(T));
+ }
+ }
+ return *this;
+}
+
+template<typename T>
+T& Vector<T>::operator[](size_t index)
+{
+ D3D12MA_HEAVY_ASSERT(index < m_Count);
+ return m_pArray[index];
+}
+
+template<typename T>
+const T& Vector<T>::operator[](size_t index) const
+{
+ D3D12MA_HEAVY_ASSERT(index < m_Count);
+ return m_pArray[index];
+}
+#endif // _D3D12MA_VECTOR_FUNCTIONS
+#endif // _D3D12MA_VECTOR
+
+#ifndef _D3D12MA_STRING_BUILDER
class StringBuilder
{
public:
- StringBuilder(const ALLOCATION_CALLBACKS& allocationCallbacks) : m_Data(allocationCallbacks) { }
+ StringBuilder(const ALLOCATION_CALLBACKS& allocationCallbacks) : m_Data(allocationCallbacks) {}
size_t GetLength() const { return m_Data.size(); }
LPCWSTR GetData() const { return m_Data.data(); }
@@ -1151,6 +1177,7 @@
Vector<WCHAR> m_Data;
};
+#ifndef _D3D12MA_STRING_BUILDER_FUNCTIONS
void StringBuilder::Add(LPCWSTR str)
{
const size_t len = wcslen(str);
@@ -1189,10 +1216,10 @@
while (num);
Add(p);
}
+#endif // _D3D12MA_STRING_BUILDER_FUNCTIONS
+#endif // _D3D12MA_STRING_BUILDER
-////////////////////////////////////////////////////////////////////////////////
-// Private class JsonWriter
-
+#ifndef _D3D12MA_JSON_WRITER
/*
Allows to conveniently build a correct JSON document to be written to the
StringBuilder passed to the constructor.
@@ -1238,8 +1265,6 @@
// Ends writing a string value by writing '"'.
void EndString(LPCWSTR pStr = NULL);
- void AddAllocationToObject(const Allocation& alloc);
-
// Writes a number value.
void WriteNumber(UINT num);
void WriteNumber(UINT64 num);
@@ -1248,6 +1273,9 @@
// Writes a null value.
void WriteNull();
+ void AddAllocationToObject(const Allocation& alloc);
+ void AddDetailedStatisticsInfoObject(const DetailedStatistics& stats);
+
private:
static const WCHAR* const INDENT;
@@ -1271,14 +1299,13 @@
void WriteIndent(bool oneLess = false);
};
+#ifndef _D3D12MA_JSON_WRITER_FUNCTIONS
const WCHAR* const JsonWriter::INDENT = L" ";
-JsonWriter::JsonWriter(const ALLOCATION_CALLBACKS& allocationCallbacks, StringBuilder& stringBuilder) :
- m_SB(stringBuilder),
+JsonWriter::JsonWriter(const ALLOCATION_CALLBACKS& allocationCallbacks, StringBuilder& stringBuilder)
+ : m_SB(stringBuilder),
m_Stack(allocationCallbacks),
- m_InsideString(false)
-{
-}
+ m_InsideString(false) {}
JsonWriter::~JsonWriter()
{
@@ -1458,6 +1485,85 @@
m_SB.Add(L"null");
}
+void JsonWriter::AddAllocationToObject(const Allocation& alloc)
+{
+ WriteString(L"Type");
+ switch (alloc.m_PackedData.GetResourceDimension()) {
+ case D3D12_RESOURCE_DIMENSION_UNKNOWN:
+ WriteString(L"UNKNOWN");
+ break;
+ case D3D12_RESOURCE_DIMENSION_BUFFER:
+ WriteString(L"BUFFER");
+ break;
+ case D3D12_RESOURCE_DIMENSION_TEXTURE1D:
+ WriteString(L"TEXTURE1D");
+ break;
+ case D3D12_RESOURCE_DIMENSION_TEXTURE2D:
+ WriteString(L"TEXTURE2D");
+ break;
+ case D3D12_RESOURCE_DIMENSION_TEXTURE3D:
+ WriteString(L"TEXTURE3D");
+ break;
+ default: D3D12MA_ASSERT(0); break;
+ }
+ WriteString(L"Size");
+ WriteNumber(alloc.GetSize());
+ LPCWSTR name = alloc.GetName();
+ if (name != NULL)
+ {
+ WriteString(L"Name");
+ WriteString(name);
+ }
+ if (alloc.m_PackedData.GetResourceFlags())
+ {
+ WriteString(L"Flags");
+ WriteNumber((UINT)alloc.m_PackedData.GetResourceFlags());
+ }
+ if (alloc.m_PackedData.GetTextureLayout())
+ {
+ WriteString(L"Layout");
+ WriteNumber((UINT)alloc.m_PackedData.GetTextureLayout());
+ }
+ if (alloc.m_CreationFrameIndex)
+ {
+ WriteString(L"CreationFrameIndex");
+ WriteNumber(alloc.m_CreationFrameIndex);
+ }
+}
+
+void JsonWriter::AddDetailedStatisticsInfoObject(const DetailedStatistics& stats)
+{
+ BeginObject();
+ WriteString(L"BlockCount");
+ WriteNumber(stats.Stats.BlockCount);
+ WriteString(L"AllocationCount");
+ WriteNumber(stats.Stats.AllocationCount);
+ WriteString(L"UnusedRangeCount");
+ WriteNumber(stats.UnusedRangeCount);
+ WriteString(L"BlockBytes");
+ WriteNumber(stats.Stats.BlockBytes);
+ WriteString(L"AllocationBytes");
+ WriteNumber(stats.Stats.AllocationBytes);
+
+ WriteString(L"AllocationSize");
+ BeginObject(true);
+ WriteString(L"Min");
+ WriteNumber(stats.AllocationSizeMin);
+ WriteString(L"Max");
+ WriteNumber(stats.AllocationSizeMax);
+ EndObject();
+
+ WriteString(L"UnusedRangeSize");
+ BeginObject(true);
+ WriteString(L"Min");
+ WriteNumber(stats.UnusedRangeSizeMin);
+ WriteString(L"Max");
+ WriteNumber(stats.UnusedRangeSizeMax);
+ EndObject();
+
+ EndObject();
+}
+
void JsonWriter::BeginValue(bool isString)
{
if (!m_Stack.empty())
@@ -1502,56 +1608,10 @@
}
}
}
+#endif // _D3D12MA_JSON_WRITER_FUNCTIONS
+#endif // _D3D12MA_JSON_WRITER
-void JsonWriter::AddAllocationToObject(const Allocation& alloc)
-{
- WriteString(L"Type");
- switch (alloc.m_PackedData.GetResourceDimension()) {
- case D3D12_RESOURCE_DIMENSION_UNKNOWN:
- WriteString(L"UNKNOWN");
- break;
- case D3D12_RESOURCE_DIMENSION_BUFFER:
- WriteString(L"BUFFER");
- break;
- case D3D12_RESOURCE_DIMENSION_TEXTURE1D:
- WriteString(L"TEXTURE1D");
- break;
- case D3D12_RESOURCE_DIMENSION_TEXTURE2D:
- WriteString(L"TEXTURE2D");
- break;
- case D3D12_RESOURCE_DIMENSION_TEXTURE3D:
- WriteString(L"TEXTURE3D");
- break;
- default: D3D12MA_ASSERT(0); break;
- }
- WriteString(L"Size");
- WriteNumber(alloc.GetSize());
- LPCWSTR name = alloc.GetName();
- if(name != NULL)
- {
- WriteString(L"Name");
- WriteString(name);
- }
- if(alloc.m_PackedData.GetResourceFlags())
- {
- WriteString(L"Flags");
- WriteNumber((UINT)alloc.m_PackedData.GetResourceFlags());
- }
- if(alloc.m_PackedData.GetTextureLayout())
- {
- WriteString(L"Layout");
- WriteNumber((UINT)alloc.m_PackedData.GetTextureLayout());
- }
- if(alloc.m_CreationFrameIndex)
- {
- WriteString(L"CreationFrameIndex");
- WriteNumber(alloc.m_CreationFrameIndex);
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Private class PoolAllocator
-
+#ifndef _D3D12MA_POOL_ALLOCATOR
/*
Allocator for objects of type T using a list of arrays (pools) to speed up
allocation. Number of elements that can be allocated is not bounded because
@@ -1567,8 +1627,10 @@
// allocationCallbacks externally owned, must outlive this object.
PoolAllocator(const ALLOCATION_CALLBACKS& allocationCallbacks, UINT firstBlockCapacity);
~PoolAllocator() { Clear(); }
+
void Clear();
- template<typename... Types> T* Alloc(Types... args);
+ template<typename... Types>
+ T* Alloc(Types... args);
void Free(T* ptr);
private:
@@ -1592,9 +1654,10 @@
ItemBlock& CreateNewBlock();
};
+#ifndef _D3D12MA_POOL_ALLOCATOR_FUNCTIONS
template<typename T>
-PoolAllocator<T>::PoolAllocator(const ALLOCATION_CALLBACKS& allocationCallbacks, UINT firstBlockCapacity) :
- m_AllocationCallbacks(allocationCallbacks),
+PoolAllocator<T>::PoolAllocator(const ALLOCATION_CALLBACKS& allocationCallbacks, UINT firstBlockCapacity)
+ : m_AllocationCallbacks(allocationCallbacks),
m_FirstBlockCapacity(firstBlockCapacity),
m_ItemBlocks(allocationCallbacks)
{
@@ -1611,8 +1674,8 @@
m_ItemBlocks.clear(true);
}
-template<typename T>
-template<typename... Types> T* PoolAllocator<T>::Alloc(Types... args)
+template<typename T> template<typename... Types>
+T* PoolAllocator<T>::Alloc(Types... args)
{
for(size_t i = m_ItemBlocks.size(); i--; )
{
@@ -1682,10 +1745,10 @@
newBlock.pItems[newBlockCapacity - 1].NextFreeIndex = UINT32_MAX;
return m_ItemBlocks.back();
}
+#endif // _D3D12MA_POOL_ALLOCATOR_FUNCTIONS
+#endif // _D3D12MA_POOL_ALLOCATOR
-////////////////////////////////////////////////////////////////////////////////
-// Private class List
-
+#ifndef _D3D12MA_LIST
/*
Doubly linked list, with elements allocated out of PoolAllocator.
Has custom interface, as well as STL-style interface, including iterator and
@@ -1703,15 +1766,137 @@
T Value;
};
+ class reverse_iterator;
+ class const_reverse_iterator;
+ class iterator
+ {
+ friend class List<T>;
+ friend class const_iterator;
+
+ public:
+ iterator() = default;
+ iterator(const reverse_iterator& src)
+ : m_pList(src.m_pList), m_pItem(src.m_pItem) {}
+
+ T& operator*() const;
+ T* operator->() const;
+
+ iterator& operator++();
+ iterator& operator--();
+ iterator operator++(int);
+ iterator operator--(int);
+
+ bool operator==(const iterator& rhs) const;
+ bool operator!=(const iterator& rhs) const;
+
+ private:
+ List<T>* m_pList = NULL;
+ Item* m_pItem = NULL;
+
+ iterator(List<T>* pList, Item* pItem) : m_pList(pList), m_pItem(pItem) {}
+ };
+
+ class reverse_iterator
+ {
+ friend class List<T>;
+ friend class const_reverse_iterator;
+
+ public:
+ reverse_iterator() = default;
+ reverse_iterator(const iterator& src)
+ : m_pList(src.m_pList), m_pItem(src.m_pItem) {}
+
+ T& operator*() const;
+ T* operator->() const;
+
+ reverse_iterator& operator++();
+ reverse_iterator& operator--();
+ reverse_iterator operator++(int);
+ reverse_iterator operator--(int);
+
+ bool operator==(const reverse_iterator& rhs) const;
+ bool operator!=(const reverse_iterator& rhs) const;
+
+ private:
+ List<T>* m_pList = NULL;
+ Item* m_pItem = NULL;
+
+ reverse_iterator(List<T>* pList, Item* pItem)
+ : m_pList(pList), m_pItem(pItem) {}
+ };
+
+ class const_iterator
+ {
+ friend class List<T>;
+
+ public:
+ const_iterator() = default;
+ const_iterator(const iterator& src)
+ : m_pList(src.m_pList), m_pItem(src.m_pItem) {}
+ const_iterator(const reverse_iterator& src)
+ : m_pList(src.m_pList), m_pItem(src.m_pItem) {}
+ const_iterator(const const_reverse_iterator& src)
+ : m_pList(src.m_pList), m_pItem(src.m_pItem) {}
+
+ iterator dropConst() const;
+ const T& operator*() const;
+ const T* operator->() const;
+
+ const_iterator& operator++();
+ const_iterator& operator--();
+ const_iterator operator++(int);
+ const_iterator operator--(int);
+
+ bool operator==(const const_iterator& rhs) const;
+ bool operator!=(const const_iterator& rhs) const;
+
+ private:
+ const List<T>* m_pList = NULL;
+ const Item* m_pItem = NULL;
+
+ const_iterator(const List<T>* pList, const Item* pItem)
+ : m_pList(pList), m_pItem(pItem) {}
+ };
+
+ class const_reverse_iterator
+ {
+ friend class List<T>;
+
+ public:
+ const_reverse_iterator() = default;
+ const_reverse_iterator(const iterator& src)
+ : m_pList(src.m_pList), m_pItem(src.m_pItem) {}
+ const_reverse_iterator(const reverse_iterator& src)
+ : m_pList(src.m_pList), m_pItem(src.m_pItem) {}
+ const_reverse_iterator(const const_iterator& src)
+ : m_pList(src.m_pList), m_pItem(src.m_pItem) {}
+
+ reverse_iterator dropConst() const;
+ const T& operator*() const;
+ const T* operator->() const;
+
+ const_reverse_iterator& operator++();
+ const_reverse_iterator& operator--();
+ const_reverse_iterator operator++(int);
+ const_reverse_iterator operator--(int);
+
+ bool operator==(const const_reverse_iterator& rhs) const;
+ bool operator!=(const const_reverse_iterator& rhs) const;
+
+ private:
+ const List<T>* m_pList = NULL;
+ const Item* m_pItem = NULL;
+
+ const_reverse_iterator(const List<T>* pList, const Item* pItem)
+ : m_pList(pList), m_pItem(pItem) {}
+ };
+
// allocationCallbacks externally owned, must outlive this object.
List(const ALLOCATION_CALLBACKS& allocationCallbacks);
-
// Intentionally not calling Clear, because that would be unnecessary
// computations to return all items to m_ItemAllocator as free.
- // ~List() {}
+ ~List() = default;
- void Clear();
-
size_t GetCount() const { return m_Count; }
bool IsEmpty() const { return m_Count == 0; }
@@ -1720,6 +1905,28 @@
Item* Back() { return m_pBack; }
const Item* Back() const { return m_pBack; }
+ bool empty() const { return IsEmpty(); }
+ size_t size() const { return GetCount(); }
+ void push_back(const T& value) { PushBack(value); }
+ iterator insert(iterator it, const T& value) { return iterator(this, InsertBefore(it.m_pItem, value)); }
+ void clear() { Clear(); }
+ void erase(iterator it) { Remove(it.m_pItem); }
+
+ iterator begin() { return iterator(this, Front()); }
+ iterator end() { return iterator(this, NULL); }
+ reverse_iterator rbegin() { return reverse_iterator(this, Back()); }
+ reverse_iterator rend() { return reverse_iterator(this, NULL); }
+
+ const_iterator cbegin() const { return const_iterator(this, Front()); }
+ const_iterator cend() const { return const_iterator(this, NULL); }
+ const_iterator begin() const { return cbegin(); }
+ const_iterator end() const { return cend(); }
+
+ const_reverse_iterator crbegin() const { return const_reverse_iterator(this, Back()); }
+ const_reverse_iterator crend() const { return const_reverse_iterator(this, NULL); }
+ const_reverse_iterator rbegin() const { return crbegin(); }
+ const_reverse_iterator rend() const { return crend(); }
+
Item* PushBack();
Item* PushFront();
Item* PushBack(const T& value);
@@ -1731,408 +1938,12 @@
Item* InsertBefore(Item* pItem);
// Item can be null - it means PushFront.
Item* InsertAfter(Item* pItem);
-
Item* InsertBefore(Item* pItem, const T& value);
Item* InsertAfter(Item* pItem, const T& value);
+ void Clear();
void Remove(Item* pItem);
- class reverse_iterator;
- class const_reverse_iterator;
- class iterator
- {
- public:
- iterator() :
- m_pList(NULL),
- m_pItem(NULL)
- {
- }
-
- iterator(const reverse_iterator& src) :
- m_pList(src.m_pList),
- m_pItem(src.m_pItem)
- {
- }
-
- T& operator*() const
- {
- D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
- return m_pItem->Value;
- }
- T* operator->() const
- {
- D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
- return &m_pItem->Value;
- }
-
- iterator& operator++()
- {
- D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
- m_pItem = m_pItem->pNext;
- return *this;
- }
- iterator& operator--()
- {
- if(m_pItem != NULL)
- {
- m_pItem = m_pItem->pPrev;
- }
- else
- {
- D3D12MA_HEAVY_ASSERT(!m_pList->IsEmpty());
- m_pItem = m_pList->Back();
- }
- return *this;
- }
-
- iterator operator++(int)
- {
- iterator result = *this;
- ++*this;
- return result;
- }
- iterator operator--(int)
- {
- iterator result = *this;
- --*this;
- return result;
- }
-
- bool operator==(const iterator& rhs) const
- {
- D3D12MA_HEAVY_ASSERT(m_pList == rhs.m_pList);
- return m_pItem == rhs.m_pItem;
- }
- bool operator!=(const iterator& rhs) const
- {
- D3D12MA_HEAVY_ASSERT(m_pList == rhs.m_pList);
- return m_pItem != rhs.m_pItem;
- }
-
- private:
- List<T>* m_pList;
- Item* m_pItem;
-
- iterator(List<T>* pList, Item* pItem) :
- m_pList(pList),
- m_pItem(pItem)
- {
- }
-
- friend class List<T>;
- friend class const_iterator;
- };
-
- class reverse_iterator
- {
- public:
- reverse_iterator() :
- m_pList(NULL),
- m_pItem(NULL)
- {
- }
-
- reverse_iterator(const iterator& src) :
- m_pList(src.m_pList),
- m_pItem(src.m_pItem)
- {
- }
-
- T& operator*() const
- {
- D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
- return m_pItem->Value;
- }
- T* operator->() const
- {
- D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
- return &m_pItem->Value;
- }
-
- reverse_iterator& operator++()
- {
- D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
- m_pItem = m_pItem->pPrev;
- return *this;
- }
- reverse_iterator& operator--()
- {
- if(m_pItem != NULL)
- {
- m_pItem = m_pItem->pNext;
- }
- else
- {
- D3D12MA_HEAVY_ASSERT(!m_pList->IsEmpty());
- m_pItem = m_pList->Front();
- }
- return *this;
- }
-
- reverse_iterator operator++(int)
- {
- reverse_iterator result = *this;
- ++*this;
- return result;
- }
- reverse_iterator operator--(int)
- {
- reverse_iterator result = *this;
- --*this;
- return result;
- }
-
- bool operator==(const reverse_iterator& rhs) const
- {
- D3D12MA_HEAVY_ASSERT(m_pList == rhs.m_pList);
- return m_pItem == rhs.m_pItem;
- }
- bool operator!=(const reverse_iterator& rhs) const
- {
- D3D12MA_HEAVY_ASSERT(m_pList == rhs.m_pList);
- return m_pItem != rhs.m_pItem;
- }
-
- private:
- List<T>* m_pList;
- Item* m_pItem;
-
- reverse_iterator(List<T>* pList, Item* pItem) :
- m_pList(pList),
- m_pItem(pItem)
- {
- }
-
- friend class List<T>;
- friend class const_reverse_iterator;
- };
-
- class const_iterator
- {
- public:
- const_iterator() :
- m_pList(NULL),
- m_pItem(NULL)
- {
- }
-
- const_iterator(const iterator& src) :
- m_pList(src.m_pList),
- m_pItem(src.m_pItem)
- {
- }
-
- const_iterator(const reverse_iterator& src) :
- m_pList(src.m_pList),
- m_pItem(src.m_pItem)
- {
- }
-
- const_iterator(const const_reverse_iterator& src) :
- m_pList(src.m_pList),
- m_pItem(src.m_pItem)
- {
- }
-
- iterator dropConst() const
- {
- return iterator(const_cast<List<T>*>(m_pList), const_cast<Item*>(m_pItem));
- }
-
- const T& operator*() const
- {
- D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
- return m_pItem->Value;
- }
- const T* operator->() const
- {
- D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
- return &m_pItem->Value;
- }
-
- const_iterator& operator++()
- {
- D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
- m_pItem = m_pItem->pNext;
- return *this;
- }
- const_iterator& operator--()
- {
- if(m_pItem != NULL)
- {
- m_pItem = m_pItem->pPrev;
- }
- else
- {
- D3D12MA_HEAVY_ASSERT(!m_pList->IsEmpty());
- m_pItem = m_pList->Back();
- }
- return *this;
- }
-
- const_iterator operator++(int)
- {
- const_iterator result = *this;
- ++*this;
- return result;
- }
- const_iterator operator--(int)
- {
- const_iterator result = *this;
- --*this;
- return result;
- }
-
- bool operator==(const const_iterator& rhs) const
- {
- D3D12MA_HEAVY_ASSERT(m_pList == rhs.m_pList);
- return m_pItem == rhs.m_pItem;
- }
- bool operator!=(const const_iterator& rhs) const
- {
- D3D12MA_HEAVY_ASSERT(m_pList == rhs.m_pList);
- return m_pItem != rhs.m_pItem;
- }
-
- private:
- const_iterator(const List<T>* pList, const Item* pItem) :
- m_pList(pList),
- m_pItem(pItem)
- {
- }
-
- const List<T>* m_pList;
- const Item* m_pItem;
-
- friend class List<T>;
- };
-
- class const_reverse_iterator
- {
- public:
- const_reverse_iterator() :
- m_pList(NULL),
- m_pItem(NULL)
- {
- }
-
- const_reverse_iterator(const iterator& src) :
- m_pList(src.m_pList),
- m_pItem(src.m_pItem)
- {
- }
-
- const_reverse_iterator(const reverse_iterator& src) :
- m_pList(src.m_pList),
- m_pItem(src.m_pItem)
- {
- }
-
- const_reverse_iterator(const const_iterator& src) :
- m_pList(src.m_pList),
- m_pItem(src.m_pItem)
- {
- }
-
- reverse_iterator dropConst() const
- {
- return reverse_iterator(const_cast<List<T>*>(m_pList), const_cast<Item*>(m_pItem));
- }
-
- const T& operator*() const
- {
- D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
- return m_pItem->Value;
- }
- const T* operator->() const
- {
- D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
- return &m_pItem->Value;
- }
-
- const_reverse_iterator& operator++()
- {
- D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
- m_pItem = m_pItem->pPrev;
- return *this;
- }
- const_reverse_iterator& operator--()
- {
- if(m_pItem != NULL)
- {
- m_pItem = m_pItem->pNext;
- }
- else
- {
- D3D12MA_HEAVY_ASSERT(!m_pList->IsEmpty());
- m_pItem = m_pList->Front();
- }
- return *this;
- }
-
- const_reverse_iterator operator++(int)
- {
- const_reverse_iterator result = *this;
- ++*this;
- return result;
- }
- const_reverse_iterator operator--(int)
- {
- const_reverse_iterator result = *this;
- --*this;
- return result;
- }
-
- bool operator==(const const_reverse_iterator& rhs) const
- {
- D3D12MA_HEAVY_ASSERT(m_pList == rhs.m_pList);
- return m_pItem == rhs.m_pItem;
- }
- bool operator!=(const const_reverse_iterator& rhs) const
- {
- D3D12MA_HEAVY_ASSERT(m_pList == rhs.m_pList);
- return m_pItem != rhs.m_pItem;
- }
-
- private:
- const_reverse_iterator(const List<T>* pList, const Item* pItem) :
- m_pList(pList),
- m_pItem(pItem)
- {
- }
-
- const List<T>* m_pList;
- const Item* m_pItem;
-
- friend class List<T>;
- };
-
- bool empty() const { return IsEmpty(); }
- size_t size() const { return GetCount(); }
-
- iterator begin() { return iterator(this, Front()); }
- iterator end() { return iterator(this, NULL); }
-
- const_iterator cbegin() const { return const_iterator(this, Front()); }
- const_iterator cend() const { return const_iterator(this, NULL); }
-
- const_iterator begin() const { return cbegin(); }
- const_iterator end() const { return cend(); }
-
- reverse_iterator rbegin() { return reverse_iterator(this, Back()); }
- reverse_iterator rend() { return reverse_iterator(this, NULL); }
-
- const_reverse_iterator crbegin() const { return const_reverse_iterator(this, Back()); }
- const_reverse_iterator crend() const { return const_reverse_iterator(this, NULL); }
-
- const_reverse_iterator rbegin() const { return crbegin(); }
- const_reverse_iterator rend() const { return crend(); }
-
- void clear() { Clear(); }
- void push_back(const T& value) { PushBack(value); }
- void erase(iterator it) { Remove(it.m_pItem); }
- iterator insert(iterator it, const T& value) { return iterator(this, InsertBefore(it.m_pItem, value)); }
-
private:
const ALLOCATION_CALLBACKS& m_AllocationCallbacks;
PoolAllocator<Item> m_ItemAllocator;
@@ -2141,15 +1952,302 @@
size_t m_Count;
};
+#ifndef _D3D12MA_LIST_ITERATOR_FUNCTIONS
template<typename T>
-List<T>::List(const ALLOCATION_CALLBACKS& allocationCallbacks) :
- m_AllocationCallbacks(allocationCallbacks),
+T& List<T>::iterator::operator*() const
+{
+ D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
+ return m_pItem->Value;
+}
+
+template<typename T>
+T* List<T>::iterator::operator->() const
+{
+ D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
+ return &m_pItem->Value;
+}
+
+template<typename T>
+typename List<T>::iterator& List<T>::iterator::operator++()
+{
+ D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
+ m_pItem = m_pItem->pNext;
+ return *this;
+}
+
+template<typename T>
+typename List<T>::iterator& List<T>::iterator::operator--()
+{
+ if (m_pItem != NULL)
+ {
+ m_pItem = m_pItem->pPrev;
+ }
+ else
+ {
+ D3D12MA_HEAVY_ASSERT(!m_pList->IsEmpty());
+ m_pItem = m_pList->Back();
+ }
+ return *this;
+}
+
+template<typename T>
+typename List<T>::iterator List<T>::iterator::operator++(int)
+{
+ iterator result = *this;
+ ++* this;
+ return result;
+}
+
+template<typename T>
+typename List<T>::iterator List<T>::iterator::operator--(int)
+{
+ iterator result = *this;
+ --* this;
+ return result;
+}
+
+template<typename T>
+bool List<T>::iterator::operator==(const iterator& rhs) const
+{
+ D3D12MA_HEAVY_ASSERT(m_pList == rhs.m_pList);
+ return m_pItem == rhs.m_pItem;
+}
+
+template<typename T>
+bool List<T>::iterator::operator!=(const iterator& rhs) const
+{
+ D3D12MA_HEAVY_ASSERT(m_pList == rhs.m_pList);
+ return m_pItem != rhs.m_pItem;
+}
+#endif // _D3D12MA_LIST_ITERATOR_FUNCTIONS
+
+#ifndef _D3D12MA_LIST_REVERSE_ITERATOR_FUNCTIONS
+template<typename T>
+T& List<T>::reverse_iterator::operator*() const
+{
+ D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
+ return m_pItem->Value;
+}
+
+template<typename T>
+T* List<T>::reverse_iterator::operator->() const
+{
+ D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
+ return &m_pItem->Value;
+}
+
+template<typename T>
+typename List<T>::reverse_iterator& List<T>::reverse_iterator::operator++()
+{
+ D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
+ m_pItem = m_pItem->pPrev;
+ return *this;
+}
+
+template<typename T>
+typename List<T>::reverse_iterator& List<T>::reverse_iterator::operator--()
+{
+ if (m_pItem != NULL)
+ {
+ m_pItem = m_pItem->pNext;
+ }
+ else
+ {
+ D3D12MA_HEAVY_ASSERT(!m_pList->IsEmpty());
+ m_pItem = m_pList->Front();
+ }
+ return *this;
+}
+
+template<typename T>
+typename List<T>::reverse_iterator List<T>::reverse_iterator::operator++(int)
+{
+ reverse_iterator result = *this;
+ ++* this;
+ return result;
+}
+
+template<typename T>
+typename List<T>::reverse_iterator List<T>::reverse_iterator::operator--(int)
+{
+ reverse_iterator result = *this;
+ --* this;
+ return result;
+}
+
+template<typename T>
+bool List<T>::reverse_iterator::operator==(const reverse_iterator& rhs) const
+{
+ D3D12MA_HEAVY_ASSERT(m_pList == rhs.m_pList);
+ return m_pItem == rhs.m_pItem;
+}
+
+template<typename T>
+bool List<T>::reverse_iterator::operator!=(const reverse_iterator& rhs) const
+{
+ D3D12MA_HEAVY_ASSERT(m_pList == rhs.m_pList);
+ return m_pItem != rhs.m_pItem;
+}
+#endif // _D3D12MA_LIST_REVERSE_ITERATOR_FUNCTIONS
+
+#ifndef _D3D12MA_LIST_CONST_ITERATOR_FUNCTIONS
+template<typename T>
+typename List<T>::iterator List<T>::const_iterator::dropConst() const
+{
+ return iterator(const_cast<List<T>*>(m_pList), const_cast<Item*>(m_pItem));
+}
+
+template<typename T>
+const T& List<T>::const_iterator::operator*() const
+{
+ D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
+ return m_pItem->Value;
+}
+
+template<typename T>
+const T* List<T>::const_iterator::operator->() const
+{
+ D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
+ return &m_pItem->Value;
+}
+
+template<typename T>
+typename List<T>::const_iterator& List<T>::const_iterator::operator++()
+{
+ D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
+ m_pItem = m_pItem->pNext;
+ return *this;
+}
+
+template<typename T>
+typename List<T>::const_iterator& List<T>::const_iterator::operator--()
+{
+ if (m_pItem != NULL)
+ {
+ m_pItem = m_pItem->pPrev;
+ }
+ else
+ {
+ D3D12MA_HEAVY_ASSERT(!m_pList->IsEmpty());
+ m_pItem = m_pList->Back();
+ }
+ return *this;
+}
+
+template<typename T>
+typename List<T>::const_iterator List<T>::const_iterator::operator++(int)
+{
+ const_iterator result = *this;
+ ++* this;
+ return result;
+}
+
+template<typename T>
+typename List<T>::const_iterator List<T>::const_iterator::operator--(int)
+{
+ const_iterator result = *this;
+ --* this;
+ return result;
+}
+
+template<typename T>
+bool List<T>::const_iterator::operator==(const const_iterator& rhs) const
+{
+ D3D12MA_HEAVY_ASSERT(m_pList == rhs.m_pList);
+ return m_pItem == rhs.m_pItem;
+}
+
+template<typename T>
+bool List<T>::const_iterator::operator!=(const const_iterator& rhs) const
+{
+ D3D12MA_HEAVY_ASSERT(m_pList == rhs.m_pList);
+ return m_pItem != rhs.m_pItem;
+}
+#endif // _D3D12MA_LIST_CONST_ITERATOR_FUNCTIONS
+
+#ifndef _D3D12MA_LIST_CONST_REVERSE_ITERATOR_FUNCTIONS
+template<typename T>
+typename List<T>::reverse_iterator List<T>::const_reverse_iterator::dropConst() const
+{
+ return reverse_iterator(const_cast<List<T>*>(m_pList), const_cast<Item*>(m_pItem));
+}
+
+template<typename T>
+const T& List<T>::const_reverse_iterator::operator*() const
+{
+ D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
+ return m_pItem->Value;
+}
+
+template<typename T>
+const T* List<T>::const_reverse_iterator::operator->() const
+{
+ D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
+ return &m_pItem->Value;
+}
+
+template<typename T>
+typename List<T>::const_reverse_iterator& List<T>::const_reverse_iterator::operator++()
+{
+ D3D12MA_HEAVY_ASSERT(m_pItem != NULL);
+ m_pItem = m_pItem->pPrev;
+ return *this;
+}
+
+template<typename T>
+typename List<T>::const_reverse_iterator& List<T>::const_reverse_iterator::operator--()
+{
+ if (m_pItem != NULL)
+ {
+ m_pItem = m_pItem->pNext;
+ }
+ else
+ {
+ D3D12MA_HEAVY_ASSERT(!m_pList->IsEmpty());
+ m_pItem = m_pList->Front();
+ }
+ return *this;
+}
+
+template<typename T>
+typename List<T>::const_reverse_iterator List<T>::const_reverse_iterator::operator++(int)
+{
+ const_reverse_iterator result = *this;
+ ++* this;
+ return result;
+}
+
+template<typename T>
+typename List<T>::const_reverse_iterator List<T>::const_reverse_iterator::operator--(int)
+{
+ const_reverse_iterator result = *this;
+ --* this;
+ return result;
+}
+
+template<typename T>
+bool List<T>::const_reverse_iterator::operator==(const const_reverse_iterator& rhs) const
+{
+ D3D12MA_HEAVY_ASSERT(m_pList == rhs.m_pList);
+ return m_pItem == rhs.m_pItem;
+}
+
+template<typename T>
+bool List<T>::const_reverse_iterator::operator!=(const const_reverse_iterator& rhs) const
+{
+ D3D12MA_HEAVY_ASSERT(m_pList == rhs.m_pList);
+ return m_pItem != rhs.m_pItem;
+}
+#endif // _D3D12MA_LIST_CONST_REVERSE_ITERATOR_FUNCTIONS
+
+#ifndef _D3D12MA_LIST_FUNCTIONS
+template<typename T>
+List<T>::List(const ALLOCATION_CALLBACKS& allocationCallbacks)
+ : m_AllocationCallbacks(allocationCallbacks),
m_ItemAllocator(allocationCallbacks, 128),
m_pFront(NULL),
m_pBack(NULL),
- m_Count(0)
-{
-}
+ m_Count(0) {}
template<typename T>
void List<T>::Clear()
@@ -2358,10 +2456,10 @@
newItem->Value = value;
return newItem;
}
+#endif // _D3D12MA_LIST_FUNCTIONS
+#endif // _D3D12MA_LIST
-////////////////////////////////////////////////////////////////////////////////
-// Private class IntrusiveLinkedList
-
+#ifndef _D3D12MA_INTRUSIVE_LINKED_LIST
/*
Expected interface of ItemTypeTraits:
struct MyItemTypeTraits
@@ -2380,204 +2478,238 @@
using ItemType = typename ItemTypeTraits::ItemType;
static ItemType* GetPrev(const ItemType* item) { return ItemTypeTraits::GetPrev(item); }
static ItemType* GetNext(const ItemType* item) { return ItemTypeTraits::GetNext(item); }
+
// Movable, not copyable.
- IntrusiveLinkedList() { }
- IntrusiveLinkedList(const IntrusiveLinkedList<ItemTypeTraits>& src) = delete;
- IntrusiveLinkedList(IntrusiveLinkedList<ItemTypeTraits>&& src) :
- m_Front(src.m_Front), m_Back(src.m_Back), m_Count(src.m_Count)
- {
- src.m_Front = src.m_Back = NULL;
- src.m_Count = 0;
- }
- ~IntrusiveLinkedList()
- {
- D3D12MA_HEAVY_ASSERT(IsEmpty());
- }
- IntrusiveLinkedList<ItemTypeTraits>& operator=(const IntrusiveLinkedList<ItemTypeTraits>& src) = delete;
- IntrusiveLinkedList<ItemTypeTraits>& operator=(IntrusiveLinkedList<ItemTypeTraits>&& src)
- {
- if(&src != this)
- {
- D3D12MA_HEAVY_ASSERT(IsEmpty());
- m_Front = src.m_Front;
- m_Back = src.m_Back;
- m_Count = src.m_Count;
- src.m_Front = src.m_Back = NULL;
- src.m_Count = 0;
- }
- return *this;
- }
- void RemoveAll()
- {
- if(!IsEmpty())
- {
- ItemType* item = m_Back;
- while(item != NULL)
- {
- ItemType* const prevItem = ItemTypeTraits::AccessPrev(item);
- ItemTypeTraits::AccessPrev(item) = NULL;
- ItemTypeTraits::AccessNext(item) = NULL;
- item = prevItem;
- }
- m_Front = NULL;
- m_Back = NULL;
- m_Count = 0;
- }
- }
+ IntrusiveLinkedList() = default;
+ IntrusiveLinkedList(const IntrusiveLinkedList&) = delete;
+ IntrusiveLinkedList(IntrusiveLinkedList&& src);
+ IntrusiveLinkedList& operator=(const IntrusiveLinkedList&) = delete;
+ IntrusiveLinkedList& operator=(IntrusiveLinkedList&& src);
+ ~IntrusiveLinkedList() { D3D12MA_HEAVY_ASSERT(IsEmpty()); }
+
size_t GetCount() const { return m_Count; }
bool IsEmpty() const { return m_Count == 0; }
+
ItemType* Front() { return m_Front; }
- const ItemType* Front() const { return m_Front; }
ItemType* Back() { return m_Back; }
+ const ItemType* Front() const { return m_Front; }
const ItemType* Back() const { return m_Back; }
- void PushBack(ItemType* item)
- {
- D3D12MA_HEAVY_ASSERT(ItemTypeTraits::GetPrev(item) == NULL && ItemTypeTraits::GetNext(item) == NULL);
- if(IsEmpty())
- {
- m_Front = item;
- m_Back = item;
- m_Count = 1;
- }
- else
- {
- ItemTypeTraits::AccessPrev(item) = m_Back;
- ItemTypeTraits::AccessNext(m_Back) = item;
- m_Back = item;
- ++m_Count;
- }
- }
- void PushFront(ItemType* item)
- {
- D3D12MA_HEAVY_ASSERT(ItemTypeTraits::GetPrev(item) == NULL && ItemTypeTraits::GetNext(item) == NULL);
- if(IsEmpty())
- {
- m_Front = item;
- m_Back = item;
- m_Count = 1;
- }
- else
- {
- ItemTypeTraits::AccessNext(item) = m_Front;
- ItemTypeTraits::AccessPrev(m_Front) = item;
- m_Front = item;
- ++m_Count;
- }
- }
- ItemType* PopBack()
- {
- D3D12MA_HEAVY_ASSERT(m_Count > 0);
- ItemType* const backItem = m_Back;
- ItemType* const prevItem = ItemTypeTraits::GetPrev(backItem);
- if(prevItem != NULL)
- {
- ItemTypeTraits::AccessNext(prevItem) = NULL;
- }
- m_Back = prevItem;
- --m_Count;
- ItemTypeTraits::AccessPrev(backItem) = NULL;
- ItemTypeTraits::AccessNext(backItem) = NULL;
- return backItem;
- }
- ItemType* PopFront()
- {
- D3D12MA_HEAVY_ASSERT(m_Count > 0);
- ItemType* const frontItem = m_Front;
- ItemType* const nextItem = ItemTypeTraits::GetNext(frontItem);
- if(nextItem != NULL)
- {
- ItemTypeTraits::AccessPrev(nextItem) = NULL;
- }
- m_Front = nextItem;
- --m_Count;
- ItemTypeTraits::AccessPrev(frontItem) = NULL;
- ItemTypeTraits::AccessNext(frontItem) = NULL;
- return frontItem;
- }
+
+ void PushBack(ItemType* item);
+ void PushFront(ItemType* item);
+ ItemType* PopBack();
+ ItemType* PopFront();
// MyItem can be null - it means PushBack.
- void InsertBefore(ItemType* existingItem, ItemType* newItem)
- {
- D3D12MA_HEAVY_ASSERT(newItem != NULL && ItemTypeTraits::GetPrev(newItem) == NULL && ItemTypeTraits::GetNext(newItem) == NULL);
- if(existingItem != NULL)
- {
- ItemType* const prevItem = ItemTypeTraits::GetPrev(existingItem);
- ItemTypeTraits::AccessPrev(newItem) = prevItem;
- ItemTypeTraits::AccessNext(newItem) = existingItem;
- ItemTypeTraits::AccessPrev(existingItem) = newItem;
- if(prevItem != NULL)
- {
- ItemTypeTraits::AccessNext(prevItem) = newItem;
- }
- else
- {
- D3D12MA_HEAVY_ASSERT(m_Front == existingItem);
- m_Front = newItem;
- }
- ++m_Count;
- }
- else
- PushBack(newItem);
- }
+ void InsertBefore(ItemType* existingItem, ItemType* newItem);
// MyItem can be null - it means PushFront.
- void InsertAfter(ItemType* existingItem, ItemType* newItem)
- {
- D3D12MA_HEAVY_ASSERT(newItem != NULL && ItemTypeTraits::GetPrev(newItem) == NULL && ItemTypeTraits::GetNext(newItem) == NULL);
- if(existingItem != NULL)
- {
- ItemType* const nextItem = ItemTypeTraits::GetNext(existingItem);
- ItemTypeTraits::AccessNext(newItem) = nextItem;
- ItemTypeTraits::AccessPrev(newItem) = existingItem;
- ItemTypeTraits::AccessNext(existingItem) = newItem;
- if(nextItem != NULL)
- {
- ItemTypeTraits::AccessPrev(nextItem) = newItem;
- }
- else
- {
- D3D12MA_HEAVY_ASSERT(m_Back == existingItem);
- m_Back = newItem;
- }
- ++m_Count;
- }
- else
- return PushFront(newItem);
- }
- void Remove(ItemType* item)
- {
- D3D12MA_HEAVY_ASSERT(item != NULL && m_Count > 0);
- if(ItemTypeTraits::GetPrev(item) != NULL)
- {
- ItemTypeTraits::AccessNext(ItemTypeTraits::AccessPrev(item)) = ItemTypeTraits::GetNext(item);
- }
- else
- {
- D3D12MA_HEAVY_ASSERT(m_Front == item);
- m_Front = ItemTypeTraits::GetNext(item);
- }
+ void InsertAfter(ItemType* existingItem, ItemType* newItem);
- if(ItemTypeTraits::GetNext(item) != NULL)
- {
- ItemTypeTraits::AccessPrev(ItemTypeTraits::AccessNext(item)) = ItemTypeTraits::GetPrev(item);
- }
- else
- {
- D3D12MA_HEAVY_ASSERT(m_Back == item);
- m_Back = ItemTypeTraits::GetPrev(item);
- }
- ItemTypeTraits::AccessPrev(item) = NULL;
- ItemTypeTraits::AccessNext(item) = NULL;
- --m_Count;
- }
+ void Remove(ItemType* item);
+ void RemoveAll();
+
private:
ItemType* m_Front = NULL;
ItemType* m_Back = NULL;
size_t m_Count = 0;
};
-////////////////////////////////////////////////////////////////////////////////
-// Private class AllocationObjectAllocator definition
+#ifndef _D3D12MA_INTRUSIVE_LINKED_LIST_FUNCTIONS
+template<typename ItemTypeTraits>
+IntrusiveLinkedList<ItemTypeTraits>::IntrusiveLinkedList(IntrusiveLinkedList&& src)
+ : m_Front(src.m_Front), m_Back(src.m_Back), m_Count(src.m_Count)
+{
+ src.m_Front = src.m_Back = NULL;
+ src.m_Count = 0;
+}
+template<typename ItemTypeTraits>
+IntrusiveLinkedList<ItemTypeTraits>& IntrusiveLinkedList<ItemTypeTraits>::operator=(IntrusiveLinkedList&& src)
+{
+ if (&src != this)
+ {
+ D3D12MA_HEAVY_ASSERT(IsEmpty());
+ m_Front = src.m_Front;
+ m_Back = src.m_Back;
+ m_Count = src.m_Count;
+ src.m_Front = src.m_Back = NULL;
+ src.m_Count = 0;
+ }
+ return *this;
+}
+
+template<typename ItemTypeTraits>
+void IntrusiveLinkedList<ItemTypeTraits>::PushBack(ItemType* item)
+{
+ D3D12MA_HEAVY_ASSERT(ItemTypeTraits::GetPrev(item) == NULL && ItemTypeTraits::GetNext(item) == NULL);
+ if (IsEmpty())
+ {
+ m_Front = item;
+ m_Back = item;
+ m_Count = 1;
+ }
+ else
+ {
+ ItemTypeTraits::AccessPrev(item) = m_Back;
+ ItemTypeTraits::AccessNext(m_Back) = item;
+ m_Back = item;
+ ++m_Count;
+ }
+}
+
+template<typename ItemTypeTraits>
+void IntrusiveLinkedList<ItemTypeTraits>::PushFront(ItemType* item)
+{
+ D3D12MA_HEAVY_ASSERT(ItemTypeTraits::GetPrev(item) == NULL && ItemTypeTraits::GetNext(item) == NULL);
+ if (IsEmpty())
+ {
+ m_Front = item;
+ m_Back = item;
+ m_Count = 1;
+ }
+ else
+ {
+ ItemTypeTraits::AccessNext(item) = m_Front;
+ ItemTypeTraits::AccessPrev(m_Front) = item;
+ m_Front = item;
+ ++m_Count;
+ }
+}
+
+template<typename ItemTypeTraits>
+typename IntrusiveLinkedList<ItemTypeTraits>::ItemType* IntrusiveLinkedList<ItemTypeTraits>::PopBack()
+{
+ D3D12MA_HEAVY_ASSERT(m_Count > 0);
+ ItemType* const backItem = m_Back;
+ ItemType* const prevItem = ItemTypeTraits::GetPrev(backItem);
+ if (prevItem != NULL)
+ {
+ ItemTypeTraits::AccessNext(prevItem) = NULL;
+ }
+ m_Back = prevItem;
+ --m_Count;
+ ItemTypeTraits::AccessPrev(backItem) = NULL;
+ ItemTypeTraits::AccessNext(backItem) = NULL;
+ return backItem;
+}
+
+template<typename ItemTypeTraits>
+typename IntrusiveLinkedList<ItemTypeTraits>::ItemType* IntrusiveLinkedList<ItemTypeTraits>::PopFront()
+{
+ D3D12MA_HEAVY_ASSERT(m_Count > 0);
+ ItemType* const frontItem = m_Front;
+ ItemType* const nextItem = ItemTypeTraits::GetNext(frontItem);
+ if (nextItem != NULL)
+ {
+ ItemTypeTraits::AccessPrev(nextItem) = NULL;
+ }
+ m_Front = nextItem;
+ --m_Count;
+ ItemTypeTraits::AccessPrev(frontItem) = NULL;
+ ItemTypeTraits::AccessNext(frontItem) = NULL;
+ return frontItem;
+}
+
+template<typename ItemTypeTraits>
+void IntrusiveLinkedList<ItemTypeTraits>::InsertBefore(ItemType* existingItem, ItemType* newItem)
+{
+ D3D12MA_HEAVY_ASSERT(newItem != NULL && ItemTypeTraits::GetPrev(newItem) == NULL && ItemTypeTraits::GetNext(newItem) == NULL);
+ if (existingItem != NULL)
+ {
+ ItemType* const prevItem = ItemTypeTraits::GetPrev(existingItem);
+ ItemTypeTraits::AccessPrev(newItem) = prevItem;
+ ItemTypeTraits::AccessNext(newItem) = existingItem;
+ ItemTypeTraits::AccessPrev(existingItem) = newItem;
+ if (prevItem != NULL)
+ {
+ ItemTypeTraits::AccessNext(prevItem) = newItem;
+ }
+ else
+ {
+ D3D12MA_HEAVY_ASSERT(m_Front == existingItem);
+ m_Front = newItem;
+ }
+ ++m_Count;
+ }
+ else
+ PushBack(newItem);
+}
+
+template<typename ItemTypeTraits>
+void IntrusiveLinkedList<ItemTypeTraits>::InsertAfter(ItemType* existingItem, ItemType* newItem)
+{
+ D3D12MA_HEAVY_ASSERT(newItem != NULL && ItemTypeTraits::GetPrev(newItem) == NULL && ItemTypeTraits::GetNext(newItem) == NULL);
+ if (existingItem != NULL)
+ {
+ ItemType* const nextItem = ItemTypeTraits::GetNext(existingItem);
+ ItemTypeTraits::AccessNext(newItem) = nextItem;
+ ItemTypeTraits::AccessPrev(newItem) = existingItem;
+ ItemTypeTraits::AccessNext(existingItem) = newItem;
+ if (nextItem != NULL)
+ {
+ ItemTypeTraits::AccessPrev(nextItem) = newItem;
+ }
+ else
+ {
+ D3D12MA_HEAVY_ASSERT(m_Back == existingItem);
+ m_Back = newItem;
+ }
+ ++m_Count;
+ }
+ else
+ return PushFront(newItem);
+}
+
+template<typename ItemTypeTraits>
+void IntrusiveLinkedList<ItemTypeTraits>::Remove(ItemType* item)
+{
+ D3D12MA_HEAVY_ASSERT(item != NULL && m_Count > 0);
+ if (ItemTypeTraits::GetPrev(item) != NULL)
+ {
+ ItemTypeTraits::AccessNext(ItemTypeTraits::AccessPrev(item)) = ItemTypeTraits::GetNext(item);
+ }
+ else
+ {
+ D3D12MA_HEAVY_ASSERT(m_Front == item);
+ m_Front = ItemTypeTraits::GetNext(item);
+ }
+
+ if (ItemTypeTraits::GetNext(item) != NULL)
+ {
+ ItemTypeTraits::AccessPrev(ItemTypeTraits::AccessNext(item)) = ItemTypeTraits::GetPrev(item);
+ }
+ else
+ {
+ D3D12MA_HEAVY_ASSERT(m_Back == item);
+ m_Back = ItemTypeTraits::GetPrev(item);
+ }
+ ItemTypeTraits::AccessPrev(item) = NULL;
+ ItemTypeTraits::AccessNext(item) = NULL;
+ --m_Count;
+}
+
+template<typename ItemTypeTraits>
+void IntrusiveLinkedList<ItemTypeTraits>::RemoveAll()
+{
+ if (!IsEmpty())
+ {
+ ItemType* item = m_Back;
+ while (item != NULL)
+ {
+ ItemType* const prevItem = ItemTypeTraits::AccessPrev(item);
+ ItemTypeTraits::AccessPrev(item) = NULL;
+ ItemTypeTraits::AccessNext(item) = NULL;
+ item = prevItem;
+ }
+ m_Front = NULL;
+ m_Back = NULL;
+ m_Count = 0;
+ }
+}
+#endif // _D3D12MA_INTRUSIVE_LINKED_LIST_FUNCTIONS
+#endif // _D3D12MA_INTRUSIVE_LINKED_LIST
+
+#ifndef _D3D12MA_ALLOCATION_OBJECT_ALLOCATOR
/*
Thread-safe wrapper over PoolAllocator free list, for allocation of Allocation objects.
*/
@@ -2585,9 +2717,11 @@
{
D3D12MA_CLASS_NO_COPY(AllocationObjectAllocator);
public:
- AllocationObjectAllocator(const ALLOCATION_CALLBACKS& allocationCallbacks);
+ AllocationObjectAllocator(const ALLOCATION_CALLBACKS& allocationCallbacks)
+ : m_Allocator(allocationCallbacks, 1024) {}
- template<typename... Types> Allocation* Allocate(Types... args);
+ template<typename... Types>
+ Allocation* Allocate(Types... args);
void Free(Allocation* alloc);
private:
@@ -2595,15 +2729,23 @@
PoolAllocator<Allocation> m_Allocator;
};
-////////////////////////////////////////////////////////////////////////////////
-// Private class BlockMetadata and derived classes - declarations
-
-enum SuballocationType
+#ifndef _D3D12MA_ALLOCATION_OBJECT_ALLOCATOR_FUNCTIONS
+template<typename... Types>
+Allocation* AllocationObjectAllocator::Allocate(Types... args)
{
- SUBALLOCATION_TYPE_FREE = 0,
- SUBALLOCATION_TYPE_ALLOCATION = 1,
-};
+ MutexLock mutexLock(m_Mutex);
+ return m_Allocator.Alloc(std::forward<Types>(args)...);
+}
+void AllocationObjectAllocator::Free(Allocation* alloc)
+{
+ MutexLock mutexLock(m_Mutex);
+ m_Allocator.Free(alloc);
+}
+#endif // _D3D12MA_ALLOCATION_OBJECT_ALLOCATOR_FUNCTIONS
+#endif // _D3D12MA_ALLOCATION_OBJECT_ALLOCATOR
+
+#ifndef _D3D12MA_SUBALLOCATION
/*
Represents a region of NormalBlock that is either assigned and returned as
allocated memory block or free.
@@ -2615,6 +2757,7 @@
void* userData;
SuballocationType type;
};
+using SuballocationList = List<Suballocation>;
// Comparator for offsets.
struct SuballocationOffsetLess
@@ -2624,6 +2767,7 @@
return lhs.offset < rhs.offset;
}
};
+
struct SuballocationOffsetGreater
{
bool operator()(const Suballocation& lhs, const Suballocation& rhs) const
@@ -2632,8 +2776,6 @@
}
};
-using SuballocationList = List<Suballocation>;
-
struct SuballocationItemSizeLess
{
bool operator()(const SuballocationList::iterator lhs, const SuballocationList::iterator rhs) const
@@ -2645,7 +2787,9 @@
return lhs->size < rhsSize;
}
};
+#endif // _D3D12MA_SUBALLOCATION
+#ifndef _D3D12MA_ALLOCATION_REQUEST
/*
Parameters of planned allocation inside a NormalBlock.
*/
@@ -2659,7 +2803,9 @@
SuballocationList::iterator item;
BOOL zeroInitialized;
};
+#endif // _D3D12MA_ALLOCATION_REQUEST
+#ifndef _D3D12MA_ZERO_INITIALIZED_RANGE
/*
Keeps track of the range of bytes that are surely initialized with zeros.
Everything outside of it is considered uninitialized memory that may contain
@@ -2670,53 +2816,61 @@
class ZeroInitializedRange
{
public:
- void Reset(UINT64 size)
- {
- D3D12MA_ASSERT(size > 0);
- m_ZeroBeg = 0;
- m_ZeroEnd = size;
- }
-
- BOOL IsRangeZeroInitialized(UINT64 beg, UINT64 end) const
- {
- D3D12MA_ASSERT(beg < end);
- return m_ZeroBeg <= beg && end <= m_ZeroEnd;
- }
-
- void MarkRangeAsUsed(UINT64 usedBeg, UINT64 usedEnd)
- {
- D3D12MA_ASSERT(usedBeg < usedEnd);
- // No new bytes marked.
- if(usedEnd <= m_ZeroBeg || m_ZeroEnd <= usedBeg)
- {
- return;
- }
- // All bytes marked.
- if(usedBeg <= m_ZeroBeg && m_ZeroEnd <= usedEnd)
- {
- m_ZeroBeg = m_ZeroEnd = 0;
- }
- // Some bytes marked.
- else
- {
- const UINT64 remainingZeroBefore = usedBeg > m_ZeroBeg ? usedBeg - m_ZeroBeg : 0;
- const UINT64 remainingZeroAfter = usedEnd < m_ZeroEnd ? m_ZeroEnd - usedEnd : 0;
- D3D12MA_ASSERT(remainingZeroBefore > 0 || remainingZeroAfter > 0);
- if(remainingZeroBefore > remainingZeroAfter)
- {
- m_ZeroEnd = usedBeg;
- }
- else
- {
- m_ZeroBeg = usedEnd;
- }
- }
- }
+ void Reset(UINT64 size);
+ BOOL IsRangeZeroInitialized(UINT64 beg, UINT64 end) const;
+ void MarkRangeAsUsed(UINT64 usedBeg, UINT64 usedEnd);
private:
UINT64 m_ZeroBeg = 0, m_ZeroEnd = 0;
};
+#ifndef _D3D12MA_ZERO_INITIALIZED_RANGE_FUNCTIONS
+void ZeroInitializedRange::Reset(UINT64 size)
+{
+ D3D12MA_ASSERT(size > 0);
+ m_ZeroBeg = 0;
+ m_ZeroEnd = size;
+}
+
+BOOL ZeroInitializedRange::IsRangeZeroInitialized(UINT64 beg, UINT64 end) const
+{
+ D3D12MA_ASSERT(beg < end);
+ return m_ZeroBeg <= beg && end <= m_ZeroEnd;
+}
+
+void ZeroInitializedRange::MarkRangeAsUsed(UINT64 usedBeg, UINT64 usedEnd)
+{
+ D3D12MA_ASSERT(usedBeg < usedEnd);
+ // No new bytes marked.
+ if (usedEnd <= m_ZeroBeg || m_ZeroEnd <= usedBeg)
+ {
+ return;
+ }
+ // All bytes marked.
+ if (usedBeg <= m_ZeroBeg && m_ZeroEnd <= usedEnd)
+ {
+ m_ZeroBeg = m_ZeroEnd = 0;
+ }
+ // Some bytes marked.
+ else
+ {
+ const UINT64 remainingZeroBefore = usedBeg > m_ZeroBeg ? usedBeg - m_ZeroBeg : 0;
+ const UINT64 remainingZeroAfter = usedEnd < m_ZeroEnd ? m_ZeroEnd - usedEnd : 0;
+ D3D12MA_ASSERT(remainingZeroBefore > 0 || remainingZeroAfter > 0);
+ if (remainingZeroBefore > remainingZeroAfter)
+ {
+ m_ZeroEnd = usedBeg;
+ }
+ else
+ {
+ m_ZeroBeg = usedEnd;
+ }
+ }
+}
+#endif // _D3D12MA_ZERO_INITIALIZED_RANGE_FUNCTIONS
+#endif // _D3D12MA_ZERO_INITIALIZED_RANGE
+
+#ifndef _D3D12MA_BLOCK_METADATA
/*
Data structure used for bookkeeping of allocations and unused ranges of memory
in a single ID3D12Heap memory block.
@@ -2726,8 +2880,8 @@
public:
BlockMetadata(const ALLOCATION_CALLBACKS* allocationCallbacks, bool isVirtual);
virtual ~BlockMetadata() = default;
- virtual void Init(UINT64 size) { m_Size = size; }
+ virtual void Init(UINT64 size) { m_Size = size; }
// Validates all data structures inside this object. If not valid, returns false.
virtual bool Validate() const = 0;
UINT64 GetSize() const { return m_Size; }
@@ -2788,12 +2942,97 @@
D3D12MA_CLASS_NO_COPY(BlockMetadata);
};
+#ifndef _D3D12MA_BLOCK_METADATA_FUNCTIONS
+BlockMetadata::BlockMetadata(const ALLOCATION_CALLBACKS* allocationCallbacks, bool isVirtual)
+ : m_Size(0),
+ m_IsVirtual(isVirtual),
+ m_pAllocationCallbacks(allocationCallbacks)
+{
+ D3D12MA_ASSERT(allocationCallbacks);
+}
+
+void BlockMetadata::PrintDetailedMap_Begin(JsonWriter& json,
+ UINT64 unusedBytes, size_t allocationCount, size_t unusedRangeCount) const
+{
+ json.BeginObject();
+
+ json.WriteString(L"TotalBytes");
+ json.WriteNumber(GetSize());
+
+ json.WriteString(L"UnusedBytes");
+ json.WriteNumber(unusedBytes);
+
+ json.WriteString(L"Allocations");
+ json.WriteNumber(allocationCount);
+
+ json.WriteString(L"UnusedRanges");
+ json.WriteNumber(unusedRangeCount);
+
+ json.WriteString(L"Suballocations");
+ json.BeginArray();
+}
+
+void BlockMetadata::PrintDetailedMap_Allocation(JsonWriter& json,
+ UINT64 offset, UINT64 size, void* userData) const
+{
+ json.BeginObject(true);
+
+ json.WriteString(L"Offset");
+ json.WriteNumber(offset);
+
+ if (IsVirtual())
+ {
+ json.WriteString(L"Type");
+ json.WriteString(L"ALLOCATION");
+ json.WriteString(L"Size");
+ json.WriteNumber(size);
+ if (userData)
+ {
+ json.WriteString(L"UserData");
+ json.WriteNumber((uintptr_t)userData);
+ }
+ }
+ else
+ {
+ const Allocation* const alloc = (const Allocation*)userData;
+ D3D12MA_ASSERT(alloc);
+ json.AddAllocationToObject(*alloc);
+ }
+ json.EndObject();
+}
+
+void BlockMetadata::PrintDetailedMap_UnusedRange(JsonWriter& json,
+ UINT64 offset, UINT64 size) const
+{
+ json.BeginObject(true);
+
+ json.WriteString(L"Offset");
+ json.WriteNumber(offset);
+
+ json.WriteString(L"Type");
+ json.WriteString(L"FREE");
+
+ json.WriteString(L"Size");
+ json.WriteNumber(size);
+
+ json.EndObject();
+}
+
+void BlockMetadata::PrintDetailedMap_End(JsonWriter& json) const
+{
+ json.EndArray();
+ json.EndObject();
+}
+#endif // _D3D12MA_BLOCK_METADATA_FUNCTIONS
+#endif // _D3D12MA_BLOCK_METADATA
+
#if 0
+#ifndef _D3D12MA_BLOCK_METADATA_GENERIC
class BlockMetadata_Generic : public BlockMetadata
{
public:
BlockMetadata_Generic(const ALLOCATION_CALLBACKS* allocationCallbacks, bool isVirtual);
- virtual ~BlockMetadata_Generic();
+ virtual ~BlockMetadata_Generic() = default;
size_t GetAllocationCount() const override { return m_Suballocations.size() - m_FreeCount; }
UINT64 GetSumFreeSize() const override { return m_SumFreeSize; }
@@ -2861,8 +3100,537 @@
D3D12MA_CLASS_NO_COPY(BlockMetadata_Generic)
};
+
+#ifndef _D3D12MA_BLOCK_METADATA_GENERIC_FUNCTIONS
+BlockMetadata_Generic::BlockMetadata_Generic(const ALLOCATION_CALLBACKS* allocationCallbacks, bool isVirtual)
+ : BlockMetadata(allocationCallbacks, isVirtual),
+ m_FreeCount(0),
+ m_SumFreeSize(0),
+ m_Suballocations(*allocationCallbacks),
+ m_FreeSuballocationsBySize(*allocationCallbacks)
+{
+ D3D12MA_ASSERT(allocationCallbacks);
+}
+
+void BlockMetadata_Generic::Init(UINT64 size)
+{
+ BlockMetadata::Init(size);
+ m_ZeroInitializedRange.Reset(size);
+
+ m_FreeCount = 1;
+ m_SumFreeSize = size;
+
+ Suballocation suballoc = {};
+ suballoc.offset = 0;
+ suballoc.size = size;
+ suballoc.type = SUBALLOCATION_TYPE_FREE;
+ suballoc.userData = NULL;
+
+ D3D12MA_ASSERT(size > MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER);
+ m_Suballocations.push_back(suballoc);
+ SuballocationList::iterator suballocItem = m_Suballocations.end();
+ --suballocItem;
+ m_FreeSuballocationsBySize.push_back(suballocItem);
+}
+
+bool BlockMetadata_Generic::Validate() const
+{
+ D3D12MA_VALIDATE(!m_Suballocations.empty());
+
+ // Expected offset of new suballocation as calculated from previous ones.
+ UINT64 calculatedOffset = 0;
+ // Expected number of free suballocations as calculated from traversing their list.
+ UINT calculatedFreeCount = 0;
+ // Expected sum size of free suballocations as calculated from traversing their list.
+ UINT64 calculatedSumFreeSize = 0;
+ // Expected number of free suballocations that should be registered in
+ // m_FreeSuballocationsBySize calculated from traversing their list.
+ size_t freeSuballocationsToRegister = 0;
+ // True if previous visited suballocation was free.
+ bool prevFree = false;
+
+ for (const auto& subAlloc : m_Suballocations)
+ {
+ // Actual offset of this suballocation doesn't match expected one.
+ D3D12MA_VALIDATE(subAlloc.offset == calculatedOffset);
+
+ const bool currFree = (subAlloc.type == SUBALLOCATION_TYPE_FREE);
+ // Two adjacent free suballocations are invalid. They should be merged.
+ D3D12MA_VALIDATE(!prevFree || !currFree);
+
+ const Allocation* const alloc = (Allocation*)subAlloc.userData;
+ if (!IsVirtual())
+ {
+ D3D12MA_VALIDATE(currFree == (alloc == NULL));
+ }
+
+ if (currFree)
+ {
+ calculatedSumFreeSize += subAlloc.size;
+ ++calculatedFreeCount;
+ if (subAlloc.size >= MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
+ {
+ ++freeSuballocationsToRegister;
+ }
+
+ // Margin required between allocations - every free space must be at least that large.
+ D3D12MA_VALIDATE(subAlloc.size >= GetDebugMargin());
+ }
+ else
+ {
+ if (!IsVirtual())
+ {
+ D3D12MA_VALIDATE(alloc->GetOffset() == subAlloc.offset);
+ D3D12MA_VALIDATE(alloc->GetSize() == subAlloc.size);
+ }
+
+ // Margin required between allocations - previous allocation must be free.
+ D3D12MA_VALIDATE(GetDebugMargin() == 0 || prevFree);
+ }
+
+ calculatedOffset += subAlloc.size;
+ prevFree = currFree;
+ }
+
+ // Number of free suballocations registered in m_FreeSuballocationsBySize doesn't
+ // match expected one.
+ D3D12MA_VALIDATE(m_FreeSuballocationsBySize.size() == freeSuballocationsToRegister);
+
+ UINT64 lastSize = 0;
+ for (size_t i = 0; i < m_FreeSuballocationsBySize.size(); ++i)
+ {
+ SuballocationList::iterator suballocItem = m_FreeSuballocationsBySize[i];
+
+ // Only free suballocations can be registered in m_FreeSuballocationsBySize.
+ D3D12MA_VALIDATE(suballocItem->type == SUBALLOCATION_TYPE_FREE);
+ // They must be sorted by size ascending.
+ D3D12MA_VALIDATE(suballocItem->size >= lastSize);
+
+ lastSize = suballocItem->size;
+ }
+
+ // Check if totals match calculacted values.
+ D3D12MA_VALIDATE(ValidateFreeSuballocationList());
+ D3D12MA_VALIDATE(calculatedOffset == GetSize());
+ D3D12MA_VALIDATE(calculatedSumFreeSize == m_SumFreeSize);
+ D3D12MA_VALIDATE(calculatedFreeCount == m_FreeCount);
+
+ return true;
+}
+
+bool BlockMetadata_Generic::IsEmpty() const
+{
+ return (m_Suballocations.size() == 1) && (m_FreeCount == 1);
+}
+
+void BlockMetadata_Generic::GetAllocationInfo(AllocHandle allocHandle, VIRTUAL_ALLOCATION_INFO& outInfo) const
+{
+ Suballocation& suballoc = *FindAtOffset((UINT64)allocHandle - 1).dropConst();
+ outInfo.Offset = suballoc.offset;
+ outInfo.Size = suballoc.size;
+ outInfo.pUserData = suballoc.userData;
+}
+
+bool BlockMetadata_Generic::CreateAllocationRequest(
+ UINT64 allocSize,
+ UINT64 allocAlignment,
+ bool upperAddress,
+ AllocationRequest* pAllocationRequest)
+{
+ D3D12MA_ASSERT(allocSize > 0);
+ D3D12MA_ASSERT(!upperAddress && "ALLOCATION_FLAG_UPPER_ADDRESS can be used only with linear algorithm.");
+ D3D12MA_ASSERT(pAllocationRequest != NULL);
+ D3D12MA_HEAVY_ASSERT(Validate());
+
+ // There is not enough total free space in this block to fullfill the request: Early return.
+ if (m_SumFreeSize < allocSize + GetDebugMargin())
+ {
+ return false;
+ }
+
+ // New algorithm, efficiently searching freeSuballocationsBySize.
+ const size_t freeSuballocCount = m_FreeSuballocationsBySize.size();
+ if (freeSuballocCount > 0)
+ {
+ // Find first free suballocation with size not less than allocSize + GetDebugMargin().
+ SuballocationList::iterator* const it = BinaryFindFirstNotLess(
+ m_FreeSuballocationsBySize.data(),
+ m_FreeSuballocationsBySize.data() + freeSuballocCount,
+ allocSize + GetDebugMargin(),
+ SuballocationItemSizeLess());
+ size_t index = it - m_FreeSuballocationsBySize.data();
+ for (; index < freeSuballocCount; ++index)
+ {
+ if (CheckAllocation(
+ allocSize,
+ allocAlignment,
+ m_FreeSuballocationsBySize[index],
+ &pAllocationRequest->allocHandle,
+ &pAllocationRequest->sumFreeSize,
+ &pAllocationRequest->sumItemSize,
+ &pAllocationRequest->zeroInitialized))
+ {
+ pAllocationRequest->item = m_FreeSuballocationsBySize[index];
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+void BlockMetadata_Generic::Alloc(
+ const AllocationRequest& request,
+ UINT64 allocSize,
+ void* userData)
+{
+ D3D12MA_ASSERT(request.item != m_Suballocations.end());
+ Suballocation& suballoc = *request.item;
+ // Given suballocation is a free block.
+ D3D12MA_ASSERT(suballoc.type == SUBALLOCATION_TYPE_FREE);
+ // Given offset is inside this suballocation.
+ UINT64 offset = (UINT64)request.allocHandle - 1;
+ D3D12MA_ASSERT(offset >= suballoc.offset);
+ const UINT64 paddingBegin = offset - suballoc.offset;
+ D3D12MA_ASSERT(suballoc.size >= paddingBegin + allocSize);
+ const UINT64 paddingEnd = suballoc.size - paddingBegin - allocSize;
+
+ // Unregister this free suballocation from m_FreeSuballocationsBySize and update
+ // it to become used.
+ UnregisterFreeSuballocation(request.item);
+
+ suballoc.offset = offset;
+ suballoc.size = allocSize;
+ suballoc.type = SUBALLOCATION_TYPE_ALLOCATION;
+ suballoc.userData = userData;
+
+ // If there are any free bytes remaining at the end, insert new free suballocation after current one.
+ if (paddingEnd)
+ {
+ Suballocation paddingSuballoc = {};
+ paddingSuballoc.offset = offset + allocSize;
+ paddingSuballoc.size = paddingEnd;
+ paddingSuballoc.type = SUBALLOCATION_TYPE_FREE;
+ SuballocationList::iterator next = request.item;
+ ++next;
+ const SuballocationList::iterator paddingEndItem =
+ m_Suballocations.insert(next, paddingSuballoc);
+ RegisterFreeSuballocation(paddingEndItem);
+ }
+
+ // If there are any free bytes remaining at the beginning, insert new free suballocation before current one.
+ if (paddingBegin)
+ {
+ Suballocation paddingSuballoc = {};
+ paddingSuballoc.offset = offset - paddingBegin;
+ paddingSuballoc.size = paddingBegin;
+ paddingSuballoc.type = SUBALLOCATION_TYPE_FREE;
+ const SuballocationList::iterator paddingBeginItem =
+ m_Suballocations.insert(request.item, paddingSuballoc);
+ RegisterFreeSuballocation(paddingBeginItem);
+ }
+
+ // Update totals.
+ m_FreeCount = m_FreeCount - 1;
+ if (paddingBegin > 0)
+ {
+ ++m_FreeCount;
+ }
+ if (paddingEnd > 0)
+ {
+ ++m_FreeCount;
+ }
+ m_SumFreeSize -= allocSize;
+
+ m_ZeroInitializedRange.MarkRangeAsUsed(offset, offset + allocSize);
+}
+
+void BlockMetadata_Generic::Free(AllocHandle allocHandle)
+{
+ FreeSuballocation(FindAtOffset((UINT64)allocHandle - 1).dropConst());
+}
+
+void BlockMetadata_Generic::Clear()
+{
+ m_FreeCount = 1;
+ m_SumFreeSize = GetSize();
+
+ m_Suballocations.clear();
+ Suballocation suballoc = {};
+ suballoc.offset = 0;
+ suballoc.size = GetSize();
+ suballoc.type = SUBALLOCATION_TYPE_FREE;
+ m_Suballocations.push_back(suballoc);
+
+ m_FreeSuballocationsBySize.clear();
+ m_FreeSuballocationsBySize.push_back(m_Suballocations.begin());
+}
+
+SuballocationList::const_iterator BlockMetadata_Generic::FindAtOffset(UINT64 offset) const
+{
+ const UINT64 last = m_Suballocations.crbegin()->offset;
+ if (last == offset)
+ return m_Suballocations.crbegin();
+ const UINT64 first = m_Suballocations.cbegin()->offset;
+ if (first == offset)
+ return m_Suballocations.cbegin();
+
+ const size_t suballocCount = m_Suballocations.size();
+ const UINT64 step = (last - first + m_Suballocations.cbegin()->size) / suballocCount;
+ auto findSuballocation = [&](auto begin, auto end) -> SuballocationList::const_iterator
+ {
+ for (auto suballocItem = begin;
+ suballocItem != end;
+ ++suballocItem)
+ {
+ const Suballocation& suballoc = *suballocItem;
+ if (suballoc.offset == offset)
+ return suballocItem;
+ }
+ D3D12MA_ASSERT(false && "Not found!");
+ return m_Suballocations.end();
+ };
+ // If requested offset is closer to the end of range, search from the end
+ if ((offset - first) > suballocCount * step / 2)
+ {
+ return findSuballocation(m_Suballocations.crbegin(), m_Suballocations.crend());
+ }
+ return findSuballocation(m_Suballocations.cbegin(), m_Suballocations.cend());
+}
+
+bool BlockMetadata_Generic::ValidateFreeSuballocationList() const
+{
+ UINT64 lastSize = 0;
+ for (size_t i = 0, count = m_FreeSuballocationsBySize.size(); i < count; ++i)
+ {
+ const SuballocationList::iterator it = m_FreeSuballocationsBySize[i];
+
+ D3D12MA_VALIDATE(it->type == SUBALLOCATION_TYPE_FREE);
+ D3D12MA_VALIDATE(it->size >= MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER);
+ D3D12MA_VALIDATE(it->size >= lastSize);
+ lastSize = it->size;
+ }
+ return true;
+}
+
+bool BlockMetadata_Generic::CheckAllocation(
+ UINT64 allocSize,
+ UINT64 allocAlignment,
+ SuballocationList::const_iterator suballocItem,
+ AllocHandle* pAllocHandle,
+ UINT64* pSumFreeSize,
+ UINT64* pSumItemSize,
+ BOOL* pZeroInitialized) const
+{
+ D3D12MA_ASSERT(allocSize > 0);
+ D3D12MA_ASSERT(suballocItem != m_Suballocations.cend());
+ D3D12MA_ASSERT(pAllocHandle != NULL && pZeroInitialized != NULL);
+
+ *pSumFreeSize = 0;
+ *pSumItemSize = 0;
+ *pZeroInitialized = FALSE;
+
+ const Suballocation& suballoc = *suballocItem;
+ D3D12MA_ASSERT(suballoc.type == SUBALLOCATION_TYPE_FREE);
+
+ *pSumFreeSize = suballoc.size;
+
+ // Size of this suballocation is too small for this request: Early return.
+ if (suballoc.size < allocSize)
+ {
+ return false;
+ }
+
+ // Start from offset equal to beginning of this suballocation and debug margin of previous allocation if present.
+ UINT64 offset = suballoc.offset + (suballocItem == m_Suballocations.cbegin() ? 0 : GetDebugMargin());
+
+ // Apply alignment.
+ offset = AlignUp(offset, allocAlignment);
+
+ // Calculate padding at the beginning based on current offset.
+ const UINT64 paddingBegin = offset - suballoc.offset;
+
+ // Fail if requested size plus margin after is bigger than size of this suballocation.
+ if (paddingBegin + allocSize + GetDebugMargin() > suballoc.size)
+ {
+ return false;
+ }
+
+ // All tests passed: Success. Offset is already filled.
+ *pZeroInitialized = m_ZeroInitializedRange.IsRangeZeroInitialized(offset, offset + allocSize);
+ *pAllocHandle = (AllocHandle)(offset + 1);
+ return true;
+}
+
+void BlockMetadata_Generic::MergeFreeWithNext(SuballocationList::iterator item)
+{
+ D3D12MA_ASSERT(item != m_Suballocations.end());
+ D3D12MA_ASSERT(item->type == SUBALLOCATION_TYPE_FREE);
+
+ SuballocationList::iterator nextItem = item;
+ ++nextItem;
+ D3D12MA_ASSERT(nextItem != m_Suballocations.end());
+ D3D12MA_ASSERT(nextItem->type == SUBALLOCATION_TYPE_FREE);
+
+ item->size += nextItem->size;
+ --m_FreeCount;
+ m_Suballocations.erase(nextItem);
+}
+
+SuballocationList::iterator BlockMetadata_Generic::FreeSuballocation(SuballocationList::iterator suballocItem)
+{
+ // Change this suballocation to be marked as free.
+ Suballocation& suballoc = *suballocItem;
+ suballoc.type = SUBALLOCATION_TYPE_FREE;
+ suballoc.userData = NULL;
+
+ // Update totals.
+ ++m_FreeCount;
+ m_SumFreeSize += suballoc.size;
+
+ // Merge with previous and/or next suballocation if it's also free.
+ bool mergeWithNext = false;
+ bool mergeWithPrev = false;
+
+ SuballocationList::iterator nextItem = suballocItem;
+ ++nextItem;
+ if ((nextItem != m_Suballocations.end()) && (nextItem->type == SUBALLOCATION_TYPE_FREE))
+ {
+ mergeWithNext = true;
+ }
+
+ SuballocationList::iterator prevItem = suballocItem;
+ if (suballocItem != m_Suballocations.begin())
+ {
+ --prevItem;
+ if (prevItem->type == SUBALLOCATION_TYPE_FREE)
+ {
+ mergeWithPrev = true;
+ }
+ }
+
+ if (mergeWithNext)
+ {
+ UnregisterFreeSuballocation(nextItem);
+ MergeFreeWithNext(suballocItem);
+ }
+
+ if (mergeWithPrev)
+ {
+ UnregisterFreeSuballocation(prevItem);
+ MergeFreeWithNext(prevItem);
+ RegisterFreeSuballocation(prevItem);
+ return prevItem;
+ }
+ else
+ {
+ RegisterFreeSuballocation(suballocItem);
+ return suballocItem;
+ }
+}
+
+void BlockMetadata_Generic::RegisterFreeSuballocation(SuballocationList::iterator item)
+{
+ D3D12MA_ASSERT(item->type == SUBALLOCATION_TYPE_FREE);
+ D3D12MA_ASSERT(item->size > 0);
+
+ // You may want to enable this validation at the beginning or at the end of
+ // this function, depending on what do you want to check.
+ D3D12MA_HEAVY_ASSERT(ValidateFreeSuballocationList());
+
+ if (item->size >= MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
+ {
+ if (m_FreeSuballocationsBySize.empty())
+ {
+ m_FreeSuballocationsBySize.push_back(item);
+ }
+ else
+ {
+ m_FreeSuballocationsBySize.InsertSorted(item, SuballocationItemSizeLess());
+ }
+ }
+
+ //D3D12MA_HEAVY_ASSERT(ValidateFreeSuballocationList());
+}
+
+void BlockMetadata_Generic::UnregisterFreeSuballocation(SuballocationList::iterator item)
+{
+ D3D12MA_ASSERT(item->type == SUBALLOCATION_TYPE_FREE);
+ D3D12MA_ASSERT(item->size > 0);
+
+ // You may want to enable this validation at the beginning or at the end of
+ // this function, depending on what do you want to check.
+ D3D12MA_HEAVY_ASSERT(ValidateFreeSuballocationList());
+
+ if (item->size >= MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
+ {
+ SuballocationList::iterator* const it = BinaryFindFirstNotLess(
+ m_FreeSuballocationsBySize.data(),
+ m_FreeSuballocationsBySize.data() + m_FreeSuballocationsBySize.size(),
+ item,
+ SuballocationItemSizeLess());
+ for (size_t index = it - m_FreeSuballocationsBySize.data();
+ index < m_FreeSuballocationsBySize.size();
+ ++index)
+ {
+ if (m_FreeSuballocationsBySize[index] == item)
+ {
+ m_FreeSuballocationsBySize.remove(index);
+ return;
+ }
+ D3D12MA_ASSERT((m_FreeSuballocationsBySize[index]->size == item->size) && "Not found.");
+ }
+ D3D12MA_ASSERT(0 && "Not found.");
+ }
+
+ //D3D12MA_HEAVY_ASSERT(ValidateFreeSuballocationList());
+}
+
+void BlockMetadata_Generic::SetAllocationUserData(AllocHandle allocHandle, void* userData)
+{
+ Suballocation& suballoc = *FindAtOffset((UINT64)allocHandle - 1).dropConst();
+ suballoc.userData = userData;
+}
+
+void BlockMetadata_Generic::AddStatistics(Statistics& inoutStats) const
+{
+ inoutStats.BlockCount++;
+ inoutStats.AllocationCount += (UINT)m_Suballocations.size() - m_FreeCount;
+ inoutStats.BlockBytes += GetSize();
+ inoutStats.AllocationBytes += GetSize() - m_SumFreeSize;
+}
+
+void BlockMetadata_Generic::AddDetailedStatistics(DetailedStatistics& inoutStats) const
+{
+ inoutStats.Stats.BlockCount++;
+ inoutStats.Stats.BlockBytes += GetSize();
+
+ for (const auto& suballoc : m_Suballocations)
+ {
+ if (suballoc.type == SUBALLOCATION_TYPE_FREE)
+ AddDetailedStatisticsUnusedRange(inoutStats, suballoc.size);
+ else
+ AddDetailedStatisticsAllocation(inoutStats, suballoc.size);
+ }
+}
+
+void BlockMetadata_Generic::WriteAllocationInfoToJson(JsonWriter& json) const
+{
+ PrintDetailedMap_Begin(json, GetSumFreeSize(), GetAllocationCount(), m_FreeCount);
+ for (const auto& suballoc : m_Suballocations)
+ {
+ if (suballoc.type == SUBALLOCATION_TYPE_FREE)
+ PrintDetailedMap_UnusedRange(json, suballoc.offset, suballoc.size);
+ else
+ PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.size, suballoc.userData);
+ }
+ PrintDetailedMap_End(json);
+}
+#endif // _D3D12MA_BLOCK_METADATA_GENERIC_FUNCTIONS
+#endif // _D3D12MA_BLOCK_METADATA_GENERIC
#endif // #if 0
+#ifndef _D3D12MA_BLOCK_METADATA_LINEAR
class BlockMetadata_Linear : public BlockMetadata
{
public:
@@ -2963,1316 +3731,7 @@
D3D12MA_CLASS_NO_COPY(BlockMetadata_Linear)
};
-class BlockMetadata_TLSF : public BlockMetadata
-{
-public:
- BlockMetadata_TLSF(const ALLOCATION_CALLBACKS* allocationCallbacks, bool isVirtual);
- virtual ~BlockMetadata_TLSF();
-
- size_t GetAllocationCount() const override { return m_AllocCount; }
- UINT64 GetSumFreeSize() const override { return m_BlocksFreeSize + m_NullBlock->size; }
- bool IsEmpty() const override { return m_NullBlock->offset == 0; }
- UINT64 GetAllocationOffset(AllocHandle allocHandle) const override { return ((Block*)allocHandle)->offset; };
-
- void Init(UINT64 size) override;
- bool Validate() const override;
- void GetAllocationInfo(AllocHandle allocHandle, VIRTUAL_ALLOCATION_INFO& outInfo) const override;
-
- bool CreateAllocationRequest(
- UINT64 allocSize,
- UINT64 allocAlignment,
- bool upperAddress,
- AllocationRequest* pAllocationRequest) override;
-
- void Alloc(
- const AllocationRequest& request,
- UINT64 allocSize,
- void* userData) override;
-
- void Free(AllocHandle allocHandle) override;
- void Clear() override;
-
- void SetAllocationUserData(AllocHandle allocHandle, void* userData) override;
-
- void AddStatistics(Statistics& inoutStats) const override;
- void AddDetailedStatistics(DetailedStatistics& inoutStats) const override;
- void WriteAllocationInfoToJson(JsonWriter& json) const override;
-
-private:
- // According to original paper it should be preferable 4 or 5:
- // M. Masmano, I. Ripoll, A. Crespo, and J. Real "TLSF: a New Dynamic Memory Allocator for Real-Time Systems"
- // http://www.gii.upv.es/tlsf/files/ecrts04_tlsf.pdf
- static const UINT8 SECOND_LEVEL_INDEX = 5;
- static const UINT16 SMALL_BUFFER_SIZE = 256;
- static const UINT INITIAL_BLOCK_ALLOC_COUNT = 16;
- static const UINT8 MEMORY_CLASS_SHIFT = 7;
- static const UINT8 MAX_MEMORY_CLASSES = 65 - MEMORY_CLASS_SHIFT;
-
- class Block
- {
- public:
- UINT64 offset;
- UINT64 size;
- Block* prevPhysical;
- Block* nextPhysical;
-
- void MarkFree() { prevFree = NULL; }
- void MarkTaken() { prevFree = this; }
- bool IsFree() const { return prevFree != this; }
- void*& UserData() { D3D12MA_HEAVY_ASSERT(!IsFree()); return userData; }
- Block*& PrevFree() { return prevFree; }
- Block*& NextFree() { D3D12MA_HEAVY_ASSERT(IsFree()); return nextFree; }
-
- private:
- Block* prevFree; // Address of the same block here indicates that block is taken
- union
- {
- Block* nextFree;
- void* userData;
- };
- };
-
- size_t m_AllocCount;
- // Total number of free blocks besides null block
- size_t m_BlocksFreeCount;
- // Total size of free blocks excluding null block
- UINT64 m_BlocksFreeSize;
- UINT32 m_IsFreeBitmap;
- UINT8 m_MemoryClasses;
- UINT32 m_InnerIsFreeBitmap[MAX_MEMORY_CLASSES];
- UINT32 m_ListsCount;
- /*
- * 0: 0-3 lists for small buffers
- * 1+: 0-(2^SLI-1) lists for normal buffers
- */
- Block** m_FreeList;
- PoolAllocator<Block> m_BlockAllocator;
- Block* m_NullBlock;
-
- UINT8 SizeToMemoryClass(UINT64 size) const;
- UINT16 SizeToSecondIndex(UINT64 size, UINT8 memoryClass) const;
- UINT32 GetListIndex(UINT8 memoryClass, UINT16 secondIndex) const;
- UINT32 GetListIndex(UINT64 size) const;
-
- void RemoveFreeBlock(Block* block);
- void InsertFreeBlock(Block* block);
- void MergeBlock(Block* block, Block* prev);
-
- Block* FindFreeBlock(UINT64 size, UINT32& listIndex) const;
- bool CheckBlock(
- Block& block,
- UINT32 listIndex,
- UINT64 allocSize,
- UINT64 allocAlignment,
- AllocationRequest* pAllocationRequest);
-
- D3D12MA_CLASS_NO_COPY(BlockMetadata_TLSF)
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// Private class MemoryBlock definition
-
-/*
-Represents a single block of device memory (heap).
-Base class for inheritance.
-Thread-safety: This class must be externally synchronized.
-*/
-class MemoryBlock
-{
-public:
- MemoryBlock(
- AllocatorPimpl* allocator,
- const D3D12_HEAP_PROPERTIES& heapProps,
- D3D12_HEAP_FLAGS heapFlags,
- UINT64 size,
- UINT id);
- virtual ~MemoryBlock();
- // Creates the ID3D12Heap.
-
- const D3D12_HEAP_PROPERTIES& GetHeapProperties() const { return m_HeapProps; }
- D3D12_HEAP_FLAGS GetHeapFlags() const { return m_HeapFlags; }
- UINT64 GetSize() const { return m_Size; }
- UINT GetId() const { return m_Id; }
- ID3D12Heap* GetHeap() const { return m_Heap; }
-
-protected:
- AllocatorPimpl* const m_Allocator;
- const D3D12_HEAP_PROPERTIES m_HeapProps;
- const D3D12_HEAP_FLAGS m_HeapFlags;
- const UINT64 m_Size;
- const UINT m_Id;
-
- HRESULT Init(ID3D12ProtectedResourceSession* pProtectedSession);
-
-private:
- ID3D12Heap* m_Heap = NULL;
-
- D3D12MA_CLASS_NO_COPY(MemoryBlock)
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// Private class NormalBlock definition
-
-/*
-Represents a single block of device memory (heap) with all the data about its
-regions (aka suballocations, Allocation), assigned and free.
-Thread-safety: This class must be externally synchronized.
-*/
-class NormalBlock : public MemoryBlock
-{
-public:
- BlockMetadata* m_pMetadata;
-
- NormalBlock(
- AllocatorPimpl* allocator,
- BlockVector* blockVector,
- const D3D12_HEAP_PROPERTIES& heapProps,
- D3D12_HEAP_FLAGS heapFlags,
- UINT64 size,
- UINT id);
- virtual ~NormalBlock();
-
- BlockVector* GetBlockVector() const { return m_BlockVector; }
-
- // 'algorithm' should be one of the *_ALGORITHM_* flags in enums POOL_FLAGS or VIRTUAL_BLOCK_FLAGS
- HRESULT Init(UINT32 algorithm, ID3D12ProtectedResourceSession* pProtectedSession);
-
- // Validates all data structures inside this object. If not valid, returns false.
- bool Validate() const;
-
-private:
- BlockVector* m_BlockVector;
-
- D3D12MA_CLASS_NO_COPY(NormalBlock)
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// Private class CommittedAllocationList definition
-
-struct CommittedAllocationListItemTraits
-{
- using ItemType = Allocation;
- static ItemType* GetPrev(const ItemType* item)
- {
- D3D12MA_ASSERT(item->m_PackedData.GetType() == Allocation::TYPE_COMMITTED || item->m_PackedData.GetType() == Allocation::TYPE_HEAP);
- return item->m_Committed.prev;
- }
- static ItemType* GetNext(const ItemType* item)
- {
- D3D12MA_ASSERT(item->m_PackedData.GetType() == Allocation::TYPE_COMMITTED || item->m_PackedData.GetType() == Allocation::TYPE_HEAP);
- return item->m_Committed.next;
- }
- static ItemType*& AccessPrev(ItemType* item)
- {
- D3D12MA_ASSERT(item->m_PackedData.GetType() == Allocation::TYPE_COMMITTED || item->m_PackedData.GetType() == Allocation::TYPE_HEAP);
- return item->m_Committed.prev;
- }
- static ItemType*& AccessNext(ItemType* item)
- {
- D3D12MA_ASSERT(item->m_PackedData.GetType() == Allocation::TYPE_COMMITTED || item->m_PackedData.GetType() == Allocation::TYPE_HEAP);
- return item->m_Committed.next;
- }
-};
-
-/*
-Stores linked list of Allocation objects that are of TYPE_COMMITTED or TYPE_HEAP.
-Thread-safe, synchronized internally.
-*/
-class CommittedAllocationList
-{
-public:
- CommittedAllocationList();
- void Init(bool useMutex, D3D12_HEAP_TYPE heapType, PoolPimpl* pool);
- ~CommittedAllocationList();
-
- D3D12_HEAP_TYPE GetHeapType() const { return m_HeapType; }
- PoolPimpl* GetPool() const { return m_Pool; }
- UINT GetMemorySegmentGroup(AllocatorPimpl* allocator) const;
-
- void AddStatistics(Statistics& inoutStats);
- void AddDetailedStatistics(DetailedStatistics& inoutStats);
- // Writes JSON array with the list of allocations.
- void BuildStatsString(JsonWriter& json);
-
- void Register(Allocation* alloc);
- void Unregister(Allocation* alloc);
-
-private:
- bool m_UseMutex = true;
- D3D12_HEAP_TYPE m_HeapType = D3D12_HEAP_TYPE_CUSTOM;
- PoolPimpl* m_Pool = NULL;
-
- D3D12MA_RW_MUTEX m_Mutex;
- using CommittedAllocationLinkedList = IntrusiveLinkedList<CommittedAllocationListItemTraits>;
- CommittedAllocationLinkedList m_AllocationList;
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// Private class BlockVector definition
-
-/*
-Sequence of NormalBlock. Represents memory blocks allocated for a specific
-heap type and possibly resource type (if only Tier 1 is supported).
-
-Synchronized internally with a mutex.
-*/
-class BlockVector
-{
- D3D12MA_CLASS_NO_COPY(BlockVector)
-public:
- BlockVector(
- AllocatorPimpl* hAllocator,
- const D3D12_HEAP_PROPERTIES& heapProps,
- D3D12_HEAP_FLAGS heapFlags,
- UINT64 preferredBlockSize,
- size_t minBlockCount,
- size_t maxBlockCount,
- bool explicitBlockSize,
- UINT64 minAllocationAlignment,
- UINT32 algorithm,
- ID3D12ProtectedResourceSession* pProtectedSession);
- ~BlockVector();
-
- HRESULT CreateMinBlocks();
-
- const D3D12_HEAP_PROPERTIES& GetHeapProperties() const { return m_HeapProps; }
- UINT64 GetPreferredBlockSize() const { return m_PreferredBlockSize; }
-
- bool IsEmpty();
-
- HRESULT Allocate(
- UINT64 size,
- UINT64 alignment,
- const ALLOCATION_DESC& allocDesc,
- size_t allocationCount,
- Allocation** pAllocations);
-
- 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);
-
-#ifdef __ID3D12Device8_INTERFACE_DEFINED__
- HRESULT CreateResource2(
- UINT64 size,
- UINT64 alignment,
- const ALLOCATION_DESC& allocDesc,
- const D3D12_RESOURCE_DESC1& resourceDesc,
- D3D12_RESOURCE_STATES InitialResourceState,
- const D3D12_CLEAR_VALUE *pOptimizedClearValue,
- Allocation** ppAllocation,
- REFIID riidResource,
- void** ppvResource);
-#endif // #ifdef __ID3D12Device8_INTERFACE_DEFINED__
-
- void AddStatistics(Statistics& inoutStats);
- void AddDetailedStatistics(DetailedStatistics& inoutStats);
-
- void WriteBlockInfoToJson(JsonWriter& json);
-
-private:
- AllocatorPimpl* const m_hAllocator;
- const D3D12_HEAP_PROPERTIES m_HeapProps;
- const D3D12_HEAP_FLAGS m_HeapFlags;
- const UINT64 m_PreferredBlockSize;
- const size_t m_MinBlockCount;
- const size_t m_MaxBlockCount;
- const bool m_ExplicitBlockSize;
- const UINT64 m_MinAllocationAlignment;
- const UINT32 m_Algorithm;
- ID3D12ProtectedResourceSession* const m_ProtectedSession;
- /* There can be at most one allocation that is completely empty - a
- hysteresis to avoid pessimistic case of alternating creation and destruction
- of a VkDeviceMemory. */
- bool m_HasEmptyBlock;
- D3D12MA_RW_MUTEX m_Mutex;
- // Incrementally sorted by sumFreeSize, ascending.
- Vector<NormalBlock*> m_Blocks;
- UINT m_NextBlockId;
-
- UINT64 CalcSumBlockSize() const;
- UINT64 CalcMaxBlockSize() const;
-
- // Finds and removes given block from vector.
- void Remove(NormalBlock* pBlock);
-
- // Performs single step in sorting m_Blocks. They may not be fully sorted
- // after this call.
- void IncrementallySortBlocks();
-
- HRESULT AllocatePage(
- UINT64 size,
- UINT64 alignment,
- const ALLOCATION_DESC& allocDesc,
- Allocation** pAllocation);
-
- HRESULT AllocateFromBlock(
- NormalBlock* pBlock,
- UINT64 size,
- UINT64 alignment,
- ALLOCATION_FLAGS allocFlags,
- Allocation** pAllocation);
-
- HRESULT CreateBlock(
- UINT64 blockSize,
- size_t* pNewBlockIndex);
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// Private class AllocatorPimpl definition
-
-static constexpr UINT HEAP_TYPE_COUNT = 4;
-static constexpr UINT STANDARD_HEAP_TYPE_COUNT = 3; // Only DEFAULT, UPLOAD, READBACK.
-static constexpr UINT DEFAULT_POOL_MAX_COUNT = 9;
-
-class CurrentBudgetData
-{
-public:
- void GetStatistics(Statistics& outStats, UINT group) const
- {
- outStats.BlockCount = m_BlockCount[group];
- outStats.AllocationCount = m_AllocationCount[group];
- outStats.BlockBytes = m_BlockBytes[group];
- outStats.AllocationBytes = m_AllocationBytes[group];
- }
- void GetBudget(bool useMutex,
- UINT64* outLocalUsage, UINT64* outLocalBudget,
- UINT64* outNonLocalUsage, UINT64* outNonLocalBudget);
-
- void AddAllocation(UINT group, UINT64 allocationBytes)
- {
- ++m_AllocationCount[group];
- m_AllocationBytes[group] += allocationBytes;
- ++m_OperationsSinceBudgetFetch;
- }
- void RemoveAllocation(UINT group, UINT64 allocationBytes)
- {
- D3D12MA_ASSERT(m_AllocationBytes[group] >= allocationBytes);
- D3D12MA_ASSERT(m_AllocationCount[group] > 0);
- m_AllocationBytes[group] -= allocationBytes;
- --m_AllocationCount[group];
- ++m_OperationsSinceBudgetFetch;
- }
- void AddBlock(UINT group, UINT64 blockBytes)
- {
- ++m_BlockCount[group];
- m_BlockBytes[group] += blockBytes;
- ++m_OperationsSinceBudgetFetch;
- }
- void RemoveBlock(UINT group, UINT64 blockBytes)
- {
- D3D12MA_ASSERT(m_BlockBytes[group] >= blockBytes);
- D3D12MA_ASSERT(m_BlockCount[group] > 0);
- m_BlockBytes[group] -= blockBytes;
- --m_BlockCount[group];
- ++m_OperationsSinceBudgetFetch;
- }
- bool ShouldUpdateBudget() const
- {
- return m_OperationsSinceBudgetFetch >= 30;
- }
-#if D3D12MA_DXGI_1_4
- HRESULT UpdateBudget(IDXGIAdapter3* adapter3, bool useMutex);
-#endif
-
-private:
- D3D12MA_ATOMIC_UINT32 m_BlockCount[DXGI_MEMORY_SEGMENT_GROUP_COUNT] = {};
- D3D12MA_ATOMIC_UINT32 m_AllocationCount[DXGI_MEMORY_SEGMENT_GROUP_COUNT] = {};
- D3D12MA_ATOMIC_UINT64 m_BlockBytes[DXGI_MEMORY_SEGMENT_GROUP_COUNT] = {};
- D3D12MA_ATOMIC_UINT64 m_AllocationBytes[DXGI_MEMORY_SEGMENT_GROUP_COUNT] = {};
-
- D3D12MA_ATOMIC_UINT32 m_OperationsSinceBudgetFetch = 0;
- D3D12MA_RW_MUTEX m_BudgetMutex;
- UINT64 m_D3D12Usage[DXGI_MEMORY_SEGMENT_GROUP_COUNT] = {};
- UINT64 m_D3D12Budget[DXGI_MEMORY_SEGMENT_GROUP_COUNT] = {};
- UINT64 m_BlockBytesAtD3D12Fetch[DXGI_MEMORY_SEGMENT_GROUP_COUNT] = {};
-};
-
-class PoolPimpl
-{
-public:
- PoolPimpl(AllocatorPimpl* allocator, const POOL_DESC& desc);
- HRESULT Init();
- ~PoolPimpl();
-
- AllocatorPimpl* GetAllocator() const { return m_Allocator; }
- const POOL_DESC& GetDesc() const { return m_Desc; }
- bool SupportsCommittedAllocations() const { return m_Desc.BlockSize == 0; }
-
- BlockVector* GetBlockVector() { return m_BlockVector; }
- CommittedAllocationList* GetCommittedAllocationList() { return SupportsCommittedAllocations() ? &m_CommittedAllocations : NULL; }
-
- void GetStatistics(Statistics& outStats);
- void CalculateStatistics(DetailedStatistics& outStats);
- void AddDetailedStatistics(DetailedStatistics& inoutStats);
-
- void SetName(LPCWSTR Name);
- LPCWSTR GetName() const { return m_Name; }
-
-private:
- friend class Allocator;
- friend struct PoolListItemTraits;
-
- AllocatorPimpl* m_Allocator; // Externally owned object.
- POOL_DESC m_Desc;
- BlockVector* m_BlockVector; // Owned object.
- CommittedAllocationList m_CommittedAllocations;
- wchar_t* m_Name;
- PoolPimpl* m_PrevPool = NULL;
- PoolPimpl* m_NextPool = NULL;
-
- void FreeName();
-};
-
-struct PoolListItemTraits
-{
- using ItemType = PoolPimpl;
- static ItemType* GetPrev(const ItemType* item) { return item->m_PrevPool; }
- static ItemType* GetNext(const ItemType* item) { return item->m_NextPool; }
- static ItemType*& AccessPrev(ItemType* item) { return item->m_PrevPool; }
- static ItemType*& AccessNext(ItemType* item) { return item->m_NextPool; }
-};
-
-struct CommittedAllocationParameters
-{
- CommittedAllocationList* m_List = NULL;
- D3D12_HEAP_PROPERTIES m_HeapProperties = {};
- D3D12_HEAP_FLAGS m_HeapFlags = D3D12_HEAP_FLAG_NONE;
- ID3D12ProtectedResourceSession* m_ProtectedSession = NULL;
-
- bool IsValid() const { return m_List != NULL; }
-};
-
-class AllocatorPimpl
-{
-public:
- std::atomic_uint32_t m_RefCount = 1;
- CurrentBudgetData m_Budget;
-
- AllocatorPimpl(const ALLOCATION_CALLBACKS& allocationCallbacks, const ALLOCATOR_DESC& desc);
- HRESULT Init(const ALLOCATOR_DESC& desc);
- ~AllocatorPimpl();
-
- ID3D12Device* GetDevice() const { return m_Device; }
-#ifdef __ID3D12Device4_INTERFACE_DEFINED__
- ID3D12Device4* GetDevice4() const { return m_Device4; }
-#endif
-#ifdef __ID3D12Device8_INTERFACE_DEFINED__
- ID3D12Device8* GetDevice8() const { return m_Device8; }
-#endif
- // Shortcut for "Allocation Callbacks", because this function is called so often.
- const ALLOCATION_CALLBACKS& GetAllocs() const { return m_AllocationCallbacks; }
- const D3D12_FEATURE_DATA_D3D12_OPTIONS& GetD3D12Options() const { return m_D3D12Options; }
- BOOL IsUMA() const { return m_D3D12Architecture.UMA; }
- BOOL IsCacheCoherentUMA() const { return m_D3D12Architecture.CacheCoherentUMA; }
- 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;
- UINT StandardHeapTypeToMemorySegmentGroup(D3D12_HEAP_TYPE heapType) const;
- UINT HeapPropertiesToMemorySegmentGroup(const D3D12_HEAP_PROPERTIES& heapProps) const;
- UINT64 GetMemoryCapacity(UINT memorySegmentGroup) const;
-
- HRESULT CreateResource(
- const ALLOCATION_DESC* pAllocDesc,
- const D3D12_RESOURCE_DESC* pResourceDesc,
- D3D12_RESOURCE_STATES InitialResourceState,
- const D3D12_CLEAR_VALUE *pOptimizedClearValue,
- Allocation** ppAllocation,
- REFIID riidResource,
- void** ppvResource);
-
-#ifdef __ID3D12Device8_INTERFACE_DEFINED__
- HRESULT CreateResource2(
- const ALLOCATION_DESC* pAllocDesc,
- const D3D12_RESOURCE_DESC1* pResourceDesc,
- D3D12_RESOURCE_STATES InitialResourceState,
- const D3D12_CLEAR_VALUE *pOptimizedClearValue,
- Allocation** ppAllocation,
- REFIID riidResource,
- void** ppvResource);
-#endif // #ifdef __ID3D12Device8_INTERFACE_DEFINED__
-
- HRESULT AllocateMemory(
- const ALLOCATION_DESC* pAllocDesc,
- const D3D12_RESOURCE_ALLOCATION_INFO* pAllocInfo,
- Allocation** ppAllocation);
-
- HRESULT CreateAliasingResource(
- Allocation* pAllocation,
- UINT64 AllocationLocalOffset,
- const D3D12_RESOURCE_DESC* pResourceDesc,
- D3D12_RESOURCE_STATES InitialResourceState,
- const D3D12_CLEAR_VALUE *pOptimizedClearValue,
- REFIID riidResource,
- void** ppvResource);
-
- // Unregisters allocation from the collection of dedicated allocations.
- // Allocation object must be deleted externally afterwards.
- void FreeCommittedMemory(Allocation* allocation);
- // Unregisters allocation from the collection of placed allocations.
- // Allocation object must be deleted externally afterwards.
- void FreePlacedMemory(Allocation* allocation);
- // Unregisters allocation from the collection of dedicated allocations and destroys associated heap.
- // Allocation object must be deleted externally afterwards.
- void FreeHeapMemory(Allocation* allocation);
-
- void SetCurrentFrameIndex(UINT frameIndex);
-
- UINT GetCurrentFrameIndex() const { return m_CurrentFrameIndex.load(); }
-
- void CalculateStatistics(TotalStatistics& outStats);
-
- void GetBudget(Budget* outLocalBudget, Budget* outNonLocalBudget);
- void GetBudgetForHeapType(Budget& outBudget, D3D12_HEAP_TYPE heapType);
-
- void BuildStatsString(WCHAR** ppStatsString, BOOL DetailedMap);
-
- void FreeStatsString(WCHAR* pStatsString);
-
-private:
- friend class Allocator;
- friend class Pool;
-
- /*
- Heuristics that decides whether a resource should better be placed in its own,
- dedicated allocation (committed resource rather than placed resource).
- */
- template<typename D3D12_RESOURCE_DESC_T>
- static bool PrefersCommittedAllocation(const D3D12_RESOURCE_DESC_T& resourceDesc);
-
- const bool m_UseMutex;
- const bool m_AlwaysCommitted;
- ID3D12Device* m_Device; // AddRef
-#ifdef __ID3D12Device4_INTERFACE_DEFINED__
- ID3D12Device4* m_Device4 = NULL; // AddRef, optional
-#endif
-#ifdef __ID3D12Device8_INTERFACE_DEFINED__
- ID3D12Device8* m_Device8 = NULL; // AddRef, optional
-#endif
- IDXGIAdapter* m_Adapter; // AddRef
-#if D3D12MA_DXGI_1_4
- IDXGIAdapter3* m_Adapter3 = NULL; // AddRef, optional
-#endif
- UINT64 m_PreferredBlockSize;
- ALLOCATION_CALLBACKS m_AllocationCallbacks;
- D3D12MA_ATOMIC_UINT32 m_CurrentFrameIndex;
- DXGI_ADAPTER_DESC m_AdapterDesc;
- D3D12_FEATURE_DATA_D3D12_OPTIONS m_D3D12Options;
- D3D12_FEATURE_DATA_ARCHITECTURE m_D3D12Architecture;
- AllocationObjectAllocator m_AllocationObjectAllocator;
-
- using PoolList = IntrusiveLinkedList<PoolListItemTraits>;
- PoolList m_Pools[HEAP_TYPE_COUNT];
- D3D12MA_RW_MUTEX m_PoolsMutex[HEAP_TYPE_COUNT];
-
- // Default pools.
- BlockVector* m_BlockVectors[DEFAULT_POOL_MAX_COUNT];
-
- CommittedAllocationList m_CommittedAllocations[STANDARD_HEAP_TYPE_COUNT];
-
- // Allocates and registers new committed resource with implicit heap, as dedicated allocation.
- // Creates and returns Allocation object and optionally D3D12 resource.
- HRESULT AllocateCommittedResource(
- const CommittedAllocationParameters& committedAllocParams,
- UINT64 resourceSize, bool withinBudget,
- const D3D12_RESOURCE_DESC* pResourceDesc,
- D3D12_RESOURCE_STATES InitialResourceState, const D3D12_CLEAR_VALUE *pOptimizedClearValue,
- Allocation** ppAllocation, REFIID riidResource, void** ppvResource);
-
-#ifdef __ID3D12Device8_INTERFACE_DEFINED__
- HRESULT AllocateCommittedResource2(
- const CommittedAllocationParameters& committedAllocParams,
- UINT64 resourceSize, bool withinBudget,
- const D3D12_RESOURCE_DESC1* pResourceDesc,
- D3D12_RESOURCE_STATES InitialResourceState, const D3D12_CLEAR_VALUE *pOptimizedClearValue,
- Allocation** ppAllocation, REFIID riidResource, void** ppvResource);
-#endif // #ifdef __ID3D12Device8_INTERFACE_DEFINED__
-
- // Allocates and registers new heap without any resources placed in it, as dedicated allocation.
- // Creates and returns Allocation object.
- HRESULT AllocateHeap(
- const CommittedAllocationParameters& committedAllocParams,
- const D3D12_RESOURCE_ALLOCATION_INFO& allocInfo, bool withinBudget,
- Allocation** ppAllocation);
-
- template<typename D3D12_RESOURCE_DESC_T>
- HRESULT CalcAllocationParams(const ALLOCATION_DESC& allocDesc, UINT64 allocSize,
- const D3D12_RESOURCE_DESC_T* resDesc, // Optional
- BlockVector*& outBlockVector, CommittedAllocationParameters& outCommittedAllocationParams, bool& outPreferCommitted);
-
- /*
- If SupportsResourceHeapTier2():
- 0: D3D12_HEAP_TYPE_DEFAULT
- 1: D3D12_HEAP_TYPE_UPLOAD
- 2: D3D12_HEAP_TYPE_READBACK
- else:
- 0: D3D12_HEAP_TYPE_DEFAULT + buffer
- 1: D3D12_HEAP_TYPE_DEFAULT + texture
- 2: D3D12_HEAP_TYPE_DEFAULT + texture RT or DS
- 3: D3D12_HEAP_TYPE_UPLOAD + buffer
- 4: D3D12_HEAP_TYPE_UPLOAD + texture
- 5: D3D12_HEAP_TYPE_UPLOAD + texture RT or DS
- 6: D3D12_HEAP_TYPE_READBACK + buffer
- 7: D3D12_HEAP_TYPE_READBACK + texture
- 8: D3D12_HEAP_TYPE_READBACK + texture RT or DS
- */
- UINT CalcDefaultPoolCount() const;
- // Returns UINT32_MAX if index cannot be calculcated.
- UINT CalcDefaultPoolIndex(const ALLOCATION_DESC& allocDesc, ResourceClass resourceClass) const;
- void CalcDefaultPoolParams(D3D12_HEAP_TYPE& outHeapType, D3D12_HEAP_FLAGS& outHeapFlags, UINT index) const;
-
- // Registers Pool object in m_Pools.
- void RegisterPool(Pool* pool, D3D12_HEAP_TYPE heapType);
- // Unregisters Pool object from m_Pools.
- void UnregisterPool(Pool* pool, D3D12_HEAP_TYPE heapType);
-
- HRESULT UpdateD3D12Budget();
-
- D3D12_RESOURCE_ALLOCATION_INFO GetResourceAllocationInfoNative(const D3D12_RESOURCE_DESC& resourceDesc) const;
-#ifdef __ID3D12Device8_INTERFACE_DEFINED__
- D3D12_RESOURCE_ALLOCATION_INFO GetResourceAllocationInfoNative(const D3D12_RESOURCE_DESC1& resourceDesc) const;
-#endif // #ifdef __ID3D12Device8_INTERFACE_DEFINED__
-
- template<typename D3D12_RESOURCE_DESC_T>
- D3D12_RESOURCE_ALLOCATION_INFO GetResourceAllocationInfo(D3D12_RESOURCE_DESC_T& inOutResourceDesc) const;
-
- bool NewAllocationWithinBudget(D3D12_HEAP_TYPE heapType, UINT64 size);
-
- // Writes object { } with data of given budget.
- static void WriteBudgetToJson(JsonWriter& json, const Budget& budget);
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// Private class BlockMetadata implementation
-
-BlockMetadata::BlockMetadata(const ALLOCATION_CALLBACKS* allocationCallbacks, bool isVirtual) :
- m_Size(0),
- m_IsVirtual(isVirtual),
- m_pAllocationCallbacks(allocationCallbacks)
-{
- D3D12MA_ASSERT(allocationCallbacks);
-}
-
-void BlockMetadata::PrintDetailedMap_Begin(JsonWriter& json,
- UINT64 unusedBytes, size_t allocationCount, size_t unusedRangeCount) const
-{
- json.BeginObject();
-
- json.WriteString(L"TotalBytes");
- json.WriteNumber(GetSize());
-
- json.WriteString(L"UnusedBytes");
- json.WriteNumber(unusedBytes);
-
- json.WriteString(L"Allocations");
- json.WriteNumber(allocationCount);
-
- json.WriteString(L"UnusedRanges");
- json.WriteNumber(unusedRangeCount);
-
- json.WriteString(L"Suballocations");
- json.BeginArray();
-}
-
-void BlockMetadata::PrintDetailedMap_Allocation(JsonWriter& json,
- UINT64 offset, UINT64 size, void* userData) const
-{
- json.BeginObject(true);
-
- json.WriteString(L"Offset");
- json.WriteNumber(offset);
-
- if (IsVirtual())
- {
- json.WriteString(L"Type");
- json.WriteString(L"ALLOCATION");
- json.WriteString(L"Size");
- json.WriteNumber(size);
- if (userData)
- {
- json.WriteString(L"UserData");
- json.WriteNumber((uintptr_t)userData);
- }
- }
- else
- {
- const Allocation* const alloc = (const Allocation*)userData;
- D3D12MA_ASSERT(alloc);
- json.AddAllocationToObject(*alloc);
- }
- json.EndObject();
-}
-
-void BlockMetadata::PrintDetailedMap_UnusedRange(JsonWriter& json,
- UINT64 offset, UINT64 size) const
-{
- json.BeginObject(true);
-
- json.WriteString(L"Offset");
- json.WriteNumber(offset);
-
- json.WriteString(L"Type");
- json.WriteString(L"FREE");
-
- json.WriteString(L"Size");
- json.WriteNumber(size);
-
- json.EndObject();
-}
-
-void BlockMetadata::PrintDetailedMap_End(JsonWriter& json) const
-{
- json.EndArray();
- json.EndObject();
-}
-
-#if 0
-////////////////////////////////////////////////////////////////////////////////
-// Private class BlockMetadata_Generic implementation
-
-BlockMetadata_Generic::BlockMetadata_Generic(const ALLOCATION_CALLBACKS* allocationCallbacks, bool isVirtual) :
- BlockMetadata(allocationCallbacks, isVirtual),
- m_FreeCount(0),
- m_SumFreeSize(0),
- m_Suballocations(*allocationCallbacks),
- m_FreeSuballocationsBySize(*allocationCallbacks)
-{
- D3D12MA_ASSERT(allocationCallbacks);
-}
-
-BlockMetadata_Generic::~BlockMetadata_Generic()
-{
-}
-
-void BlockMetadata_Generic::Init(UINT64 size)
-{
- BlockMetadata::Init(size);
- m_ZeroInitializedRange.Reset(size);
-
- m_FreeCount = 1;
- m_SumFreeSize = size;
-
- Suballocation suballoc = {};
- suballoc.offset = 0;
- suballoc.size = size;
- suballoc.type = SUBALLOCATION_TYPE_FREE;
- suballoc.userData = NULL;
-
- D3D12MA_ASSERT(size > MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER);
- m_Suballocations.push_back(suballoc);
- SuballocationList::iterator suballocItem = m_Suballocations.end();
- --suballocItem;
- m_FreeSuballocationsBySize.push_back(suballocItem);
-}
-
-bool BlockMetadata_Generic::Validate() const
-{
- D3D12MA_VALIDATE(!m_Suballocations.empty());
-
- // Expected offset of new suballocation as calculated from previous ones.
- UINT64 calculatedOffset = 0;
- // Expected number of free suballocations as calculated from traversing their list.
- UINT calculatedFreeCount = 0;
- // Expected sum size of free suballocations as calculated from traversing their list.
- UINT64 calculatedSumFreeSize = 0;
- // Expected number of free suballocations that should be registered in
- // m_FreeSuballocationsBySize calculated from traversing their list.
- size_t freeSuballocationsToRegister = 0;
- // True if previous visited suballocation was free.
- bool prevFree = false;
-
- for(const auto& subAlloc : m_Suballocations)
- {
- // Actual offset of this suballocation doesn't match expected one.
- D3D12MA_VALIDATE(subAlloc.offset == calculatedOffset);
-
- const bool currFree = (subAlloc.type == SUBALLOCATION_TYPE_FREE);
- // Two adjacent free suballocations are invalid. They should be merged.
- D3D12MA_VALIDATE(!prevFree || !currFree);
-
- const Allocation* const alloc = (Allocation*)subAlloc.userData;
- if(!IsVirtual())
- {
- D3D12MA_VALIDATE(currFree == (alloc == NULL));
- }
-
- if(currFree)
- {
- calculatedSumFreeSize += subAlloc.size;
- ++calculatedFreeCount;
- if(subAlloc.size >= MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
- {
- ++freeSuballocationsToRegister;
- }
-
- // Margin required between allocations - every free space must be at least that large.
- D3D12MA_VALIDATE(subAlloc.size >= GetDebugMargin());
- }
- else
- {
- if(!IsVirtual())
- {
- D3D12MA_VALIDATE(alloc->GetOffset() == subAlloc.offset);
- D3D12MA_VALIDATE(alloc->GetSize() == subAlloc.size);
- }
-
- // Margin required between allocations - previous allocation must be free.
- D3D12MA_VALIDATE(GetDebugMargin() == 0 || prevFree);
- }
-
- calculatedOffset += subAlloc.size;
- prevFree = currFree;
- }
-
- // Number of free suballocations registered in m_FreeSuballocationsBySize doesn't
- // match expected one.
- D3D12MA_VALIDATE(m_FreeSuballocationsBySize.size() == freeSuballocationsToRegister);
-
- UINT64 lastSize = 0;
- for(size_t i = 0; i < m_FreeSuballocationsBySize.size(); ++i)
- {
- SuballocationList::iterator suballocItem = m_FreeSuballocationsBySize[i];
-
- // Only free suballocations can be registered in m_FreeSuballocationsBySize.
- D3D12MA_VALIDATE(suballocItem->type == SUBALLOCATION_TYPE_FREE);
- // They must be sorted by size ascending.
- D3D12MA_VALIDATE(suballocItem->size >= lastSize);
-
- lastSize = suballocItem->size;
- }
-
- // Check if totals match calculacted values.
- D3D12MA_VALIDATE(ValidateFreeSuballocationList());
- D3D12MA_VALIDATE(calculatedOffset == GetSize());
- D3D12MA_VALIDATE(calculatedSumFreeSize == m_SumFreeSize);
- D3D12MA_VALIDATE(calculatedFreeCount == m_FreeCount);
-
- return true;
-}
-
-bool BlockMetadata_Generic::IsEmpty() const
-{
- return (m_Suballocations.size() == 1) && (m_FreeCount == 1);
-}
-
-void BlockMetadata_Generic::GetAllocationInfo(AllocHandle allocHandle, VIRTUAL_ALLOCATION_INFO& outInfo) const
-{
- Suballocation& suballoc = *FindAtOffset((UINT64)allocHandle - 1).dropConst();
- outInfo.Offset = suballoc.offset;
- outInfo.Size = suballoc.size;
- outInfo.pUserData = suballoc.userData;
-}
-
-bool BlockMetadata_Generic::CreateAllocationRequest(
- UINT64 allocSize,
- UINT64 allocAlignment,
- bool upperAddress,
- AllocationRequest* pAllocationRequest)
-{
- D3D12MA_ASSERT(allocSize > 0);
- D3D12MA_ASSERT(!upperAddress && "ALLOCATION_FLAG_UPPER_ADDRESS can be used only with linear algorithm.");
- D3D12MA_ASSERT(pAllocationRequest != NULL);
- D3D12MA_HEAVY_ASSERT(Validate());
-
- // There is not enough total free space in this block to fullfill the request: Early return.
- if(m_SumFreeSize < allocSize + GetDebugMargin())
- {
- return false;
- }
-
- // New algorithm, efficiently searching freeSuballocationsBySize.
- const size_t freeSuballocCount = m_FreeSuballocationsBySize.size();
- if(freeSuballocCount > 0)
- {
- // Find first free suballocation with size not less than allocSize + GetDebugMargin().
- SuballocationList::iterator* const it = BinaryFindFirstNotLess(
- m_FreeSuballocationsBySize.data(),
- m_FreeSuballocationsBySize.data() + freeSuballocCount,
- allocSize + GetDebugMargin(),
- SuballocationItemSizeLess());
- size_t index = it - m_FreeSuballocationsBySize.data();
- for(; index < freeSuballocCount; ++index)
- {
- if(CheckAllocation(
- allocSize,
- allocAlignment,
- m_FreeSuballocationsBySize[index],
- &pAllocationRequest->allocHandle,
- &pAllocationRequest->sumFreeSize,
- &pAllocationRequest->sumItemSize,
- &pAllocationRequest->zeroInitialized))
- {
- pAllocationRequest->item = m_FreeSuballocationsBySize[index];
- return true;
- }
- }
- }
-
- return false;
-}
-
-void BlockMetadata_Generic::Alloc(
- const AllocationRequest& request,
- UINT64 allocSize,
- void* userData)
-{
- D3D12MA_ASSERT(request.item != m_Suballocations.end());
- Suballocation& suballoc = *request.item;
- // Given suballocation is a free block.
- D3D12MA_ASSERT(suballoc.type == SUBALLOCATION_TYPE_FREE);
- // Given offset is inside this suballocation.
- UINT64 offset = (UINT64)request.allocHandle - 1;
- D3D12MA_ASSERT(offset >= suballoc.offset);
- const UINT64 paddingBegin = offset - suballoc.offset;
- D3D12MA_ASSERT(suballoc.size >= paddingBegin + allocSize);
- const UINT64 paddingEnd = suballoc.size - paddingBegin - allocSize;
-
- // Unregister this free suballocation from m_FreeSuballocationsBySize and update
- // it to become used.
- UnregisterFreeSuballocation(request.item);
-
- suballoc.offset = offset;
- suballoc.size = allocSize;
- suballoc.type = SUBALLOCATION_TYPE_ALLOCATION;
- suballoc.userData = userData;
-
- // If there are any free bytes remaining at the end, insert new free suballocation after current one.
- if(paddingEnd)
- {
- Suballocation paddingSuballoc = {};
- paddingSuballoc.offset = offset + allocSize;
- paddingSuballoc.size = paddingEnd;
- paddingSuballoc.type = SUBALLOCATION_TYPE_FREE;
- SuballocationList::iterator next = request.item;
- ++next;
- const SuballocationList::iterator paddingEndItem =
- m_Suballocations.insert(next, paddingSuballoc);
- RegisterFreeSuballocation(paddingEndItem);
- }
-
- // If there are any free bytes remaining at the beginning, insert new free suballocation before current one.
- if(paddingBegin)
- {
- Suballocation paddingSuballoc = {};
- paddingSuballoc.offset = offset - paddingBegin;
- paddingSuballoc.size = paddingBegin;
- paddingSuballoc.type = SUBALLOCATION_TYPE_FREE;
- const SuballocationList::iterator paddingBeginItem =
- m_Suballocations.insert(request.item, paddingSuballoc);
- RegisterFreeSuballocation(paddingBeginItem);
- }
-
- // Update totals.
- m_FreeCount = m_FreeCount - 1;
- if(paddingBegin > 0)
- {
- ++m_FreeCount;
- }
- if(paddingEnd > 0)
- {
- ++m_FreeCount;
- }
- m_SumFreeSize -= allocSize;
-
- m_ZeroInitializedRange.MarkRangeAsUsed(offset, offset + allocSize);
-}
-
-void BlockMetadata_Generic::Free(AllocHandle allocHandle)
-{
- FreeSuballocation(FindAtOffset((UINT64)allocHandle - 1).dropConst());
-}
-
-void BlockMetadata_Generic::Clear()
-{
- m_FreeCount = 1;
- m_SumFreeSize = GetSize();
-
- m_Suballocations.clear();
- Suballocation suballoc = {};
- suballoc.offset = 0;
- suballoc.size = GetSize();
- suballoc.type = SUBALLOCATION_TYPE_FREE;
- m_Suballocations.push_back(suballoc);
-
- m_FreeSuballocationsBySize.clear();
- m_FreeSuballocationsBySize.push_back(m_Suballocations.begin());
-}
-
-SuballocationList::const_iterator BlockMetadata_Generic::FindAtOffset(UINT64 offset) const
-{
- const UINT64 last = m_Suballocations.crbegin()->offset;
- if (last == offset)
- return m_Suballocations.crbegin();
- const UINT64 first = m_Suballocations.cbegin()->offset;
- if (first == offset)
- return m_Suballocations.cbegin();
-
- const size_t suballocCount = m_Suballocations.size();
- const UINT64 step = (last - first + m_Suballocations.cbegin()->size) / suballocCount;
- auto findSuballocation = [&](auto begin, auto end) -> SuballocationList::const_iterator
- {
- for (auto suballocItem = begin;
- suballocItem != end;
- ++suballocItem)
- {
- const Suballocation& suballoc = *suballocItem;
- if (suballoc.offset == offset)
- return suballocItem;
- }
- D3D12MA_ASSERT(false && "Not found!");
- return m_Suballocations.end();
- };
- // If requested offset is closer to the end of range, search from the end
- if ((offset - first) > suballocCount * step / 2)
- {
- return findSuballocation(m_Suballocations.crbegin(), m_Suballocations.crend());
- }
- return findSuballocation(m_Suballocations.cbegin(), m_Suballocations.cend());
-}
-
-bool BlockMetadata_Generic::ValidateFreeSuballocationList() const
-{
- UINT64 lastSize = 0;
- for(size_t i = 0, count = m_FreeSuballocationsBySize.size(); i < count; ++i)
- {
- const SuballocationList::iterator it = m_FreeSuballocationsBySize[i];
-
- D3D12MA_VALIDATE(it->type == SUBALLOCATION_TYPE_FREE);
- D3D12MA_VALIDATE(it->size >= MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER);
- D3D12MA_VALIDATE(it->size >= lastSize);
- lastSize = it->size;
- }
- return true;
-}
-
-bool BlockMetadata_Generic::CheckAllocation(
- UINT64 allocSize,
- UINT64 allocAlignment,
- SuballocationList::const_iterator suballocItem,
- AllocHandle* pAllocHandle,
- UINT64* pSumFreeSize,
- UINT64* pSumItemSize,
- BOOL *pZeroInitialized) const
-{
- D3D12MA_ASSERT(allocSize > 0);
- D3D12MA_ASSERT(suballocItem != m_Suballocations.cend());
- D3D12MA_ASSERT(pAllocHandle != NULL && pZeroInitialized != NULL);
-
- *pSumFreeSize = 0;
- *pSumItemSize = 0;
- *pZeroInitialized = FALSE;
-
- const Suballocation& suballoc = *suballocItem;
- D3D12MA_ASSERT(suballoc.type == SUBALLOCATION_TYPE_FREE);
-
- *pSumFreeSize = suballoc.size;
-
- // Size of this suballocation is too small for this request: Early return.
- if(suballoc.size < allocSize)
- {
- return false;
- }
-
- // Start from offset equal to beginning of this suballocation and debug margin of previous allocation if present.
- UINT64 offset = suballoc.offset + (suballocItem == m_Suballocations.cbegin() ? 0 : GetDebugMargin());
-
- // Apply alignment.
- offset = AlignUp(offset, allocAlignment);
-
- // Calculate padding at the beginning based on current offset.
- const UINT64 paddingBegin = offset - suballoc.offset;
-
- // Fail if requested size plus margin after is bigger than size of this suballocation.
- if(paddingBegin + allocSize + GetDebugMargin() > suballoc.size)
- {
- return false;
- }
-
- // All tests passed: Success. Offset is already filled.
- *pZeroInitialized = m_ZeroInitializedRange.IsRangeZeroInitialized(offset, offset + allocSize);
- *pAllocHandle = (AllocHandle)(offset + 1);
- return true;
-}
-
-void BlockMetadata_Generic::MergeFreeWithNext(SuballocationList::iterator item)
-{
- D3D12MA_ASSERT(item != m_Suballocations.end());
- D3D12MA_ASSERT(item->type == SUBALLOCATION_TYPE_FREE);
-
- SuballocationList::iterator nextItem = item;
- ++nextItem;
- D3D12MA_ASSERT(nextItem != m_Suballocations.end());
- D3D12MA_ASSERT(nextItem->type == SUBALLOCATION_TYPE_FREE);
-
- item->size += nextItem->size;
- --m_FreeCount;
- m_Suballocations.erase(nextItem);
-}
-
-SuballocationList::iterator BlockMetadata_Generic::FreeSuballocation(SuballocationList::iterator suballocItem)
-{
- // Change this suballocation to be marked as free.
- Suballocation& suballoc = *suballocItem;
- suballoc.type = SUBALLOCATION_TYPE_FREE;
- suballoc.userData = NULL;
-
- // Update totals.
- ++m_FreeCount;
- m_SumFreeSize += suballoc.size;
-
- // Merge with previous and/or next suballocation if it's also free.
- bool mergeWithNext = false;
- bool mergeWithPrev = false;
-
- SuballocationList::iterator nextItem = suballocItem;
- ++nextItem;
- if((nextItem != m_Suballocations.end()) && (nextItem->type == SUBALLOCATION_TYPE_FREE))
- {
- mergeWithNext = true;
- }
-
- SuballocationList::iterator prevItem = suballocItem;
- if(suballocItem != m_Suballocations.begin())
- {
- --prevItem;
- if(prevItem->type == SUBALLOCATION_TYPE_FREE)
- {
- mergeWithPrev = true;
- }
- }
-
- if(mergeWithNext)
- {
- UnregisterFreeSuballocation(nextItem);
- MergeFreeWithNext(suballocItem);
- }
-
- if(mergeWithPrev)
- {
- UnregisterFreeSuballocation(prevItem);
- MergeFreeWithNext(prevItem);
- RegisterFreeSuballocation(prevItem);
- return prevItem;
- }
- else
- {
- RegisterFreeSuballocation(suballocItem);
- return suballocItem;
- }
-}
-
-void BlockMetadata_Generic::RegisterFreeSuballocation(SuballocationList::iterator item)
-{
- D3D12MA_ASSERT(item->type == SUBALLOCATION_TYPE_FREE);
- D3D12MA_ASSERT(item->size > 0);
-
- // You may want to enable this validation at the beginning or at the end of
- // this function, depending on what do you want to check.
- D3D12MA_HEAVY_ASSERT(ValidateFreeSuballocationList());
-
- if(item->size >= MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
- {
- if(m_FreeSuballocationsBySize.empty())
- {
- m_FreeSuballocationsBySize.push_back(item);
- }
- else
- {
- m_FreeSuballocationsBySize.InsertSorted(item, SuballocationItemSizeLess());
- }
- }
-
- //D3D12MA_HEAVY_ASSERT(ValidateFreeSuballocationList());
-}
-
-void BlockMetadata_Generic::UnregisterFreeSuballocation(SuballocationList::iterator item)
-{
- D3D12MA_ASSERT(item->type == SUBALLOCATION_TYPE_FREE);
- D3D12MA_ASSERT(item->size > 0);
-
- // You may want to enable this validation at the beginning or at the end of
- // this function, depending on what do you want to check.
- D3D12MA_HEAVY_ASSERT(ValidateFreeSuballocationList());
-
- if(item->size >= MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
- {
- SuballocationList::iterator* const it = BinaryFindFirstNotLess(
- m_FreeSuballocationsBySize.data(),
- m_FreeSuballocationsBySize.data() + m_FreeSuballocationsBySize.size(),
- item,
- SuballocationItemSizeLess());
- for(size_t index = it - m_FreeSuballocationsBySize.data();
- index < m_FreeSuballocationsBySize.size();
- ++index)
- {
- if(m_FreeSuballocationsBySize[index] == item)
- {
- m_FreeSuballocationsBySize.remove(index);
- return;
- }
- D3D12MA_ASSERT((m_FreeSuballocationsBySize[index]->size == item->size) && "Not found.");
- }
- D3D12MA_ASSERT(0 && "Not found.");
- }
-
- //D3D12MA_HEAVY_ASSERT(ValidateFreeSuballocationList());
-}
-
-void BlockMetadata_Generic::SetAllocationUserData(AllocHandle allocHandle, void* userData)
-{
- Suballocation& suballoc = *FindAtOffset((UINT64)allocHandle - 1).dropConst();
- suballoc.userData = userData;
-}
-
-void BlockMetadata_Generic::AddStatistics(Statistics& inoutStats) const
-{
- inoutStats.BlockCount++;
- inoutStats.AllocationCount += (UINT)m_Suballocations.size() - m_FreeCount;
- inoutStats.BlockBytes += GetSize();
- inoutStats.AllocationBytes += GetSize() - m_SumFreeSize;
-}
-
-void BlockMetadata_Generic::AddDetailedStatistics(DetailedStatistics& inoutStats) const
-{
- inoutStats.Stats.BlockCount++;
- inoutStats.Stats.BlockBytes += GetSize();
-
- for(const auto& suballoc : m_Suballocations)
- {
- if(suballoc.type == SUBALLOCATION_TYPE_FREE)
- AddDetailedStatisticsUnusedRange(inoutStats, suballoc.size);
- else
- AddDetailedStatisticsAllocation(inoutStats, suballoc.size);
- }
-}
-
-void BlockMetadata_Generic::WriteAllocationInfoToJson(JsonWriter& json) const
-{
- PrintDetailedMap_Begin(json, GetSumFreeSize(), GetAllocationCount(), m_FreeCount);
- for(const auto& suballoc : m_Suballocations)
- {
- if (suballoc.type == SUBALLOCATION_TYPE_FREE)
- PrintDetailedMap_UnusedRange(json, suballoc.offset, suballoc.size);
- else
- PrintDetailedMap_Allocation(json, suballoc.offset, suballoc.size, suballoc.userData);
- }
- PrintDetailedMap_End(json);
-}
-#endif // #if 0
-
-////////////////////////////////////////////////////////////////////////////////
-// Private class BlockMetadata_Linear implementation
-
+#ifndef _D3D12MA_BLOCK_METADATA_LINEAR_FUNCTIONS
BlockMetadata_Linear::BlockMetadata_Linear(const ALLOCATION_CALLBACKS* allocationCallbacks, bool isVirtual)
: BlockMetadata(allocationCallbacks, isVirtual),
m_SumFreeSize(0),
@@ -5410,29 +4869,127 @@
}
return false;
}
+#endif // _D3D12MA_BLOCK_METADATA_LINEAR_FUNCTIONS
+#endif // _D3D12MA_BLOCK_METADATA_LINEAR
-////////////////////////////////////////////////////////////////////////////////
-// Private class BlockMetadata_TLSF implementation
+#ifndef _D3D12MA_BLOCK_METADATA_TLSF
+class BlockMetadata_TLSF : public BlockMetadata
+{
+public:
+ BlockMetadata_TLSF(const ALLOCATION_CALLBACKS* allocationCallbacks, bool isVirtual);
+ virtual ~BlockMetadata_TLSF();
+ size_t GetAllocationCount() const override { return m_AllocCount; }
+ UINT64 GetSumFreeSize() const override { return m_BlocksFreeSize + m_NullBlock->size; }
+ bool IsEmpty() const override { return m_NullBlock->offset == 0; }
+ UINT64 GetAllocationOffset(AllocHandle allocHandle) const override { return ((Block*)allocHandle)->offset; };
+
+ void Init(UINT64 size) override;
+ bool Validate() const override;
+ void GetAllocationInfo(AllocHandle allocHandle, VIRTUAL_ALLOCATION_INFO& outInfo) const override;
+
+ bool CreateAllocationRequest(
+ UINT64 allocSize,
+ UINT64 allocAlignment,
+ bool upperAddress,
+ AllocationRequest* pAllocationRequest) override;
+
+ void Alloc(
+ const AllocationRequest& request,
+ UINT64 allocSize,
+ void* userData) override;
+
+ void Free(AllocHandle allocHandle) override;
+ void Clear() override;
+
+ void SetAllocationUserData(AllocHandle allocHandle, void* userData) override;
+
+ void AddStatistics(Statistics& inoutStats) const override;
+ void AddDetailedStatistics(DetailedStatistics& inoutStats) const override;
+ void WriteAllocationInfoToJson(JsonWriter& json) const override;
+
+private:
+ // According to original paper it should be preferable 4 or 5:
+ // M. Masmano, I. Ripoll, A. Crespo, and J. Real "TLSF: a New Dynamic Memory Allocator for Real-Time Systems"
+ // http://www.gii.upv.es/tlsf/files/ecrts04_tlsf.pdf
+ static const UINT8 SECOND_LEVEL_INDEX = 5;
+ static const UINT16 SMALL_BUFFER_SIZE = 256;
+ static const UINT INITIAL_BLOCK_ALLOC_COUNT = 16;
+ static const UINT8 MEMORY_CLASS_SHIFT = 7;
+ static const UINT8 MAX_MEMORY_CLASSES = 65 - MEMORY_CLASS_SHIFT;
+
+ class Block
+ {
+ public:
+ UINT64 offset;
+ UINT64 size;
+ Block* prevPhysical;
+ Block* nextPhysical;
+
+ void MarkFree() { prevFree = NULL; }
+ void MarkTaken() { prevFree = this; }
+ bool IsFree() const { return prevFree != this; }
+ void*& UserData() { D3D12MA_HEAVY_ASSERT(!IsFree()); return userData; }
+ Block*& PrevFree() { return prevFree; }
+ Block*& NextFree() { D3D12MA_HEAVY_ASSERT(IsFree()); return nextFree; }
+
+ private:
+ Block* prevFree; // Address of the same block here indicates that block is taken
+ union
+ {
+ Block* nextFree;
+ void* userData;
+ };
+ };
+
+ size_t m_AllocCount = 0;
+ // Total number of free blocks besides null block
+ size_t m_BlocksFreeCount = 0;
+ // Total size of free blocks excluding null block
+ UINT64 m_BlocksFreeSize = 0;
+ UINT32 m_IsFreeBitmap = 0;
+ UINT8 m_MemoryClasses = 0;
+ UINT32 m_InnerIsFreeBitmap[MAX_MEMORY_CLASSES];
+ UINT32 m_ListsCount = 0;
+ /*
+ * 0: 0-3 lists for small buffers
+ * 1+: 0-(2^SLI-1) lists for normal buffers
+ */
+ Block** m_FreeList = NULL;
+ PoolAllocator<Block> m_BlockAllocator;
+ Block* m_NullBlock = NULL;
+
+ UINT8 SizeToMemoryClass(UINT64 size) const;
+ UINT16 SizeToSecondIndex(UINT64 size, UINT8 memoryClass) const;
+ UINT32 GetListIndex(UINT8 memoryClass, UINT16 secondIndex) const;
+ UINT32 GetListIndex(UINT64 size) const;
+
+ void RemoveFreeBlock(Block* block);
+ void InsertFreeBlock(Block* block);
+ void MergeBlock(Block* block, Block* prev);
+
+ Block* FindFreeBlock(UINT64 size, UINT32& listIndex) const;
+ bool CheckBlock(
+ Block& block,
+ UINT32 listIndex,
+ UINT64 allocSize,
+ UINT64 allocAlignment,
+ AllocationRequest* pAllocationRequest);
+
+ D3D12MA_CLASS_NO_COPY(BlockMetadata_TLSF)
+};
+
+#ifndef _D3D12MA_BLOCK_METADATA_TLSF_FUNCTIONS
BlockMetadata_TLSF::BlockMetadata_TLSF(const ALLOCATION_CALLBACKS* allocationCallbacks, bool isVirtual)
: BlockMetadata(allocationCallbacks, isVirtual),
- m_AllocCount(0),
- m_BlocksFreeCount(0),
- m_BlocksFreeSize(0),
- m_IsFreeBitmap(0),
- m_MemoryClasses(0),
- m_ListsCount(0),
- m_FreeList(NULL),
- m_BlockAllocator(*allocationCallbacks, INITIAL_BLOCK_ALLOC_COUNT),
- m_NullBlock(NULL)
+ m_BlockAllocator(*allocationCallbacks, INITIAL_BLOCK_ALLOC_COUNT)
{
D3D12MA_ASSERT(allocationCallbacks);
}
BlockMetadata_TLSF::~BlockMetadata_TLSF()
{
- if (m_FreeList)
- D3D12MA_DELETE_ARRAY(*GetAllocs(), m_FreeList, m_ListsCount);
+ D3D12MA_DELETE_ARRAY(*GetAllocs(), m_FreeList, m_ListsCount);
}
void BlockMetadata_TLSF::Init(UINT64 size)
@@ -5566,7 +5123,7 @@
{
D3D12MA_ASSERT(allocSize > 0 && "Cannot allocate empty block!");
D3D12MA_ASSERT(!upperAddress && "ALLOCATION_FLAG_UPPER_ADDRESS can be used only with linear algorithm.");
- D3D12MA_ASSERT(pAllocationRequest != NULL);
+ D3D12MA_ASSERT(pAllocationRequest != NULL);
D3D12MA_HEAVY_ASSERT(Validate());
allocSize += GetDebugMargin();
@@ -6018,841 +5575,328 @@
return true;
}
+#endif // _D3D12MA_BLOCK_METADATA_TLSF_FUNCTIONS
+#endif // _D3D12MA_BLOCK_METADATA_TLSF
-////////////////////////////////////////////////////////////////////////////////
-// Private class NormalBlock implementation
-
-NormalBlock::NormalBlock(
- AllocatorPimpl* allocator,
- BlockVector* blockVector,
- const D3D12_HEAP_PROPERTIES& heapProps,
- D3D12_HEAP_FLAGS heapFlags,
- UINT64 size,
- UINT id) :
- MemoryBlock(allocator, heapProps, heapFlags, size, id),
- m_pMetadata(NULL),
- m_BlockVector(blockVector)
+#ifndef _D3D12MA_MEMORY_BLOCK
+/*
+Represents a single block of device memory (heap).
+Base class for inheritance.
+Thread-safety: This class must be externally synchronized.
+*/
+class MemoryBlock
{
-}
+public:
+ // Creates the ID3D12Heap.
+ MemoryBlock(
+ AllocatorPimpl* allocator,
+ const D3D12_HEAP_PROPERTIES& heapProps,
+ D3D12_HEAP_FLAGS heapFlags,
+ UINT64 size,
+ UINT id);
+ virtual ~MemoryBlock();
-NormalBlock::~NormalBlock()
+ const D3D12_HEAP_PROPERTIES& GetHeapProperties() const { return m_HeapProps; }
+ D3D12_HEAP_FLAGS GetHeapFlags() const { return m_HeapFlags; }
+ UINT64 GetSize() const { return m_Size; }
+ UINT GetId() const { return m_Id; }
+ ID3D12Heap* GetHeap() const { return m_Heap; }
+
+protected:
+ AllocatorPimpl* const m_Allocator;
+ const D3D12_HEAP_PROPERTIES m_HeapProps;
+ const D3D12_HEAP_FLAGS m_HeapFlags;
+ const UINT64 m_Size;
+ const UINT m_Id;
+
+ HRESULT Init(ID3D12ProtectedResourceSession* pProtectedSession);
+
+private:
+ ID3D12Heap* m_Heap = NULL;
+
+ D3D12MA_CLASS_NO_COPY(MemoryBlock)
+};
+#endif // _D3D12MA_MEMORY_BLOCK
+
+#ifndef _D3D12MA_NORMAL_BLOCK
+/*
+Represents a single block of device memory (heap) with all the data about its
+regions (aka suballocations, Allocation), assigned and free.
+Thread-safety: This class must be externally synchronized.
+*/
+class NormalBlock : public MemoryBlock
{
- if(m_pMetadata != NULL)
+public:
+ BlockMetadata* m_pMetadata;
+
+ NormalBlock(
+ AllocatorPimpl* allocator,
+ BlockVector* blockVector,
+ const D3D12_HEAP_PROPERTIES& heapProps,
+ D3D12_HEAP_FLAGS heapFlags,
+ UINT64 size,
+ UINT id);
+ virtual ~NormalBlock();
+
+ BlockVector* GetBlockVector() const { return m_BlockVector; }
+
+ // 'algorithm' should be one of the *_ALGORITHM_* flags in enums POOL_FLAGS or VIRTUAL_BLOCK_FLAGS
+ HRESULT Init(UINT32 algorithm, ID3D12ProtectedResourceSession* pProtectedSession);
+
+ // Validates all data structures inside this object. If not valid, returns false.
+ bool Validate() const;
+
+private:
+ BlockVector* m_BlockVector;
+
+ D3D12MA_CLASS_NO_COPY(NormalBlock)
+};
+#endif // _D3D12MA_NORMAL_BLOCK
+
+#ifndef _D3D12MA_COMMITTED_ALLOCATION_LIST_ITEM_TRAITS
+struct CommittedAllocationListItemTraits
+{
+ using ItemType = Allocation;
+
+ static ItemType* GetPrev(const ItemType* item)
{
- // 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_ASSERT(item->m_PackedData.GetType() == Allocation::TYPE_COMMITTED || item->m_PackedData.GetType() == Allocation::TYPE_HEAP);
+ return item->m_Committed.prev;
}
-}
-
-HRESULT NormalBlock::Init(UINT32 algorithm, ID3D12ProtectedResourceSession* pProtectedSession)
-{
- HRESULT hr = MemoryBlock::Init(pProtectedSession);
- if(FAILED(hr))
+ static ItemType* GetNext(const ItemType* item)
{
- return hr;
+ D3D12MA_ASSERT(item->m_PackedData.GetType() == Allocation::TYPE_COMMITTED || item->m_PackedData.GetType() == Allocation::TYPE_HEAP);
+ return item->m_Committed.next;
}
+ static ItemType*& AccessPrev(ItemType* item)
+ {
+ D3D12MA_ASSERT(item->m_PackedData.GetType() == Allocation::TYPE_COMMITTED || item->m_PackedData.GetType() == Allocation::TYPE_HEAP);
+ return item->m_Committed.prev;
+ }
+ static ItemType*& AccessNext(ItemType* item)
+ {
+ D3D12MA_ASSERT(item->m_PackedData.GetType() == Allocation::TYPE_COMMITTED || item->m_PackedData.GetType() == Allocation::TYPE_HEAP);
+ return item->m_Committed.next;
+ }
+};
+#endif // _D3D12MA_COMMITTED_ALLOCATION_LIST_ITEM_TRAITS
+
+#ifndef _D3D12MA_COMMITTED_ALLOCATION_LIST
+/*
+Stores linked list of Allocation objects that are of TYPE_COMMITTED or TYPE_HEAP.
+Thread-safe, synchronized internally.
+*/
+class CommittedAllocationList
+{
+public:
+ CommittedAllocationList() = default;
+ void Init(bool useMutex, D3D12_HEAP_TYPE heapType, PoolPimpl* pool);
+ ~CommittedAllocationList();
+
+ D3D12_HEAP_TYPE GetHeapType() const { return m_HeapType; }
+ PoolPimpl* GetPool() const { return m_Pool; }
+ UINT GetMemorySegmentGroup(AllocatorPimpl* allocator) const;
- switch (algorithm)
- {
- case POOL_FLAG_ALGORITHM_LINEAR:
- m_pMetadata = D3D12MA_NEW(m_Allocator->GetAllocs(), BlockMetadata_Linear)(&m_Allocator->GetAllocs(), false);
- break;
- default:
- D3D12MA_ASSERT(0);
- case 0:
- m_pMetadata = D3D12MA_NEW(m_Allocator->GetAllocs(), BlockMetadata_TLSF)(&m_Allocator->GetAllocs(), false);
- break;
- }
- m_pMetadata->Init(m_Size);
+ void AddStatistics(Statistics& inoutStats);
+ void AddDetailedStatistics(DetailedStatistics& inoutStats);
+ // Writes JSON array with the list of allocations.
+ void BuildStatsString(JsonWriter& json);
- return hr;
-}
+ void Register(Allocation* alloc);
+ void Unregister(Allocation* alloc);
-bool NormalBlock::Validate() const
+private:
+ using CommittedAllocationLinkedList = IntrusiveLinkedList<CommittedAllocationListItemTraits>;
+
+ bool m_UseMutex = true;
+ D3D12_HEAP_TYPE m_HeapType = D3D12_HEAP_TYPE_CUSTOM;
+ PoolPimpl* m_Pool = NULL;
+
+ D3D12MA_RW_MUTEX m_Mutex;
+ CommittedAllocationLinkedList m_AllocationList;
+};
+#endif // _D3D12MA_COMMITTED_ALLOCATION_LIST
+
+#ifndef _D3D12M_COMMITTED_ALLOCATION_PARAMETERS
+struct CommittedAllocationParameters
{
- D3D12MA_VALIDATE(GetHeap() &&
- m_pMetadata &&
- m_pMetadata->GetSize() != 0 &&
- m_pMetadata->GetSize() == GetSize());
- return m_pMetadata->Validate();
-}
+ CommittedAllocationList* m_List = NULL;
+ D3D12_HEAP_PROPERTIES m_HeapProperties = {};
+ D3D12_HEAP_FLAGS m_HeapFlags = D3D12_HEAP_FLAG_NONE;
+ ID3D12ProtectedResourceSession* m_ProtectedSession = NULL;
-////////////////////////////////////////////////////////////////////////////////
-// Private class MemoryBlock definition
+ bool IsValid() const { return m_List != NULL; }
+};
+#endif // _D3D12M_COMMITTED_ALLOCATION_PARAMETERS
-MemoryBlock::MemoryBlock(
- AllocatorPimpl* allocator,
- const D3D12_HEAP_PROPERTIES& heapProps,
- D3D12_HEAP_FLAGS heapFlags,
- UINT64 size,
- UINT id) :
- m_Allocator(allocator),
- m_HeapProps(heapProps),
- m_HeapFlags(heapFlags),
- m_Size(size),
- m_Id(id)
+#ifndef _D3D12MA_BLOCK_VECTOR
+/*
+Sequence of NormalBlock. Represents memory blocks allocated for a specific
+heap type and possibly resource type (if only Tier 1 is supported).
+
+Synchronized internally with a mutex.
+*/
+class BlockVector
{
-}
+ D3D12MA_CLASS_NO_COPY(BlockVector)
+public:
+ BlockVector(
+ AllocatorPimpl* hAllocator,
+ const D3D12_HEAP_PROPERTIES& heapProps,
+ D3D12_HEAP_FLAGS heapFlags,
+ UINT64 preferredBlockSize,
+ size_t minBlockCount,
+ size_t maxBlockCount,
+ bool explicitBlockSize,
+ UINT64 minAllocationAlignment,
+ UINT32 algorithm,
+ ID3D12ProtectedResourceSession* pProtectedSession);
+ ~BlockVector();
-MemoryBlock::~MemoryBlock()
-{
- if(m_Heap)
- {
- m_Heap->Release();
- m_Allocator->m_Budget.RemoveBlock(
- m_Allocator->HeapPropertiesToMemorySegmentGroup(m_HeapProps), m_Size);
- }
-}
+ const D3D12_HEAP_PROPERTIES& GetHeapProperties() const { return m_HeapProps; }
+ UINT64 GetPreferredBlockSize() const { return m_PreferredBlockSize; }
-HRESULT MemoryBlock::Init(ID3D12ProtectedResourceSession* pProtectedSession)
-{
- D3D12MA_ASSERT(m_Heap == NULL && m_Size > 0);
+ HRESULT CreateMinBlocks();
+ bool IsEmpty();
- D3D12_HEAP_DESC heapDesc = {};
- heapDesc.SizeInBytes = m_Size;
- heapDesc.Properties = m_HeapProps;
- heapDesc.Alignment = HeapFlagsToAlignment(m_HeapFlags);
- heapDesc.Flags = m_HeapFlags;
+ HRESULT Allocate(
+ UINT64 size,
+ UINT64 alignment,
+ const ALLOCATION_DESC& allocDesc,
+ size_t allocationCount,
+ Allocation** pAllocations);
- HRESULT hr;
-#ifdef __ID3D12Device4_INTERFACE_DEFINED__
- ID3D12Device4* const device4 = m_Allocator->GetDevice4();
- if(device4)
- hr = m_Allocator->GetDevice4()->CreateHeap1(&heapDesc, pProtectedSession, D3D12MA_IID_PPV_ARGS(&m_Heap));
- else
-#endif
- {
- if(pProtectedSession == NULL)
- hr = m_Allocator->GetDevice()->CreateHeap(&heapDesc, D3D12MA_IID_PPV_ARGS(&m_Heap));
- else
- hr = E_NOINTERFACE;
- }
-
- if(SUCCEEDED(hr))
- {
- m_Allocator->m_Budget.AddBlock(
- m_Allocator->HeapPropertiesToMemorySegmentGroup(m_HeapProps), m_Size);
- }
- return hr;
-}
+ void Free(
+ Allocation* hAllocation);
-////////////////////////////////////////////////////////////////////////////////
-// Private class CommittedAllocationList implementation
-
-CommittedAllocationList::CommittedAllocationList()
-{
-}
-
-void CommittedAllocationList::Init(bool useMutex, D3D12_HEAP_TYPE heapType, PoolPimpl* pool)
-{
- m_UseMutex = useMutex;
- m_HeapType = heapType;
- m_Pool = pool;
-}
-
-CommittedAllocationList::~CommittedAllocationList()
-{
- if(!m_AllocationList.IsEmpty())
- {
- D3D12MA_ASSERT(0 && "Unfreed committed allocations found!");
- }
-}
-
-UINT CommittedAllocationList::GetMemorySegmentGroup(AllocatorPimpl* allocator) const
-{
- if(m_Pool)
- return allocator->HeapPropertiesToMemorySegmentGroup(m_Pool->GetDesc().HeapProperties);
- else
- return allocator->StandardHeapTypeToMemorySegmentGroup(m_HeapType);
-}
-
-void CommittedAllocationList::AddStatistics(Statistics& inoutStats)
-{
- MutexLockRead lock(m_Mutex, m_UseMutex);
-
- for(Allocation* alloc = m_AllocationList.Front();
- alloc != NULL; alloc = m_AllocationList.GetNext(alloc))
- {
- const UINT64 size = alloc->GetSize();
- inoutStats.BlockCount++;
- inoutStats.AllocationCount++;
- inoutStats.BlockBytes += size;
- inoutStats.AllocationBytes += size;
- }
-}
-
-void CommittedAllocationList::AddDetailedStatistics(DetailedStatistics& inoutStats)
-{
- MutexLockRead lock(m_Mutex, m_UseMutex);
-
- for(Allocation* alloc = m_AllocationList.Front();
- alloc != NULL; alloc = m_AllocationList.GetNext(alloc))
- {
- const UINT64 size = alloc->GetSize();
- inoutStats.Stats.BlockCount++;
- inoutStats.Stats.BlockBytes += size;
- AddDetailedStatisticsAllocation(inoutStats, size);
- }
-}
-
-void CommittedAllocationList::BuildStatsString(JsonWriter& json)
-{
- MutexLockRead lock(m_Mutex, m_UseMutex);
-
- json.BeginArray();
- for(Allocation* alloc = m_AllocationList.Front();
- alloc != NULL; alloc = m_AllocationList.GetNext(alloc))
- {
- json.BeginObject(true);
- json.AddAllocationToObject(*alloc);
- json.EndObject();
- }
- json.EndArray();
-}
-
-void CommittedAllocationList::Register(Allocation* alloc)
-{
- MutexLockWrite lock(m_Mutex, m_UseMutex);
- m_AllocationList.PushBack(alloc);
-}
-
-void CommittedAllocationList::Unregister(Allocation* alloc)
-{
- MutexLockWrite lock(m_Mutex, m_UseMutex);
- m_AllocationList.Remove(alloc);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Private class BlockVector implementation
-
-BlockVector::BlockVector(
- AllocatorPimpl* hAllocator,
- const D3D12_HEAP_PROPERTIES& heapProps,
- D3D12_HEAP_FLAGS heapFlags,
- UINT64 preferredBlockSize,
- size_t minBlockCount,
- size_t maxBlockCount,
- bool explicitBlockSize,
- UINT64 minAllocationAlignment,
- UINT32 algorithm,
- ID3D12ProtectedResourceSession* pProtectedSession) :
- m_hAllocator(hAllocator),
- m_HeapProps(heapProps),
- m_HeapFlags(heapFlags),
- m_PreferredBlockSize(preferredBlockSize),
- m_MinBlockCount(minBlockCount),
- m_MaxBlockCount(maxBlockCount),
- m_ExplicitBlockSize(explicitBlockSize),
- m_MinAllocationAlignment(minAllocationAlignment),
- m_Algorithm(algorithm),
- m_ProtectedSession(pProtectedSession),
- m_HasEmptyBlock(false),
- m_Blocks(hAllocator->GetAllocs()),
- m_NextBlockId(0)
-{
-}
-
-BlockVector::~BlockVector()
-{
- for(size_t i = m_Blocks.size(); i--; )
- {
- D3D12MA_DELETE(m_hAllocator->GetAllocs(), m_Blocks[i]);
- }
-}
-
-HRESULT BlockVector::CreateMinBlocks()
-{
- for(size_t i = 0; i < m_MinBlockCount; ++i)
- {
- HRESULT hr = CreateBlock(m_PreferredBlockSize, NULL);
- if(FAILED(hr))
- {
- return hr;
- }
- }
- return S_OK;
-}
-
-bool BlockVector::IsEmpty()
-{
- MutexLockRead lock(m_Mutex, m_hAllocator->UseMutex());
- return m_Blocks.empty();
-}
-
-HRESULT BlockVector::Allocate(
- UINT64 size,
- UINT64 alignment,
- const ALLOCATION_DESC& allocDesc,
- size_t allocationCount,
- Allocation** pAllocations)
-{
- size_t allocIndex;
- HRESULT hr = S_OK;
-
- {
- MutexLockWrite lock(m_Mutex, m_hAllocator->UseMutex());
- for(allocIndex = 0; allocIndex < allocationCount; ++allocIndex)
- {
- hr = AllocatePage(
- size,
- alignment,
- allocDesc,
- pAllocations + allocIndex);
- if(FAILED(hr))
- {
- break;
- }
- }
- }
-
- if(FAILED(hr))
- {
- // Free all already created allocations.
- while(allocIndex--)
- {
- Free(pAllocations[allocIndex]);
- }
- ZeroMemory(pAllocations, sizeof(Allocation*) * allocationCount);
- }
-
- return hr;
-}
-
-HRESULT BlockVector::AllocatePage(
- UINT64 size,
- UINT64 alignment,
- const ALLOCATION_DESC& allocDesc,
- Allocation** pAllocation)
-{
- // Early reject: requested allocation size is larger that maximum block size for this block vector.
- if(size + D3D12MA_DEBUG_MARGIN > m_PreferredBlockSize)
- {
- return E_OUTOFMEMORY;
- }
-
- UINT64 freeMemory = UINT64_MAX;
- if(IsHeapTypeStandard(m_HeapProps.Type))
- {
- Budget budget = {};
- m_hAllocator->GetBudgetForHeapType(budget, m_HeapProps.Type);
- freeMemory = (budget.UsageBytes < budget.BudgetBytes) ? (budget.BudgetBytes - budget.UsageBytes) : 0;
- }
-
- const bool canCreateNewBlock =
- ((allocDesc.Flags & ALLOCATION_FLAG_NEVER_ALLOCATE) == 0) &&
- (m_Blocks.size() < m_MaxBlockCount) &&
- // Even if we don't have to stay within budget with this allocation, when the
- // budget would be exceeded, we don't want to allocate new blocks, but always
- // create resources as committed.
- freeMemory >= size;
-
- // 1. Search existing allocations
- {
- // Forward order in m_Blocks - prefer blocks with smallest amount of free space.
- for(size_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex )
- {
- NormalBlock* const pCurrBlock = m_Blocks[blockIndex];
- D3D12MA_ASSERT(pCurrBlock);
- HRESULT hr = AllocateFromBlock(
- pCurrBlock,
- size,
- alignment,
- allocDesc.Flags,
- pAllocation);
- if(SUCCEEDED(hr))
- {
- return hr;
- }
- }
- }
-
- // 2. Try to create new block.
- if(canCreateNewBlock)
- {
- // Calculate optimal size for new block.
- UINT64 newBlockSize = m_PreferredBlockSize;
- UINT newBlockSizeShift = 0;
-
- if(!m_ExplicitBlockSize)
- {
- // Allocate 1/8, 1/4, 1/2 as first blocks.
- const UINT64 maxExistingBlockSize = CalcMaxBlockSize();
- for(UINT i = 0; i < NEW_BLOCK_SIZE_SHIFT_MAX; ++i)
- {
- const UINT64 smallerNewBlockSize = newBlockSize / 2;
- if(smallerNewBlockSize > maxExistingBlockSize && smallerNewBlockSize >= size * 2)
- {
- newBlockSize = smallerNewBlockSize;
- ++newBlockSizeShift;
- }
- else
- {
- break;
- }
- }
- }
-
- size_t newBlockIndex = 0;
- HRESULT hr = newBlockSize <= freeMemory ?
- CreateBlock(newBlockSize, &newBlockIndex) : E_OUTOFMEMORY;
- // Allocation of this size failed? Try 1/2, 1/4, 1/8 of m_PreferredBlockSize.
- if(!m_ExplicitBlockSize)
- {
- while(FAILED(hr) && newBlockSizeShift < NEW_BLOCK_SIZE_SHIFT_MAX)
- {
- const UINT64 smallerNewBlockSize = newBlockSize / 2;
- if(smallerNewBlockSize >= size)
- {
- newBlockSize = smallerNewBlockSize;
- ++newBlockSizeShift;
- hr = newBlockSize <= freeMemory ?
- CreateBlock(newBlockSize, &newBlockIndex) : E_OUTOFMEMORY;
- }
- else
- {
- break;
- }
- }
- }
-
- if(SUCCEEDED(hr))
- {
- NormalBlock* const pBlock = m_Blocks[newBlockIndex];
- D3D12MA_ASSERT(pBlock->m_pMetadata->GetSize() >= size);
-
- hr = AllocateFromBlock(
- pBlock,
- size,
- alignment,
- allocDesc.Flags,
- pAllocation);
- if(SUCCEEDED(hr))
- {
- return hr;
- }
- else
- {
- // Allocation from new block failed, possibly due to D3D12MA_DEBUG_MARGIN or alignment.
- return E_OUTOFMEMORY;
- }
- }
- }
-
- return E_OUTOFMEMORY;
-}
-
-void BlockVector::Free(Allocation* hAllocation)
-{
- NormalBlock* pBlockToDelete = NULL;
-
- bool budgetExceeded = false;
- if(IsHeapTypeStandard(m_HeapProps.Type))
- {
- Budget budget = {};
- m_hAllocator->GetBudgetForHeapType(budget, m_HeapProps.Type);
- budgetExceeded = budget.UsageBytes >= budget.BudgetBytes;
- }
-
- // Scope for lock.
- {
- MutexLockWrite lock(m_Mutex, m_hAllocator->UseMutex());
-
- NormalBlock* pBlock = hAllocation->m_Placed.block;
-
- pBlock->m_pMetadata->Free(hAllocation->GetAllocHandle());
- D3D12MA_HEAVY_ASSERT(pBlock->Validate());
-
- const size_t blockCount = m_Blocks.size();
- // pBlock became empty after this deallocation.
- if(pBlock->m_pMetadata->IsEmpty())
- {
- // Already has empty Allocation. We don't want to have two, so delete this one.
- if((m_HasEmptyBlock || budgetExceeded) &&
- blockCount > m_MinBlockCount)
- {
- pBlockToDelete = pBlock;
- Remove(pBlock);
- }
- // We now have first empty block.
- else
- {
- m_HasEmptyBlock = true;
- }
- }
- // pBlock didn't become empty, but we have another empty block - find and free that one.
- // (This is optional, heuristics.)
- else if(m_HasEmptyBlock && blockCount > m_MinBlockCount)
- {
- NormalBlock* pLastBlock = m_Blocks.back();
- if(pLastBlock->m_pMetadata->IsEmpty())
- {
- pBlockToDelete = pLastBlock;
- m_Blocks.pop_back();
- m_HasEmptyBlock = false;
- }
- }
-
- IncrementallySortBlocks();
- }
-
- // Destruction of a free Allocation. Deferred until this point, outside of mutex
- // lock, for performance reason.
- if(pBlockToDelete != NULL)
- {
- D3D12MA_DELETE(m_hAllocator->GetAllocs(), pBlockToDelete);
- }
-}
-
-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,
- D3D12MA_IID_PPV_ARGS(&res));
- if(SUCCEEDED(hr))
- {
- if(ppvResource != NULL)
- {
- hr = res->QueryInterface(riidResource, ppvResource);
- }
- if(SUCCEEDED(hr))
- {
- (*ppAllocation)->SetResource(res, &resourceDesc);
- }
- else
- {
- res->Release();
- SAFE_RELEASE(*ppAllocation);
- }
- }
- else
- {
- SAFE_RELEASE(*ppAllocation);
- }
- }
- return hr;
-}
+ 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);
#ifdef __ID3D12Device8_INTERFACE_DEFINED__
-HRESULT BlockVector::CreateResource2(
- UINT64 size,
- UINT64 alignment,
- const ALLOCATION_DESC& allocDesc,
- const D3D12_RESOURCE_DESC1& resourceDesc,
- D3D12_RESOURCE_STATES InitialResourceState,
- const D3D12_CLEAR_VALUE *pOptimizedClearValue,
- Allocation** ppAllocation,
- REFIID riidResource,
- void** ppvResource)
-{
- ID3D12Device8* const device8 = m_hAllocator->GetDevice8();
- if(device8 == NULL)
- {
- return E_NOINTERFACE;
- }
-
- HRESULT hr = Allocate(size, alignment, allocDesc, 1, ppAllocation);
- if(SUCCEEDED(hr))
- {
- ID3D12Resource* res = NULL;
- hr = device8->CreatePlacedResource1(
- (*ppAllocation)->m_Placed.block->GetHeap(),
- (*ppAllocation)->GetOffset(),
- &resourceDesc,
- InitialResourceState,
- pOptimizedClearValue,
- D3D12MA_IID_PPV_ARGS(&res));
- if(SUCCEEDED(hr))
- {
- if(ppvResource != NULL)
- {
- hr = res->QueryInterface(riidResource, ppvResource);
- }
- if(SUCCEEDED(hr))
- {
- (*ppAllocation)->SetResource(res, &resourceDesc);
- }
- else
- {
- res->Release();
- SAFE_RELEASE(*ppAllocation);
- }
- }
- else
- {
- SAFE_RELEASE(*ppAllocation);
- }
- }
- return hr;
-}
+ HRESULT CreateResource2(
+ UINT64 size,
+ UINT64 alignment,
+ const ALLOCATION_DESC& allocDesc,
+ const D3D12_RESOURCE_DESC1& resourceDesc,
+ D3D12_RESOURCE_STATES InitialResourceState,
+ const D3D12_CLEAR_VALUE *pOptimizedClearValue,
+ Allocation** ppAllocation,
+ REFIID riidResource,
+ void** ppvResource);
#endif // #ifdef __ID3D12Device8_INTERFACE_DEFINED__
-UINT64 BlockVector::CalcSumBlockSize() const
+ void AddStatistics(Statistics& inoutStats);
+ void AddDetailedStatistics(DetailedStatistics& inoutStats);
+
+ void WriteBlockInfoToJson(JsonWriter& json);
+
+private:
+ AllocatorPimpl* const m_hAllocator;
+ const D3D12_HEAP_PROPERTIES m_HeapProps;
+ const D3D12_HEAP_FLAGS m_HeapFlags;
+ const UINT64 m_PreferredBlockSize;
+ const size_t m_MinBlockCount;
+ const size_t m_MaxBlockCount;
+ const bool m_ExplicitBlockSize;
+ const UINT64 m_MinAllocationAlignment;
+ const UINT32 m_Algorithm;
+ ID3D12ProtectedResourceSession* const m_ProtectedSession;
+ /* There can be at most one allocation that is completely empty - a
+ hysteresis to avoid pessimistic case of alternating creation and destruction
+ of a VkDeviceMemory. */
+ bool m_HasEmptyBlock;
+ D3D12MA_RW_MUTEX m_Mutex;
+ // Incrementally sorted by sumFreeSize, ascending.
+ Vector<NormalBlock*> m_Blocks;
+ UINT m_NextBlockId;
+
+ UINT64 CalcSumBlockSize() const;
+ UINT64 CalcMaxBlockSize() const;
+
+ // Finds and removes given block from vector.
+ void Remove(NormalBlock* pBlock);
+
+ // Performs single step in sorting m_Blocks. They may not be fully sorted
+ // after this call.
+ void IncrementallySortBlocks();
+
+ HRESULT AllocatePage(
+ UINT64 size,
+ UINT64 alignment,
+ const ALLOCATION_DESC& allocDesc,
+ Allocation** pAllocation);
+
+ HRESULT AllocateFromBlock(
+ NormalBlock* pBlock,
+ UINT64 size,
+ UINT64 alignment,
+ ALLOCATION_FLAGS allocFlags,
+ Allocation** pAllocation);
+
+ HRESULT CreateBlock(
+ UINT64 blockSize,
+ size_t* pNewBlockIndex);
+};
+#endif // _D3D12MA_BLOCK_VECTOR
+
+#ifndef _D3D12MA_CURRENT_BUDGET_DATA
+class CurrentBudgetData
{
- UINT64 result = 0;
- for(size_t i = m_Blocks.size(); i--; )
- {
- result += m_Blocks[i]->m_pMetadata->GetSize();
- }
- return result;
-}
+public:
+ bool ShouldUpdateBudget() const { return m_OperationsSinceBudgetFetch >= 30; }
-UINT64 BlockVector::CalcMaxBlockSize() const
-{
- UINT64 result = 0;
- for(size_t i = m_Blocks.size(); i--; )
- {
- result = D3D12MA_MAX(result, m_Blocks[i]->m_pMetadata->GetSize());
- if(result >= m_PreferredBlockSize)
- {
- break;
- }
- }
- return result;
-}
+ void GetStatistics(Statistics& outStats, UINT group) const;
+ void GetBudget(bool useMutex,
+ UINT64* outLocalUsage, UINT64* outLocalBudget,
+ UINT64* outNonLocalUsage, UINT64* outNonLocalBudget);
-void BlockVector::Remove(NormalBlock* pBlock)
-{
- for(size_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex)
- {
- if(m_Blocks[blockIndex] == pBlock)
- {
- m_Blocks.remove(blockIndex);
- return;
- }
- }
- D3D12MA_ASSERT(0);
-}
-
-void BlockVector::IncrementallySortBlocks()
-{
- // Bubble sort only until first swap.
- for(size_t i = 1; i < m_Blocks.size(); ++i)
- {
- if(m_Blocks[i - 1]->m_pMetadata->GetSumFreeSize() > m_Blocks[i]->m_pMetadata->GetSumFreeSize())
- {
- D3D12MA_SWAP(m_Blocks[i - 1], m_Blocks[i]);
- return;
- }
- }
-}
-
-HRESULT BlockVector::AllocateFromBlock(
- NormalBlock* pBlock,
- UINT64 size,
- UINT64 alignment,
- ALLOCATION_FLAGS allocFlags,
- Allocation** pAllocation)
-{
- alignment = D3D12MA_MAX(alignment, m_MinAllocationAlignment);
-
- AllocationRequest currRequest = {};
- if(pBlock->m_pMetadata->CreateAllocationRequest(
- size,
- alignment,
- allocFlags & ALLOCATION_FLAG_UPPER_ADDRESS,
- &currRequest))
- {
- // We no longer have an empty Allocation.
- if(pBlock->m_pMetadata->IsEmpty())
- {
- m_HasEmptyBlock = false;
- }
-
- *pAllocation = m_hAllocator->GetAllocationObjectAllocator().Allocate(m_hAllocator, size, currRequest.zeroInitialized);
- pBlock->m_pMetadata->Alloc(currRequest, size, *pAllocation);
- (*pAllocation)->InitPlaced(currRequest.allocHandle, alignment, pBlock);
- D3D12MA_HEAVY_ASSERT(pBlock->Validate());
- m_hAllocator->m_Budget.AddAllocation(m_hAllocator->HeapPropertiesToMemorySegmentGroup(m_HeapProps), size);
- return S_OK;
- }
- return E_OUTOFMEMORY;
-}
-
-HRESULT BlockVector::CreateBlock(
- UINT64 blockSize,
- size_t* pNewBlockIndex)
-{
- NormalBlock* const pBlock = D3D12MA_NEW(m_hAllocator->GetAllocs(), NormalBlock)(
- m_hAllocator,
- this,
- m_HeapProps,
- m_HeapFlags,
- blockSize,
- m_NextBlockId++);
- HRESULT hr = pBlock->Init(m_Algorithm, m_ProtectedSession);
- if(FAILED(hr))
- {
- D3D12MA_DELETE(m_hAllocator->GetAllocs(), pBlock);
- return hr;
- }
-
- m_Blocks.push_back(pBlock);
- if(pNewBlockIndex != NULL)
- {
- *pNewBlockIndex = m_Blocks.size() - 1;
- }
-
- return hr;
-}
-
-void BlockVector::AddStatistics(Statistics& inoutStats)
-{
- MutexLockRead lock(m_Mutex, m_hAllocator->UseMutex());
-
- for(size_t i = 0; i < m_Blocks.size(); ++i)
- {
- const NormalBlock* const pBlock = m_Blocks[i];
- D3D12MA_ASSERT(pBlock);
- D3D12MA_HEAVY_ASSERT(pBlock->Validate());
- pBlock->m_pMetadata->AddStatistics(inoutStats);
- }
-}
-
-void BlockVector::AddDetailedStatistics(DetailedStatistics& inoutStats)
-{
- MutexLockRead lock(m_Mutex, m_hAllocator->UseMutex());
-
- for(size_t i = 0; i < m_Blocks.size(); ++i)
- {
- const NormalBlock* const pBlock = m_Blocks[i];
- D3D12MA_ASSERT(pBlock);
- D3D12MA_HEAVY_ASSERT(pBlock->Validate());
- pBlock->m_pMetadata->AddDetailedStatistics(inoutStats);
- }
-}
-
-void BlockVector::WriteBlockInfoToJson(JsonWriter& json)
-{
- MutexLockRead lock(m_Mutex, m_hAllocator->UseMutex());
-
- json.BeginObject();
-
- for (size_t i = 0, count = m_Blocks.size(); i < count; ++i)
- {
- const NormalBlock* const pBlock = m_Blocks[i];
- D3D12MA_ASSERT(pBlock);
- D3D12MA_HEAVY_ASSERT(pBlock->Validate());
- json.BeginString();
- json.ContinueString(pBlock->GetId());
- json.EndString();
-
- pBlock->m_pMetadata->WriteAllocationInfoToJson(json);
- }
-
- json.EndObject();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Private class PoolPimpl
-
-PoolPimpl::PoolPimpl(AllocatorPimpl* allocator, const POOL_DESC& desc) :
- m_Allocator(allocator),
- m_Desc(desc),
- m_BlockVector(NULL),
- m_Name(NULL)
-{
- const bool explicitBlockSize = desc.BlockSize != 0;
- const UINT64 preferredBlockSize = explicitBlockSize ? desc.BlockSize : D3D12MA_DEFAULT_BLOCK_SIZE;
- UINT maxBlockCount = desc.MaxBlockCount != 0 ? desc.MaxBlockCount : UINT_MAX;
-
-#ifndef __ID3D12Device4_INTERFACE_DEFINED__
- D3D12MA_ASSERT(m_Desc.pProtectedSession == NULL);
+#if D3D12MA_DXGI_1_4
+ HRESULT UpdateBudget(IDXGIAdapter3* adapter3, bool useMutex);
#endif
- m_BlockVector = D3D12MA_NEW(allocator->GetAllocs(), BlockVector)(
- allocator, desc.HeapProperties, desc.HeapFlags,
- preferredBlockSize,
- desc.MinBlockCount, maxBlockCount,
- explicitBlockSize,
- D3D12MA_MAX(desc.MinAllocationAlignment, (UINT64)D3D12MA_DEBUG_ALIGNMENT),
- desc.Flags & POOL_FLAG_ALGORITHM_MASK,
- desc.pProtectedSession);
-}
+ void AddAllocation(UINT group, UINT64 allocationBytes);
+ void RemoveAllocation(UINT group, UINT64 allocationBytes);
-HRESULT PoolPimpl::Init()
+ void AddBlock(UINT group, UINT64 blockBytes);
+ void RemoveBlock(UINT group, UINT64 blockBytes);
+
+private:
+ D3D12MA_ATOMIC_UINT32 m_BlockCount[DXGI_MEMORY_SEGMENT_GROUP_COUNT] = {};
+ D3D12MA_ATOMIC_UINT32 m_AllocationCount[DXGI_MEMORY_SEGMENT_GROUP_COUNT] = {};
+ D3D12MA_ATOMIC_UINT64 m_BlockBytes[DXGI_MEMORY_SEGMENT_GROUP_COUNT] = {};
+ D3D12MA_ATOMIC_UINT64 m_AllocationBytes[DXGI_MEMORY_SEGMENT_GROUP_COUNT] = {};
+
+ D3D12MA_ATOMIC_UINT32 m_OperationsSinceBudgetFetch = 0;
+ D3D12MA_RW_MUTEX m_BudgetMutex;
+ UINT64 m_D3D12Usage[DXGI_MEMORY_SEGMENT_GROUP_COUNT] = {};
+ UINT64 m_D3D12Budget[DXGI_MEMORY_SEGMENT_GROUP_COUNT] = {};
+ UINT64 m_BlockBytesAtD3D12Fetch[DXGI_MEMORY_SEGMENT_GROUP_COUNT] = {};
+};
+
+#ifndef _D3D12MA_CURRENT_BUDGET_DATA_FUNCTIONS
+void CurrentBudgetData::GetStatistics(Statistics& outStats, UINT group) const
{
- m_CommittedAllocations.Init(m_Allocator->UseMutex(), m_Desc.HeapProperties.Type, this);
- return m_BlockVector->CreateMinBlocks();
+ outStats.BlockCount = m_BlockCount[group];
+ outStats.AllocationCount = m_AllocationCount[group];
+ outStats.BlockBytes = m_BlockBytes[group];
+ outStats.AllocationBytes = m_AllocationBytes[group];
}
-PoolPimpl::~PoolPimpl()
-{
- D3D12MA_ASSERT(m_PrevPool == NULL && m_NextPool == NULL);
- FreeName();
- D3D12MA_DELETE(m_Allocator->GetAllocs(), m_BlockVector);
-}
-
-void PoolPimpl::GetStatistics(Statistics& outStats)
-{
- ClearStatistics(outStats);
- m_BlockVector->AddStatistics(outStats);
- m_CommittedAllocations.AddStatistics(outStats);
-}
-
-void PoolPimpl::CalculateStatistics(DetailedStatistics& outStats)
-{
- ClearDetailedStatistics(outStats);
- AddDetailedStatistics(outStats);
-}
-
-void PoolPimpl::AddDetailedStatistics(DetailedStatistics& inoutStats)
-{
- m_BlockVector->AddDetailedStatistics(inoutStats);
- m_CommittedAllocations.AddDetailedStatistics(inoutStats);
-}
-
-void PoolPimpl::SetName(LPCWSTR Name)
-{
- FreeName();
-
- if(Name)
- {
- const size_t nameCharCount = wcslen(Name) + 1;
- m_Name = D3D12MA_NEW_ARRAY(m_Allocator->GetAllocs(), WCHAR, nameCharCount);
- memcpy(m_Name, Name, nameCharCount * sizeof(WCHAR));
- }
-}
-
-void PoolPimpl::FreeName()
-{
- if(m_Name)
- {
- const size_t nameCharCount = wcslen(m_Name) + 1;
- D3D12MA_DELETE_ARRAY(m_Allocator->GetAllocs(), m_Name, nameCharCount);
- m_Name = NULL;
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Private class CurrentBudgetData implementation
-
void CurrentBudgetData::GetBudget(bool useMutex,
UINT64* outLocalUsage, UINT64* outLocalBudget,
UINT64* outNonLocalUsage, UINT64* outNonLocalBudget)
{
MutexLockRead lockRead(m_BudgetMutex, useMutex);
- if(outLocalUsage)
+ if (outLocalUsage)
{
const UINT64 D3D12Usage = m_D3D12Usage[DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY];
const UINT64 blockBytes = m_BlockBytes[DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY];
@@ -6860,10 +5904,10 @@
*outLocalUsage = D3D12Usage + blockBytes > blockBytesAtD3D12Fetch ?
D3D12Usage + blockBytes - blockBytesAtD3D12Fetch : 0;
}
- if(outLocalBudget)
+ if (outLocalBudget)
*outLocalBudget = m_D3D12Budget[DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY];
- if(outNonLocalUsage)
+ if (outNonLocalUsage)
{
const UINT64 D3D12Usage = m_D3D12Usage[DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL_COPY];
const UINT64 blockBytes = m_BlockBytes[DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL_COPY];
@@ -6871,7 +5915,7 @@
*outNonLocalUsage = D3D12Usage + blockBytes > blockBytesAtD3D12Fetch ?
D3D12Usage + blockBytes - blockBytesAtD3D12Fetch : 0;
}
- if(outNonLocalBudget)
+ if (outNonLocalBudget)
*outNonLocalBudget = m_D3D12Budget[DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL_COPY];
}
@@ -6885,16 +5929,16 @@
const HRESULT hrLocal = adapter3->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &infoLocal);
const HRESULT hrNonLocal = adapter3->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL, &infoNonLocal);
- if(SUCCEEDED(hrLocal) || SUCCEEDED(hrNonLocal))
+ if (SUCCEEDED(hrLocal) || SUCCEEDED(hrNonLocal))
{
MutexLockWrite lockWrite(m_BudgetMutex, useMutex);
- if(SUCCEEDED(hrLocal))
+ if (SUCCEEDED(hrLocal))
{
m_D3D12Usage[0] = infoLocal.CurrentUsage;
m_D3D12Budget[0] = infoLocal.Budget;
}
- if(SUCCEEDED(hrNonLocal))
+ if (SUCCEEDED(hrNonLocal))
{
m_D3D12Usage[1] = infoNonLocal.CurrentUsage;
m_D3D12Budget[1] = infoNonLocal.Budget;
@@ -6909,66 +5953,287 @@
}
#endif // #if D3D12MA_DXGI_1_4
-////////////////////////////////////////////////////////////////////////////////
-// Public class Pool implementation
-
-void Pool::ReleaseThis()
+void CurrentBudgetData::AddAllocation(UINT group, UINT64 allocationBytes)
{
- if(this == NULL)
- {
- return;
- }
-
- D3D12MA_DELETE(m_Pimpl->GetAllocator()->GetAllocs(), this);
+ ++m_AllocationCount[group];
+ m_AllocationBytes[group] += allocationBytes;
+ ++m_OperationsSinceBudgetFetch;
}
-POOL_DESC Pool::GetDesc() const
+void CurrentBudgetData::RemoveAllocation(UINT group, UINT64 allocationBytes)
{
- return m_Pimpl->GetDesc();
+ D3D12MA_ASSERT(m_AllocationBytes[group] >= allocationBytes);
+ D3D12MA_ASSERT(m_AllocationCount[group] > 0);
+ m_AllocationBytes[group] -= allocationBytes;
+ --m_AllocationCount[group];
+ ++m_OperationsSinceBudgetFetch;
}
-void Pool::GetStatistics(Statistics* pStats)
+void CurrentBudgetData::AddBlock(UINT group, UINT64 blockBytes)
{
- D3D12MA_ASSERT(pStats);
- D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- m_Pimpl->GetStatistics(*pStats);
+ ++m_BlockCount[group];
+ m_BlockBytes[group] += blockBytes;
+ ++m_OperationsSinceBudgetFetch;
}
-void Pool::CalculateStatistics(DetailedStatistics* pStats)
+void CurrentBudgetData::RemoveBlock(UINT group, UINT64 blockBytes)
{
- D3D12MA_ASSERT(pStats);
- D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- m_Pimpl->CalculateStatistics(*pStats);
+ D3D12MA_ASSERT(m_BlockBytes[group] >= blockBytes);
+ D3D12MA_ASSERT(m_BlockCount[group] > 0);
+ m_BlockBytes[group] -= blockBytes;
+ --m_BlockCount[group];
+ ++m_OperationsSinceBudgetFetch;
}
+#endif // _D3D12MA_CURRENT_BUDGET_DATA_FUNCTIONS
+#endif // _D3D12MA_CURRENT_BUDGET_DATA
-void Pool::SetName(LPCWSTR Name)
+#ifndef _D3D12MA_POOL_PIMPL
+class PoolPimpl
{
- D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- m_Pimpl->SetName(Name);
-}
+ friend class Allocator;
+ friend struct PoolListItemTraits;
+public:
+ PoolPimpl(AllocatorPimpl* allocator, const POOL_DESC& desc);
+ ~PoolPimpl();
-LPCWSTR Pool::GetName() const
+ AllocatorPimpl* GetAllocator() const { return m_Allocator; }
+ const POOL_DESC& GetDesc() const { return m_Desc; }
+ bool SupportsCommittedAllocations() const { return m_Desc.BlockSize == 0; }
+ LPCWSTR GetName() const { return m_Name; }
+
+ BlockVector* GetBlockVector() { return m_BlockVector; }
+ CommittedAllocationList* GetCommittedAllocationList() { return SupportsCommittedAllocations() ? &m_CommittedAllocations : NULL; }
+
+ HRESULT Init();
+ void GetStatistics(Statistics& outStats);
+ void CalculateStatistics(DetailedStatistics& outStats);
+ void AddDetailedStatistics(DetailedStatistics& inoutStats);
+ void SetName(LPCWSTR Name);
+
+private:
+ AllocatorPimpl* m_Allocator; // Externally owned object.
+ POOL_DESC m_Desc;
+ BlockVector* m_BlockVector; // Owned object.
+ CommittedAllocationList m_CommittedAllocations;
+ wchar_t* m_Name;
+ PoolPimpl* m_PrevPool = NULL;
+ PoolPimpl* m_NextPool = NULL;
+
+ void FreeName();
+};
+
+struct PoolListItemTraits
{
- return m_Pimpl->GetName();
-}
+ using ItemType = PoolPimpl;
+ static ItemType* GetPrev(const ItemType* item) { return item->m_PrevPool; }
+ static ItemType* GetNext(const ItemType* item) { return item->m_NextPool; }
+ static ItemType*& AccessPrev(ItemType* item) { return item->m_PrevPool; }
+ static ItemType*& AccessNext(ItemType* item) { return item->m_NextPool; }
+};
+#endif // _D3D12MA_POOL_PIMPL
-Pool::Pool(Allocator* allocator, const POOL_DESC &desc) :
- m_Pimpl(D3D12MA_NEW(allocator->m_Pimpl->GetAllocs(), PoolPimpl)(allocator->m_Pimpl, desc))
+
+#ifndef _D3D12MA_ALLOCATOR_PIMPL
+class AllocatorPimpl
{
-}
+ friend class Allocator;
+ friend class Pool;
+public:
+ std::atomic_uint32_t m_RefCount = 1;
+ CurrentBudgetData m_Budget;
-Pool::~Pool()
-{
- m_Pimpl->GetAllocator()->UnregisterPool(this, m_Pimpl->GetDesc().HeapProperties.Type);
+ AllocatorPimpl(const ALLOCATION_CALLBACKS& allocationCallbacks, const ALLOCATOR_DESC& desc);
+ ~AllocatorPimpl();
- D3D12MA_DELETE(m_Pimpl->GetAllocator()->GetAllocs(), m_Pimpl);
-}
+ ID3D12Device* GetDevice() const { return m_Device; }
+#ifdef __ID3D12Device4_INTERFACE_DEFINED__
+ ID3D12Device4* GetDevice4() const { return m_Device4; }
+#endif
+#ifdef __ID3D12Device8_INTERFACE_DEFINED__
+ ID3D12Device8* GetDevice8() const { return m_Device8; }
+#endif
+ // Shortcut for "Allocation Callbacks", because this function is called so often.
+ const ALLOCATION_CALLBACKS& GetAllocs() const { return m_AllocationCallbacks; }
+ const D3D12_FEATURE_DATA_D3D12_OPTIONS& GetD3D12Options() const { return m_D3D12Options; }
+ BOOL IsUMA() const { return m_D3D12Architecture.UMA; }
+ BOOL IsCacheCoherentUMA() const { return m_D3D12Architecture.CacheCoherentUMA; }
+ bool SupportsResourceHeapTier2() const { return m_D3D12Options.ResourceHeapTier >= D3D12_RESOURCE_HEAP_TIER_2; }
+ bool UseMutex() const { return m_UseMutex; }
+ AllocationObjectAllocator& GetAllocationObjectAllocator() { return m_AllocationObjectAllocator; }
+ UINT GetCurrentFrameIndex() const { return m_CurrentFrameIndex.load(); }
-////////////////////////////////////////////////////////////////////////////////
-// Private class AllocatorPimpl implementation
+ HRESULT Init(const ALLOCATOR_DESC& desc);
+ bool HeapFlagsFulfillResourceHeapTier(D3D12_HEAP_FLAGS flags) const;
+ UINT StandardHeapTypeToMemorySegmentGroup(D3D12_HEAP_TYPE heapType) const;
+ UINT HeapPropertiesToMemorySegmentGroup(const D3D12_HEAP_PROPERTIES& heapProps) const;
+ UINT64 GetMemoryCapacity(UINT memorySegmentGroup) const;
-AllocatorPimpl::AllocatorPimpl(const ALLOCATION_CALLBACKS& allocationCallbacks, const ALLOCATOR_DESC& desc) :
- m_UseMutex((desc.Flags & ALLOCATOR_FLAG_SINGLETHREADED) == 0),
+ HRESULT CreateResource(
+ const ALLOCATION_DESC* pAllocDesc,
+ const D3D12_RESOURCE_DESC* pResourceDesc,
+ D3D12_RESOURCE_STATES InitialResourceState,
+ const D3D12_CLEAR_VALUE *pOptimizedClearValue,
+ Allocation** ppAllocation,
+ REFIID riidResource,
+ void** ppvResource);
+
+#ifdef __ID3D12Device8_INTERFACE_DEFINED__
+ HRESULT CreateResource2(
+ const ALLOCATION_DESC* pAllocDesc,
+ const D3D12_RESOURCE_DESC1* pResourceDesc,
+ D3D12_RESOURCE_STATES InitialResourceState,
+ const D3D12_CLEAR_VALUE *pOptimizedClearValue,
+ Allocation** ppAllocation,
+ REFIID riidResource,
+ void** ppvResource);
+#endif // #ifdef __ID3D12Device8_INTERFACE_DEFINED__
+
+ HRESULT CreateAliasingResource(
+ Allocation* pAllocation,
+ UINT64 AllocationLocalOffset,
+ const D3D12_RESOURCE_DESC* pResourceDesc,
+ D3D12_RESOURCE_STATES InitialResourceState,
+ const D3D12_CLEAR_VALUE *pOptimizedClearValue,
+ REFIID riidResource,
+ void** ppvResource);
+
+ HRESULT AllocateMemory(
+ const ALLOCATION_DESC* pAllocDesc,
+ const D3D12_RESOURCE_ALLOCATION_INFO* pAllocInfo,
+ Allocation** ppAllocation);
+
+ // Unregisters allocation from the collection of dedicated allocations.
+ // Allocation object must be deleted externally afterwards.
+ void FreeCommittedMemory(Allocation* allocation);
+ // Unregisters allocation from the collection of placed allocations.
+ // Allocation object must be deleted externally afterwards.
+ void FreePlacedMemory(Allocation* allocation);
+ // Unregisters allocation from the collection of dedicated allocations and destroys associated heap.
+ // Allocation object must be deleted externally afterwards.
+ void FreeHeapMemory(Allocation* allocation);
+
+ void SetCurrentFrameIndex(UINT frameIndex);
+
+ void CalculateStatistics(TotalStatistics& outStats);
+
+ void GetBudget(Budget* outLocalBudget, Budget* outNonLocalBudget);
+ void GetBudgetForHeapType(Budget& outBudget, D3D12_HEAP_TYPE heapType);
+
+ void BuildStatsString(WCHAR** ppStatsString, BOOL DetailedMap);
+ void FreeStatsString(WCHAR* pStatsString);
+
+private:
+ using PoolList = IntrusiveLinkedList<PoolListItemTraits>;
+
+ const bool m_UseMutex;
+ const bool m_AlwaysCommitted;
+ ID3D12Device* m_Device; // AddRef
+#ifdef __ID3D12Device4_INTERFACE_DEFINED__
+ ID3D12Device4* m_Device4 = NULL; // AddRef, optional
+#endif
+#ifdef __ID3D12Device8_INTERFACE_DEFINED__
+ ID3D12Device8* m_Device8 = NULL; // AddRef, optional
+#endif
+ IDXGIAdapter* m_Adapter; // AddRef
+#if D3D12MA_DXGI_1_4
+ IDXGIAdapter3* m_Adapter3 = NULL; // AddRef, optional
+#endif
+ UINT64 m_PreferredBlockSize;
+ ALLOCATION_CALLBACKS m_AllocationCallbacks;
+ D3D12MA_ATOMIC_UINT32 m_CurrentFrameIndex;
+ DXGI_ADAPTER_DESC m_AdapterDesc;
+ D3D12_FEATURE_DATA_D3D12_OPTIONS m_D3D12Options;
+ D3D12_FEATURE_DATA_ARCHITECTURE m_D3D12Architecture;
+ AllocationObjectAllocator m_AllocationObjectAllocator;
+
+ D3D12MA_RW_MUTEX m_PoolsMutex[HEAP_TYPE_COUNT];
+ PoolList m_Pools[HEAP_TYPE_COUNT];
+ // Default pools.
+ BlockVector* m_BlockVectors[DEFAULT_POOL_MAX_COUNT];
+ CommittedAllocationList m_CommittedAllocations[STANDARD_HEAP_TYPE_COUNT];
+
+ /*
+ Heuristics that decides whether a resource should better be placed in its own,
+ dedicated allocation (committed resource rather than placed resource).
+ */
+ template<typename D3D12_RESOURCE_DESC_T>
+ static bool PrefersCommittedAllocation(const D3D12_RESOURCE_DESC_T& resourceDesc);
+
+ // Allocates and registers new committed resource with implicit heap, as dedicated allocation.
+ // Creates and returns Allocation object and optionally D3D12 resource.
+ HRESULT AllocateCommittedResource(
+ const CommittedAllocationParameters& committedAllocParams,
+ UINT64 resourceSize, bool withinBudget,
+ const D3D12_RESOURCE_DESC* pResourceDesc,
+ D3D12_RESOURCE_STATES InitialResourceState, const D3D12_CLEAR_VALUE *pOptimizedClearValue,
+ Allocation** ppAllocation, REFIID riidResource, void** ppvResource);
+
+#ifdef __ID3D12Device8_INTERFACE_DEFINED__
+ HRESULT AllocateCommittedResource2(
+ const CommittedAllocationParameters& committedAllocParams,
+ UINT64 resourceSize, bool withinBudget,
+ const D3D12_RESOURCE_DESC1* pResourceDesc,
+ D3D12_RESOURCE_STATES InitialResourceState, const D3D12_CLEAR_VALUE *pOptimizedClearValue,
+ Allocation** ppAllocation, REFIID riidResource, void** ppvResource);
+#endif
+
+ // Allocates and registers new heap without any resources placed in it, as dedicated allocation.
+ // Creates and returns Allocation object.
+ HRESULT AllocateHeap(
+ const CommittedAllocationParameters& committedAllocParams,
+ const D3D12_RESOURCE_ALLOCATION_INFO& allocInfo, bool withinBudget,
+ Allocation** ppAllocation);
+
+ template<typename D3D12_RESOURCE_DESC_T>
+ HRESULT CalcAllocationParams(const ALLOCATION_DESC& allocDesc, UINT64 allocSize,
+ const D3D12_RESOURCE_DESC_T* resDesc, // Optional
+ BlockVector*& outBlockVector, CommittedAllocationParameters& outCommittedAllocationParams, bool& outPreferCommitted);
+
+ /*
+ If SupportsResourceHeapTier2():
+ 0: D3D12_HEAP_TYPE_DEFAULT
+ 1: D3D12_HEAP_TYPE_UPLOAD
+ 2: D3D12_HEAP_TYPE_READBACK
+ else:
+ 0: D3D12_HEAP_TYPE_DEFAULT + buffer
+ 1: D3D12_HEAP_TYPE_DEFAULT + texture
+ 2: D3D12_HEAP_TYPE_DEFAULT + texture RT or DS
+ 3: D3D12_HEAP_TYPE_UPLOAD + buffer
+ 4: D3D12_HEAP_TYPE_UPLOAD + texture
+ 5: D3D12_HEAP_TYPE_UPLOAD + texture RT or DS
+ 6: D3D12_HEAP_TYPE_READBACK + buffer
+ 7: D3D12_HEAP_TYPE_READBACK + texture
+ 8: D3D12_HEAP_TYPE_READBACK + texture RT or DS
+ */
+ UINT CalcDefaultPoolCount() const;
+ // Returns UINT32_MAX if index cannot be calculcated.
+ UINT CalcDefaultPoolIndex(const ALLOCATION_DESC& allocDesc, ResourceClass resourceClass) const;
+ void CalcDefaultPoolParams(D3D12_HEAP_TYPE& outHeapType, D3D12_HEAP_FLAGS& outHeapFlags, UINT index) const;
+
+ // Registers Pool object in m_Pools.
+ void RegisterPool(Pool* pool, D3D12_HEAP_TYPE heapType);
+ // Unregisters Pool object from m_Pools.
+ void UnregisterPool(Pool* pool, D3D12_HEAP_TYPE heapType);
+
+ HRESULT UpdateD3D12Budget();
+
+ D3D12_RESOURCE_ALLOCATION_INFO GetResourceAllocationInfoNative(const D3D12_RESOURCE_DESC& resourceDesc) const;
+#ifdef __ID3D12Device8_INTERFACE_DEFINED__
+ D3D12_RESOURCE_ALLOCATION_INFO GetResourceAllocationInfoNative(const D3D12_RESOURCE_DESC1& resourceDesc) const;
+#endif
+
+ template<typename D3D12_RESOURCE_DESC_T>
+ D3D12_RESOURCE_ALLOCATION_INFO GetResourceAllocationInfo(D3D12_RESOURCE_DESC_T& inOutResourceDesc) const;
+
+ bool NewAllocationWithinBudget(D3D12_HEAP_TYPE heapType, UINT64 size);
+
+ // Writes object { } with data of given budget.
+ static void WriteBudgetToJson(JsonWriter& json, const Budget& budget);
+};
+
+#ifndef _D3D12MA_ALLOCATOR_PIMPL_FUNCTINOS
+AllocatorPimpl::AllocatorPimpl(const ALLOCATION_CALLBACKS& allocationCallbacks, const ALLOCATOR_DESC& desc)
+ : m_UseMutex((desc.Flags & ALLOCATOR_FLAG_SINGLETHREADED) == 0),
m_AlwaysCommitted((desc.Flags & ALLOCATOR_FLAG_ALWAYS_COMMITTED) != 0),
m_Device(desc.pDevice),
m_Adapter(desc.pAdapter),
@@ -6984,7 +6249,7 @@
ZeroMemory(m_BlockVectors, sizeof(m_BlockVectors));
- for(UINT i = 0; i < STANDARD_HEAP_TYPE_COUNT; ++i)
+ for (UINT i = 0; i < STANDARD_HEAP_TYPE_COUNT; ++i)
{
m_CommittedAllocations[i].Init(
m_UseMutex,
@@ -7011,13 +6276,13 @@
#endif
HRESULT hr = m_Adapter->GetDesc(&m_AdapterDesc);
- if(FAILED(hr))
+ 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;
}
@@ -7026,7 +6291,7 @@
#endif
hr = m_Device->CheckFeatureSupport(D3D12_FEATURE_ARCHITECTURE, &m_D3D12Architecture, sizeof(m_D3D12Architecture));
- if(FAILED(hr))
+ if (FAILED(hr))
{
m_D3D12Architecture.UMA = FALSE;
m_D3D12Architecture.CacheCoherentUMA = FALSE;
@@ -7034,7 +6299,7 @@
D3D12_HEAP_PROPERTIES heapProps = {};
const UINT defaultPoolCount = CalcDefaultPoolCount();
- for(UINT i = 0; i < defaultPoolCount; ++i)
+ for (UINT i = 0; i < defaultPoolCount; ++i)
{
D3D12_HEAP_FLAGS heapFlags;
CalcDefaultPoolParams(heapProps.Type, heapFlags, i);
@@ -7074,14 +6339,14 @@
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]);
}
- for(UINT i = HEAP_TYPE_COUNT; i--; )
+ for (UINT i = HEAP_TYPE_COUNT; i--; )
{
- if(!m_Pools[i].IsEmpty())
+ if (!m_Pools[i].IsEmpty())
{
D3D12MA_ASSERT(0 && "Unfreed pools found!");
}
@@ -7090,25 +6355,59 @@
bool AllocatorPimpl::HeapFlagsFulfillResourceHeapTier(D3D12_HEAP_FLAGS flags) const
{
- if(SupportsResourceHeapTier2())
+ 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 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;
}
}
+UINT AllocatorPimpl::StandardHeapTypeToMemorySegmentGroup(D3D12_HEAP_TYPE heapType) const
+{
+ D3D12MA_ASSERT(IsHeapTypeStandard(heapType));
+ if (IsUMA())
+ return DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY;
+ return heapType == D3D12_HEAP_TYPE_DEFAULT ?
+ DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY : DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL_COPY;
+}
+
+UINT AllocatorPimpl::HeapPropertiesToMemorySegmentGroup(const D3D12_HEAP_PROPERTIES& heapProps) const
+{
+ if (IsUMA())
+ return DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY;
+ if (heapProps.MemoryPoolPreference == D3D12_MEMORY_POOL_UNKNOWN)
+ return StandardHeapTypeToMemorySegmentGroup(heapProps.Type);
+ return heapProps.MemoryPoolPreference == D3D12_MEMORY_POOL_L1 ?
+ DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY : DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL_COPY;
+}
+
+UINT64 AllocatorPimpl::GetMemoryCapacity(UINT memorySegmentGroup) const
+{
+ switch (memorySegmentGroup)
+ {
+ case DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY:
+ return IsUMA() ?
+ m_AdapterDesc.DedicatedVideoMemory + m_AdapterDesc.SharedSystemMemory : m_AdapterDesc.DedicatedVideoMemory;
+ case DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL_COPY:
+ return IsUMA() ? 0 : m_AdapterDesc.SharedSystemMemory;
+ default:
+ D3D12MA_ASSERT(0);
+ return UINT64_MAX;
+ }
+}
+
HRESULT AllocatorPimpl::CreateResource(
const ALLOCATION_DESC* pAllocDesc,
const D3D12_RESOURCE_DESC* pResourceDesc,
D3D12_RESOURCE_STATES InitialResourceState,
- const D3D12_CLEAR_VALUE *pOptimizedClearValue,
+ const D3D12_CLEAR_VALUE* pOptimizedClearValue,
Allocation** ppAllocation,
REFIID riidResource,
void** ppvResource)
@@ -7116,7 +6415,7 @@
D3D12MA_ASSERT(pAllocDesc && pResourceDesc && ppAllocation);
*ppAllocation = NULL;
- if(ppvResource)
+ if (ppvResource)
{
*ppvResource = NULL;
}
@@ -7132,36 +6431,36 @@
HRESULT hr = CalcAllocationParams<D3D12_RESOURCE_DESC>(*pAllocDesc, resAllocInfo.SizeInBytes,
pResourceDesc,
blockVector, committedAllocationParams, preferCommitted);
- if(FAILED(hr))
+ if (FAILED(hr))
return hr;
const bool withinBudget = (pAllocDesc->Flags & ALLOCATION_FLAG_WITHIN_BUDGET) != 0;
hr = E_INVALIDARG;
- if(committedAllocationParams.IsValid() && preferCommitted)
+ if (committedAllocationParams.IsValid() && preferCommitted)
{
hr = AllocateCommittedResource(committedAllocationParams,
resAllocInfo.SizeInBytes, withinBudget, &finalResourceDesc,
InitialResourceState, pOptimizedClearValue,
ppAllocation, riidResource, ppvResource);
- if(SUCCEEDED(hr))
+ if (SUCCEEDED(hr))
return hr;
}
- if(blockVector != NULL)
+ if (blockVector != NULL)
{
hr = blockVector->CreateResource(resAllocInfo.SizeInBytes, resAllocInfo.Alignment,
*pAllocDesc, finalResourceDesc,
InitialResourceState, pOptimizedClearValue,
ppAllocation, riidResource, ppvResource);
- if(SUCCEEDED(hr))
+ if (SUCCEEDED(hr))
return hr;
}
- if(committedAllocationParams.IsValid() && !preferCommitted)
+ if (committedAllocationParams.IsValid() && !preferCommitted)
{
hr = AllocateCommittedResource(committedAllocationParams,
resAllocInfo.SizeInBytes, withinBudget, &finalResourceDesc,
InitialResourceState, pOptimizedClearValue,
ppAllocation, riidResource, ppvResource);
- if(SUCCEEDED(hr))
+ if (SUCCEEDED(hr))
return hr;
}
return hr;
@@ -7172,7 +6471,7 @@
const ALLOCATION_DESC* pAllocDesc,
const D3D12_RESOURCE_DESC1* pResourceDesc,
D3D12_RESOURCE_STATES InitialResourceState,
- const D3D12_CLEAR_VALUE *pOptimizedClearValue,
+ const D3D12_CLEAR_VALUE* pOptimizedClearValue,
Allocation** ppAllocation,
REFIID riidResource,
void** ppvResource)
@@ -7180,11 +6479,11 @@
D3D12MA_ASSERT(pAllocDesc && pResourceDesc && ppAllocation);
*ppAllocation = NULL;
- if(ppvResource)
+ if (ppvResource)
{
*ppvResource = NULL;
}
- if(m_Device8 == NULL)
+ if (m_Device8 == NULL)
{
return E_NOINTERFACE;
}
@@ -7200,36 +6499,36 @@
HRESULT hr = CalcAllocationParams<D3D12_RESOURCE_DESC1>(*pAllocDesc, resAllocInfo.SizeInBytes,
pResourceDesc,
blockVector, committedAllocationParams, preferCommitted);
- if(FAILED(hr))
+ if (FAILED(hr))
return hr;
-
+
const bool withinBudget = (pAllocDesc->Flags & ALLOCATION_FLAG_WITHIN_BUDGET) != 0;
hr = E_INVALIDARG;
- if(committedAllocationParams.IsValid() && preferCommitted)
+ if (committedAllocationParams.IsValid() && preferCommitted)
{
hr = AllocateCommittedResource2(committedAllocationParams,
- resAllocInfo.SizeInBytes, withinBudget,&finalResourceDesc,
+ resAllocInfo.SizeInBytes, withinBudget, &finalResourceDesc,
InitialResourceState, pOptimizedClearValue,
ppAllocation, riidResource, ppvResource);
- if(SUCCEEDED(hr))
+ if (SUCCEEDED(hr))
return hr;
}
- if(blockVector != NULL)
+ if (blockVector != NULL)
{
hr = blockVector->CreateResource2(resAllocInfo.SizeInBytes, resAllocInfo.Alignment,
*pAllocDesc, finalResourceDesc,
InitialResourceState, pOptimizedClearValue,
ppAllocation, riidResource, ppvResource);
- if(SUCCEEDED(hr))
+ if (SUCCEEDED(hr))
return hr;
}
- if(committedAllocationParams.IsValid() && !preferCommitted)
+ if (committedAllocationParams.IsValid() && !preferCommitted)
{
hr = AllocateCommittedResource2(committedAllocationParams,
- resAllocInfo.SizeInBytes, withinBudget,&finalResourceDesc,
+ resAllocInfo.SizeInBytes, withinBudget, &finalResourceDesc,
InitialResourceState, pOptimizedClearValue,
ppAllocation, riidResource, ppvResource);
- if(SUCCEEDED(hr))
+ if (SUCCEEDED(hr))
return hr;
}
return hr;
@@ -7249,28 +6548,28 @@
HRESULT hr = CalcAllocationParams<D3D12_RESOURCE_DESC>(*pAllocDesc, pAllocInfo->SizeInBytes,
NULL, // pResDesc
blockVector, committedAllocationParams, preferCommitted);
- if(FAILED(hr))
+ if (FAILED(hr))
return hr;
-
+
const bool withinBudget = (pAllocDesc->Flags & ALLOCATION_FLAG_WITHIN_BUDGET) != 0;
hr = E_INVALIDARG;
- if(committedAllocationParams.IsValid() && preferCommitted)
+ if (committedAllocationParams.IsValid() && preferCommitted)
{
hr = AllocateHeap(committedAllocationParams, *pAllocInfo, withinBudget, ppAllocation);
- if(SUCCEEDED(hr))
+ if (SUCCEEDED(hr))
return hr;
}
- if(blockVector != NULL)
+ if (blockVector != NULL)
{
hr = blockVector->Allocate(pAllocInfo->SizeInBytes, pAllocInfo->Alignment,
*pAllocDesc, 1, (Allocation**)ppAllocation);
- if(SUCCEEDED(hr))
+ if (SUCCEEDED(hr))
return hr;
}
- if(committedAllocationParams.IsValid() && !preferCommitted)
+ if (committedAllocationParams.IsValid() && !preferCommitted)
{
hr = AllocateHeap(committedAllocationParams, *pAllocInfo, withinBudget, ppAllocation);
- if(SUCCEEDED(hr))
+ if (SUCCEEDED(hr))
return hr;
}
return hr;
@@ -7281,7 +6580,7 @@
UINT64 AllocationLocalOffset,
const D3D12_RESOURCE_DESC* pResourceDesc,
D3D12_RESOURCE_STATES InitialResourceState,
- const D3D12_CLEAR_VALUE *pOptimizedClearValue,
+ const D3D12_CLEAR_VALUE* pOptimizedClearValue,
REFIID riidResource,
void** ppvResource)
{
@@ -7297,7 +6596,7 @@
const UINT64 existingSize = pAllocation->GetSize();
const UINT64 newOffset = existingOffset + AllocationLocalOffset;
- if(existingHeap == NULL ||
+ if (existingHeap == NULL ||
AllocationLocalOffset + resAllocInfo.SizeInBytes > existingSize ||
newOffset % resAllocInfo.Alignment != 0)
{
@@ -7314,375 +6613,6 @@
ppvResource);
}
-template<typename D3D12_RESOURCE_DESC_T>
-bool AllocatorPimpl::PrefersCommittedAllocation(const D3D12_RESOURCE_DESC_T& resourceDesc)
-{
- // Intentional. It may change in the future.
- return false;
-}
-
-HRESULT AllocatorPimpl::AllocateCommittedResource(
- const CommittedAllocationParameters& committedAllocParams,
- UINT64 resourceSize, bool withinBudget,
- const D3D12_RESOURCE_DESC* pResourceDesc,
- D3D12_RESOURCE_STATES InitialResourceState, const D3D12_CLEAR_VALUE *pOptimizedClearValue,
- Allocation** ppAllocation, REFIID riidResource, void** ppvResource)
-{
- D3D12MA_ASSERT(committedAllocParams.IsValid());
-
- 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
- * 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]
- */
- 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));
- }
- else
-#endif
- {
- if(committedAllocParams.m_ProtectedSession == NULL)
- {
- hr = m_Device->CreateCommittedResource(
- &committedAllocParams.m_HeapProperties,
- committedAllocParams.m_HeapFlags & ~RESOURCE_CLASS_HEAP_FLAGS,
- pResourceDesc, InitialResourceState,
- pOptimizedClearValue, D3D12MA_IID_PPV_ARGS(&res));
- }
- else
- hr = E_NOINTERFACE;
- }
-
- if(SUCCEEDED(hr))
- {
- if(ppvResource != NULL)
- {
- hr = res->QueryInterface(riidResource, ppvResource);
- }
- if(SUCCEEDED(hr))
- {
- const BOOL wasZeroInitialized = TRUE;
- Allocation* alloc = m_AllocationObjectAllocator.Allocate(this, resourceSize, wasZeroInitialized);
- alloc->InitCommitted(committedAllocParams.m_List);
- alloc->SetResource(res, pResourceDesc);
-
- *ppAllocation = alloc;
-
- committedAllocParams.m_List->Register(alloc);
-
- const UINT memSegmentGroup = HeapPropertiesToMemorySegmentGroup(committedAllocParams.m_HeapProperties);
- m_Budget.AddBlock(memSegmentGroup, resourceSize);
- m_Budget.AddAllocation(memSegmentGroup, resourceSize);
- }
- else
- {
- res->Release();
- }
- }
- return hr;
-}
-
-#ifdef __ID3D12Device8_INTERFACE_DEFINED__
-HRESULT AllocatorPimpl::AllocateCommittedResource2(
- const CommittedAllocationParameters& committedAllocParams,
- UINT64 resourceSize, bool withinBudget,
- const D3D12_RESOURCE_DESC1* pResourceDesc,
- D3D12_RESOURCE_STATES InitialResourceState, const D3D12_CLEAR_VALUE *pOptimizedClearValue,
- Allocation** ppAllocation, REFIID riidResource, void** ppvResource)
-{
- D3D12MA_ASSERT(committedAllocParams.IsValid());
-
- if(m_Device8 == NULL)
- {
- return E_NOINTERFACE;
- }
-
- if(withinBudget &&
- !NewAllocationWithinBudget(committedAllocParams.m_HeapProperties.Type, resourceSize))
- {
- return E_OUTOFMEMORY;
- }
-
- ID3D12Resource* res = NULL;
- HRESULT 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,
- pOptimizedClearValue, committedAllocParams.m_ProtectedSession, D3D12MA_IID_PPV_ARGS(&res));
- if(SUCCEEDED(hr))
- {
- if(ppvResource != NULL)
- {
- hr = res->QueryInterface(riidResource, ppvResource);
- }
- if(SUCCEEDED(hr))
- {
- const BOOL wasZeroInitialized = TRUE;
- Allocation* alloc = m_AllocationObjectAllocator.Allocate(this, resourceSize, wasZeroInitialized);
- alloc->InitCommitted(committedAllocParams.m_List);
- alloc->SetResource(res, pResourceDesc);
-
- *ppAllocation = alloc;
-
- committedAllocParams.m_List->Register(alloc);
-
- const UINT memSegmentGroup = HeapPropertiesToMemorySegmentGroup(committedAllocParams.m_HeapProperties);
- m_Budget.AddBlock(memSegmentGroup, resourceSize);
- m_Budget.AddAllocation(memSegmentGroup, resourceSize);
- }
- else
- {
- res->Release();
- }
- }
- return hr;
-}
-#endif // #ifdef __ID3D12Device8_INTERFACE_DEFINED__
-
-HRESULT AllocatorPimpl::AllocateHeap(
- const CommittedAllocationParameters& committedAllocParams,
- const D3D12_RESOURCE_ALLOCATION_INFO& allocInfo, bool withinBudget,
- Allocation** ppAllocation)
-{
- D3D12MA_ASSERT(committedAllocParams.IsValid());
-
- *ppAllocation = nullptr;
-
- if(withinBudget &&
- !NewAllocationWithinBudget(committedAllocParams.m_HeapProperties.Type, allocInfo.SizeInBytes))
- {
- return E_OUTOFMEMORY;
- }
-
- D3D12_HEAP_DESC heapDesc = {};
- heapDesc.SizeInBytes = allocInfo.SizeInBytes;
- heapDesc.Properties = committedAllocParams.m_HeapProperties;
- heapDesc.Alignment = allocInfo.Alignment;
- heapDesc.Flags = committedAllocParams.m_HeapFlags;
-
- HRESULT hr;
- ID3D12Heap* heap = nullptr;
-#ifdef __ID3D12Device4_INTERFACE_DEFINED__
- if(m_Device4)
- hr = m_Device4->CreateHeap1(&heapDesc, committedAllocParams.m_ProtectedSession, D3D12MA_IID_PPV_ARGS(&heap));
- else
-#endif
- {
- if(committedAllocParams.m_ProtectedSession == NULL)
- hr = m_Device->CreateHeap(&heapDesc, D3D12MA_IID_PPV_ARGS(&heap));
- else
- hr = E_NOINTERFACE;
- }
-
- if(SUCCEEDED(hr))
- {
- const BOOL wasZeroInitialized = TRUE;
- (*ppAllocation) = m_AllocationObjectAllocator.Allocate(this, allocInfo.SizeInBytes, wasZeroInitialized);
- (*ppAllocation)->InitHeap(committedAllocParams.m_List, heap);
- committedAllocParams.m_List->Register(*ppAllocation);
-
- const UINT memSegmentGroup = HeapPropertiesToMemorySegmentGroup(committedAllocParams.m_HeapProperties);
- m_Budget.AddBlock(memSegmentGroup, allocInfo.SizeInBytes);
- m_Budget.AddAllocation(memSegmentGroup, allocInfo.SizeInBytes);
- }
- return hr;
-}
-
-template<typename D3D12_RESOURCE_DESC_T>
-HRESULT AllocatorPimpl::CalcAllocationParams(const ALLOCATION_DESC& allocDesc, UINT64 allocSize,
- const D3D12_RESOURCE_DESC_T* resDesc,
- BlockVector*& outBlockVector, CommittedAllocationParameters& outCommittedAllocationParams, bool& outPreferCommitted)
-{
- outBlockVector = NULL;
- outCommittedAllocationParams = CommittedAllocationParameters();
- outPreferCommitted = false;
-
- if(allocDesc.CustomPool != NULL)
- {
- PoolPimpl* const pool = allocDesc.CustomPool->m_Pimpl;
-
- outBlockVector = pool->GetBlockVector();
-
- outCommittedAllocationParams.m_ProtectedSession = pool->GetDesc().pProtectedSession;
- outCommittedAllocationParams.m_HeapProperties = pool->GetDesc().HeapProperties;
- outCommittedAllocationParams.m_HeapFlags = pool->GetDesc().HeapFlags;
- outCommittedAllocationParams.m_List = pool->GetCommittedAllocationList();
- }
- else
- {
- if(!IsHeapTypeStandard(allocDesc.HeapType))
- {
- return E_INVALIDARG;
- }
-
- outCommittedAllocationParams.m_HeapProperties = StandardHeapTypeToHeapProperties(allocDesc.HeapType);
- outCommittedAllocationParams.m_HeapFlags = allocDesc.ExtraHeapFlags;
- outCommittedAllocationParams.m_List = &m_CommittedAllocations[HeapTypeToIndex(allocDesc.HeapType)];
-
- const ResourceClass resourceClass = (resDesc != NULL) ?
- ResourceDescToResourceClass(*resDesc) : HeapFlagsToResourceClass(allocDesc.ExtraHeapFlags);
- const UINT defaultPoolIndex = CalcDefaultPoolIndex(allocDesc, resourceClass);
- if(defaultPoolIndex != UINT32_MAX)
- {
- outBlockVector = m_BlockVectors[defaultPoolIndex];
- const UINT64 preferredBlockSize = outBlockVector->GetPreferredBlockSize();
- if(allocSize > preferredBlockSize)
- {
- outBlockVector = NULL;
- }
- else if(allocSize > preferredBlockSize / 2)
- {
- // Heuristics: Allocate committed memory if requested size if greater than half of preferred block size.
- outPreferCommitted = true;
- }
- }
-
- const D3D12_HEAP_FLAGS extraHeapFlags = allocDesc.ExtraHeapFlags & ~RESOURCE_CLASS_HEAP_FLAGS;
- if(outBlockVector != NULL && extraHeapFlags != 0)
- {
- outBlockVector = NULL;
- }
- }
-
- if((allocDesc.Flags & ALLOCATION_FLAG_COMMITTED) != 0 ||
- m_AlwaysCommitted)
- {
- outBlockVector = NULL;
- }
- if((allocDesc.Flags & ALLOCATION_FLAG_NEVER_ALLOCATE) != 0)
- {
- outCommittedAllocationParams.m_List = NULL;
- }
-
- if(resDesc != NULL && !outPreferCommitted && PrefersCommittedAllocation(*resDesc))
- {
- outPreferCommitted = true;
- }
-
- return (outBlockVector != NULL || outCommittedAllocationParams.m_List != NULL) ? S_OK : E_INVALIDARG;
-}
-
-UINT AllocatorPimpl::CalcDefaultPoolCount() const
-{
- if(SupportsResourceHeapTier2())
- {
- return 3;
- }
- else
- {
- return 9;
- }
-}
-
-UINT AllocatorPimpl::CalcDefaultPoolIndex(const ALLOCATION_DESC& allocDesc, ResourceClass resourceClass) const
-{
- const D3D12_HEAP_FLAGS extraHeapFlags = allocDesc.ExtraHeapFlags & ~RESOURCE_CLASS_HEAP_FLAGS;
- if(extraHeapFlags != 0)
- {
- return UINT32_MAX;
- }
-
- UINT poolIndex = UINT_MAX;
- switch(allocDesc.HeapType)
- {
- case D3D12_HEAP_TYPE_DEFAULT: poolIndex = 0; break;
- case D3D12_HEAP_TYPE_UPLOAD: poolIndex = 1; break;
- case D3D12_HEAP_TYPE_READBACK: poolIndex = 2; break;
- default: D3D12MA_ASSERT(0);
- }
-
- if(SupportsResourceHeapTier2())
- return poolIndex;
- else
- {
- switch(resourceClass)
- {
- case ResourceClass::Buffer:
- return poolIndex * 3;
- case ResourceClass::Non_RT_DS_Texture:
- return poolIndex * 3 + 1;
- case ResourceClass::RT_DS_Texture:
- return poolIndex * 3 + 2;
- default:
- return UINT32_MAX;
- }
- }
-}
-
-void AllocatorPimpl::CalcDefaultPoolParams(D3D12_HEAP_TYPE& outHeapType, D3D12_HEAP_FLAGS& outHeapFlags, UINT index) const
-{
- outHeapType = D3D12_HEAP_TYPE_DEFAULT;
- outHeapFlags = D3D12_HEAP_FLAG_NONE;
-
- if(!SupportsResourceHeapTier2())
- {
- switch(index % 3)
- {
- case 0:
- outHeapFlags = D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES | D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES;
- break;
- case 1:
- outHeapFlags = D3D12_HEAP_FLAG_DENY_BUFFERS | D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES;
- break;
- case 2:
- outHeapFlags = D3D12_HEAP_FLAG_DENY_BUFFERS | D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES;
- break;
- }
-
- index /= 3;
- }
-
- switch(index)
- {
- case 0:
- outHeapType = D3D12_HEAP_TYPE_DEFAULT;
- break;
- case 1:
- outHeapType = D3D12_HEAP_TYPE_UPLOAD;
- break;
- case 2:
- outHeapType = D3D12_HEAP_TYPE_READBACK;
- break;
- default:
- D3D12MA_ASSERT(0);
- }
-}
-
-void AllocatorPimpl::RegisterPool(Pool* pool, D3D12_HEAP_TYPE heapType)
-{
- const UINT heapTypeIndex = HeapTypeToIndex(heapType);
-
- MutexLockWrite lock(m_PoolsMutex[heapTypeIndex], m_UseMutex);
- m_Pools[heapTypeIndex].PushBack(pool->m_Pimpl);
-}
-
-void AllocatorPimpl::UnregisterPool(Pool* pool, D3D12_HEAP_TYPE heapType)
-{
- const UINT heapTypeIndex = HeapTypeToIndex(heapType);
-
- MutexLockWrite lock(m_PoolsMutex[heapTypeIndex], m_UseMutex);
- m_Pools[heapTypeIndex].Remove(pool->m_Pimpl);
-}
-
void AllocatorPimpl::FreeCommittedMemory(Allocation* allocation)
{
D3D12MA_ASSERT(allocation && allocation->m_PackedData.GetType() == Allocation::TYPE_COMMITTED);
@@ -7734,17 +6664,17 @@
void AllocatorPimpl::CalculateStatistics(TotalStatistics& outStats)
{
// Init stats
- for(size_t i = 0; i < HEAP_TYPE_COUNT; i++)
+ for (size_t i = 0; i < HEAP_TYPE_COUNT; i++)
ClearDetailedStatistics(outStats.HeapType[i]);
- for(size_t i = 0; i < DXGI_MEMORY_SEGMENT_GROUP_COUNT; i++)
+ for (size_t i = 0; i < DXGI_MEMORY_SEGMENT_GROUP_COUNT; i++)
ClearDetailedStatistics(outStats.MemorySegmentGroup[i]);
ClearDetailedStatistics(outStats.Total);
// Process default pools. 3 standard heap types only. Add them to outStats.HeapType[i].
- if(SupportsResourceHeapTier2())
+ if (SupportsResourceHeapTier2())
{
// DEFAULT, UPLOAD, READBACK.
- for(size_t heapTypeIndex = 0; heapTypeIndex < STANDARD_HEAP_TYPE_COUNT; ++heapTypeIndex)
+ for (size_t heapTypeIndex = 0; heapTypeIndex < STANDARD_HEAP_TYPE_COUNT; ++heapTypeIndex)
{
BlockVector* const pBlockVector = m_BlockVectors[heapTypeIndex];
D3D12MA_ASSERT(pBlockVector);
@@ -7754,9 +6684,9 @@
else
{
// DEFAULT, UPLOAD, READBACK.
- for(size_t heapTypeIndex = 0; heapTypeIndex < STANDARD_HEAP_TYPE_COUNT; ++heapTypeIndex)
+ for (size_t heapTypeIndex = 0; heapTypeIndex < STANDARD_HEAP_TYPE_COUNT; ++heapTypeIndex)
{
- for(size_t heapSubType = 0; heapSubType < 3; ++heapSubType)
+ for (size_t heapSubType = 0; heapSubType < 3; ++heapSubType)
{
BlockVector* const pBlockVector = m_BlockVectors[heapTypeIndex * 3 + heapSubType];
D3D12MA_ASSERT(pBlockVector);
@@ -7778,11 +6708,11 @@
// Process custom pools.
DetailedStatistics tmpStats;
- for(size_t heapTypeIndex = 0; heapTypeIndex < HEAP_TYPE_COUNT; ++heapTypeIndex)
+ for (size_t heapTypeIndex = 0; heapTypeIndex < HEAP_TYPE_COUNT; ++heapTypeIndex)
{
MutexLockRead lock(m_PoolsMutex[heapTypeIndex], m_UseMutex);
PoolList& poolList = m_Pools[heapTypeIndex];
- for(PoolPimpl* pool = poolList.Front(); pool != NULL; pool = poolList.GetNext(pool))
+ for (PoolPimpl* pool = poolList.Front(); pool != NULL; pool = poolList.GetNext(pool))
{
const D3D12_HEAP_PROPERTIES& poolHeapProps = pool->GetDesc().HeapProperties;
ClearDetailedStatistics(tmpStats);
@@ -7795,7 +6725,7 @@
}
// Process committed allocations. 3 standard heap types only.
- for(UINT heapTypeIndex = 0; heapTypeIndex < STANDARD_HEAP_TYPE_COUNT; ++heapTypeIndex)
+ for (UINT heapTypeIndex = 0; heapTypeIndex < STANDARD_HEAP_TYPE_COUNT; ++heapTypeIndex)
{
ClearDetailedStatistics(tmpStats);
m_CommittedAllocations[heapTypeIndex].AddDetailedStatistics(tmpStats);
@@ -7839,15 +6769,15 @@
void AllocatorPimpl::GetBudget(Budget* outLocalBudget, Budget* outNonLocalBudget)
{
- if(outLocalBudget)
+ if (outLocalBudget)
m_Budget.GetStatistics(outLocalBudget->Stats, DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY);
- if(outNonLocalBudget)
+ if (outNonLocalBudget)
m_Budget.GetStatistics(outNonLocalBudget->Stats, DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL_COPY);
#if D3D12MA_DXGI_1_4
- if(m_Adapter3)
+ if (m_Adapter3)
{
- if(!m_Budget.ShouldUpdateBudget())
+ if (!m_Budget.ShouldUpdateBudget())
{
m_Budget.GetBudget(m_UseMutex,
outLocalBudget ? &outLocalBudget->UsageBytes : NULL,
@@ -7864,12 +6794,12 @@
else
#endif
{
- if(outLocalBudget)
+ if (outLocalBudget)
{
outLocalBudget->UsageBytes = outLocalBudget->Stats.BlockBytes;
outLocalBudget->BudgetBytes = GetMemoryCapacity(DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY) * 8 / 10; // 80% heuristics.
}
- if(outNonLocalBudget)
+ if (outNonLocalBudget)
{
outNonLocalBudget->UsageBytes = outNonLocalBudget->Stats.BlockBytes;
outNonLocalBudget->BudgetBytes = GetMemoryCapacity(DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL_COPY) * 8 / 10; // 80% heuristics.
@@ -7879,7 +6809,7 @@
void AllocatorPimpl::GetBudgetForHeapType(Budget& outBudget, D3D12_HEAP_TYPE heapType)
{
- switch(heapType)
+ switch (heapType)
{
case D3D12_HEAP_TYPE_DEFAULT:
GetBudget(&outBudget, NULL);
@@ -7892,39 +6822,6 @@
}
}
-static void AddDetailedStatisticsInfoToJson(JsonWriter& json, const DetailedStatistics& stats)
-{
- json.BeginObject();
- json.WriteString(L"BlockCount");
- json.WriteNumber(stats.Stats.BlockCount);
- json.WriteString(L"AllocationCount");
- json.WriteNumber(stats.Stats.AllocationCount);
- json.WriteString(L"UnusedRangeCount");
- json.WriteNumber(stats.UnusedRangeCount);
- json.WriteString(L"BlockBytes");
- json.WriteNumber(stats.Stats.BlockBytes);
- json.WriteString(L"AllocationBytes");
- json.WriteNumber(stats.Stats.AllocationBytes);
-
- json.WriteString(L"AllocationSize");
- json.BeginObject(true);
- json.WriteString(L"Min");
- json.WriteNumber(stats.AllocationSizeMin);
- json.WriteString(L"Max");
- json.WriteNumber(stats.AllocationSizeMax);
- json.EndObject();
-
- json.WriteString(L"UnusedRangeSize");
- json.BeginObject(true);
- json.WriteString(L"Min");
- json.WriteNumber(stats.UnusedRangeSizeMin);
- json.WriteString(L"Max");
- json.WriteNumber(stats.UnusedRangeSizeMax);
- json.EndObject();
-
- json.EndObject();
-}
-
void AllocatorPimpl::BuildStatsString(WCHAR** ppStatsString, BOOL DetailedMap)
{
StringBuilder sb(GetAllocs());
@@ -7938,13 +6835,13 @@
CalculateStatistics(stats);
json.BeginObject();
-
+
json.WriteString(L"Total");
- AddDetailedStatisticsInfoToJson(json, stats.Total);
+ json.AddDetailedStatisticsInfoObject(stats.Total);
for (size_t heapType = 0; heapType < HEAP_TYPE_COUNT; ++heapType)
{
json.WriteString(HeapTypeNames[heapType]);
- AddDetailedStatisticsInfoToJson(json, stats.HeapType[heapType]);
+ json.AddDetailedStatisticsInfoObject(stats.HeapType[heapType]);
}
json.WriteString(L"Budget");
@@ -8077,10 +6974,379 @@
Free(GetAllocs(), pStatsString);
}
+template<typename D3D12_RESOURCE_DESC_T>
+bool AllocatorPimpl::PrefersCommittedAllocation(const D3D12_RESOURCE_DESC_T& resourceDesc)
+{
+ // Intentional. It may change in the future.
+ return false;
+}
+
+HRESULT AllocatorPimpl::AllocateCommittedResource(
+ const CommittedAllocationParameters& committedAllocParams,
+ UINT64 resourceSize, bool withinBudget,
+ const D3D12_RESOURCE_DESC* pResourceDesc,
+ D3D12_RESOURCE_STATES InitialResourceState, const D3D12_CLEAR_VALUE* pOptimizedClearValue,
+ Allocation** ppAllocation, REFIID riidResource, void** ppvResource)
+{
+ D3D12MA_ASSERT(committedAllocParams.IsValid());
+
+ 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
+ * 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]
+ */
+ 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));
+ }
+ else
+#endif
+ {
+ if (committedAllocParams.m_ProtectedSession == NULL)
+ {
+ hr = m_Device->CreateCommittedResource(
+ &committedAllocParams.m_HeapProperties,
+ committedAllocParams.m_HeapFlags & ~RESOURCE_CLASS_HEAP_FLAGS,
+ pResourceDesc, InitialResourceState,
+ pOptimizedClearValue, D3D12MA_IID_PPV_ARGS(&res));
+ }
+ else
+ hr = E_NOINTERFACE;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (ppvResource != NULL)
+ {
+ hr = res->QueryInterface(riidResource, ppvResource);
+ }
+ if (SUCCEEDED(hr))
+ {
+ const BOOL wasZeroInitialized = TRUE;
+ Allocation* alloc = m_AllocationObjectAllocator.Allocate(this, resourceSize, wasZeroInitialized);
+ alloc->InitCommitted(committedAllocParams.m_List);
+ alloc->SetResource(res, pResourceDesc);
+
+ *ppAllocation = alloc;
+
+ committedAllocParams.m_List->Register(alloc);
+
+ const UINT memSegmentGroup = HeapPropertiesToMemorySegmentGroup(committedAllocParams.m_HeapProperties);
+ m_Budget.AddBlock(memSegmentGroup, resourceSize);
+ m_Budget.AddAllocation(memSegmentGroup, resourceSize);
+ }
+ else
+ {
+ res->Release();
+ }
+ }
+ return hr;
+}
+
+#ifdef __ID3D12Device8_INTERFACE_DEFINED__
+HRESULT AllocatorPimpl::AllocateCommittedResource2(
+ const CommittedAllocationParameters& committedAllocParams,
+ UINT64 resourceSize, bool withinBudget,
+ const D3D12_RESOURCE_DESC1* pResourceDesc,
+ D3D12_RESOURCE_STATES InitialResourceState, const D3D12_CLEAR_VALUE* pOptimizedClearValue,
+ Allocation** ppAllocation, REFIID riidResource, void** ppvResource)
+{
+ D3D12MA_ASSERT(committedAllocParams.IsValid());
+
+ if (m_Device8 == NULL)
+ {
+ return E_NOINTERFACE;
+ }
+
+ if (withinBudget &&
+ !NewAllocationWithinBudget(committedAllocParams.m_HeapProperties.Type, resourceSize))
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ ID3D12Resource* res = NULL;
+ HRESULT 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,
+ pOptimizedClearValue, committedAllocParams.m_ProtectedSession, D3D12MA_IID_PPV_ARGS(&res));
+ if (SUCCEEDED(hr))
+ {
+ if (ppvResource != NULL)
+ {
+ hr = res->QueryInterface(riidResource, ppvResource);
+ }
+ if (SUCCEEDED(hr))
+ {
+ const BOOL wasZeroInitialized = TRUE;
+ Allocation* alloc = m_AllocationObjectAllocator.Allocate(this, resourceSize, wasZeroInitialized);
+ alloc->InitCommitted(committedAllocParams.m_List);
+ alloc->SetResource(res, pResourceDesc);
+
+ *ppAllocation = alloc;
+
+ committedAllocParams.m_List->Register(alloc);
+
+ const UINT memSegmentGroup = HeapPropertiesToMemorySegmentGroup(committedAllocParams.m_HeapProperties);
+ m_Budget.AddBlock(memSegmentGroup, resourceSize);
+ m_Budget.AddAllocation(memSegmentGroup, resourceSize);
+ }
+ else
+ {
+ res->Release();
+ }
+ }
+ return hr;
+}
+#endif // #ifdef __ID3D12Device8_INTERFACE_DEFINED__
+
+HRESULT AllocatorPimpl::AllocateHeap(
+ const CommittedAllocationParameters& committedAllocParams,
+ const D3D12_RESOURCE_ALLOCATION_INFO& allocInfo, bool withinBudget,
+ Allocation** ppAllocation)
+{
+ D3D12MA_ASSERT(committedAllocParams.IsValid());
+
+ *ppAllocation = nullptr;
+
+ if (withinBudget &&
+ !NewAllocationWithinBudget(committedAllocParams.m_HeapProperties.Type, allocInfo.SizeInBytes))
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ D3D12_HEAP_DESC heapDesc = {};
+ heapDesc.SizeInBytes = allocInfo.SizeInBytes;
+ heapDesc.Properties = committedAllocParams.m_HeapProperties;
+ heapDesc.Alignment = allocInfo.Alignment;
+ heapDesc.Flags = committedAllocParams.m_HeapFlags;
+
+ HRESULT hr;
+ ID3D12Heap* heap = nullptr;
+#ifdef __ID3D12Device4_INTERFACE_DEFINED__
+ if (m_Device4)
+ hr = m_Device4->CreateHeap1(&heapDesc, committedAllocParams.m_ProtectedSession, D3D12MA_IID_PPV_ARGS(&heap));
+ else
+#endif
+ {
+ if (committedAllocParams.m_ProtectedSession == NULL)
+ hr = m_Device->CreateHeap(&heapDesc, D3D12MA_IID_PPV_ARGS(&heap));
+ else
+ hr = E_NOINTERFACE;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ const BOOL wasZeroInitialized = TRUE;
+ (*ppAllocation) = m_AllocationObjectAllocator.Allocate(this, allocInfo.SizeInBytes, wasZeroInitialized);
+ (*ppAllocation)->InitHeap(committedAllocParams.m_List, heap);
+ committedAllocParams.m_List->Register(*ppAllocation);
+
+ const UINT memSegmentGroup = HeapPropertiesToMemorySegmentGroup(committedAllocParams.m_HeapProperties);
+ m_Budget.AddBlock(memSegmentGroup, allocInfo.SizeInBytes);
+ m_Budget.AddAllocation(memSegmentGroup, allocInfo.SizeInBytes);
+ }
+ return hr;
+}
+
+template<typename D3D12_RESOURCE_DESC_T>
+HRESULT AllocatorPimpl::CalcAllocationParams(const ALLOCATION_DESC& allocDesc, UINT64 allocSize,
+ const D3D12_RESOURCE_DESC_T* resDesc,
+ BlockVector*& outBlockVector, CommittedAllocationParameters& outCommittedAllocationParams, bool& outPreferCommitted)
+{
+ outBlockVector = NULL;
+ outCommittedAllocationParams = CommittedAllocationParameters();
+ outPreferCommitted = false;
+
+ if (allocDesc.CustomPool != NULL)
+ {
+ PoolPimpl* const pool = allocDesc.CustomPool->m_Pimpl;
+
+ outBlockVector = pool->GetBlockVector();
+
+ outCommittedAllocationParams.m_ProtectedSession = pool->GetDesc().pProtectedSession;
+ outCommittedAllocationParams.m_HeapProperties = pool->GetDesc().HeapProperties;
+ outCommittedAllocationParams.m_HeapFlags = pool->GetDesc().HeapFlags;
+ outCommittedAllocationParams.m_List = pool->GetCommittedAllocationList();
+ }
+ else
+ {
+ if (!IsHeapTypeStandard(allocDesc.HeapType))
+ {
+ return E_INVALIDARG;
+ }
+
+ outCommittedAllocationParams.m_HeapProperties = StandardHeapTypeToHeapProperties(allocDesc.HeapType);
+ outCommittedAllocationParams.m_HeapFlags = allocDesc.ExtraHeapFlags;
+ outCommittedAllocationParams.m_List = &m_CommittedAllocations[HeapTypeToIndex(allocDesc.HeapType)];
+
+ const ResourceClass resourceClass = (resDesc != NULL) ?
+ ResourceDescToResourceClass(*resDesc) : HeapFlagsToResourceClass(allocDesc.ExtraHeapFlags);
+ const UINT defaultPoolIndex = CalcDefaultPoolIndex(allocDesc, resourceClass);
+ if (defaultPoolIndex != UINT32_MAX)
+ {
+ outBlockVector = m_BlockVectors[defaultPoolIndex];
+ const UINT64 preferredBlockSize = outBlockVector->GetPreferredBlockSize();
+ if (allocSize > preferredBlockSize)
+ {
+ outBlockVector = NULL;
+ }
+ else if (allocSize > preferredBlockSize / 2)
+ {
+ // Heuristics: Allocate committed memory if requested size if greater than half of preferred block size.
+ outPreferCommitted = true;
+ }
+ }
+
+ const D3D12_HEAP_FLAGS extraHeapFlags = allocDesc.ExtraHeapFlags & ~RESOURCE_CLASS_HEAP_FLAGS;
+ if (outBlockVector != NULL && extraHeapFlags != 0)
+ {
+ outBlockVector = NULL;
+ }
+ }
+
+ if ((allocDesc.Flags & ALLOCATION_FLAG_COMMITTED) != 0 ||
+ m_AlwaysCommitted)
+ {
+ outBlockVector = NULL;
+ }
+ if ((allocDesc.Flags & ALLOCATION_FLAG_NEVER_ALLOCATE) != 0)
+ {
+ outCommittedAllocationParams.m_List = NULL;
+ }
+
+ if (resDesc != NULL && !outPreferCommitted && PrefersCommittedAllocation(*resDesc))
+ {
+ outPreferCommitted = true;
+ }
+
+ return (outBlockVector != NULL || outCommittedAllocationParams.m_List != NULL) ? S_OK : E_INVALIDARG;
+}
+
+UINT AllocatorPimpl::CalcDefaultPoolCount() const
+{
+ if (SupportsResourceHeapTier2())
+ {
+ return 3;
+ }
+ else
+ {
+ return 9;
+ }
+}
+
+UINT AllocatorPimpl::CalcDefaultPoolIndex(const ALLOCATION_DESC& allocDesc, ResourceClass resourceClass) const
+{
+ const D3D12_HEAP_FLAGS extraHeapFlags = allocDesc.ExtraHeapFlags & ~RESOURCE_CLASS_HEAP_FLAGS;
+ if (extraHeapFlags != 0)
+ {
+ return UINT32_MAX;
+ }
+
+ UINT poolIndex = UINT_MAX;
+ switch (allocDesc.HeapType)
+ {
+ case D3D12_HEAP_TYPE_DEFAULT: poolIndex = 0; break;
+ case D3D12_HEAP_TYPE_UPLOAD: poolIndex = 1; break;
+ case D3D12_HEAP_TYPE_READBACK: poolIndex = 2; break;
+ default: D3D12MA_ASSERT(0);
+ }
+
+ if (SupportsResourceHeapTier2())
+ return poolIndex;
+ else
+ {
+ switch (resourceClass)
+ {
+ case ResourceClass::Buffer:
+ return poolIndex * 3;
+ case ResourceClass::Non_RT_DS_Texture:
+ return poolIndex * 3 + 1;
+ case ResourceClass::RT_DS_Texture:
+ return poolIndex * 3 + 2;
+ default:
+ return UINT32_MAX;
+ }
+ }
+}
+
+void AllocatorPimpl::CalcDefaultPoolParams(D3D12_HEAP_TYPE& outHeapType, D3D12_HEAP_FLAGS& outHeapFlags, UINT index) const
+{
+ outHeapType = D3D12_HEAP_TYPE_DEFAULT;
+ outHeapFlags = D3D12_HEAP_FLAG_NONE;
+
+ if (!SupportsResourceHeapTier2())
+ {
+ switch (index % 3)
+ {
+ case 0:
+ outHeapFlags = D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES | D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES;
+ break;
+ case 1:
+ outHeapFlags = D3D12_HEAP_FLAG_DENY_BUFFERS | D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES;
+ break;
+ case 2:
+ outHeapFlags = D3D12_HEAP_FLAG_DENY_BUFFERS | D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES;
+ break;
+ }
+
+ index /= 3;
+ }
+
+ switch (index)
+ {
+ case 0:
+ outHeapType = D3D12_HEAP_TYPE_DEFAULT;
+ break;
+ case 1:
+ outHeapType = D3D12_HEAP_TYPE_UPLOAD;
+ break;
+ case 2:
+ outHeapType = D3D12_HEAP_TYPE_READBACK;
+ break;
+ default:
+ D3D12MA_ASSERT(0);
+ }
+}
+
+void AllocatorPimpl::RegisterPool(Pool* pool, D3D12_HEAP_TYPE heapType)
+{
+ const UINT heapTypeIndex = HeapTypeToIndex(heapType);
+
+ MutexLockWrite lock(m_PoolsMutex[heapTypeIndex], m_UseMutex);
+ m_Pools[heapTypeIndex].PushBack(pool->m_Pimpl);
+}
+
+void AllocatorPimpl::UnregisterPool(Pool* pool, D3D12_HEAP_TYPE heapType)
+{
+ const UINT heapTypeIndex = HeapTypeToIndex(heapType);
+
+ MutexLockWrite lock(m_PoolsMutex[heapTypeIndex], m_UseMutex);
+ m_Pools[heapTypeIndex].Remove(pool->m_Pimpl);
+}
+
HRESULT AllocatorPimpl::UpdateD3D12Budget()
{
#if D3D12MA_DXGI_1_4
- if(m_Adapter3)
+ if (m_Adapter3)
return m_Budget.UpdateBudget(m_Adapter3, m_UseMutex);
else
return E_NOINTERFACE;
@@ -8108,22 +7374,22 @@
{
/* Optional optimization: Microsoft documentation says:
https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-getresourceallocationinfo
-
+
Your application can forgo using GetResourceAllocationInfo for buffer resources
(D3D12_RESOURCE_DIMENSION_BUFFER). Buffers have the same size on all adapters,
which is merely the smallest multiple of 64KB that's greater or equal to
D3D12_RESOURCE_DESC::Width.
*/
- if(inOutResourceDesc.Alignment == 0 &&
+ if (inOutResourceDesc.Alignment == 0 &&
inOutResourceDesc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
{
return {
AlignUp<UINT64>(inOutResourceDesc.Width, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT), // SizeInBytes
- D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT}; // Alignment
+ D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT }; // Alignment
}
#if D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT
- if(inOutResourceDesc.Alignment == 0 &&
+ if (inOutResourceDesc.Alignment == 0 &&
inOutResourceDesc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D &&
(inOutResourceDesc.Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) == 0
#if D3D12MA_USE_SMALL_RESOURCE_PLACEMENT_ALIGNMENT == 1
@@ -8141,7 +7407,7 @@
inOutResourceDesc.Alignment = smallAlignmentToTry;
const D3D12_RESOURCE_ALLOCATION_INFO smallAllocInfo = GetResourceAllocationInfoNative(inOutResourceDesc);
// Check if alignment requested has been granted.
- if(smallAllocInfo.Alignment == smallAlignmentToTry)
+ if (smallAllocInfo.Alignment == smallAlignmentToTry)
{
return smallAllocInfo;
}
@@ -8178,49 +7444,905 @@
}
json.EndObject();
}
+#endif // _D3D12MA_ALLOCATOR_PIMPL
+#endif // _D3D12MA_ALLOCATOR_PIMPL
-UINT AllocatorPimpl::StandardHeapTypeToMemorySegmentGroup(D3D12_HEAP_TYPE heapType) const
+#ifndef _D3D12MA_VIRTUAL_BLOCK_PIMPL
+class VirtualBlockPimpl
{
- D3D12MA_ASSERT(IsHeapTypeStandard(heapType));
- if(IsUMA())
- return DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY;
- return heapType == D3D12_HEAP_TYPE_DEFAULT ?
- DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY : DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL_COPY;
-}
+public:
+ const ALLOCATION_CALLBACKS m_AllocationCallbacks;
+ const UINT64 m_Size;
+ BlockMetadata* m_Metadata;
-UINT AllocatorPimpl::HeapPropertiesToMemorySegmentGroup(const D3D12_HEAP_PROPERTIES& heapProps) const
-{
- if(IsUMA())
- return DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY;
- if(heapProps.MemoryPoolPreference == D3D12_MEMORY_POOL_UNKNOWN)
- return StandardHeapTypeToMemorySegmentGroup(heapProps.Type);
- return heapProps.MemoryPoolPreference == D3D12_MEMORY_POOL_L1 ?
- DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY : DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL_COPY;
-}
+ VirtualBlockPimpl(const ALLOCATION_CALLBACKS& allocationCallbacks, const VIRTUAL_BLOCK_DESC& desc);
+ ~VirtualBlockPimpl();
+};
-UINT64 AllocatorPimpl::GetMemoryCapacity(UINT memorySegmentGroup) const
+#ifndef _D3D12MA_VIRTUAL_BLOCK_PIMPL_FUNCTIONS
+VirtualBlockPimpl::VirtualBlockPimpl(const ALLOCATION_CALLBACKS& allocationCallbacks, const VIRTUAL_BLOCK_DESC& desc)
+ : m_AllocationCallbacks(allocationCallbacks), m_Size(desc.Size)
{
- switch(memorySegmentGroup)
+ switch (desc.Flags & VIRTUAL_BLOCK_FLAG_ALGORITHM_MASK)
{
- case DXGI_MEMORY_SEGMENT_GROUP_LOCAL_COPY:
- return IsUMA() ?
- m_AdapterDesc.DedicatedVideoMemory + m_AdapterDesc.SharedSystemMemory : m_AdapterDesc.DedicatedVideoMemory;
- case DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL_COPY:
- return IsUMA() ? 0 : m_AdapterDesc.SharedSystemMemory;
+ case VIRTUAL_BLOCK_FLAG_ALGORITHM_LINEAR:
+ m_Metadata = D3D12MA_NEW(allocationCallbacks, BlockMetadata_Linear)(&m_AllocationCallbacks, true);
+ break;
default:
D3D12MA_ASSERT(0);
- return UINT64_MAX;
+ case 0:
+ m_Metadata = D3D12MA_NEW(allocationCallbacks, BlockMetadata_TLSF)(&m_AllocationCallbacks, true);
+ break;
+ }
+ m_Metadata->Init(m_Size);
+}
+
+VirtualBlockPimpl::~VirtualBlockPimpl()
+{
+ D3D12MA_DELETE(m_AllocationCallbacks, m_Metadata);
+}
+#endif // _D3D12MA_VIRTUAL_BLOCK_PIMPL_FUNCTIONS
+#endif // _D3D12MA_VIRTUAL_BLOCK_PIMPL
+
+
+#ifndef _D3D12MA_MEMORY_BLOCK_FUNCTIONS
+MemoryBlock::MemoryBlock(
+ AllocatorPimpl* allocator,
+ const D3D12_HEAP_PROPERTIES& heapProps,
+ D3D12_HEAP_FLAGS heapFlags,
+ UINT64 size,
+ UINT id)
+ : m_Allocator(allocator),
+ m_HeapProps(heapProps),
+ m_HeapFlags(heapFlags),
+ m_Size(size),
+ m_Id(id) {}
+
+MemoryBlock::~MemoryBlock()
+{
+ if (m_Heap)
+ {
+ m_Heap->Release();
+ m_Allocator->m_Budget.RemoveBlock(
+ m_Allocator->HeapPropertiesToMemorySegmentGroup(m_HeapProps), m_Size);
}
}
-////////////////////////////////////////////////////////////////////////////////
-// Public but internal class IUnknownImpl implementation
+HRESULT MemoryBlock::Init(ID3D12ProtectedResourceSession* pProtectedSession)
+{
+ D3D12MA_ASSERT(m_Heap == NULL && m_Size > 0);
+ D3D12_HEAP_DESC heapDesc = {};
+ heapDesc.SizeInBytes = m_Size;
+ heapDesc.Properties = m_HeapProps;
+ heapDesc.Alignment = HeapFlagsToAlignment(m_HeapFlags);
+ heapDesc.Flags = m_HeapFlags;
+
+ HRESULT hr;
+#ifdef __ID3D12Device4_INTERFACE_DEFINED__
+ ID3D12Device4* const device4 = m_Allocator->GetDevice4();
+ if (device4)
+ hr = m_Allocator->GetDevice4()->CreateHeap1(&heapDesc, pProtectedSession, D3D12MA_IID_PPV_ARGS(&m_Heap));
+ else
+#endif
+ {
+ if (pProtectedSession == NULL)
+ hr = m_Allocator->GetDevice()->CreateHeap(&heapDesc, D3D12MA_IID_PPV_ARGS(&m_Heap));
+ else
+ hr = E_NOINTERFACE;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ m_Allocator->m_Budget.AddBlock(
+ m_Allocator->HeapPropertiesToMemorySegmentGroup(m_HeapProps), m_Size);
+ }
+ return hr;
+}
+#endif // _D3D12MA_MEMORY_BLOCK_FUNCTIONS
+
+#ifndef _D3D12MA_NORMAL_BLOCK_FUNCTIONS
+NormalBlock::NormalBlock(
+ AllocatorPimpl* allocator,
+ BlockVector* blockVector,
+ const D3D12_HEAP_PROPERTIES& heapProps,
+ D3D12_HEAP_FLAGS heapFlags,
+ UINT64 size,
+ UINT id)
+ : MemoryBlock(allocator, heapProps, heapFlags, size, id),
+ m_pMetadata(NULL),
+ m_BlockVector(blockVector) {}
+
+NormalBlock::~NormalBlock()
+{
+ if (m_pMetadata != NULL)
+ {
+ // 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);
+ }
+}
+
+HRESULT NormalBlock::Init(UINT32 algorithm, ID3D12ProtectedResourceSession* pProtectedSession)
+{
+ HRESULT hr = MemoryBlock::Init(pProtectedSession);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ switch (algorithm)
+ {
+ case POOL_FLAG_ALGORITHM_LINEAR:
+ m_pMetadata = D3D12MA_NEW(m_Allocator->GetAllocs(), BlockMetadata_Linear)(&m_Allocator->GetAllocs(), false);
+ break;
+ default:
+ D3D12MA_ASSERT(0);
+ case 0:
+ m_pMetadata = D3D12MA_NEW(m_Allocator->GetAllocs(), BlockMetadata_TLSF)(&m_Allocator->GetAllocs(), false);
+ break;
+ }
+ m_pMetadata->Init(m_Size);
+
+ return hr;
+}
+
+bool NormalBlock::Validate() const
+{
+ D3D12MA_VALIDATE(GetHeap() &&
+ m_pMetadata &&
+ m_pMetadata->GetSize() != 0 &&
+ m_pMetadata->GetSize() == GetSize());
+ return m_pMetadata->Validate();
+}
+#endif // _D3D12MA_NORMAL_BLOCK_FUNCTIONS
+
+#ifndef _D3D12MA_COMMITTED_ALLOCATION_LIST_FUNCTIONS
+void CommittedAllocationList::Init(bool useMutex, D3D12_HEAP_TYPE heapType, PoolPimpl* pool)
+{
+ m_UseMutex = useMutex;
+ m_HeapType = heapType;
+ m_Pool = pool;
+}
+
+CommittedAllocationList::~CommittedAllocationList()
+{
+ if (!m_AllocationList.IsEmpty())
+ {
+ D3D12MA_ASSERT(0 && "Unfreed committed allocations found!");
+ }
+}
+
+UINT CommittedAllocationList::GetMemorySegmentGroup(AllocatorPimpl* allocator) const
+{
+ if (m_Pool)
+ return allocator->HeapPropertiesToMemorySegmentGroup(m_Pool->GetDesc().HeapProperties);
+ else
+ return allocator->StandardHeapTypeToMemorySegmentGroup(m_HeapType);
+}
+
+void CommittedAllocationList::AddStatistics(Statistics& inoutStats)
+{
+ MutexLockRead lock(m_Mutex, m_UseMutex);
+
+ for (Allocation* alloc = m_AllocationList.Front();
+ alloc != NULL; alloc = m_AllocationList.GetNext(alloc))
+ {
+ const UINT64 size = alloc->GetSize();
+ inoutStats.BlockCount++;
+ inoutStats.AllocationCount++;
+ inoutStats.BlockBytes += size;
+ inoutStats.AllocationBytes += size;
+ }
+}
+
+void CommittedAllocationList::AddDetailedStatistics(DetailedStatistics& inoutStats)
+{
+ MutexLockRead lock(m_Mutex, m_UseMutex);
+
+ for (Allocation* alloc = m_AllocationList.Front();
+ alloc != NULL; alloc = m_AllocationList.GetNext(alloc))
+ {
+ const UINT64 size = alloc->GetSize();
+ inoutStats.Stats.BlockCount++;
+ inoutStats.Stats.BlockBytes += size;
+ AddDetailedStatisticsAllocation(inoutStats, size);
+ }
+}
+
+void CommittedAllocationList::BuildStatsString(JsonWriter& json)
+{
+ MutexLockRead lock(m_Mutex, m_UseMutex);
+
+ json.BeginArray();
+ for (Allocation* alloc = m_AllocationList.Front();
+ alloc != NULL; alloc = m_AllocationList.GetNext(alloc))
+ {
+ json.BeginObject(true);
+ json.AddAllocationToObject(*alloc);
+ json.EndObject();
+ }
+ json.EndArray();
+}
+
+void CommittedAllocationList::Register(Allocation* alloc)
+{
+ MutexLockWrite lock(m_Mutex, m_UseMutex);
+ m_AllocationList.PushBack(alloc);
+}
+
+void CommittedAllocationList::Unregister(Allocation* alloc)
+{
+ MutexLockWrite lock(m_Mutex, m_UseMutex);
+ m_AllocationList.Remove(alloc);
+}
+#endif // _D3D12MA_COMMITTED_ALLOCATION_LIST_FUNCTIONS
+
+#ifndef _D3D12MA_BLOCK_VECTOR_FUNCTIONS
+BlockVector::BlockVector(
+ AllocatorPimpl* hAllocator,
+ const D3D12_HEAP_PROPERTIES& heapProps,
+ D3D12_HEAP_FLAGS heapFlags,
+ UINT64 preferredBlockSize,
+ size_t minBlockCount,
+ size_t maxBlockCount,
+ bool explicitBlockSize,
+ UINT64 minAllocationAlignment,
+ UINT32 algorithm,
+ ID3D12ProtectedResourceSession* pProtectedSession)
+ : m_hAllocator(hAllocator),
+ m_HeapProps(heapProps),
+ m_HeapFlags(heapFlags),
+ m_PreferredBlockSize(preferredBlockSize),
+ m_MinBlockCount(minBlockCount),
+ m_MaxBlockCount(maxBlockCount),
+ m_ExplicitBlockSize(explicitBlockSize),
+ m_MinAllocationAlignment(minAllocationAlignment),
+ m_Algorithm(algorithm),
+ m_ProtectedSession(pProtectedSession),
+ m_HasEmptyBlock(false),
+ m_Blocks(hAllocator->GetAllocs()),
+ m_NextBlockId(0) {}
+
+BlockVector::~BlockVector()
+{
+ for (size_t i = m_Blocks.size(); i--; )
+ {
+ D3D12MA_DELETE(m_hAllocator->GetAllocs(), m_Blocks[i]);
+ }
+}
+
+HRESULT BlockVector::CreateMinBlocks()
+{
+ for (size_t i = 0; i < m_MinBlockCount; ++i)
+ {
+ HRESULT hr = CreateBlock(m_PreferredBlockSize, NULL);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+ }
+ return S_OK;
+}
+
+bool BlockVector::IsEmpty()
+{
+ MutexLockRead lock(m_Mutex, m_hAllocator->UseMutex());
+ return m_Blocks.empty();
+}
+
+HRESULT BlockVector::Allocate(
+ UINT64 size,
+ UINT64 alignment,
+ const ALLOCATION_DESC& allocDesc,
+ size_t allocationCount,
+ Allocation** pAllocations)
+{
+ size_t allocIndex;
+ HRESULT hr = S_OK;
+
+ {
+ MutexLockWrite lock(m_Mutex, m_hAllocator->UseMutex());
+ for (allocIndex = 0; allocIndex < allocationCount; ++allocIndex)
+ {
+ hr = AllocatePage(
+ size,
+ alignment,
+ allocDesc,
+ pAllocations + allocIndex);
+ if (FAILED(hr))
+ {
+ break;
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ // Free all already created allocations.
+ while (allocIndex--)
+ {
+ Free(pAllocations[allocIndex]);
+ }
+ ZeroMemory(pAllocations, sizeof(Allocation*) * allocationCount);
+ }
+
+ return hr;
+}
+
+void BlockVector::Free(Allocation* hAllocation)
+{
+ NormalBlock* pBlockToDelete = NULL;
+
+ bool budgetExceeded = false;
+ if (IsHeapTypeStandard(m_HeapProps.Type))
+ {
+ Budget budget = {};
+ m_hAllocator->GetBudgetForHeapType(budget, m_HeapProps.Type);
+ budgetExceeded = budget.UsageBytes >= budget.BudgetBytes;
+ }
+
+ // Scope for lock.
+ {
+ MutexLockWrite lock(m_Mutex, m_hAllocator->UseMutex());
+
+ NormalBlock* pBlock = hAllocation->m_Placed.block;
+
+ pBlock->m_pMetadata->Free(hAllocation->GetAllocHandle());
+ D3D12MA_HEAVY_ASSERT(pBlock->Validate());
+
+ const size_t blockCount = m_Blocks.size();
+ // pBlock became empty after this deallocation.
+ if (pBlock->m_pMetadata->IsEmpty())
+ {
+ // Already has empty Allocation. We don't want to have two, so delete this one.
+ if ((m_HasEmptyBlock || budgetExceeded) &&
+ blockCount > m_MinBlockCount)
+ {
+ pBlockToDelete = pBlock;
+ Remove(pBlock);
+ }
+ // We now have first empty block.
+ else
+ {
+ m_HasEmptyBlock = true;
+ }
+ }
+ // pBlock didn't become empty, but we have another empty block - find and free that one.
+ // (This is optional, heuristics.)
+ else if (m_HasEmptyBlock && blockCount > m_MinBlockCount)
+ {
+ NormalBlock* pLastBlock = m_Blocks.back();
+ if (pLastBlock->m_pMetadata->IsEmpty())
+ {
+ pBlockToDelete = pLastBlock;
+ m_Blocks.pop_back();
+ m_HasEmptyBlock = false;
+ }
+ }
+
+ IncrementallySortBlocks();
+ }
+
+ // Destruction of a free Allocation. Deferred until this point, outside of mutex
+ // lock, for performance reason.
+ if (pBlockToDelete != NULL)
+ {
+ D3D12MA_DELETE(m_hAllocator->GetAllocs(), pBlockToDelete);
+ }
+}
+
+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,
+ D3D12MA_IID_PPV_ARGS(&res));
+ if (SUCCEEDED(hr))
+ {
+ if (ppvResource != NULL)
+ {
+ hr = res->QueryInterface(riidResource, ppvResource);
+ }
+ if (SUCCEEDED(hr))
+ {
+ (*ppAllocation)->SetResource(res, &resourceDesc);
+ }
+ else
+ {
+ res->Release();
+ SAFE_RELEASE(*ppAllocation);
+ }
+ }
+ else
+ {
+ SAFE_RELEASE(*ppAllocation);
+ }
+ }
+ return hr;
+}
+
+#ifdef __ID3D12Device8_INTERFACE_DEFINED__
+HRESULT BlockVector::CreateResource2(
+ UINT64 size,
+ UINT64 alignment,
+ const ALLOCATION_DESC& allocDesc,
+ const D3D12_RESOURCE_DESC1& resourceDesc,
+ D3D12_RESOURCE_STATES InitialResourceState,
+ const D3D12_CLEAR_VALUE* pOptimizedClearValue,
+ Allocation** ppAllocation,
+ REFIID riidResource,
+ void** ppvResource)
+{
+ ID3D12Device8* const device8 = m_hAllocator->GetDevice8();
+ if (device8 == NULL)
+ {
+ return E_NOINTERFACE;
+ }
+
+ HRESULT hr = Allocate(size, alignment, allocDesc, 1, ppAllocation);
+ if (SUCCEEDED(hr))
+ {
+ ID3D12Resource* res = NULL;
+ hr = device8->CreatePlacedResource1(
+ (*ppAllocation)->m_Placed.block->GetHeap(),
+ (*ppAllocation)->GetOffset(),
+ &resourceDesc,
+ InitialResourceState,
+ pOptimizedClearValue,
+ D3D12MA_IID_PPV_ARGS(&res));
+ if (SUCCEEDED(hr))
+ {
+ if (ppvResource != NULL)
+ {
+ hr = res->QueryInterface(riidResource, ppvResource);
+ }
+ if (SUCCEEDED(hr))
+ {
+ (*ppAllocation)->SetResource(res, &resourceDesc);
+ }
+ else
+ {
+ res->Release();
+ SAFE_RELEASE(*ppAllocation);
+ }
+ }
+ else
+ {
+ SAFE_RELEASE(*ppAllocation);
+ }
+ }
+ return hr;
+}
+#endif // #ifdef __ID3D12Device8_INTERFACE_DEFINED__
+
+void BlockVector::AddStatistics(Statistics& inoutStats)
+{
+ MutexLockRead lock(m_Mutex, m_hAllocator->UseMutex());
+
+ for (size_t i = 0; i < m_Blocks.size(); ++i)
+ {
+ const NormalBlock* const pBlock = m_Blocks[i];
+ D3D12MA_ASSERT(pBlock);
+ D3D12MA_HEAVY_ASSERT(pBlock->Validate());
+ pBlock->m_pMetadata->AddStatistics(inoutStats);
+ }
+}
+
+void BlockVector::AddDetailedStatistics(DetailedStatistics& inoutStats)
+{
+ MutexLockRead lock(m_Mutex, m_hAllocator->UseMutex());
+
+ for (size_t i = 0; i < m_Blocks.size(); ++i)
+ {
+ const NormalBlock* const pBlock = m_Blocks[i];
+ D3D12MA_ASSERT(pBlock);
+ D3D12MA_HEAVY_ASSERT(pBlock->Validate());
+ pBlock->m_pMetadata->AddDetailedStatistics(inoutStats);
+ }
+}
+
+void BlockVector::WriteBlockInfoToJson(JsonWriter& json)
+{
+ MutexLockRead lock(m_Mutex, m_hAllocator->UseMutex());
+
+ json.BeginObject();
+
+ for (size_t i = 0, count = m_Blocks.size(); i < count; ++i)
+ {
+ const NormalBlock* const pBlock = m_Blocks[i];
+ D3D12MA_ASSERT(pBlock);
+ D3D12MA_HEAVY_ASSERT(pBlock->Validate());
+ json.BeginString();
+ json.ContinueString(pBlock->GetId());
+ json.EndString();
+
+ pBlock->m_pMetadata->WriteAllocationInfoToJson(json);
+ }
+
+ json.EndObject();
+}
+
+UINT64 BlockVector::CalcSumBlockSize() const
+{
+ UINT64 result = 0;
+ for (size_t i = m_Blocks.size(); i--; )
+ {
+ result += m_Blocks[i]->m_pMetadata->GetSize();
+ }
+ return result;
+}
+
+UINT64 BlockVector::CalcMaxBlockSize() const
+{
+ UINT64 result = 0;
+ for (size_t i = m_Blocks.size(); i--; )
+ {
+ result = D3D12MA_MAX(result, m_Blocks[i]->m_pMetadata->GetSize());
+ if (result >= m_PreferredBlockSize)
+ {
+ break;
+ }
+ }
+ return result;
+}
+
+void BlockVector::Remove(NormalBlock* pBlock)
+{
+ for (size_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex)
+ {
+ if (m_Blocks[blockIndex] == pBlock)
+ {
+ m_Blocks.remove(blockIndex);
+ return;
+ }
+ }
+ D3D12MA_ASSERT(0);
+}
+
+void BlockVector::IncrementallySortBlocks()
+{
+ // Bubble sort only until first swap.
+ for (size_t i = 1; i < m_Blocks.size(); ++i)
+ {
+ if (m_Blocks[i - 1]->m_pMetadata->GetSumFreeSize() > m_Blocks[i]->m_pMetadata->GetSumFreeSize())
+ {
+ D3D12MA_SWAP(m_Blocks[i - 1], m_Blocks[i]);
+ return;
+ }
+ }
+}
+
+HRESULT BlockVector::AllocatePage(
+ UINT64 size,
+ UINT64 alignment,
+ const ALLOCATION_DESC& allocDesc,
+ Allocation** pAllocation)
+{
+ // Early reject: requested allocation size is larger that maximum block size for this block vector.
+ if (size + D3D12MA_DEBUG_MARGIN > m_PreferredBlockSize)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ UINT64 freeMemory = UINT64_MAX;
+ if (IsHeapTypeStandard(m_HeapProps.Type))
+ {
+ Budget budget = {};
+ m_hAllocator->GetBudgetForHeapType(budget, m_HeapProps.Type);
+ freeMemory = (budget.UsageBytes < budget.BudgetBytes) ? (budget.BudgetBytes - budget.UsageBytes) : 0;
+ }
+
+ const bool canCreateNewBlock =
+ ((allocDesc.Flags & ALLOCATION_FLAG_NEVER_ALLOCATE) == 0) &&
+ (m_Blocks.size() < m_MaxBlockCount) &&
+ // Even if we don't have to stay within budget with this allocation, when the
+ // budget would be exceeded, we don't want to allocate new blocks, but always
+ // create resources as committed.
+ freeMemory >= size;
+
+ // 1. Search existing allocations
+ {
+ // Forward order in m_Blocks - prefer blocks with smallest amount of free space.
+ for (size_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex)
+ {
+ NormalBlock* const pCurrBlock = m_Blocks[blockIndex];
+ D3D12MA_ASSERT(pCurrBlock);
+ HRESULT hr = AllocateFromBlock(
+ pCurrBlock,
+ size,
+ alignment,
+ allocDesc.Flags,
+ pAllocation);
+ if (SUCCEEDED(hr))
+ {
+ return hr;
+ }
+ }
+ }
+
+ // 2. Try to create new block.
+ if (canCreateNewBlock)
+ {
+ // Calculate optimal size for new block.
+ UINT64 newBlockSize = m_PreferredBlockSize;
+ UINT newBlockSizeShift = 0;
+
+ if (!m_ExplicitBlockSize)
+ {
+ // Allocate 1/8, 1/4, 1/2 as first blocks.
+ const UINT64 maxExistingBlockSize = CalcMaxBlockSize();
+ for (UINT i = 0; i < NEW_BLOCK_SIZE_SHIFT_MAX; ++i)
+ {
+ const UINT64 smallerNewBlockSize = newBlockSize / 2;
+ if (smallerNewBlockSize > maxExistingBlockSize && smallerNewBlockSize >= size * 2)
+ {
+ newBlockSize = smallerNewBlockSize;
+ ++newBlockSizeShift;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+
+ size_t newBlockIndex = 0;
+ HRESULT hr = newBlockSize <= freeMemory ?
+ CreateBlock(newBlockSize, &newBlockIndex) : E_OUTOFMEMORY;
+ // Allocation of this size failed? Try 1/2, 1/4, 1/8 of m_PreferredBlockSize.
+ if (!m_ExplicitBlockSize)
+ {
+ while (FAILED(hr) && newBlockSizeShift < NEW_BLOCK_SIZE_SHIFT_MAX)
+ {
+ const UINT64 smallerNewBlockSize = newBlockSize / 2;
+ if (smallerNewBlockSize >= size)
+ {
+ newBlockSize = smallerNewBlockSize;
+ ++newBlockSizeShift;
+ hr = newBlockSize <= freeMemory ?
+ CreateBlock(newBlockSize, &newBlockIndex) : E_OUTOFMEMORY;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ NormalBlock* const pBlock = m_Blocks[newBlockIndex];
+ D3D12MA_ASSERT(pBlock->m_pMetadata->GetSize() >= size);
+
+ hr = AllocateFromBlock(
+ pBlock,
+ size,
+ alignment,
+ allocDesc.Flags,
+ pAllocation);
+ if (SUCCEEDED(hr))
+ {
+ return hr;
+ }
+ else
+ {
+ // Allocation from new block failed, possibly due to D3D12MA_DEBUG_MARGIN or alignment.
+ return E_OUTOFMEMORY;
+ }
+ }
+ }
+
+ return E_OUTOFMEMORY;
+}
+
+HRESULT BlockVector::AllocateFromBlock(
+ NormalBlock* pBlock,
+ UINT64 size,
+ UINT64 alignment,
+ ALLOCATION_FLAGS allocFlags,
+ Allocation** pAllocation)
+{
+ alignment = D3D12MA_MAX(alignment, m_MinAllocationAlignment);
+
+ AllocationRequest currRequest = {};
+ if (pBlock->m_pMetadata->CreateAllocationRequest(
+ size,
+ alignment,
+ allocFlags & ALLOCATION_FLAG_UPPER_ADDRESS,
+ &currRequest))
+ {
+ // We no longer have an empty Allocation.
+ if (pBlock->m_pMetadata->IsEmpty())
+ {
+ m_HasEmptyBlock = false;
+ }
+
+ *pAllocation = m_hAllocator->GetAllocationObjectAllocator().Allocate(m_hAllocator, size, currRequest.zeroInitialized);
+ pBlock->m_pMetadata->Alloc(currRequest, size, *pAllocation);
+ (*pAllocation)->InitPlaced(currRequest.allocHandle, alignment, pBlock);
+ D3D12MA_HEAVY_ASSERT(pBlock->Validate());
+ m_hAllocator->m_Budget.AddAllocation(m_hAllocator->HeapPropertiesToMemorySegmentGroup(m_HeapProps), size);
+ return S_OK;
+ }
+ return E_OUTOFMEMORY;
+}
+
+HRESULT BlockVector::CreateBlock(
+ UINT64 blockSize,
+ size_t* pNewBlockIndex)
+{
+ NormalBlock* const pBlock = D3D12MA_NEW(m_hAllocator->GetAllocs(), NormalBlock)(
+ m_hAllocator,
+ this,
+ m_HeapProps,
+ m_HeapFlags,
+ blockSize,
+ m_NextBlockId++);
+ HRESULT hr = pBlock->Init(m_Algorithm, m_ProtectedSession);
+ if (FAILED(hr))
+ {
+ D3D12MA_DELETE(m_hAllocator->GetAllocs(), pBlock);
+ return hr;
+ }
+
+ m_Blocks.push_back(pBlock);
+ if (pNewBlockIndex != NULL)
+ {
+ *pNewBlockIndex = m_Blocks.size() - 1;
+ }
+
+ return hr;
+}
+#endif // _D3D12MA_BLOCK_VECTOR_FUNCTIONS
+
+#ifndef _D3D12MA_POOL_PIMPL_FUNCTIONS
+PoolPimpl::PoolPimpl(AllocatorPimpl* allocator, const POOL_DESC& desc)
+ : m_Allocator(allocator),
+ m_Desc(desc),
+ m_BlockVector(NULL),
+ m_Name(NULL)
+{
+ const bool explicitBlockSize = desc.BlockSize != 0;
+ const UINT64 preferredBlockSize = explicitBlockSize ? desc.BlockSize : D3D12MA_DEFAULT_BLOCK_SIZE;
+ UINT maxBlockCount = desc.MaxBlockCount != 0 ? desc.MaxBlockCount : UINT_MAX;
+
+#ifndef __ID3D12Device4_INTERFACE_DEFINED__
+ D3D12MA_ASSERT(m_Desc.pProtectedSession == NULL);
+#endif
+
+ m_BlockVector = D3D12MA_NEW(allocator->GetAllocs(), BlockVector)(
+ allocator, desc.HeapProperties, desc.HeapFlags,
+ preferredBlockSize,
+ desc.MinBlockCount, maxBlockCount,
+ explicitBlockSize,
+ D3D12MA_MAX(desc.MinAllocationAlignment, (UINT64)D3D12MA_DEBUG_ALIGNMENT),
+ desc.Flags & POOL_FLAG_ALGORITHM_MASK,
+ desc.pProtectedSession);
+}
+
+PoolPimpl::~PoolPimpl()
+{
+ D3D12MA_ASSERT(m_PrevPool == NULL && m_NextPool == NULL);
+ FreeName();
+ D3D12MA_DELETE(m_Allocator->GetAllocs(), m_BlockVector);
+}
+
+HRESULT PoolPimpl::Init()
+{
+ m_CommittedAllocations.Init(m_Allocator->UseMutex(), m_Desc.HeapProperties.Type, this);
+ return m_BlockVector->CreateMinBlocks();
+}
+
+void PoolPimpl::GetStatistics(Statistics& outStats)
+{
+ ClearStatistics(outStats);
+ m_BlockVector->AddStatistics(outStats);
+ m_CommittedAllocations.AddStatistics(outStats);
+}
+
+void PoolPimpl::CalculateStatistics(DetailedStatistics& outStats)
+{
+ ClearDetailedStatistics(outStats);
+ AddDetailedStatistics(outStats);
+}
+
+void PoolPimpl::AddDetailedStatistics(DetailedStatistics& inoutStats)
+{
+ m_BlockVector->AddDetailedStatistics(inoutStats);
+ m_CommittedAllocations.AddDetailedStatistics(inoutStats);
+}
+
+void PoolPimpl::SetName(LPCWSTR Name)
+{
+ FreeName();
+
+ if (Name)
+ {
+ const size_t nameCharCount = wcslen(Name) + 1;
+ m_Name = D3D12MA_NEW_ARRAY(m_Allocator->GetAllocs(), WCHAR, nameCharCount);
+ memcpy(m_Name, Name, nameCharCount * sizeof(WCHAR));
+ }
+}
+
+void PoolPimpl::FreeName()
+{
+ if (m_Name)
+ {
+ const size_t nameCharCount = wcslen(m_Name) + 1;
+ D3D12MA_DELETE_ARRAY(m_Allocator->GetAllocs(), m_Name, nameCharCount);
+ m_Name = NULL;
+ }
+}
+#endif // _D3D12MA_POOL_PIMPL_FUNCTIONS
+
+
+#ifndef _D3D12MA_PUBLIC_FUNCTIONS
+HRESULT CreateAllocator(const ALLOCATOR_DESC* pDesc, Allocator** ppAllocator)
+{
+ if (!pDesc || !ppAllocator || !pDesc->pDevice || !pDesc->pAdapter ||
+ !(pDesc->PreferredBlockSize == 0 || (pDesc->PreferredBlockSize >= 16 && pDesc->PreferredBlockSize < 0x10000000000ull)))
+ {
+ D3D12MA_ASSERT(0 && "Invalid arguments passed to CreateAllocator.");
+ return E_INVALIDARG;
+ }
+
+ D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
+
+ ALLOCATION_CALLBACKS allocationCallbacks;
+ SetupAllocationCallbacks(allocationCallbacks, pDesc->pAllocationCallbacks);
+
+ *ppAllocator = D3D12MA_NEW(allocationCallbacks, Allocator)(allocationCallbacks, *pDesc);
+ HRESULT hr = (*ppAllocator)->m_Pimpl->Init(*pDesc);
+ if (FAILED(hr))
+ {
+ D3D12MA_DELETE(allocationCallbacks, *ppAllocator);
+ *ppAllocator = NULL;
+ }
+ return hr;
+}
+
+HRESULT CreateVirtualBlock(const VIRTUAL_BLOCK_DESC* pDesc, VirtualBlock** ppVirtualBlock)
+{
+ if (!pDesc || !ppVirtualBlock)
+ {
+ D3D12MA_ASSERT(0 && "Invalid arguments passed to CreateVirtualBlock.");
+ return E_INVALIDARG;
+ }
+
+ D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
+
+ ALLOCATION_CALLBACKS allocationCallbacks;
+ SetupAllocationCallbacks(allocationCallbacks, pDesc->pAllocationCallbacks);
+
+ *ppVirtualBlock = D3D12MA_NEW(allocationCallbacks, VirtualBlock)(allocationCallbacks, *pDesc);
+ return S_OK;
+}
+
+#ifndef _D3D12MA_IUNKNOWN_IMPL_FUNCTIONS
HRESULT STDMETHODCALLTYPE IUnknownImpl::QueryInterface(REFIID riid, void** ppvObject)
{
- if(ppvObject == NULL)
+ if (ppvObject == NULL)
return E_POINTER;
- if(riid == IID_IUnknown)
+ if (riid == IID_IUnknown)
{
++m_RefCount;
*ppvObject = this;
@@ -8239,15 +8361,14 @@
{
D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- const uint32_t newRefCount = --m_RefCount;
- if(newRefCount == 0)
+ const uint32_t newRefCount = --m_RefCount;
+ if (newRefCount == 0)
ReleaseThis();
return newRefCount;
}
+#endif // _D3D12MA_IUNKNOWN_IMPL_FUNCTIONS
-////////////////////////////////////////////////////////////////////////////////
-// Public class Allocation implementation
-
+#ifndef _D3D12MA_ALLOCATION_FUNCTIONS
void Allocation::PackedData::SetType(Type type)
{
const UINT u = (UINT)type;
@@ -8276,36 +8397,9 @@
m_TextureLayout = u;
}
-void Allocation::ReleaseThis()
-{
- if(this == NULL)
- {
- return;
- }
-
- SAFE_RELEASE(m_Resource);
-
- switch(m_PackedData.GetType())
- {
- case TYPE_COMMITTED:
- m_Allocator->FreeCommittedMemory(this);
- break;
- case TYPE_PLACED:
- m_Allocator->FreePlacedMemory(this);
- break;
- case TYPE_HEAP:
- m_Allocator->FreeHeapMemory(this);
- break;
- }
-
- FreeName();
-
- m_Allocator->GetAllocationObjectAllocator().Free(this);
-}
-
UINT64 Allocation::GetOffset() const
{
- switch(m_PackedData.GetType())
+ switch (m_PackedData.GetType())
{
case TYPE_COMMITTED:
case TYPE_HEAP:
@@ -8320,7 +8414,7 @@
ID3D12Heap* Allocation::GetHeap() const
{
- switch(m_PackedData.GetType())
+ switch (m_PackedData.GetType())
{
case TYPE_COMMITTED:
return NULL;
@@ -8338,7 +8432,7 @@
{
FreeName();
- if(Name)
+ if (Name)
{
const size_t nameCharCount = wcslen(Name) + 1;
m_Name = D3D12MA_NEW_ARRAY(m_Allocator->GetAllocs(), WCHAR, nameCharCount);
@@ -8346,12 +8440,39 @@
}
}
-Allocation::Allocation(AllocatorPimpl* allocator, UINT64 size, BOOL wasZeroInitialized) :
- m_Allocator{allocator},
- m_Size{size},
- m_Resource{NULL},
- m_CreationFrameIndex{allocator->GetCurrentFrameIndex()},
- m_Name{NULL}
+void Allocation::ReleaseThis()
+{
+ if (this == NULL)
+ {
+ return;
+ }
+
+ SAFE_RELEASE(m_Resource);
+
+ switch (m_PackedData.GetType())
+ {
+ case TYPE_COMMITTED:
+ m_Allocator->FreeCommittedMemory(this);
+ break;
+ case TYPE_PLACED:
+ m_Allocator->FreePlacedMemory(this);
+ break;
+ case TYPE_HEAP:
+ m_Allocator->FreeHeapMemory(this);
+ break;
+ }
+
+ FreeName();
+
+ m_Allocator->GetAllocationObjectAllocator().Free(this);
+}
+
+Allocation::Allocation(AllocatorPimpl* allocator, UINT64 size, BOOL wasZeroInitialized)
+ : m_Allocator{ allocator },
+ m_Size{ size },
+ m_Resource{ NULL },
+ m_CreationFrameIndex{ allocator->GetCurrentFrameIndex() },
+ m_Name{ NULL }
{
D3D12MA_ASSERT(allocator);
@@ -8413,62 +8534,78 @@
void Allocation::FreeName()
{
- if(m_Name)
+ if (m_Name)
{
const size_t nameCharCount = wcslen(m_Name) + 1;
D3D12MA_DELETE_ARRAY(m_Allocator->GetAllocs(), m_Name, nameCharCount);
m_Name = NULL;
}
}
+#endif // _D3D12MA_ALLOCATION_FUNCTIONS
-////////////////////////////////////////////////////////////////////////////////
-// Private class AllocationObjectAllocator implementation
-
-AllocationObjectAllocator::AllocationObjectAllocator(const ALLOCATION_CALLBACKS& allocationCallbacks) :
- m_Allocator(allocationCallbacks, 1024)
+#ifndef _D3D12MA_POOL_FUNCTIONS
+POOL_DESC Pool::GetDesc() const
{
+ return m_Pimpl->GetDesc();
}
-template<typename... Types> Allocation* AllocationObjectAllocator::Allocate(Types... args)
+void Pool::GetStatistics(Statistics* pStats)
{
- MutexLock mutexLock(m_Mutex);
- return m_Allocator.Alloc(std::forward<Types>(args)...);
+ D3D12MA_ASSERT(pStats);
+ D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
+ m_Pimpl->GetStatistics(*pStats);
}
-void AllocationObjectAllocator::Free(Allocation* alloc)
+void Pool::CalculateStatistics(DetailedStatistics* pStats)
{
- MutexLock mutexLock(m_Mutex);
- m_Allocator.Free(alloc);
+ D3D12MA_ASSERT(pStats);
+ D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
+ m_Pimpl->CalculateStatistics(*pStats);
}
-////////////////////////////////////////////////////////////////////////////////
-// Public class Allocator implementation
-
-Allocator::Allocator(const ALLOCATION_CALLBACKS& allocationCallbacks, const ALLOCATOR_DESC& desc) :
- m_Pimpl(D3D12MA_NEW(allocationCallbacks, AllocatorPimpl)(allocationCallbacks, desc))
+void Pool::SetName(LPCWSTR Name)
{
+ D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
+ m_Pimpl->SetName(Name);
}
-Allocator::~Allocator()
+LPCWSTR Pool::GetName() const
{
- D3D12MA_DELETE(m_Pimpl->GetAllocs(), m_Pimpl);
+ return m_Pimpl->GetName();
}
-void Allocator::ReleaseThis()
+void Pool::ReleaseThis()
{
- // Copy is needed because otherwise we would call destructor and invalidate the structure with callbacks before using it to free memory.
- const ALLOCATION_CALLBACKS allocationCallbacksCopy = m_Pimpl->GetAllocs();
- D3D12MA_DELETE(allocationCallbacksCopy, this);
+ if (this == NULL)
+ {
+ return;
+ }
+
+ D3D12MA_DELETE(m_Pimpl->GetAllocator()->GetAllocs(), this);
}
+Pool::Pool(Allocator* allocator, const POOL_DESC& desc)
+ : m_Pimpl(D3D12MA_NEW(allocator->m_Pimpl->GetAllocs(), PoolPimpl)(allocator->m_Pimpl, desc)) {}
+
+Pool::~Pool()
+{
+ m_Pimpl->GetAllocator()->UnregisterPool(this, m_Pimpl->GetDesc().HeapProperties.Type);
+
+ D3D12MA_DELETE(m_Pimpl->GetAllocator()->GetAllocs(), m_Pimpl);
+}
+#endif // _D3D12MA_POOL_FUNCTIONS
+
+#ifndef _D3D12MA_ALLOCATOR_FUNCTIONS
const D3D12_FEATURE_DATA_D3D12_OPTIONS& Allocator::GetD3D12Options() const
{
return m_Pimpl->GetD3D12Options();
}
+
BOOL Allocator::IsUMA() const
{
return m_Pimpl->IsUMA();
}
+
BOOL Allocator::IsCacheCoherentUMA() const
{
return m_Pimpl->IsCacheCoherentUMA();
@@ -8483,18 +8620,18 @@
const ALLOCATION_DESC* pAllocDesc,
const D3D12_RESOURCE_DESC* pResourceDesc,
D3D12_RESOURCE_STATES InitialResourceState,
- const D3D12_CLEAR_VALUE *pOptimizedClearValue,
+ const D3D12_CLEAR_VALUE* pOptimizedClearValue,
Allocation** ppAllocation,
REFIID riidResource,
void** ppvResource)
{
- if(!pAllocDesc || !pResourceDesc || !ppAllocation)
+ if (!pAllocDesc || !pResourceDesc || !ppAllocation)
{
D3D12MA_ASSERT(0 && "Invalid arguments passed to Allocator::CreateResource.");
return E_INVALIDARG;
}
D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- return m_Pimpl->CreateResource(pAllocDesc, pResourceDesc, InitialResourceState, pOptimizedClearValue, ppAllocation, riidResource, ppvResource);
+ return m_Pimpl->CreateResource(pAllocDesc, pResourceDesc, InitialResourceState, pOptimizedClearValue, ppAllocation, riidResource, ppvResource);
}
#ifdef __ID3D12Device8_INTERFACE_DEFINED__
@@ -8502,48 +8639,33 @@
const ALLOCATION_DESC* pAllocDesc,
const D3D12_RESOURCE_DESC1* pResourceDesc,
D3D12_RESOURCE_STATES InitialResourceState,
- const D3D12_CLEAR_VALUE *pOptimizedClearValue,
+ const D3D12_CLEAR_VALUE* pOptimizedClearValue,
Allocation** ppAllocation,
REFIID riidResource,
void** ppvResource)
{
- if(!pAllocDesc || !pResourceDesc || !ppAllocation)
+ if (!pAllocDesc || !pResourceDesc || !ppAllocation)
{
D3D12MA_ASSERT(0 && "Invalid arguments passed to Allocator::CreateResource2.");
return E_INVALIDARG;
}
D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- return m_Pimpl->CreateResource2(pAllocDesc, pResourceDesc, InitialResourceState, pOptimizedClearValue, ppAllocation, riidResource, ppvResource);
+ return m_Pimpl->CreateResource2(pAllocDesc, pResourceDesc, InitialResourceState, pOptimizedClearValue, ppAllocation, riidResource, ppvResource);
}
#endif // #ifdef __ID3D12Device8_INTERFACE_DEFINED__
-static inline bool ValidateAllocateMemoryParameters(
- const ALLOCATION_DESC* pAllocDesc,
- const D3D12_RESOURCE_ALLOCATION_INFO* pAllocInfo,
- Allocation** ppAllocation)
-{
- return pAllocDesc &&
- pAllocInfo &&
- ppAllocation &&
- (pAllocInfo->Alignment == 0 ||
- pAllocInfo->Alignment == D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT ||
- pAllocInfo->Alignment == D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT) &&
- pAllocInfo->SizeInBytes != 0 &&
- pAllocInfo->SizeInBytes % (64ull * 1024) == 0;
-}
-
HRESULT Allocator::AllocateMemory(
const ALLOCATION_DESC* pAllocDesc,
const D3D12_RESOURCE_ALLOCATION_INFO* pAllocInfo,
Allocation** ppAllocation)
{
- if(!ValidateAllocateMemoryParameters(pAllocDesc, pAllocInfo, ppAllocation))
+ if (!ValidateAllocateMemoryParameters(pAllocDesc, pAllocInfo, ppAllocation))
{
D3D12MA_ASSERT(0 && "Invalid arguments passed to Allocator::AllocateMemory.");
return E_INVALIDARG;
}
D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- return m_Pimpl->AllocateMemory(pAllocDesc, pAllocInfo, ppAllocation);
+ return m_Pimpl->AllocateMemory(pAllocDesc, pAllocInfo, ppAllocation);
}
HRESULT Allocator::CreateAliasingResource(
@@ -8551,39 +8673,39 @@
UINT64 AllocationLocalOffset,
const D3D12_RESOURCE_DESC* pResourceDesc,
D3D12_RESOURCE_STATES InitialResourceState,
- const D3D12_CLEAR_VALUE *pOptimizedClearValue,
+ const D3D12_CLEAR_VALUE* pOptimizedClearValue,
REFIID riidResource,
void** ppvResource)
{
- if(!pAllocation || !pResourceDesc || !ppvResource)
+ if (!pAllocation || !pResourceDesc || !ppvResource)
{
D3D12MA_ASSERT(0 && "Invalid arguments passed to Allocator::CreateAliasingResource.");
return E_INVALIDARG;
}
D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- return m_Pimpl->CreateAliasingResource(pAllocation, AllocationLocalOffset, pResourceDesc, InitialResourceState, pOptimizedClearValue, riidResource, ppvResource);
+ return m_Pimpl->CreateAliasingResource(pAllocation, AllocationLocalOffset, pResourceDesc, InitialResourceState, pOptimizedClearValue, riidResource, ppvResource);
}
HRESULT Allocator::CreatePool(
const POOL_DESC* pPoolDesc,
Pool** ppPool)
{
- if(!pPoolDesc || !ppPool ||
+ if (!pPoolDesc || !ppPool ||
(pPoolDesc->MaxBlockCount > 0 && pPoolDesc->MaxBlockCount < pPoolDesc->MinBlockCount) ||
(pPoolDesc->MinAllocationAlignment > 0 && !IsPow2(pPoolDesc->MinAllocationAlignment)))
{
D3D12MA_ASSERT(0 && "Invalid arguments passed to Allocator::CreatePool.");
return E_INVALIDARG;
}
- if(!m_Pimpl->HeapFlagsFulfillResourceHeapTier(pPoolDesc->HeapFlags))
+ 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);
+ * ppPool = D3D12MA_NEW(m_Pimpl->GetAllocs(), Pool)(this, *pPoolDesc);
HRESULT hr = (*ppPool)->m_Pimpl->Init();
- if(SUCCEEDED(hr))
+ if (SUCCEEDED(hr))
{
m_Pimpl->RegisterPool(*ppPool, pPoolDesc->HeapProperties.Type);
}
@@ -8598,31 +8720,31 @@
void Allocator::SetCurrentFrameIndex(UINT frameIndex)
{
D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- m_Pimpl->SetCurrentFrameIndex(frameIndex);
+ m_Pimpl->SetCurrentFrameIndex(frameIndex);
+}
+
+void Allocator::GetBudget(Budget* pLocalBudget, Budget* pNonLocalBudget)
+{
+ if (pLocalBudget == NULL && pNonLocalBudget == NULL)
+ {
+ return;
+ }
+ D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
+ m_Pimpl->GetBudget(pLocalBudget, pNonLocalBudget);
}
void Allocator::CalculateStatistics(TotalStatistics* pStats)
{
D3D12MA_ASSERT(pStats);
D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- m_Pimpl->CalculateStatistics(*pStats);
-}
-
-void Allocator::GetBudget(Budget* pLocalBudget, Budget* pNonLocalBudget)
-{
- if(pLocalBudget == NULL && pNonLocalBudget == NULL)
- {
- return;
- }
- D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- m_Pimpl->GetBudget(pLocalBudget, pNonLocalBudget);
+ m_Pimpl->CalculateStatistics(*pStats);
}
void Allocator::BuildStatsString(WCHAR** ppStatsString, BOOL DetailedMap) const
{
D3D12MA_ASSERT(ppStatsString);
D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- m_Pimpl->BuildStatsString(ppStatsString, DetailedMap);
+ m_Pimpl->BuildStatsString(ppStatsString, DetailedMap);
}
void Allocator::FreeStatsString(WCHAR* pStatsString) const
@@ -8630,76 +8752,32 @@
if (pStatsString != NULL)
{
D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- m_Pimpl->FreeStatsString(pStatsString);
+ m_Pimpl->FreeStatsString(pStatsString);
}
}
-////////////////////////////////////////////////////////////////////////////////
-// Private class VirtualBlockPimpl definition
-
-class VirtualBlockPimpl
-{
-public:
- const ALLOCATION_CALLBACKS m_AllocationCallbacks;
- const UINT64 m_Size;
- BlockMetadata* m_Metadata;
-
- VirtualBlockPimpl(const ALLOCATION_CALLBACKS& allocationCallbacks, const VIRTUAL_BLOCK_DESC& desc);
- ~VirtualBlockPimpl();
-};
-
-VirtualBlockPimpl::VirtualBlockPimpl(const ALLOCATION_CALLBACKS& allocationCallbacks, const VIRTUAL_BLOCK_DESC& desc) :
- m_AllocationCallbacks(allocationCallbacks),
- m_Size(desc.Size)
-{
- switch (desc.Flags & VIRTUAL_BLOCK_FLAG_ALGORITHM_MASK)
- {
- case VIRTUAL_BLOCK_FLAG_ALGORITHM_LINEAR:
- m_Metadata = D3D12MA_NEW(allocationCallbacks, BlockMetadata_Linear)(&m_AllocationCallbacks, true);
- break;
- default:
- D3D12MA_ASSERT(0);
- case 0:
- m_Metadata = D3D12MA_NEW(allocationCallbacks, BlockMetadata_TLSF)(&m_AllocationCallbacks, true);
- break;
- }
- m_Metadata->Init(m_Size);
-}
-
-VirtualBlockPimpl::~VirtualBlockPimpl()
-{
- D3D12MA_DELETE(m_AllocationCallbacks, m_Metadata);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Public class VirtualBlock implementation
-
-VirtualBlock::VirtualBlock(const ALLOCATION_CALLBACKS& allocationCallbacks, const VIRTUAL_BLOCK_DESC& desc) :
- m_Pimpl(D3D12MA_NEW(allocationCallbacks, VirtualBlockPimpl)(allocationCallbacks, desc))
-{
-}
-
-VirtualBlock::~VirtualBlock()
-{
- // THIS IS AN IMPORTANT ASSERT!
- // Hitting it means you have some memory leak - unreleased allocations in this virtual block.
- D3D12MA_ASSERT(m_Pimpl->m_Metadata->IsEmpty() && "Some allocations were not freed before destruction of this virtual block!");
-
- D3D12MA_DELETE(m_Pimpl->m_AllocationCallbacks, m_Pimpl);
-}
-
-void VirtualBlock::ReleaseThis()
+void Allocator::ReleaseThis()
{
// Copy is needed because otherwise we would call destructor and invalidate the structure with callbacks before using it to free memory.
- const ALLOCATION_CALLBACKS allocationCallbacksCopy = m_Pimpl->m_AllocationCallbacks;
+ const ALLOCATION_CALLBACKS allocationCallbacksCopy = m_Pimpl->GetAllocs();
D3D12MA_DELETE(allocationCallbacksCopy, this);
}
+Allocator::Allocator(const ALLOCATION_CALLBACKS& allocationCallbacks, const ALLOCATOR_DESC& desc)
+ : m_Pimpl(D3D12MA_NEW(allocationCallbacks, AllocatorPimpl)(allocationCallbacks, desc)) {}
+
+Allocator::~Allocator()
+{
+ D3D12MA_DELETE(m_Pimpl->GetAllocs(), m_Pimpl);
+}
+#endif // _D3D12MA_ALLOCATOR_FUNCTIONS
+
+#ifndef _D3D12MA_VIRTUAL_BLOCK_FUNCTIONS
BOOL VirtualBlock::IsEmpty() const
{
D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- return m_Pimpl->m_Metadata->IsEmpty() ? TRUE : FALSE;
+ return m_Pimpl->m_Metadata->IsEmpty() ? TRUE : FALSE;
}
void VirtualBlock::GetAllocationInfo(VirtualAllocation allocation, VIRTUAL_ALLOCATION_INFO* pInfo) const
@@ -8708,22 +8786,22 @@
D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- m_Pimpl->m_Metadata->GetAllocationInfo(allocation.AllocHandle, *pInfo);
+ m_Pimpl->m_Metadata->GetAllocationInfo(allocation.AllocHandle, *pInfo);
}
HRESULT VirtualBlock::Allocate(const VIRTUAL_ALLOCATION_DESC* pDesc, VirtualAllocation* pAllocation, UINT64* pOffset)
{
- if(!pDesc || !pAllocation || pDesc->Size == 0 || !IsPow2(pDesc->Alignment))
+ if (!pDesc || !pAllocation || pDesc->Size == 0 || !IsPow2(pDesc->Alignment))
{
D3D12MA_ASSERT(0 && "Invalid arguments passed to VirtualBlock::Allocate.");
return E_INVALIDARG;
}
D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
-
- const UINT64 alignment = pDesc->Alignment != 0 ? pDesc->Alignment : 1;
+
+ const UINT64 alignment = pDesc->Alignment != 0 ? pDesc->Alignment : 1;
AllocationRequest allocRequest = {};
- if(m_Pimpl->m_Metadata->CreateAllocationRequest(
+ if (m_Pimpl->m_Metadata->CreateAllocationRequest(
pDesc->Size,
alignment,
pDesc->Flags & VIRTUAL_ALLOCATION_FLAG_UPPER_ADDRESS,
@@ -8747,12 +8825,12 @@
void VirtualBlock::FreeAllocation(VirtualAllocation allocation)
{
- if(allocation.AllocHandle == (AllocHandle)0)
+ if (allocation.AllocHandle == (AllocHandle)0)
return;
D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- m_Pimpl->m_Metadata->Free(allocation.AllocHandle);
+ m_Pimpl->m_Metadata->Free(allocation.AllocHandle);
D3D12MA_HEAVY_ASSERT(m_Pimpl->m_Metadata->Validate());
}
@@ -8760,7 +8838,7 @@
{
D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- m_Pimpl->m_Metadata->Clear();
+ m_Pimpl->m_Metadata->Clear();
D3D12MA_HEAVY_ASSERT(m_Pimpl->m_Metadata->Validate());
}
@@ -8770,14 +8848,14 @@
D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- m_Pimpl->m_Metadata->SetAllocationUserData(allocation.AllocHandle, pUserData);
+ m_Pimpl->m_Metadata->SetAllocationUserData(allocation.AllocHandle, pUserData);
}
void VirtualBlock::GetStatistics(Statistics* pStats) const
{
D3D12MA_ASSERT(pStats);
D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- D3D12MA_HEAVY_ASSERT(m_Pimpl->m_Metadata->Validate());
+ D3D12MA_HEAVY_ASSERT(m_Pimpl->m_Metadata->Validate());
ClearStatistics(*pStats);
m_Pimpl->m_Metadata->AddStatistics(*pStats);
}
@@ -8786,7 +8864,7 @@
{
D3D12MA_ASSERT(pStats);
D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- D3D12MA_HEAVY_ASSERT(m_Pimpl->m_Metadata->Validate());
+ D3D12MA_HEAVY_ASSERT(m_Pimpl->m_Metadata->Validate());
ClearDetailedStatistics(*pStats);
m_Pimpl->m_Metadata->AddDetailedStatistics(*pStats);
}
@@ -8797,7 +8875,7 @@
D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- StringBuilder sb(m_Pimpl->m_AllocationCallbacks);
+ StringBuilder sb(m_Pimpl->m_AllocationCallbacks);
{
JsonWriter json(m_Pimpl->m_AllocationCallbacks, sb);
D3D12MA_HEAVY_ASSERT(m_Pimpl->m_Metadata->Validate());
@@ -8816,53 +8894,28 @@
if (pStatsString != NULL)
{
D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
- D3D12MA::Free(m_Pimpl->m_AllocationCallbacks, pStatsString);
+ D3D12MA::Free(m_Pimpl->m_AllocationCallbacks, pStatsString);
}
}
-
-////////////////////////////////////////////////////////////////////////////////
-// Public global functions
-
-HRESULT CreateAllocator(const ALLOCATOR_DESC* pDesc, Allocator** ppAllocator)
+void VirtualBlock::ReleaseThis()
{
- if(!pDesc || !ppAllocator || !pDesc->pDevice || !pDesc->pAdapter ||
- !(pDesc->PreferredBlockSize == 0 || (pDesc->PreferredBlockSize >= 16 && pDesc->PreferredBlockSize < 0x10000000000ull)))
- {
- D3D12MA_ASSERT(0 && "Invalid arguments passed to CreateAllocator.");
- return E_INVALIDARG;
- }
-
- D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
-
- ALLOCATION_CALLBACKS allocationCallbacks;
- SetupAllocationCallbacks(allocationCallbacks, pDesc->pAllocationCallbacks);
-
- *ppAllocator = D3D12MA_NEW(allocationCallbacks, Allocator)(allocationCallbacks, *pDesc);
- HRESULT hr = (*ppAllocator)->m_Pimpl->Init(*pDesc);
- if(FAILED(hr))
- {
- D3D12MA_DELETE(allocationCallbacks, *ppAllocator);
- *ppAllocator = NULL;
- }
- return hr;
+ // Copy is needed because otherwise we would call destructor and invalidate the structure with callbacks before using it to free memory.
+ const ALLOCATION_CALLBACKS allocationCallbacksCopy = m_Pimpl->m_AllocationCallbacks;
+ D3D12MA_DELETE(allocationCallbacksCopy, this);
}
-HRESULT CreateVirtualBlock(const VIRTUAL_BLOCK_DESC* pDesc, VirtualBlock** ppVirtualBlock)
+VirtualBlock::VirtualBlock(const ALLOCATION_CALLBACKS& allocationCallbacks, const VIRTUAL_BLOCK_DESC& desc)
+ : m_Pimpl(D3D12MA_NEW(allocationCallbacks, VirtualBlockPimpl)(allocationCallbacks, desc)) {}
+
+VirtualBlock::~VirtualBlock()
{
- if(!pDesc || !ppVirtualBlock)
- {
- D3D12MA_ASSERT(0 && "Invalid arguments passed to CreateVirtualBlock.");
- return E_INVALIDARG;
- }
+ // THIS IS AN IMPORTANT ASSERT!
+ // Hitting it means you have some memory leak - unreleased allocations in this virtual block.
+ D3D12MA_ASSERT(m_Pimpl->m_Metadata->IsEmpty() && "Some allocations were not freed before destruction of this virtual block!");
- D3D12MA_DEBUG_GLOBAL_MUTEX_LOCK
-
- ALLOCATION_CALLBACKS allocationCallbacks;
- SetupAllocationCallbacks(allocationCallbacks, pDesc->pAllocationCallbacks);
-
- *ppVirtualBlock = D3D12MA_NEW(allocationCallbacks, VirtualBlock)(allocationCallbacks, *pDesc);
- return S_OK;
+ D3D12MA_DELETE(m_Pimpl->m_AllocationCallbacks, m_Pimpl);
}
-
+#endif // _D3D12MA_VIRTUAL_BLOCK_FUNCTIONS
+#endif // _D3D12MA_PUBLIC_FUNCTIONS
} // namespace D3D12MA