New JSON dump format
Unified across VMA and D3D12MA. Updated Python script for visualization - now called GpuMemDumpVis.py. Code by @medranSolus
@ -41,7 +41,7 @@ Additional features:
|
|||||||
- Statistics: Obtain brief or detailed statistics about the amount of memory used, unused, number of allocated heaps, number of allocations etc. - globally and per memory heap type. Current memory usage and budget as reported by the system can also be queried.
|
- Statistics: Obtain brief or detailed statistics about the amount of memory used, unused, number of allocated heaps, number of allocations etc. - globally and per memory heap type. Current memory usage and budget as reported by the system can also be queried.
|
||||||
- Debug annotations: Associate custom `void* pPrivateData` and debug `LPCWSTR pName` with each allocation.
|
- Debug annotations: Associate custom `void* pPrivateData` and debug `LPCWSTR pName` with each allocation.
|
||||||
- JSON dump: Obtain a string in JSON format with detailed map of internal state, including list of allocations, their string names, and gaps between them.
|
- JSON dump: Obtain a string in JSON format with detailed map of internal state, including list of allocations, their string names, and gaps between them.
|
||||||
- Convert this JSON dump into a picture to visualize your memory using attached Python script.
|
- Convert this JSON dump into a picture to visualize your memory. See [tools/GpuMemDumpVis](tools/GpuMemDumpVis/README.md).
|
||||||
- Virtual allocator - an API that exposes the core allocation algorithm to be used without allocating real GPU memory, to allocate your own stuff, e.g. sub-allocate pieces of one large buffer.
|
- Virtual allocator - an API that exposes the core allocation algorithm to be used without allocating real GPU memory, to allocate your own stuff, e.g. sub-allocate pieces of one large buffer.
|
||||||
|
|
||||||
# Prerequisites
|
# Prerequisites
|
||||||
|
@ -237,7 +237,6 @@ enum ALLOCATION_FLAGS
|
|||||||
*/
|
*/
|
||||||
ALLOCATION_FLAG_UPPER_ADDRESS = 0x8,
|
ALLOCATION_FLAG_UPPER_ADDRESS = 0x8,
|
||||||
|
|
||||||
|
|
||||||
/** Set this flag if the allocated memory will have aliasing resources.
|
/** Set this flag if the allocated memory will have aliasing resources.
|
||||||
|
|
||||||
Use this when calling D3D12MA::Allocator::CreateResource() and similar to
|
Use this when calling D3D12MA::Allocator::CreateResource() and similar to
|
||||||
@ -570,7 +569,6 @@ private:
|
|||||||
UINT64 m_Size;
|
UINT64 m_Size;
|
||||||
UINT64 m_Alignment;
|
UINT64 m_Alignment;
|
||||||
ID3D12Resource* m_Resource;
|
ID3D12Resource* m_Resource;
|
||||||
UINT m_CreationFrameIndex;
|
|
||||||
void* m_pPrivateData;
|
void* m_pPrivateData;
|
||||||
wchar_t* m_Name;
|
wchar_t* m_Name;
|
||||||
|
|
||||||
@ -1246,8 +1244,9 @@ public:
|
|||||||
*/
|
*/
|
||||||
void CalculateStatistics(TotalStatistics* pStats);
|
void CalculateStatistics(TotalStatistics* pStats);
|
||||||
|
|
||||||
/// Builds and returns statistics as a string in JSON format.
|
/** \brief Builds and returns statistics as a string in JSON format.
|
||||||
/** @param[out] ppStatsString Must be freed using Allocator::FreeStatsString.
|
*
|
||||||
|
@param[out] ppStatsString Must be freed using Allocator::FreeStatsString.
|
||||||
@param DetailedMap `TRUE` to include full list of allocations (can make the string quite long), `FALSE` to only return statistics.
|
@param DetailedMap `TRUE` to include full list of allocations (can make the string quite long), `FALSE` to only return statistics.
|
||||||
*/
|
*/
|
||||||
void BuildStatsString(WCHAR** ppStatsString, BOOL DetailedMap) const;
|
void BuildStatsString(WCHAR** ppStatsString, BOOL DetailedMap) const;
|
||||||
|
@ -1511,61 +1511,61 @@ void JsonWriter::AddAllocationToObject(const Allocation& alloc)
|
|||||||
break;
|
break;
|
||||||
default: D3D12MA_ASSERT(0); break;
|
default: D3D12MA_ASSERT(0); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteString(L"Size");
|
WriteString(L"Size");
|
||||||
WriteNumber(alloc.GetSize());
|
WriteNumber(alloc.GetSize());
|
||||||
|
WriteString(L"Usage");
|
||||||
|
WriteNumber((UINT)alloc.m_PackedData.GetResourceFlags());
|
||||||
|
|
||||||
|
void* privateData = alloc.GetPrivateData();
|
||||||
|
if (privateData)
|
||||||
|
{
|
||||||
|
WriteString(L"CustomData");
|
||||||
|
WriteNumber((uintptr_t)privateData);
|
||||||
|
}
|
||||||
|
|
||||||
LPCWSTR name = alloc.GetName();
|
LPCWSTR name = alloc.GetName();
|
||||||
if (name != NULL)
|
if (name != NULL)
|
||||||
{
|
{
|
||||||
WriteString(L"Name");
|
WriteString(L"Name");
|
||||||
WriteString(name);
|
WriteString(name);
|
||||||
}
|
}
|
||||||
if (alloc.m_PackedData.GetResourceFlags())
|
|
||||||
{
|
|
||||||
WriteString(L"Flags");
|
|
||||||
WriteNumber((UINT)alloc.m_PackedData.GetResourceFlags());
|
|
||||||
}
|
|
||||||
if (alloc.m_PackedData.GetTextureLayout())
|
if (alloc.m_PackedData.GetTextureLayout())
|
||||||
{
|
{
|
||||||
WriteString(L"Layout");
|
WriteString(L"Layout");
|
||||||
WriteNumber((UINT)alloc.m_PackedData.GetTextureLayout());
|
WriteNumber((UINT)alloc.m_PackedData.GetTextureLayout());
|
||||||
}
|
}
|
||||||
if (alloc.m_CreationFrameIndex)
|
|
||||||
{
|
|
||||||
WriteString(L"CreationFrameIndex");
|
|
||||||
WriteNumber(alloc.m_CreationFrameIndex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void JsonWriter::AddDetailedStatisticsInfoObject(const DetailedStatistics& stats)
|
void JsonWriter::AddDetailedStatisticsInfoObject(const DetailedStatistics& stats)
|
||||||
{
|
{
|
||||||
BeginObject();
|
BeginObject();
|
||||||
|
|
||||||
WriteString(L"BlockCount");
|
WriteString(L"BlockCount");
|
||||||
WriteNumber(stats.Stats.BlockCount);
|
WriteNumber(stats.Stats.BlockCount);
|
||||||
WriteString(L"AllocationCount");
|
|
||||||
WriteNumber(stats.Stats.AllocationCount);
|
|
||||||
WriteString(L"UnusedRangeCount");
|
|
||||||
WriteNumber(stats.UnusedRangeCount);
|
|
||||||
WriteString(L"BlockBytes");
|
WriteString(L"BlockBytes");
|
||||||
WriteNumber(stats.Stats.BlockBytes);
|
WriteNumber(stats.Stats.BlockBytes);
|
||||||
|
WriteString(L"AllocationCount");
|
||||||
|
WriteNumber(stats.Stats.AllocationCount);
|
||||||
WriteString(L"AllocationBytes");
|
WriteString(L"AllocationBytes");
|
||||||
WriteNumber(stats.Stats.AllocationBytes);
|
WriteNumber(stats.Stats.AllocationBytes);
|
||||||
|
WriteString(L"UnusedRangeCount");
|
||||||
|
WriteNumber(stats.UnusedRangeCount);
|
||||||
|
|
||||||
WriteString(L"AllocationSize");
|
if (stats.Stats.AllocationCount > 1)
|
||||||
BeginObject(true);
|
{
|
||||||
WriteString(L"Min");
|
WriteString(L"AllocationSizeMin");
|
||||||
WriteNumber(stats.AllocationSizeMin);
|
WriteNumber(stats.AllocationSizeMin);
|
||||||
WriteString(L"Max");
|
WriteString(L"AllocationSizeMax");
|
||||||
WriteNumber(stats.AllocationSizeMax);
|
WriteNumber(stats.AllocationSizeMax);
|
||||||
EndObject();
|
}
|
||||||
|
if (stats.UnusedRangeCount > 1)
|
||||||
WriteString(L"UnusedRangeSize");
|
{
|
||||||
BeginObject(true);
|
WriteString(L"UnusedRangeSizeMin");
|
||||||
WriteString(L"Min");
|
WriteNumber(stats.UnusedRangeSizeMin);
|
||||||
WriteNumber(stats.UnusedRangeSizeMin);
|
WriteString(L"UnusedRangeSizeMax");
|
||||||
WriteString(L"Max");
|
WriteNumber(stats.UnusedRangeSizeMax);
|
||||||
WriteNumber(stats.UnusedRangeSizeMax);
|
}
|
||||||
EndObject();
|
|
||||||
|
|
||||||
EndObject();
|
EndObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2965,8 +2965,6 @@ BlockMetadata::BlockMetadata(const ALLOCATION_CALLBACKS* allocationCallbacks, bo
|
|||||||
void BlockMetadata::PrintDetailedMap_Begin(JsonWriter& json,
|
void BlockMetadata::PrintDetailedMap_Begin(JsonWriter& json,
|
||||||
UINT64 unusedBytes, size_t allocationCount, size_t unusedRangeCount) const
|
UINT64 unusedBytes, size_t allocationCount, size_t unusedRangeCount) const
|
||||||
{
|
{
|
||||||
json.BeginObject();
|
|
||||||
|
|
||||||
json.WriteString(L"TotalBytes");
|
json.WriteString(L"TotalBytes");
|
||||||
json.WriteNumber(GetSize());
|
json.WriteNumber(GetSize());
|
||||||
|
|
||||||
@ -2993,13 +2991,11 @@ void BlockMetadata::PrintDetailedMap_Allocation(JsonWriter& json,
|
|||||||
|
|
||||||
if (IsVirtual())
|
if (IsVirtual())
|
||||||
{
|
{
|
||||||
json.WriteString(L"Type");
|
|
||||||
json.WriteString(L"ALLOCATION");
|
|
||||||
json.WriteString(L"Size");
|
json.WriteString(L"Size");
|
||||||
json.WriteNumber(size);
|
json.WriteNumber(size);
|
||||||
if (privateData)
|
if (privateData)
|
||||||
{
|
{
|
||||||
json.WriteString(L"PrivateData");
|
json.WriteString(L"CustomData");
|
||||||
json.WriteNumber((uintptr_t)privateData);
|
json.WriteNumber((uintptr_t)privateData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3032,7 +3028,6 @@ void BlockMetadata::PrintDetailedMap_UnusedRange(JsonWriter& json,
|
|||||||
void BlockMetadata::PrintDetailedMap_End(JsonWriter& json) const
|
void BlockMetadata::PrintDetailedMap_End(JsonWriter& json) const
|
||||||
{
|
{
|
||||||
json.EndArray();
|
json.EndArray();
|
||||||
json.EndObject();
|
|
||||||
}
|
}
|
||||||
#endif // _D3D12MA_BLOCK_METADATA_FUNCTIONS
|
#endif // _D3D12MA_BLOCK_METADATA_FUNCTIONS
|
||||||
#endif // _D3D12MA_BLOCK_METADATA
|
#endif // _D3D12MA_BLOCK_METADATA
|
||||||
@ -5942,6 +5937,7 @@ public:
|
|||||||
~BlockVector();
|
~BlockVector();
|
||||||
|
|
||||||
const D3D12_HEAP_PROPERTIES& GetHeapProperties() const { return m_HeapProps; }
|
const D3D12_HEAP_PROPERTIES& GetHeapProperties() const { return m_HeapProps; }
|
||||||
|
D3D12_HEAP_FLAGS GetHeapFlags() const { return m_HeapFlags; }
|
||||||
UINT64 GetPreferredBlockSize() const { return m_PreferredBlockSize; }
|
UINT64 GetPreferredBlockSize() const { return m_PreferredBlockSize; }
|
||||||
UINT32 GetAlgorithm() const { return m_Algorithm; }
|
UINT32 GetAlgorithm() const { return m_Algorithm; }
|
||||||
// To be used only while the m_Mutex is locked. Used during defragmentation.
|
// To be used only while the m_Mutex is locked. Used during defragmentation.
|
||||||
@ -6409,13 +6405,13 @@ public:
|
|||||||
void FreeHeapMemory(Allocation* allocation);
|
void FreeHeapMemory(Allocation* allocation);
|
||||||
|
|
||||||
void SetCurrentFrameIndex(UINT frameIndex);
|
void SetCurrentFrameIndex(UINT frameIndex);
|
||||||
|
// For more deailed stats use outCutomHeaps to access statistics divided into L0 and L1 group
|
||||||
void CalculateStatistics(TotalStatistics& outStats);
|
void CalculateStatistics(TotalStatistics& outStats, DetailedStatistics outCutomHeaps[2] = NULL);
|
||||||
|
|
||||||
void GetBudget(Budget* outLocalBudget, Budget* outNonLocalBudget);
|
void GetBudget(Budget* outLocalBudget, Budget* outNonLocalBudget);
|
||||||
void GetBudgetForHeapType(Budget& outBudget, D3D12_HEAP_TYPE heapType);
|
void GetBudgetForHeapType(Budget& outBudget, D3D12_HEAP_TYPE heapType);
|
||||||
|
|
||||||
void BuildStatsString(WCHAR** ppStatsString, BOOL DetailedMap);
|
void BuildStatsString(WCHAR** ppStatsString, BOOL detailedMap);
|
||||||
void FreeStatsString(WCHAR* pStatsString);
|
void FreeStatsString(WCHAR* pStatsString);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -6945,7 +6941,7 @@ void AllocatorPimpl::SetCurrentFrameIndex(UINT frameIndex)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void AllocatorPimpl::CalculateStatistics(TotalStatistics& outStats)
|
void AllocatorPimpl::CalculateStatistics(TotalStatistics& outStats, DetailedStatistics outCutomHeaps[2])
|
||||||
{
|
{
|
||||||
// Init stats
|
// Init stats
|
||||||
for (size_t i = 0; i < HEAP_TYPE_COUNT; i++)
|
for (size_t i = 0; i < HEAP_TYPE_COUNT; i++)
|
||||||
@ -6953,6 +6949,11 @@ void AllocatorPimpl::CalculateStatistics(TotalStatistics& outStats)
|
|||||||
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.MemorySegmentGroup[i]);
|
||||||
ClearDetailedStatistics(outStats.Total);
|
ClearDetailedStatistics(outStats.Total);
|
||||||
|
if (outCutomHeaps)
|
||||||
|
{
|
||||||
|
ClearDetailedStatistics(outCutomHeaps[0]);
|
||||||
|
ClearDetailedStatistics(outCutomHeaps[1]);
|
||||||
|
}
|
||||||
|
|
||||||
// Process default pools. 3 standard heap types only. Add them to outStats.HeapType[i].
|
// Process default pools. 3 standard heap types only. Add them to outStats.HeapType[i].
|
||||||
if (SupportsResourceHeapTier2())
|
if (SupportsResourceHeapTier2())
|
||||||
@ -7003,8 +7004,13 @@ void AllocatorPimpl::CalculateStatistics(TotalStatistics& outStats)
|
|||||||
pool->AddDetailedStatistics(tmpStats);
|
pool->AddDetailedStatistics(tmpStats);
|
||||||
AddDetailedStatistics(
|
AddDetailedStatistics(
|
||||||
outStats.HeapType[heapTypeIndex], tmpStats);
|
outStats.HeapType[heapTypeIndex], tmpStats);
|
||||||
|
|
||||||
|
UINT memorySegment = HeapPropertiesToMemorySegmentGroup(poolHeapProps);
|
||||||
AddDetailedStatistics(
|
AddDetailedStatistics(
|
||||||
outStats.MemorySegmentGroup[HeapPropertiesToMemorySegmentGroup(poolHeapProps)], tmpStats);
|
outStats.MemorySegmentGroup[memorySegment], tmpStats);
|
||||||
|
|
||||||
|
if (outCutomHeaps)
|
||||||
|
AddDetailedStatistics(outCutomHeaps[memorySegment], tmpStats);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7106,155 +7112,354 @@ void AllocatorPimpl::GetBudgetForHeapType(Budget& outBudget, D3D12_HEAP_TYPE hea
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AllocatorPimpl::BuildStatsString(WCHAR** ppStatsString, BOOL DetailedMap)
|
void AllocatorPimpl::BuildStatsString(WCHAR** ppStatsString, BOOL detailedMap)
|
||||||
{
|
{
|
||||||
StringBuilder sb(GetAllocs());
|
StringBuilder sb(GetAllocs());
|
||||||
{
|
{
|
||||||
JsonWriter json(GetAllocs(), sb);
|
|
||||||
|
|
||||||
Budget localBudget = {}, nonLocalBudget = {};
|
Budget localBudget = {}, nonLocalBudget = {};
|
||||||
GetBudget(&localBudget, &nonLocalBudget);
|
GetBudget(&localBudget, &nonLocalBudget);
|
||||||
|
|
||||||
TotalStatistics stats;
|
TotalStatistics stats;
|
||||||
CalculateStatistics(stats);
|
DetailedStatistics customHeaps[2];
|
||||||
|
CalculateStatistics(stats, customHeaps);
|
||||||
|
|
||||||
json.BeginObject();
|
JsonWriter json(GetAllocs(), sb);
|
||||||
|
|
||||||
json.WriteString(L"Total");
|
|
||||||
json.AddDetailedStatisticsInfoObject(stats.Total);
|
|
||||||
for (size_t heapType = 0; heapType < HEAP_TYPE_COUNT; ++heapType)
|
|
||||||
{
|
|
||||||
json.WriteString(HeapTypeNames[heapType]);
|
|
||||||
json.AddDetailedStatisticsInfoObject(stats.HeapType[heapType]);
|
|
||||||
}
|
|
||||||
|
|
||||||
json.WriteString(L"Budget");
|
|
||||||
json.BeginObject();
|
json.BeginObject();
|
||||||
{
|
{
|
||||||
json.WriteString(L"Local");
|
json.WriteString(L"General");
|
||||||
WriteBudgetToJson(json, localBudget);
|
|
||||||
json.WriteString(L"NonLocal");
|
|
||||||
WriteBudgetToJson(json, nonLocalBudget);
|
|
||||||
}
|
|
||||||
json.EndObject();
|
|
||||||
|
|
||||||
if (DetailedMap)
|
|
||||||
{
|
|
||||||
json.WriteString(L"DetailedMap");
|
|
||||||
json.BeginObject();
|
json.BeginObject();
|
||||||
|
{
|
||||||
|
json.WriteString(L"API");
|
||||||
|
json.WriteString(L"Direct3D 12");
|
||||||
|
|
||||||
|
json.WriteString(L"GPU");
|
||||||
|
json.WriteString(m_AdapterDesc.Description);
|
||||||
|
|
||||||
|
json.WriteString(L"DedicatedVideoMemory");
|
||||||
|
json.WriteNumber(m_AdapterDesc.DedicatedVideoMemory);
|
||||||
|
json.WriteString(L"DedicatedSystemMemory");
|
||||||
|
json.WriteNumber(m_AdapterDesc.DedicatedSystemMemory);
|
||||||
|
json.WriteString(L"SharedSystemMemory");
|
||||||
|
json.WriteNumber(m_AdapterDesc.SharedSystemMemory);
|
||||||
|
|
||||||
|
json.WriteString(L"ResourceHeapTier");
|
||||||
|
json.WriteNumber(static_cast<UINT>(m_D3D12Options.ResourceHeapTier));
|
||||||
|
|
||||||
|
json.WriteString(L"ResourceBindingTier");
|
||||||
|
json.WriteNumber(static_cast<UINT>(m_D3D12Options.ResourceBindingTier));
|
||||||
|
|
||||||
|
json.WriteString(L"TiledResourcesTier");
|
||||||
|
json.WriteNumber(static_cast<UINT>(m_D3D12Options.TiledResourcesTier));
|
||||||
|
|
||||||
|
json.WriteString(L"TileBasedRenderer");
|
||||||
|
json.WriteBool(m_D3D12Architecture.TileBasedRenderer);
|
||||||
|
|
||||||
|
json.WriteString(L"UMA");
|
||||||
|
json.WriteBool(m_D3D12Architecture.UMA);
|
||||||
|
json.WriteString(L"CacheCoherentUMA");
|
||||||
|
json.WriteBool(m_D3D12Architecture.CacheCoherentUMA);
|
||||||
|
}
|
||||||
|
json.EndObject();
|
||||||
|
}
|
||||||
|
{
|
||||||
|
json.WriteString(L"Total");
|
||||||
|
json.AddDetailedStatisticsInfoObject(stats.Total);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
json.WriteString(L"MemoryInfo");
|
||||||
|
json.BeginObject();
|
||||||
|
{
|
||||||
|
json.WriteString(L"L0");
|
||||||
|
json.BeginObject();
|
||||||
|
{
|
||||||
|
json.WriteString(L"Budget");
|
||||||
|
WriteBudgetToJson(json, IsUMA() ? localBudget : nonLocalBudget); // When UMA device only L0 present as local
|
||||||
|
|
||||||
|
json.WriteString(L"Stats");
|
||||||
|
json.AddDetailedStatisticsInfoObject(stats.MemorySegmentGroup[!IsUMA()]);
|
||||||
|
|
||||||
|
json.WriteString(L"MemoryPools");
|
||||||
|
json.BeginObject();
|
||||||
|
{
|
||||||
|
if (IsUMA())
|
||||||
|
{
|
||||||
|
json.WriteString(L"DEFAULT");
|
||||||
|
json.BeginObject();
|
||||||
|
{
|
||||||
|
json.WriteString(L"Flags");
|
||||||
|
json.BeginArray(true);
|
||||||
|
json.EndArray();
|
||||||
|
json.WriteString(L"Stats");
|
||||||
|
json.AddDetailedStatisticsInfoObject(stats.HeapType[0]);
|
||||||
|
}
|
||||||
|
json.EndObject();
|
||||||
|
}
|
||||||
|
json.WriteString(L"UPLOAD");
|
||||||
|
json.BeginObject();
|
||||||
|
{
|
||||||
|
json.WriteString(L"Flags");
|
||||||
|
json.BeginArray(true);
|
||||||
|
json.EndArray();
|
||||||
|
json.WriteString(L"Stats");
|
||||||
|
json.AddDetailedStatisticsInfoObject(stats.HeapType[1]);
|
||||||
|
}
|
||||||
|
json.EndObject();
|
||||||
|
|
||||||
|
json.WriteString(L"READBACK");
|
||||||
|
json.BeginObject();
|
||||||
|
{
|
||||||
|
json.WriteString(L"Flags");
|
||||||
|
json.BeginArray(true);
|
||||||
|
json.EndArray();
|
||||||
|
json.WriteString(L"Stats");
|
||||||
|
json.AddDetailedStatisticsInfoObject(stats.HeapType[2]);
|
||||||
|
}
|
||||||
|
json.EndObject();
|
||||||
|
|
||||||
|
json.WriteString(L"CUSTOM");
|
||||||
|
json.BeginObject();
|
||||||
|
{
|
||||||
|
json.WriteString(L"Flags");
|
||||||
|
json.BeginArray(true);
|
||||||
|
json.EndArray();
|
||||||
|
json.WriteString(L"Stats");
|
||||||
|
json.AddDetailedStatisticsInfoObject(customHeaps[!IsUMA()]);
|
||||||
|
}
|
||||||
|
json.EndObject();
|
||||||
|
}
|
||||||
|
json.EndObject();
|
||||||
|
}
|
||||||
|
json.EndObject();
|
||||||
|
if (!IsUMA())
|
||||||
|
{
|
||||||
|
json.WriteString(L"L1");
|
||||||
|
json.BeginObject();
|
||||||
|
{
|
||||||
|
json.WriteString(L"Flags");
|
||||||
|
json.BeginArray(true);
|
||||||
|
json.EndArray();
|
||||||
|
|
||||||
|
json.WriteString(L"Size");
|
||||||
|
json.WriteNumber(0U);
|
||||||
|
|
||||||
|
json.WriteString(L"Budget");
|
||||||
|
WriteBudgetToJson(json, localBudget);
|
||||||
|
|
||||||
|
json.WriteString(L"Stats");
|
||||||
|
json.AddDetailedStatisticsInfoObject(stats.MemorySegmentGroup[0]);
|
||||||
|
|
||||||
|
json.WriteString(L"MemoryPools");
|
||||||
|
json.BeginObject();
|
||||||
|
{
|
||||||
|
json.WriteString(L"DEFAULT");
|
||||||
|
json.BeginObject();
|
||||||
|
{
|
||||||
|
json.WriteString(L"Flags");
|
||||||
|
json.BeginArray(true);
|
||||||
|
json.EndArray();
|
||||||
|
json.WriteString(L"Stats");
|
||||||
|
json.AddDetailedStatisticsInfoObject(stats.HeapType[0]);
|
||||||
|
}
|
||||||
|
json.EndObject();
|
||||||
|
|
||||||
|
json.WriteString(L"CUSTOM");
|
||||||
|
json.BeginObject();
|
||||||
|
{
|
||||||
|
json.WriteString(L"Flags");
|
||||||
|
json.BeginArray(true);
|
||||||
|
json.EndArray();
|
||||||
|
json.WriteString(L"Stats");
|
||||||
|
json.AddDetailedStatisticsInfoObject(customHeaps[0]);
|
||||||
|
}
|
||||||
|
json.EndObject();
|
||||||
|
}
|
||||||
|
json.EndObject();
|
||||||
|
}
|
||||||
|
json.EndObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
json.EndObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (detailedMap)
|
||||||
|
{
|
||||||
|
const auto writeHeapInfo = [&](BlockVector* blockVector, CommittedAllocationList* committedAllocs, bool customHeap)
|
||||||
|
{
|
||||||
|
D3D12MA_ASSERT(blockVector);
|
||||||
|
|
||||||
|
D3D12_HEAP_FLAGS flags = blockVector->GetHeapFlags();
|
||||||
|
json.WriteString(L"Flags");
|
||||||
|
json.BeginArray(true);
|
||||||
|
{
|
||||||
|
if (flags & D3D12_HEAP_FLAG_SHARED)
|
||||||
|
json.WriteString(L"HEAP_FLAG_SHARED");
|
||||||
|
if (flags & D3D12_HEAP_FLAG_ALLOW_DISPLAY)
|
||||||
|
json.WriteString(L"HEAP_FLAG_ALLOW_DISPLAY");
|
||||||
|
if (flags & D3D12_HEAP_FLAG_SHARED_CROSS_ADAPTER)
|
||||||
|
json.WriteString(L"HEAP_FLAG_CROSS_ADAPTER");
|
||||||
|
if (flags & D3D12_HEAP_FLAG_HARDWARE_PROTECTED)
|
||||||
|
json.WriteString(L"HEAP_FLAG_HARDWARE_PROTECTED");
|
||||||
|
if (flags & D3D12_HEAP_FLAG_ALLOW_WRITE_WATCH)
|
||||||
|
json.WriteString(L"HEAP_FLAG_ALLOW_WRITE_WATCH");
|
||||||
|
if (flags & D3D12_HEAP_FLAG_ALLOW_SHADER_ATOMICS)
|
||||||
|
json.WriteString(L"HEAP_FLAG_ALLOW_SHADER_ATOMICS");
|
||||||
|
#ifdef __ID3D12Device8_INTERFACE_DEFINED__
|
||||||
|
if (flags & D3D12_HEAP_FLAG_CREATE_NOT_RESIDENT)
|
||||||
|
json.WriteString(L"HEAP_FLAG_CREATE_NOT_RESIDENT");
|
||||||
|
if (flags & D3D12_HEAP_FLAG_CREATE_NOT_ZEROED)
|
||||||
|
json.WriteString(L"HEAP_FLAG_CREATE_NOT_ZEROED");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (flags & D3D12_HEAP_FLAG_DENY_BUFFERS)
|
||||||
|
json.WriteString(L"HEAP_FLAG_DENY_BUFFERS");
|
||||||
|
if (flags & D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES)
|
||||||
|
json.WriteString(L"HEAP_FLAG_DENY_RT_DS_TEXTURES");
|
||||||
|
if (flags & D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES)
|
||||||
|
json.WriteString(L"HEAP_FLAG_DENY_NON_RT_DS_TEXTURES");
|
||||||
|
|
||||||
|
flags &= ~(D3D12_HEAP_FLAG_SHARED
|
||||||
|
| D3D12_HEAP_FLAG_DENY_BUFFERS
|
||||||
|
| D3D12_HEAP_FLAG_ALLOW_DISPLAY
|
||||||
|
| D3D12_HEAP_FLAG_SHARED_CROSS_ADAPTER
|
||||||
|
| D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES
|
||||||
|
| D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES
|
||||||
|
| D3D12_HEAP_FLAG_HARDWARE_PROTECTED
|
||||||
|
| D3D12_HEAP_FLAG_ALLOW_WRITE_WATCH
|
||||||
|
| D3D12_HEAP_FLAG_ALLOW_SHADER_ATOMICS);
|
||||||
|
#ifdef __ID3D12Device8_INTERFACE_DEFINED__
|
||||||
|
flags &= ~(D3D12_HEAP_FLAG_CREATE_NOT_RESIDENT
|
||||||
|
| D3D12_HEAP_FLAG_CREATE_NOT_ZEROED);
|
||||||
|
#endif
|
||||||
|
if (flags != 0)
|
||||||
|
json.WriteNumber((UINT)flags);
|
||||||
|
|
||||||
|
if (customHeap)
|
||||||
|
{
|
||||||
|
const D3D12_HEAP_PROPERTIES& properties = blockVector->GetHeapProperties();
|
||||||
|
switch (properties.MemoryPoolPreference)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
D3D12MA_ASSERT(0);
|
||||||
|
case D3D12_MEMORY_POOL_UNKNOWN:
|
||||||
|
json.WriteString(L"MEMORY_POOL_UNKNOWN");
|
||||||
|
break;
|
||||||
|
case D3D12_MEMORY_POOL_L0:
|
||||||
|
json.WriteString(L"MEMORY_POOL_L0");
|
||||||
|
break;
|
||||||
|
case D3D12_MEMORY_POOL_L1:
|
||||||
|
json.WriteString(L"MEMORY_POOL_L1");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (properties.CPUPageProperty)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
D3D12MA_ASSERT(0);
|
||||||
|
case D3D12_CPU_PAGE_PROPERTY_UNKNOWN:
|
||||||
|
json.WriteString(L"CPU_PAGE_PROPERTY_UNKNOWN");
|
||||||
|
break;
|
||||||
|
case D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE:
|
||||||
|
json.WriteString(L"CPU_PAGE_PROPERTY_NOT_AVAILABLE");
|
||||||
|
break;
|
||||||
|
case D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE:
|
||||||
|
json.WriteString(L"CPU_PAGE_PROPERTY_WRITE_COMBINE");
|
||||||
|
break;
|
||||||
|
case D3D12_CPU_PAGE_PROPERTY_WRITE_BACK:
|
||||||
|
json.WriteString(L"CPU_PAGE_PROPERTY_WRITE_BACK");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
json.EndArray();
|
||||||
|
|
||||||
|
json.WriteString(L"PreferredBlockSize");
|
||||||
|
json.WriteNumber(blockVector->GetPreferredBlockSize());
|
||||||
|
|
||||||
|
json.WriteString(L"Blocks");
|
||||||
|
blockVector->WriteBlockInfoToJson(json);
|
||||||
|
|
||||||
|
json.WriteString(L"DedicatedAllocations");
|
||||||
|
json.BeginArray();
|
||||||
|
if (committedAllocs)
|
||||||
|
committedAllocs->BuildStatsString(json);
|
||||||
|
json.EndArray();
|
||||||
|
};
|
||||||
|
|
||||||
json.WriteString(L"DefaultPools");
|
json.WriteString(L"DefaultPools");
|
||||||
json.BeginObject();
|
json.BeginObject();
|
||||||
|
|
||||||
if (SupportsResourceHeapTier2())
|
|
||||||
{
|
{
|
||||||
for (size_t heapType = 0; heapType < STANDARD_HEAP_TYPE_COUNT; ++heapType)
|
if (SupportsResourceHeapTier2())
|
||||||
{
|
{
|
||||||
json.WriteString(HeapTypeNames[heapType]);
|
for (uint8_t heapType = 0; heapType < STANDARD_HEAP_TYPE_COUNT; ++heapType)
|
||||||
json.BeginObject();
|
|
||||||
|
|
||||||
json.WriteString(L"Blocks");
|
|
||||||
|
|
||||||
BlockVector* blockVector = m_BlockVectors[heapType];
|
|
||||||
D3D12MA_ASSERT(blockVector);
|
|
||||||
blockVector->WriteBlockInfoToJson(json);
|
|
||||||
|
|
||||||
json.EndObject(); // heap name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (size_t heapType = 0; heapType < STANDARD_HEAP_TYPE_COUNT; ++heapType)
|
|
||||||
{
|
|
||||||
for (size_t heapSubType = 0; heapSubType < 3; ++heapSubType)
|
|
||||||
{
|
{
|
||||||
static const WCHAR* const heapSubTypeName[] = {
|
json.WriteString(HeapTypeNames[heapType]);
|
||||||
L" + buffer",
|
|
||||||
L" + texture",
|
|
||||||
L" + texture RT or DS",
|
|
||||||
};
|
|
||||||
json.BeginString();
|
|
||||||
json.ContinueString(HeapTypeNames[heapType]);
|
|
||||||
json.ContinueString(heapSubTypeName[heapSubType]);
|
|
||||||
json.EndString();
|
|
||||||
json.BeginObject();
|
json.BeginObject();
|
||||||
|
writeHeapInfo(m_BlockVectors[heapType], m_CommittedAllocations + heapType, false);
|
||||||
json.WriteString(L"Blocks");
|
json.EndObject();
|
||||||
|
|
||||||
BlockVector* blockVector = m_BlockVectors[heapType * 3 + heapSubType];
|
|
||||||
D3D12MA_ASSERT(blockVector);
|
|
||||||
blockVector->WriteBlockInfoToJson(json);
|
|
||||||
|
|
||||||
json.EndObject(); // heap name
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
|
|
||||||
json.EndObject(); // DefaultPools
|
|
||||||
|
|
||||||
json.WriteString(L"CommittedAllocations");
|
|
||||||
json.BeginObject();
|
|
||||||
|
|
||||||
for (size_t heapTypeIndex = 0; heapTypeIndex < STANDARD_HEAP_TYPE_COUNT; ++heapTypeIndex)
|
|
||||||
{
|
|
||||||
json.WriteString(HeapTypeNames[heapTypeIndex]);
|
|
||||||
json.BeginArray();
|
|
||||||
m_CommittedAllocations[heapTypeIndex].BuildStatsString(json);
|
|
||||||
json.EndArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
json.EndObject(); // CommittedAllocations
|
|
||||||
|
|
||||||
json.WriteString(L"Pools");
|
|
||||||
json.BeginObject();
|
|
||||||
|
|
||||||
for (size_t heapTypeIndex = 0; heapTypeIndex < HEAP_TYPE_COUNT; ++heapTypeIndex)
|
|
||||||
{
|
|
||||||
json.WriteString(HeapTypeNames[heapTypeIndex]);
|
|
||||||
json.BeginArray();
|
|
||||||
MutexLockRead mutex(m_PoolsMutex[heapTypeIndex], m_UseMutex);
|
|
||||||
size_t index = 0;
|
|
||||||
for (auto* item = m_Pools[heapTypeIndex].Front(); item != nullptr; item = PoolList::GetNext(item))
|
|
||||||
{
|
{
|
||||||
json.BeginObject();
|
for (uint8_t heapType = 0; heapType < STANDARD_HEAP_TYPE_COUNT; ++heapType)
|
||||||
json.WriteString(L"Name");
|
|
||||||
if (item->GetName() != nullptr)
|
|
||||||
{
|
{
|
||||||
json.WriteString(item->GetName());
|
for (uint8_t heapSubType = 0; heapSubType < 3; ++heapSubType)
|
||||||
|
{
|
||||||
|
static const WCHAR* const heapSubTypeName[] = {
|
||||||
|
L" - Buffers",
|
||||||
|
L" - Textures",
|
||||||
|
L" - Textures RT/DS",
|
||||||
|
};
|
||||||
|
json.BeginString(HeapTypeNames[heapType]);
|
||||||
|
json.EndString(heapSubTypeName[heapSubType]);
|
||||||
|
|
||||||
|
json.BeginObject();
|
||||||
|
writeHeapInfo(m_BlockVectors[heapType + heapSubType], m_CommittedAllocations + heapType, false);
|
||||||
|
json.EndObject();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
json.BeginString();
|
|
||||||
json.ContinueString(index);
|
|
||||||
json.EndString();
|
|
||||||
}
|
|
||||||
++index;
|
|
||||||
|
|
||||||
json.WriteString(L"Blocks");
|
|
||||||
item->GetBlockVector()->WriteBlockInfoToJson(json);
|
|
||||||
|
|
||||||
json.WriteString(L"CommittedAllocations");
|
|
||||||
json.BeginArray();
|
|
||||||
if (item->SupportsCommittedAllocations())
|
|
||||||
item->GetCommittedAllocationList()->BuildStatsString(json);
|
|
||||||
json.EndArray();
|
|
||||||
|
|
||||||
json.EndObject();
|
|
||||||
}
|
}
|
||||||
json.EndArray();
|
|
||||||
}
|
}
|
||||||
|
json.EndObject();
|
||||||
|
|
||||||
json.EndObject(); // Pools
|
json.WriteString(L"CustomPools");
|
||||||
|
json.BeginObject();
|
||||||
|
for (uint8_t heapTypeIndex = 0; heapTypeIndex < HEAP_TYPE_COUNT; ++heapTypeIndex)
|
||||||
|
{
|
||||||
|
MutexLockRead mutex(m_PoolsMutex[heapTypeIndex], m_UseMutex);
|
||||||
|
auto* item = m_Pools[heapTypeIndex].Front();
|
||||||
|
if (item != NULL)
|
||||||
|
{
|
||||||
|
size_t index = 0;
|
||||||
|
json.WriteString(HeapTypeNames[heapTypeIndex]);
|
||||||
|
json.BeginArray();
|
||||||
|
do
|
||||||
|
{
|
||||||
|
json.BeginObject();
|
||||||
|
json.WriteString(L"Name");
|
||||||
|
json.BeginString();
|
||||||
|
json.ContinueString(index++);
|
||||||
|
if (item->GetName())
|
||||||
|
{
|
||||||
|
json.WriteString(L" - ");
|
||||||
|
json.WriteString(item->GetName());
|
||||||
|
}
|
||||||
|
json.EndString();
|
||||||
|
|
||||||
json.EndObject(); // DetailedMap
|
writeHeapInfo(item->GetBlockVector(), item->GetCommittedAllocationList(), heapTypeIndex == 3);
|
||||||
|
json.EndObject();
|
||||||
|
} while ((item = PoolList::GetNext(item)) != NULL);
|
||||||
|
json.EndArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
json.EndObject();
|
||||||
}
|
}
|
||||||
json.EndObject();
|
json.EndObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
const size_t length = sb.GetLength();
|
const size_t length = sb.GetLength();
|
||||||
WCHAR* result = AllocateArray<WCHAR>(GetAllocs(), length + 1);
|
WCHAR* result = AllocateArray<WCHAR>(GetAllocs(), length + 2);
|
||||||
memcpy(result, sb.GetData(), length * sizeof(WCHAR));
|
result[0] = 0xFEFF;
|
||||||
result[length] = L'\0';
|
memcpy(result + 1, sb.GetData(), length * sizeof(WCHAR));
|
||||||
|
result[length + 1] = L'\0';
|
||||||
*ppStatsString = result;
|
*ppStatsString = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7710,18 +7915,10 @@ void AllocatorPimpl::WriteBudgetToJson(JsonWriter& json, const Budget& budget)
|
|||||||
{
|
{
|
||||||
json.BeginObject();
|
json.BeginObject();
|
||||||
{
|
{
|
||||||
json.WriteString(L"BlockCount");
|
|
||||||
json.WriteNumber(budget.Stats.BlockCount);
|
|
||||||
json.WriteString(L"AllocationCount");
|
|
||||||
json.WriteNumber(budget.Stats.AllocationCount);
|
|
||||||
json.WriteString(L"BlockBytes");
|
|
||||||
json.WriteNumber(budget.Stats.BlockBytes);
|
|
||||||
json.WriteString(L"AllocationBytes");
|
|
||||||
json.WriteNumber(budget.Stats.AllocationBytes);
|
|
||||||
json.WriteString(L"UsageBytes");
|
|
||||||
json.WriteNumber(budget.UsageBytes);
|
|
||||||
json.WriteString(L"BudgetBytes");
|
json.WriteString(L"BudgetBytes");
|
||||||
json.WriteNumber(budget.BudgetBytes);
|
json.WriteNumber(budget.BudgetBytes);
|
||||||
|
json.WriteString(L"UsageBytes");
|
||||||
|
json.WriteNumber(budget.UsageBytes);
|
||||||
}
|
}
|
||||||
json.EndObject();
|
json.EndObject();
|
||||||
}
|
}
|
||||||
@ -8254,7 +8451,9 @@ void BlockVector::WriteBlockInfoToJson(JsonWriter& json)
|
|||||||
json.ContinueString(pBlock->GetId());
|
json.ContinueString(pBlock->GetId());
|
||||||
json.EndString();
|
json.EndString();
|
||||||
|
|
||||||
|
json.BeginObject();
|
||||||
pBlock->m_pMetadata->WriteAllocationInfoToJson(json);
|
pBlock->m_pMetadata->WriteAllocationInfoToJson(json);
|
||||||
|
json.EndObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
json.EndObject();
|
json.EndObject();
|
||||||
@ -9423,7 +9622,6 @@ Allocation::Allocation(AllocatorPimpl* allocator, UINT64 size, UINT64 alignment,
|
|||||||
m_Size{ size },
|
m_Size{ size },
|
||||||
m_Alignment{ alignment },
|
m_Alignment{ alignment },
|
||||||
m_Resource{ NULL },
|
m_Resource{ NULL },
|
||||||
m_CreationFrameIndex{ allocator->GetCurrentFrameIndex() },
|
|
||||||
m_Name{ NULL }
|
m_Name{ NULL }
|
||||||
{
|
{
|
||||||
D3D12MA_ASSERT(allocator);
|
D3D12MA_ASSERT(allocator);
|
||||||
|
213
src/Tests.cpp
@ -439,51 +439,194 @@ static void TestDebugMarginNotInVirtualAllocator(const TestContext& ctx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void TestFrameIndexAndJson(const TestContext& ctx)
|
static void TestJson(const TestContext& ctx)
|
||||||
{
|
{
|
||||||
const UINT64 bufSize = 32ull * 1024;
|
wprintf(L"Test JSON\n");
|
||||||
|
|
||||||
|
std::vector<ComPtr<D3D12MA::Pool>> pools;
|
||||||
|
std::vector<ComPtr<D3D12MA::Allocation>> allocs;
|
||||||
|
|
||||||
D3D12MA::ALLOCATION_DESC allocDesc = {};
|
D3D12MA::ALLOCATION_DESC allocDesc = {};
|
||||||
allocDesc.HeapType = D3D12_HEAP_TYPE_UPLOAD;
|
D3D12_RESOURCE_DESC resDesc = {};
|
||||||
allocDesc.Flags = D3D12MA::ALLOCATION_FLAG_COMMITTED;
|
resDesc.Alignment = 0;
|
||||||
|
resDesc.MipLevels = 1;
|
||||||
|
resDesc.SampleDesc.Count = 1;
|
||||||
|
resDesc.SampleDesc.Quality = 0;
|
||||||
|
|
||||||
D3D12_RESOURCE_DESC resourceDesc;
|
D3D12_RESOURCE_ALLOCATION_INFO allocInfo = {};
|
||||||
FillResourceDescForBuffer(resourceDesc, bufSize);
|
allocInfo.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
|
||||||
|
allocInfo.SizeInBytes = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
|
||||||
|
|
||||||
const UINT BEGIN_INDEX = 10;
|
// Select if using custom pool or default
|
||||||
const UINT END_INDEX = 20;
|
for (UINT8 poolType = 0; poolType < 2; ++poolType)
|
||||||
for (UINT frameIndex = BEGIN_INDEX; frameIndex < END_INDEX; ++frameIndex)
|
|
||||||
{
|
{
|
||||||
ctx.allocator->SetCurrentFrameIndex(frameIndex);
|
// Select different heaps
|
||||||
D3D12MA::Allocation* alloc = nullptr;
|
for (UINT8 heapType = 0; heapType < 5; ++heapType)
|
||||||
CHECK_HR(ctx.allocator->CreateResource(
|
|
||||||
&allocDesc,
|
|
||||||
&resourceDesc,
|
|
||||||
D3D12_RESOURCE_STATE_GENERIC_READ,
|
|
||||||
NULL,
|
|
||||||
&alloc,
|
|
||||||
IID_NULL,
|
|
||||||
NULL));
|
|
||||||
|
|
||||||
WCHAR* statsString;
|
|
||||||
ctx.allocator->BuildStatsString(&statsString, TRUE);
|
|
||||||
const UINT BUFFER_SIZE = 1024;
|
|
||||||
WCHAR buffer[BUFFER_SIZE];
|
|
||||||
for (UINT testIndex = BEGIN_INDEX; testIndex < END_INDEX; ++testIndex)
|
|
||||||
{
|
{
|
||||||
swprintf(buffer, BUFFER_SIZE, L"\"CreationFrameIndex\": %u", testIndex);
|
D3D12_RESOURCE_STATES state;
|
||||||
if (testIndex == frameIndex)
|
D3D12_CPU_PAGE_PROPERTY cpuPageType = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||||
|
D3D12_MEMORY_POOL memoryPool = D3D12_MEMORY_POOL_UNKNOWN;
|
||||||
|
switch (heapType)
|
||||||
{
|
{
|
||||||
CHECK_BOOL(wcsstr(statsString, buffer) != NULL);
|
case 0:
|
||||||
|
allocDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT;
|
||||||
|
state = D3D12_RESOURCE_STATE_COMMON;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
allocDesc.HeapType = D3D12_HEAP_TYPE_UPLOAD;
|
||||||
|
state = D3D12_RESOURCE_STATE_GENERIC_READ;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
allocDesc.HeapType = D3D12_HEAP_TYPE_READBACK;
|
||||||
|
state = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
allocDesc.HeapType = D3D12_HEAP_TYPE_CUSTOM;
|
||||||
|
state = D3D12_RESOURCE_STATE_COMMON;
|
||||||
|
cpuPageType = D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE;
|
||||||
|
memoryPool = ctx.allocator->IsUMA() ? D3D12_MEMORY_POOL_L0 : D3D12_MEMORY_POOL_L1;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
allocDesc.HeapType = D3D12_HEAP_TYPE_CUSTOM;
|
||||||
|
state = D3D12_RESOURCE_STATE_GENERIC_READ;
|
||||||
|
cpuPageType = D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE;
|
||||||
|
memoryPool = D3D12_MEMORY_POOL_L0;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else
|
// Skip custom heaps for default pools
|
||||||
|
if (poolType == 0 && heapType > 2)
|
||||||
|
continue;
|
||||||
|
const bool texturesPossible = heapType == 0 || heapType == 3;
|
||||||
|
|
||||||
|
// Select different resource region types
|
||||||
|
for (UINT8 resType = 0; resType < 3; ++resType)
|
||||||
{
|
{
|
||||||
CHECK_BOOL(wcsstr(statsString, buffer) == NULL);
|
allocDesc.ExtraHeapFlags = D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS;
|
||||||
|
D3D12_RESOURCE_FLAGS resFlags = D3D12_RESOURCE_FLAG_NONE;
|
||||||
|
if (texturesPossible)
|
||||||
|
{
|
||||||
|
switch (resType)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
allocDesc.ExtraHeapFlags = D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
allocDesc.ExtraHeapFlags = D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES;
|
||||||
|
resFlags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (poolType)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
allocDesc.CustomPool = nullptr;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
ComPtr<D3D12MA::Pool> pool;
|
||||||
|
D3D12MA::POOL_DESC poolDesc = {};
|
||||||
|
poolDesc.HeapFlags = allocDesc.ExtraHeapFlags;
|
||||||
|
poolDesc.HeapProperties.Type = allocDesc.HeapType;
|
||||||
|
poolDesc.HeapProperties.CPUPageProperty = cpuPageType;
|
||||||
|
poolDesc.HeapProperties.MemoryPoolPreference = memoryPool;
|
||||||
|
CHECK_HR(ctx.allocator->CreatePool(&poolDesc, &pool));
|
||||||
|
|
||||||
|
allocDesc.CustomPool = pool.Get();
|
||||||
|
pools.emplace_back(std::move(pool));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select different allocation flags
|
||||||
|
for (UINT8 allocFlag = 0; allocFlag < 2; ++allocFlag)
|
||||||
|
{
|
||||||
|
switch (allocFlag)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
allocDesc.Flags = D3D12MA::ALLOCATION_FLAG_NONE;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
allocDesc.Flags = D3D12MA::ALLOCATION_FLAG_COMMITTED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select different alloc types (block, buffer, texture, etc.)
|
||||||
|
for (UINT8 allocType = 0; allocType < 5; ++allocType)
|
||||||
|
{
|
||||||
|
// Select different data stored in the allocation
|
||||||
|
for (UINT8 data = 0; data < 4; ++data)
|
||||||
|
{
|
||||||
|
ComPtr<D3D12MA::Allocation> alloc;
|
||||||
|
|
||||||
|
if (texturesPossible && resType != 0)
|
||||||
|
{
|
||||||
|
resDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
|
||||||
|
resDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
switch (allocType % 3)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
resDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE1D;
|
||||||
|
resDesc.Width = 512;
|
||||||
|
resDesc.Height = 1;
|
||||||
|
resDesc.DepthOrArraySize = 1;
|
||||||
|
resDesc.Flags = resFlags;
|
||||||
|
CHECK_HR(ctx.allocator->CreateResource(&allocDesc, &resDesc, state, nullptr, &alloc, IID_NULL, nullptr));
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
resDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
||||||
|
resDesc.Width = 1024;
|
||||||
|
resDesc.Height = 512;
|
||||||
|
resDesc.DepthOrArraySize = 1;
|
||||||
|
resDesc.Flags = resFlags;
|
||||||
|
CHECK_HR(ctx.allocator->CreateResource(&allocDesc, &resDesc, state, nullptr, &alloc, IID_NULL, nullptr));
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
resDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE3D;
|
||||||
|
resDesc.Width = 512;
|
||||||
|
resDesc.Height = 256;
|
||||||
|
resDesc.DepthOrArraySize = 128;
|
||||||
|
resDesc.Flags = resFlags;
|
||||||
|
CHECK_HR(ctx.allocator->CreateResource(&allocDesc, &resDesc, state, nullptr, &alloc, IID_NULL, nullptr));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (allocType % 2)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
CHECK_HR(ctx.allocator->AllocateMemory(&allocDesc, &allocInfo, &alloc));
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
FillResourceDescForBuffer(resDesc, 1024);
|
||||||
|
CHECK_HR(ctx.allocator->CreateResource(&allocDesc, &resDesc, state, nullptr, &alloc, IID_NULL, nullptr));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (data)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
alloc->SetPrivateData((void*)16112007);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
alloc->SetName(L"SHEPURD");
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
alloc->SetPrivateData((void*)26012010);
|
||||||
|
alloc->SetName(L"JOKER");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
allocs.emplace_back(std::move(alloc));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctx.allocator->FreeStatsString(statsString);
|
|
||||||
alloc->Release();
|
|
||||||
}
|
}
|
||||||
|
SaveStatsStringToFile(ctx, L"JSON_D3D12.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void TestCommittedResourcesAndJson(const TestContext& ctx)
|
static void TestCommittedResourcesAndJson(const TestContext& ctx)
|
||||||
@ -2689,8 +2832,8 @@ static void TestVirtualBlocks(const TestContext& ctx)
|
|||||||
block->BuildStatsString(&json);
|
block->BuildStatsString(&json);
|
||||||
{
|
{
|
||||||
std::wstring str(json);
|
std::wstring str(json);
|
||||||
CHECK_BOOL(str.find(L"\"PrivateData\": 1") != std::wstring::npos);
|
CHECK_BOOL(str.find(L"\"CustomData\": 1") != std::wstring::npos);
|
||||||
CHECK_BOOL(str.find(L"\"PrivateData\": 2") != std::wstring::npos);
|
CHECK_BOOL(str.find(L"\"CustomData\": 2") != std::wstring::npos);
|
||||||
}
|
}
|
||||||
block->FreeStatsString(json);
|
block->FreeStatsString(json);
|
||||||
|
|
||||||
@ -3839,7 +3982,7 @@ static void TestGroupBasics(const TestContext& ctx)
|
|||||||
TestDebugMargin(ctx);
|
TestDebugMargin(ctx);
|
||||||
TestDebugMarginNotInVirtualAllocator(ctx);
|
TestDebugMarginNotInVirtualAllocator(ctx);
|
||||||
#else
|
#else
|
||||||
TestFrameIndexAndJson(ctx);
|
TestJson(ctx);
|
||||||
TestCommittedResourcesAndJson(ctx);
|
TestCommittedResourcesAndJson(ctx);
|
||||||
TestCustomHeapFlags(ctx);
|
TestCustomHeapFlags(ctx);
|
||||||
TestPlacedResources(ctx);
|
TestPlacedResources(ctx);
|
||||||
|
@ -1,282 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright (c) 2019-2022 Advanced Micro Devices, Inc. All rights reserved.
|
|
||||||
#
|
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
# of this software and associated documentation files (the "Software"), to deal
|
|
||||||
# in the Software without restriction, including without limitation the rights
|
|
||||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
# copies of the Software, and to permit persons to whom the Software is
|
|
||||||
# furnished to do so, subject to the following conditions:
|
|
||||||
#
|
|
||||||
# The above copyright notice and this permission notice shall be included in
|
|
||||||
# all copies or substantial portions of the Software.
|
|
||||||
#
|
|
||||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
# THE SOFTWARE.
|
|
||||||
#
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import json
|
|
||||||
from PIL import Image, ImageDraw, ImageFont
|
|
||||||
|
|
||||||
|
|
||||||
PROGRAM_VERSION = 'D3D12MA Dump Visualization 1.0.0'
|
|
||||||
IMG_SIZE_X = 1200
|
|
||||||
IMG_MARGIN = 8
|
|
||||||
FONT_SIZE = 10
|
|
||||||
MAP_SIZE = 24
|
|
||||||
COLOR_TEXT_H1 = (0, 0, 0, 255)
|
|
||||||
COLOR_TEXT_H2 = (150, 150, 150, 255)
|
|
||||||
COLOR_OUTLINE = (155, 155, 155, 255)
|
|
||||||
COLOR_OUTLINE_HARD = (0, 0, 0, 255)
|
|
||||||
COLOR_GRID_LINE = (224, 224, 224, 255)
|
|
||||||
|
|
||||||
|
|
||||||
argParser = argparse.ArgumentParser(description='Visualization of D3D12 Memory Allocator JSON dump.')
|
|
||||||
argParser.add_argument('DumpFile', type=argparse.FileType(mode='r', encoding='utf_16_le'), help='Path to source JSON file with memory dump created by D3D12 Memory Allocator library')
|
|
||||||
argParser.add_argument('-v', '--version', action='version', version=PROGRAM_VERSION)
|
|
||||||
argParser.add_argument('-o', '--output', required=True, help='Path to destination image file (e.g. PNG)')
|
|
||||||
args = argParser.parse_args()
|
|
||||||
|
|
||||||
data = {}
|
|
||||||
|
|
||||||
|
|
||||||
def ProcessBlock(dstBlockList, iBlockId, objBlock, sAlgorithm):
|
|
||||||
iBlockSize = int(objBlock['TotalBytes'])
|
|
||||||
arrSuballocs = objBlock['Suballocations']
|
|
||||||
dstBlockObj = {'ID': iBlockId, 'Size':iBlockSize, 'Suballocations':[]}
|
|
||||||
dstBlockObj['Algorithm'] = sAlgorithm
|
|
||||||
for objSuballoc in arrSuballocs:
|
|
||||||
dstBlockObj['Suballocations'].append((objSuballoc['Type'], int(objSuballoc['Size']), int(objSuballoc.get('Flags', 0)), int(objSuballoc.get('Layout', 0))))
|
|
||||||
dstBlockList.append(dstBlockObj)
|
|
||||||
|
|
||||||
|
|
||||||
def GetDataForHeapType(sHeapType):
|
|
||||||
global data
|
|
||||||
if sHeapType in data:
|
|
||||||
return data[sHeapType]
|
|
||||||
else:
|
|
||||||
newHeapTypeData = {'CommittedAllocations':[], 'DefaultPoolBlocks':[], 'CustomPools':{}}
|
|
||||||
data[sHeapType] = newHeapTypeData
|
|
||||||
return newHeapTypeData
|
|
||||||
|
|
||||||
|
|
||||||
# Returns tuple:
|
|
||||||
# [0] image height : integer
|
|
||||||
# [1] pixels per byte : float
|
|
||||||
def CalcParams():
|
|
||||||
global data
|
|
||||||
iImgSizeY = IMG_MARGIN
|
|
||||||
iImgSizeY += FONT_SIZE + IMG_MARGIN # Grid lines legend - sizes
|
|
||||||
iMaxBlockSize = 0
|
|
||||||
for dictMemType in data.values():
|
|
||||||
iImgSizeY += IMG_MARGIN + FONT_SIZE
|
|
||||||
lDedicatedAllocations = dictMemType['CommittedAllocations']
|
|
||||||
iImgSizeY += len(lDedicatedAllocations) * (IMG_MARGIN * 2 + FONT_SIZE + MAP_SIZE)
|
|
||||||
for tDedicatedAlloc in lDedicatedAllocations:
|
|
||||||
iMaxBlockSize = max(iMaxBlockSize, tDedicatedAlloc[1])
|
|
||||||
lDefaultPoolBlocks = dictMemType['DefaultPoolBlocks']
|
|
||||||
iImgSizeY += len(lDefaultPoolBlocks) * (IMG_MARGIN * 2 + FONT_SIZE + MAP_SIZE)
|
|
||||||
for objBlock in lDefaultPoolBlocks:
|
|
||||||
iMaxBlockSize = max(iMaxBlockSize, objBlock['Size'])
|
|
||||||
for poolData in dictMemType['CustomPools'].values():
|
|
||||||
iImgSizeY += len(poolData) * (IMG_MARGIN * 2 + FONT_SIZE + MAP_SIZE)
|
|
||||||
for objBlock in poolData['Blocks']:
|
|
||||||
iMaxBlockSize = max(iMaxBlockSize, objBlock['Size'])
|
|
||||||
for tDedicatedAlloc in poolData['CommittedAllocations']:
|
|
||||||
iMaxBlockSize = max(iMaxBlockSize, tDedicatedAlloc[1])
|
|
||||||
fPixelsPerByte = (IMG_SIZE_X - IMG_MARGIN * 2) / float(iMaxBlockSize)
|
|
||||||
return iImgSizeY, fPixelsPerByte
|
|
||||||
|
|
||||||
|
|
||||||
def TypeToColor(sType, iFlags, iLayout):
|
|
||||||
if sType == 'FREE':
|
|
||||||
return 220, 220, 220, 255
|
|
||||||
elif sType == 'BUFFER':
|
|
||||||
return 255, 255, 0, 255 # Yellow
|
|
||||||
elif sType == 'TEXTURE2D' or sType == 'TEXTURE1D' or sType == 'TEXTURE3D':
|
|
||||||
if iLayout != 0: # D3D12_TEXTURE_LAYOUT_UNKNOWN
|
|
||||||
return 0, 255, 0, 255 # Green
|
|
||||||
else:
|
|
||||||
if (iFlags & 0x2) != 0: # D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL
|
|
||||||
return 246, 128, 255, 255 # Pink
|
|
||||||
elif (iFlags & 0x5) != 0: # D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS
|
|
||||||
return 179, 179, 255, 255 # Blue
|
|
||||||
elif (iFlags & 0x8) == 0: # Not having D3D12_RESOURCE_FLAG_DENY_SHARED_RESOURCE
|
|
||||||
return 0, 255, 255, 255 # Aqua
|
|
||||||
else:
|
|
||||||
return 183, 255, 255, 255 # Light aqua
|
|
||||||
else:
|
|
||||||
return 175, 175, 175, 255 # Gray
|
|
||||||
assert False
|
|
||||||
return 0, 0, 0, 255
|
|
||||||
|
|
||||||
|
|
||||||
def DrawCommittedAllocationBlock(draw, y, tAlloc):
|
|
||||||
global fPixelsPerByte
|
|
||||||
iSizeBytes = tAlloc[1]
|
|
||||||
iSizePixels = int(iSizeBytes * fPixelsPerByte)
|
|
||||||
draw.rectangle([IMG_MARGIN, y, IMG_MARGIN + iSizePixels, y + MAP_SIZE], fill=TypeToColor(tAlloc[0], tAlloc[2], tAlloc[3]), outline=COLOR_OUTLINE)
|
|
||||||
|
|
||||||
|
|
||||||
def DrawBlock(draw, y, objBlock):
|
|
||||||
global fPixelsPerByte
|
|
||||||
iSizeBytes = objBlock['Size']
|
|
||||||
iSizePixels = int(iSizeBytes * fPixelsPerByte)
|
|
||||||
draw.rectangle([IMG_MARGIN, y, IMG_MARGIN + iSizePixels, y + MAP_SIZE], fill=TypeToColor('FREE', 0, 0), outline=None)
|
|
||||||
iByte = 0
|
|
||||||
iX = 0
|
|
||||||
iLastHardLineX = -1
|
|
||||||
for tSuballoc in objBlock['Suballocations']:
|
|
||||||
sType = tSuballoc[0]
|
|
||||||
iByteEnd = iByte + tSuballoc[1]
|
|
||||||
iXEnd = int(iByteEnd * fPixelsPerByte)
|
|
||||||
if sType != 'FREE':
|
|
||||||
if iXEnd > iX + 1:
|
|
||||||
iFlags = tSuballoc[2]
|
|
||||||
iLayout = tSuballoc[3]
|
|
||||||
draw.rectangle([IMG_MARGIN + iX, y, IMG_MARGIN + iXEnd, y + MAP_SIZE], fill=TypeToColor(sType, iFlags, iLayout), outline=COLOR_OUTLINE)
|
|
||||||
# Hard line was been overwritten by rectangle outline: redraw it.
|
|
||||||
if iLastHardLineX == iX:
|
|
||||||
draw.line([IMG_MARGIN + iX, y, IMG_MARGIN + iX, y + MAP_SIZE], fill=COLOR_OUTLINE_HARD)
|
|
||||||
else:
|
|
||||||
draw.line([IMG_MARGIN + iX, y, IMG_MARGIN + iX, y + MAP_SIZE], fill=COLOR_OUTLINE_HARD)
|
|
||||||
iLastHardLineX = iX
|
|
||||||
iByte = iByteEnd
|
|
||||||
iX = iXEnd
|
|
||||||
|
|
||||||
|
|
||||||
def BytesToStr(iBytes):
|
|
||||||
if iBytes < 1024:
|
|
||||||
return "%d B" % iBytes
|
|
||||||
iBytes /= 1024
|
|
||||||
if iBytes < 1024:
|
|
||||||
return "%d KB" % iBytes
|
|
||||||
iBytes /= 1024
|
|
||||||
if iBytes < 1024:
|
|
||||||
return "%d MB" % iBytes
|
|
||||||
iBytes /= 1024
|
|
||||||
return "%d GB" % iBytes
|
|
||||||
|
|
||||||
|
|
||||||
jsonSrc = json.load(args.DumpFile)
|
|
||||||
objDetailedMap = jsonSrc['DetailedMap']
|
|
||||||
if 'CommittedAllocations' in objDetailedMap:
|
|
||||||
for tType in objDetailedMap['CommittedAllocations'].items():
|
|
||||||
sHeapType = tType[0]
|
|
||||||
typeData = GetDataForHeapType(sHeapType)
|
|
||||||
for objAlloc in tType[1]:
|
|
||||||
typeData['CommittedAllocations'].append((objAlloc['Type'], int(objAlloc['Size']), int(objAlloc.get('Flags', 0)), int(objAlloc.get('Layout', 0))))
|
|
||||||
if 'DefaultPools' in objDetailedMap:
|
|
||||||
for tType in objDetailedMap['DefaultPools'].items():
|
|
||||||
sHeapType = tType[0]
|
|
||||||
typeData = GetDataForHeapType(sHeapType)
|
|
||||||
for sBlockId, objBlock in tType[1]['Blocks'].items():
|
|
||||||
ProcessBlock(typeData['DefaultPoolBlocks'], int(sBlockId), objBlock, '')
|
|
||||||
if 'Pools' in objDetailedMap:
|
|
||||||
for tType in objDetailedMap['Pools'].items():
|
|
||||||
sHeapType = tType[0]
|
|
||||||
typeData = GetDataForHeapType(sHeapType)
|
|
||||||
for pool in tType[1]:
|
|
||||||
typeData['CustomPools'][pool['Name']] = {'Blocks':[], 'CommittedAllocations':[]}
|
|
||||||
for sBlockId, objBlock in pool['Blocks'].items():
|
|
||||||
ProcessBlock(typeData['CustomPools'][pool['Name']]['Blocks'], int(sBlockId), objBlock, '')
|
|
||||||
for objAlloc in pool['CommittedAllocations']:
|
|
||||||
typeData['CustomPools'][pool['Name']]['CommittedAllocations'].append((objAlloc['Type'], int(objAlloc['Size']), int(objAlloc.get('Flags', 0)), int(objAlloc.get('Layout', 0))))
|
|
||||||
|
|
||||||
iImgSizeY, fPixelsPerByte = CalcParams()
|
|
||||||
|
|
||||||
img = Image.new('RGB', (IMG_SIZE_X, iImgSizeY), 'white')
|
|
||||||
draw = ImageDraw.Draw(img)
|
|
||||||
|
|
||||||
try:
|
|
||||||
font = ImageFont.truetype('segoeuib.ttf')
|
|
||||||
except:
|
|
||||||
font = ImageFont.load_default()
|
|
||||||
|
|
||||||
y = IMG_MARGIN
|
|
||||||
|
|
||||||
# Draw grid lines
|
|
||||||
iBytesBetweenGridLines = 32
|
|
||||||
while iBytesBetweenGridLines * fPixelsPerByte < 64:
|
|
||||||
iBytesBetweenGridLines *= 2
|
|
||||||
iByte = 0
|
|
||||||
TEXT_MARGIN = 4
|
|
||||||
while True:
|
|
||||||
iX = int(iByte * fPixelsPerByte)
|
|
||||||
if iX > IMG_SIZE_X - 2 * IMG_MARGIN:
|
|
||||||
break
|
|
||||||
draw.line([iX + IMG_MARGIN, 0, iX + IMG_MARGIN, iImgSizeY], fill=COLOR_GRID_LINE)
|
|
||||||
if iByte == 0:
|
|
||||||
draw.text((iX + IMG_MARGIN + TEXT_MARGIN, y), "0", fill=COLOR_TEXT_H2, font=font)
|
|
||||||
else:
|
|
||||||
text = BytesToStr(iByte)
|
|
||||||
textSize = draw.textsize(text, font=font)
|
|
||||||
draw.text((iX + IMG_MARGIN - textSize[0] - TEXT_MARGIN, y), text, fill=COLOR_TEXT_H2, font=font)
|
|
||||||
iByte += iBytesBetweenGridLines
|
|
||||||
y += FONT_SIZE + IMG_MARGIN
|
|
||||||
|
|
||||||
# Draw main content
|
|
||||||
for sHeapType in data.keys():
|
|
||||||
dictMemType = data[sHeapType]
|
|
||||||
draw.text((IMG_MARGIN, y), sHeapType, fill=COLOR_TEXT_H1, font=font)
|
|
||||||
y += FONT_SIZE + IMG_MARGIN
|
|
||||||
index = 0
|
|
||||||
for tCommittedAlloc in dictMemType['CommittedAllocations']:
|
|
||||||
draw.text((IMG_MARGIN, y), "Committed allocation %d" % index, fill=COLOR_TEXT_H2, font=font)
|
|
||||||
y += FONT_SIZE + IMG_MARGIN
|
|
||||||
DrawCommittedAllocationBlock(draw, y, tCommittedAlloc)
|
|
||||||
y += MAP_SIZE + IMG_MARGIN
|
|
||||||
index += 1
|
|
||||||
for objBlock in dictMemType['DefaultPoolBlocks']:
|
|
||||||
draw.text((IMG_MARGIN, y), "Default pool block %d" % objBlock['ID'], fill=COLOR_TEXT_H2, font=font)
|
|
||||||
y += FONT_SIZE + IMG_MARGIN
|
|
||||||
DrawBlock(draw, y, objBlock)
|
|
||||||
y += MAP_SIZE + IMG_MARGIN
|
|
||||||
for sPoolName, pool in dictMemType['CustomPools'].items():
|
|
||||||
index = 0
|
|
||||||
for objBlock in pool['Blocks']:
|
|
||||||
if 'Algorithm' in objBlock and objBlock['Algorithm']:
|
|
||||||
sAlgorithm = ' (Algorithm: %s)' % (objBlock['Algorithm'])
|
|
||||||
else:
|
|
||||||
sAlgorithm = ''
|
|
||||||
draw.text((IMG_MARGIN, y), "Custom pool %s%s block %d" % (sPoolName, sAlgorithm, objBlock['ID']), fill=COLOR_TEXT_H2, font=font)
|
|
||||||
y += FONT_SIZE + IMG_MARGIN
|
|
||||||
DrawBlock(draw, y, objBlock)
|
|
||||||
y += 2 * (FONT_SIZE + IMG_MARGIN)
|
|
||||||
index += 1
|
|
||||||
index = 0
|
|
||||||
for objAlloc in pool['CommittedAllocations']:
|
|
||||||
draw.text((IMG_MARGIN, y), "Custom pool %s%s committed allocation %d" % (sPoolName, sAlgorithm, index), fill=COLOR_TEXT_H2, font=font)
|
|
||||||
y += FONT_SIZE + IMG_MARGIN
|
|
||||||
DrawCommittedAllocationBlock(draw, y, objAlloc)
|
|
||||||
y += MAP_SIZE + IMG_MARGIN
|
|
||||||
index += 1
|
|
||||||
del draw
|
|
||||||
img.save(args.output)
|
|
||||||
|
|
||||||
"""
|
|
||||||
Main data structure - variable `data` - is a dictionary. Key is string - heap type ('DEFAULT', 'UPLOAD', or 'READBACK'). Value is dictionary of:
|
|
||||||
- Fixed key 'CommittedAllocations'. Value is list of tuples, each containing:
|
|
||||||
- [0]: Type : string
|
|
||||||
- [1]: Size : integer
|
|
||||||
- [2]: Flags : integer (0 if unknown)
|
|
||||||
- [3]: Layout : integer (0 if unknown)
|
|
||||||
- Fixed key 'DefaultPoolBlocks'. Value is list of objects, each containing dictionary with:
|
|
||||||
- Fixed key 'ID'. Value is int.
|
|
||||||
- Fixed key 'Size'. Value is int.
|
|
||||||
- Fixed key 'Suballocations'. Value is list of tuples as above.
|
|
||||||
- Fixed key 'CustomPools'. Value is dictionary.
|
|
||||||
- Key is string with pool ID/name. Value is a dictionary with:
|
|
||||||
- Fixed key 'Blocks'. Value is a list of objects representing memory blocks, each containing dictionary with:
|
|
||||||
- Fixed key 'ID'. Value is int.
|
|
||||||
- Fixed key 'Size'. Value is int.
|
|
||||||
- Fixed key 'Algorithm'. Optional. Value is string.
|
|
||||||
- Fixed key 'Suballocations'. Value is list of tuples as above.
|
|
||||||
- Fixed key 'CommittedAllocations'. Value is list of tuples as above.
|
|
||||||
"""
|
|
334
tools/GpuMemDumpVis/GpuMemDumpVis.py
Normal file
@ -0,0 +1,334 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2018-2022 Advanced Micro Devices, Inc. All rights reserved.
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
|
# in the Software without restriction, including without limitation the rights
|
||||||
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
|
# furnished to do so, subject to the following conditions:
|
||||||
|
#
|
||||||
|
# The above copyright notice and this permission notice shall be included in
|
||||||
|
# all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
# THE SOFTWARE.
|
||||||
|
#
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
from PIL import Image, ImageDraw, ImageFont
|
||||||
|
|
||||||
|
|
||||||
|
PROGRAM_VERSION = 'Vulkan/D3D12 Memory Allocator Dump Visualization 3.0.0'
|
||||||
|
IMG_WIDTH = 1200
|
||||||
|
IMG_MARGIN = 8
|
||||||
|
TEXT_MARGIN = 4
|
||||||
|
FONT_SIZE = 10
|
||||||
|
MAP_SIZE = 24
|
||||||
|
COLOR_TEXT_H1 = (0, 0, 0, 255)
|
||||||
|
COLOR_TEXT_H2 = (150, 150, 150, 255)
|
||||||
|
COLOR_OUTLINE = (155, 155, 155, 255)
|
||||||
|
COLOR_OUTLINE_HARD = (0, 0, 0, 255)
|
||||||
|
COLOR_GRID_LINE = (224, 224, 224, 255)
|
||||||
|
|
||||||
|
currentApi = ""
|
||||||
|
data = {}
|
||||||
|
|
||||||
|
|
||||||
|
def ParseArgs():
|
||||||
|
argParser = argparse.ArgumentParser(description='Visualization of Vulkan/D3D12 Memory Allocator JSON dump.')
|
||||||
|
argParser.add_argument('DumpFile', help='Path to source JSON file with memory dump created by Vulkan/D3D12 Memory Allocator library')
|
||||||
|
argParser.add_argument('-v', '--version', action='version', version=PROGRAM_VERSION)
|
||||||
|
argParser.add_argument('-o', '--output', required=True, help='Path to destination image file (e.g. PNG)')
|
||||||
|
return argParser.parse_args()
|
||||||
|
|
||||||
|
def GetDataForMemoryPool(poolTypeName):
|
||||||
|
global data
|
||||||
|
if poolTypeName in data:
|
||||||
|
return data[poolTypeName]
|
||||||
|
else:
|
||||||
|
newPoolData = {'DedicatedAllocations':[], 'Blocks':[], 'CustomPools':{}}
|
||||||
|
data[poolTypeName] = newPoolData
|
||||||
|
return newPoolData
|
||||||
|
|
||||||
|
def ProcessBlock(poolData, block):
|
||||||
|
blockInfo = {'ID': block[0], 'Size': int(block[1]['TotalBytes']), 'Suballocations':[]}
|
||||||
|
for alloc in block[1]['Suballocations']:
|
||||||
|
allocData = {'Type': alloc['Type'], 'Size': int(alloc['Size']), 'Usage': int(alloc['Usage']) if 'Usage' in alloc else 0 }
|
||||||
|
blockInfo['Suballocations'].append(allocData)
|
||||||
|
poolData['Blocks'].append(blockInfo)
|
||||||
|
|
||||||
|
def IsDataEmpty():
|
||||||
|
global data
|
||||||
|
for poolData in data.values():
|
||||||
|
if len(poolData['DedicatedAllocations']) > 0:
|
||||||
|
return False
|
||||||
|
if len(poolData['Blocks']) > 0:
|
||||||
|
return False
|
||||||
|
for customPool in poolData['CustomPools'].values():
|
||||||
|
if len(customPool['Blocks']) > 0:
|
||||||
|
return False
|
||||||
|
if len(customPool['DedicatedAllocations']) > 0:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def RemoveEmptyType():
|
||||||
|
global data
|
||||||
|
for poolType in list(data.keys()):
|
||||||
|
if len(data[poolType]['DedicatedAllocations']) > 0:
|
||||||
|
continue
|
||||||
|
if len(data[poolType]['Blocks']) > 0:
|
||||||
|
continue
|
||||||
|
empty = True
|
||||||
|
for customPool in data[poolType]['CustomPools'].values():
|
||||||
|
if len(data[poolType]['Blocks']) > 0:
|
||||||
|
empty = False
|
||||||
|
break
|
||||||
|
if len(data[poolType]['DedicatedAllocations']) > 0:
|
||||||
|
empty = False
|
||||||
|
break
|
||||||
|
if empty:
|
||||||
|
del data[poolType]
|
||||||
|
|
||||||
|
# Returns tuple:
|
||||||
|
# [0] image height : integer
|
||||||
|
# [1] pixels per byte : float
|
||||||
|
def CalcParams():
|
||||||
|
global data
|
||||||
|
height = IMG_MARGIN
|
||||||
|
height += FONT_SIZE + IMG_MARGIN # Grid lines legend - sizes
|
||||||
|
maxBlockSize = 0
|
||||||
|
# Get height occupied by every memory pool
|
||||||
|
for poolData in data.values():
|
||||||
|
height += IMG_MARGIN + FONT_SIZE
|
||||||
|
height += len(poolData['DedicatedAllocations']) * (IMG_MARGIN * 2 + FONT_SIZE + MAP_SIZE)
|
||||||
|
height += len(poolData['Blocks']) * (IMG_MARGIN * 2 + FONT_SIZE + MAP_SIZE)
|
||||||
|
# Get longest block size
|
||||||
|
for dedicatedAlloc in poolData['DedicatedAllocations']:
|
||||||
|
maxBlockSize = max(maxBlockSize, dedicatedAlloc['Size'])
|
||||||
|
for block in poolData['Blocks']:
|
||||||
|
maxBlockSize = max(maxBlockSize, block['Size'])
|
||||||
|
# Same for custom pools
|
||||||
|
for customPoolData in poolData['CustomPools'].values():
|
||||||
|
height += len(customPoolData['DedicatedAllocations']) * (IMG_MARGIN * 2 + FONT_SIZE + MAP_SIZE)
|
||||||
|
height += len(customPoolData['Blocks']) * (IMG_MARGIN * 2 + FONT_SIZE + MAP_SIZE)
|
||||||
|
height += FONT_SIZE * 2 + IMG_MARGIN if len(customPoolData['DedicatedAllocations']) == 0 else 0
|
||||||
|
# Get longest block size
|
||||||
|
for dedicatedAlloc in customPoolData['DedicatedAllocations']:
|
||||||
|
maxBlockSize = max(maxBlockSize, dedicatedAlloc['Size'])
|
||||||
|
for block in customPoolData['Blocks']:
|
||||||
|
maxBlockSize = max(maxBlockSize, block['Size'])
|
||||||
|
|
||||||
|
return height + FONT_SIZE, (IMG_WIDTH - IMG_MARGIN * 2) / float(maxBlockSize)
|
||||||
|
|
||||||
|
def BytesToStr(bytes):
|
||||||
|
if bytes < 1024:
|
||||||
|
return "%d B" % bytes
|
||||||
|
bytes /= 1024
|
||||||
|
if bytes < 1024:
|
||||||
|
return "%d KiB" % bytes
|
||||||
|
bytes /= 1024
|
||||||
|
if bytes < 1024:
|
||||||
|
return "%d MiB" % bytes
|
||||||
|
bytes /= 1024
|
||||||
|
return "%d GiB" % bytes
|
||||||
|
|
||||||
|
def TypeToColor(type, usage):
|
||||||
|
global currentApi
|
||||||
|
if type == 'FREE':
|
||||||
|
return 220, 220, 220, 255
|
||||||
|
elif type == 'UNKNOWN':
|
||||||
|
return 175, 175, 175, 255 # Gray
|
||||||
|
|
||||||
|
if currentApi == 'Vulkan':
|
||||||
|
if type == 'BUFFER':
|
||||||
|
if (usage & 0x1C0) != 0: # INDIRECT_BUFFER | VERTEX_BUFFER | INDEX_BUFFER
|
||||||
|
return 255, 148, 148, 255 # Red
|
||||||
|
elif (usage & 0x28) != 0: # STORAGE_BUFFER | STORAGE_TEXEL_BUFFER
|
||||||
|
return 255, 187, 121, 255 # Orange
|
||||||
|
elif (usage & 0x14) != 0: # UNIFORM_BUFFER | UNIFORM_TEXEL_BUFFER
|
||||||
|
return 255, 255, 0, 255 # Yellow
|
||||||
|
else:
|
||||||
|
return 255, 255, 165, 255 # Light yellow
|
||||||
|
elif type == 'IMAGE_OPTIMAL':
|
||||||
|
if (usage & 0x20) != 0: # DEPTH_STENCIL_ATTACHMENT
|
||||||
|
return 246, 128, 255, 255 # Pink
|
||||||
|
elif (usage & 0xD0) != 0: # INPUT_ATTACHMENT | TRANSIENT_ATTACHMENT | COLOR_ATTACHMENT
|
||||||
|
return 179, 179, 255, 255 # Blue
|
||||||
|
elif (usage & 0x4) != 0: # SAMPLED
|
||||||
|
return 0, 255, 255, 255 # Aqua
|
||||||
|
else:
|
||||||
|
return 183, 255, 255, 255 # Light aqua
|
||||||
|
elif type == 'IMAGE_LINEAR' :
|
||||||
|
return 0, 255, 0, 255 # Green
|
||||||
|
elif type == 'IMAGE_UNKNOWN':
|
||||||
|
return 0, 255, 164, 255 # Green/aqua
|
||||||
|
elif currentApi == 'Direct3D 12':
|
||||||
|
if type == 'BUFFER':
|
||||||
|
return 255, 255, 165, 255 # Light yellow
|
||||||
|
elif type == 'TEXTURE1D' or type == 'TEXTURE2D' or type == 'TEXTURE3D':
|
||||||
|
if (usage & 0x2) != 0: # D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL
|
||||||
|
return 246, 128, 255, 255 # Pink
|
||||||
|
elif (usage & 0x5) != 0: # D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS
|
||||||
|
return 179, 179, 255, 255 # Blue
|
||||||
|
elif (usage & 0x8) == 0: # Not having D3D12_RESOURCE_FLAG_DENY_SHARED_RESOURCE
|
||||||
|
return 0, 255, 255, 255 # Aqua
|
||||||
|
else:
|
||||||
|
return 183, 255, 255, 255 # Light aqua
|
||||||
|
else:
|
||||||
|
print("Unknown graphics API!")
|
||||||
|
exit(1)
|
||||||
|
assert False
|
||||||
|
return 0, 0, 0, 255
|
||||||
|
|
||||||
|
def DrawBlock(draw, y, block, pixelsPerByte):
|
||||||
|
sizePixels = int(block['Size'] * pixelsPerByte)
|
||||||
|
draw.rectangle([IMG_MARGIN, y, IMG_MARGIN + sizePixels, y + MAP_SIZE], fill=TypeToColor('FREE', 0), outline=None)
|
||||||
|
byte = 0
|
||||||
|
x = 0
|
||||||
|
lastHardLineX = -1
|
||||||
|
for alloc in block['Suballocations']:
|
||||||
|
byteEnd = byte + alloc['Size']
|
||||||
|
xEnd = int(byteEnd * pixelsPerByte)
|
||||||
|
if alloc['Type'] != 'FREE':
|
||||||
|
if xEnd > x + 1:
|
||||||
|
draw.rectangle([IMG_MARGIN + x, y, IMG_MARGIN + xEnd, y + MAP_SIZE], fill=TypeToColor(alloc['Type'], alloc['Usage']), outline=COLOR_OUTLINE)
|
||||||
|
# Hard line was been overwritten by rectangle outline: redraw it.
|
||||||
|
if lastHardLineX == x:
|
||||||
|
draw.line([IMG_MARGIN + x, y, IMG_MARGIN + x, y + MAP_SIZE], fill=COLOR_OUTLINE_HARD)
|
||||||
|
else:
|
||||||
|
draw.line([IMG_MARGIN + x, y, IMG_MARGIN + x, y + MAP_SIZE], fill=COLOR_OUTLINE_HARD)
|
||||||
|
lastHardLineX = x
|
||||||
|
byte = byteEnd
|
||||||
|
x = xEnd
|
||||||
|
|
||||||
|
def DrawDedicatedAllocationBlock(draw, y, dedicatedAlloc, pixelsPerByte):
|
||||||
|
sizePixels = int(dedicatedAlloc['Size'] * pixelsPerByte)
|
||||||
|
draw.rectangle([IMG_MARGIN, y, IMG_MARGIN + sizePixels, y + MAP_SIZE], fill=TypeToColor(dedicatedAlloc['Type'], dedicatedAlloc['Usage']), outline=COLOR_OUTLINE)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
args = ParseArgs()
|
||||||
|
jsonSrc = json.load(open(args.DumpFile, 'rb'))
|
||||||
|
|
||||||
|
if 'General' in jsonSrc:
|
||||||
|
currentApi = jsonSrc['General']['API']
|
||||||
|
else:
|
||||||
|
print("Wrong JSON format, cannot determine graphics API!")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
# Process default pools
|
||||||
|
if 'DefaultPools' in jsonSrc:
|
||||||
|
for memoryPool in jsonSrc['DefaultPools'].items():
|
||||||
|
poolData = GetDataForMemoryPool(memoryPool[0])
|
||||||
|
# Get dedicated allocations
|
||||||
|
for dedicatedAlloc in memoryPool[1]['DedicatedAllocations']:
|
||||||
|
allocData = {'Type': dedicatedAlloc['Type'], 'Size': int(dedicatedAlloc['Size']), 'Usage': int(dedicatedAlloc['Usage'])}
|
||||||
|
poolData['DedicatedAllocations'].append(allocData)
|
||||||
|
# Get allocations in block vectors
|
||||||
|
for block in memoryPool[1]['Blocks'].items():
|
||||||
|
ProcessBlock(poolData, block)
|
||||||
|
# Process custom pools
|
||||||
|
if 'CustomPools' in jsonSrc:
|
||||||
|
for memoryPool in jsonSrc['CustomPools'].items():
|
||||||
|
poolData = GetDataForMemoryPool(memoryPool[0])
|
||||||
|
for pool in memoryPool[1]:
|
||||||
|
poolName = pool['Name']
|
||||||
|
poolData['CustomPools'][poolName] = {'DedicatedAllocations':[], 'Blocks':[]}
|
||||||
|
# Get dedicated allocations
|
||||||
|
for dedicatedAlloc in pool['DedicatedAllocations']:
|
||||||
|
allocData = {'Type': dedicatedAlloc['Type'], 'Size': int(dedicatedAlloc['Size']), 'Usage': int(dedicatedAlloc['Usage'])}
|
||||||
|
poolData['CustomPools'][poolName]['DedicatedAllocations'].append(allocData)
|
||||||
|
# Get allocations in block vectors
|
||||||
|
for block in pool['Blocks'].items():
|
||||||
|
ProcessBlock(poolData['CustomPools'][poolName], block)
|
||||||
|
|
||||||
|
if IsDataEmpty():
|
||||||
|
print("There is nothing to put on the image. Please make sure you generated the stats string with detailed map enabled.")
|
||||||
|
exit(1)
|
||||||
|
RemoveEmptyType()
|
||||||
|
# Calculate dimmensions and create data image
|
||||||
|
imgHeight, pixelsPerByte = CalcParams()
|
||||||
|
img = Image.new('RGB', (IMG_WIDTH, imgHeight), 'white')
|
||||||
|
draw = ImageDraw.Draw(img)
|
||||||
|
try:
|
||||||
|
font = ImageFont.truetype('segoeuib.ttf')
|
||||||
|
except:
|
||||||
|
font = ImageFont.load_default()
|
||||||
|
|
||||||
|
# Draw grid lines
|
||||||
|
bytesBetweenGridLines = 32
|
||||||
|
while bytesBetweenGridLines * pixelsPerByte < 64:
|
||||||
|
bytesBetweenGridLines *= 2
|
||||||
|
byte = 0
|
||||||
|
y = IMG_MARGIN
|
||||||
|
while True:
|
||||||
|
x = int(byte * pixelsPerByte)
|
||||||
|
if x > IMG_WIDTH - 2 * IMG_MARGIN:
|
||||||
|
break
|
||||||
|
draw.line([x + IMG_MARGIN, 0, x + IMG_MARGIN, imgHeight], fill=COLOR_GRID_LINE)
|
||||||
|
if byte == 0:
|
||||||
|
draw.text((x + IMG_MARGIN + TEXT_MARGIN, y), "0", fill=COLOR_TEXT_H2, font=font)
|
||||||
|
else:
|
||||||
|
text = BytesToStr(byte)
|
||||||
|
textSize = draw.textsize(text, font=font)
|
||||||
|
draw.text((x + IMG_MARGIN - textSize[0] - TEXT_MARGIN, y), text, fill=COLOR_TEXT_H2, font=font)
|
||||||
|
byte += bytesBetweenGridLines
|
||||||
|
y += FONT_SIZE + IMG_MARGIN
|
||||||
|
|
||||||
|
# Draw main content
|
||||||
|
for memType in sorted(data.keys()):
|
||||||
|
memPoolData = data[memType]
|
||||||
|
draw.text((IMG_MARGIN, y), "Memory pool %s" % memType, fill=COLOR_TEXT_H1, font=font)
|
||||||
|
y += FONT_SIZE + IMG_MARGIN
|
||||||
|
# Draw block vectors
|
||||||
|
for block in memPoolData['Blocks']:
|
||||||
|
draw.text((IMG_MARGIN, y), "Default pool block %s" % block['ID'], fill=COLOR_TEXT_H2, font=font)
|
||||||
|
y += FONT_SIZE + IMG_MARGIN
|
||||||
|
DrawBlock(draw, y, block, pixelsPerByte)
|
||||||
|
y += MAP_SIZE + IMG_MARGIN
|
||||||
|
index = 0
|
||||||
|
# Draw dedicated allocations
|
||||||
|
for dedicatedAlloc in memPoolData['DedicatedAllocations']:
|
||||||
|
draw.text((IMG_MARGIN, y), "Dedicated allocation %d" % index, fill=COLOR_TEXT_H2, font=font)
|
||||||
|
y += FONT_SIZE + IMG_MARGIN
|
||||||
|
DrawDedicatedAllocationBlock(draw, y, dedicatedAlloc, pixelsPerByte)
|
||||||
|
y += MAP_SIZE + IMG_MARGIN
|
||||||
|
index += 1
|
||||||
|
for poolName, pool in memPoolData['CustomPools'].items():
|
||||||
|
for block in pool['Blocks']:
|
||||||
|
draw.text((IMG_MARGIN, y), "Custom pool %s block %s" % (poolName, block['ID']), fill=COLOR_TEXT_H2, font=font)
|
||||||
|
y += FONT_SIZE + IMG_MARGIN
|
||||||
|
DrawBlock(draw, y, block, pixelsPerByte)
|
||||||
|
y += 2 * (FONT_SIZE + IMG_MARGIN)
|
||||||
|
index = 0
|
||||||
|
for dedicatedAlloc in pool['DedicatedAllocations']:
|
||||||
|
draw.text((IMG_MARGIN, y), "Custom pool %s dedicated allocation %d" % (poolName, index), fill=COLOR_TEXT_H2, font=font)
|
||||||
|
y += FONT_SIZE + IMG_MARGIN
|
||||||
|
DrawDedicatedAllocationBlock(draw, y, dedicatedAlloc, pixelsPerByte)
|
||||||
|
y += MAP_SIZE + IMG_MARGIN
|
||||||
|
index += 1
|
||||||
|
del draw
|
||||||
|
img.save(args.output)
|
||||||
|
|
||||||
|
"""
|
||||||
|
Main data structure - variable `data` - is a dictionary. Key is string - memory type name. Value is dictionary of:
|
||||||
|
- Fixed key 'DedicatedAllocations'. Value is list of objects, each containing dictionary with:
|
||||||
|
- Fixed key 'Type'. Value is string.
|
||||||
|
- Fixed key 'Size'. Value is int.
|
||||||
|
- Fixed key 'Usage'. Value is int.
|
||||||
|
- Fixed key 'Blocks'. Value is list of objects, each containing dictionary with:
|
||||||
|
- Fixed key 'ID'. Value is int.
|
||||||
|
- Fixed key 'Size'. Value is int.
|
||||||
|
- Fixed key 'Suballocations'. Value is list of objects as above.
|
||||||
|
- Fixed key 'CustomPools'. Value is dictionary.
|
||||||
|
- Key is string with pool ID/name. Value is a dictionary with:
|
||||||
|
- Fixed key 'DedicatedAllocations'. Value is list of objects as above.
|
||||||
|
- Fixed key 'Blocks'. Value is a list of objects representing memory blocks as above.
|
||||||
|
"""
|
45
tools/GpuMemDumpVis/README.md
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
# GpuMemDumpVis
|
||||||
|
|
||||||
|
Vulkan/D3D12 Memory Allocator Dump Visualization.
|
||||||
|
It is an auxiliary tool that can visualize internal state of [Vulkan Memory Allocator](https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator) and
|
||||||
|
[D3D12 Memory Allocator](https://github.com/GPUOpen-LibrariesAndSDKs/D3D12MemoryAllocator) libraries on a picture.
|
||||||
|
It is a Python script that must be launched from command line with appropriate parameters.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- Python 3 installed
|
||||||
|
- [Pillow](http://python-pillow.org/) - Python Imaging Library (Fork) installed
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
python GpuMemDumpVis.py -o OUTPUT_FILE INPUT_FILE
|
||||||
|
```
|
||||||
|
|
||||||
|
* `INPUT_FILE` - path to source file to be read, containing dump of internal state of the VMA/D3D12MA library in JSON format (encoding: UTF-8/UTF-16), generated using `vmaBuildStatsString()` and `D3D12MA::Allocator::BuildStatsString()` functions.
|
||||||
|
* `OUTPUT_FILE` - path to destination file to be written that will contain generated image. Image format is automatically recognized based on file extension. List of supported formats can be found [here](http://pillow.readthedocs.io/en/latest/handbook/image-file-formats.html) and includes: BMP, GIF, JPEG, PNG, TGA.
|
||||||
|
|
||||||
|
You can also use typical options:
|
||||||
|
|
||||||
|
* `-h` - to see help on command line syntax
|
||||||
|
* `-v` - to see program version number
|
||||||
|
|
||||||
|
## Example output
|
||||||
|
|
||||||
|
![Example output](README_files/ExampleOutput.png "Example output")
|
||||||
|
|
||||||
|
## Legend
|
||||||
|
|
||||||
|
* ![Free space](README_files/Legend_Bkg.png "Free space") Light gray without border - a space in Vulkan device memory block unused by any allocation.
|
||||||
|
* ![Buffer 1](README_files/Legend_Buffer_1.png "Buffer 1") Buffer with usage containing INDIRECT_BUFFER, VERTEX_BUFFER, or INDEX_BUFFER.
|
||||||
|
* ![Buffer 2](README_files/Legend_Buffer_2.png "Buffer 2") Buffer with usage containing STORAGE_BUFFER or STORAGE_TEXEL_BUFFER.
|
||||||
|
* ![Buffer 3](README_files/Legend_Buffer_3.png "Buffer 3") Buffer with usage containing UNIFORM_BUFFER or UNIFORM_TEXEL_BUFFER.
|
||||||
|
* ![Buffer 4](README_files/Legend_Buffer_4.png "Buffer 4") Other buffer.
|
||||||
|
* ![Image 1](README_files/Legend_Image_1.png "Image 1") Image with OPTIMAL tiling and usage containing DEPTH_STENCIL_ATTACHMENT or 1D/2D/3D texture with usage containing D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL.
|
||||||
|
* ![Image 2](README_files/Legend_Image_2.png "Image 2") Image with OPTIMAL tiling and usage containing INPUT_ATTACHMENT, TRANSIENT_ATTACHMENT or COLOR_ATTACHMENT, or 1D/2D/3D texture with usage containing D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET or D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS.
|
||||||
|
* ![Image 3](README_files/Legend_Image_3.png "Image 3") Image with OPTIMAL tiling and usage containing SAMPLED or 1D/2D/3D texture with usage not containing D3D12_RESOURCE_FLAG_DENY_SHARED_RESOURCE.
|
||||||
|
* ![Image 4](README_files/Legend_Image_4.png "Image 4") Other image with OPTIMAL tiling or 1D/2D/3D texture.
|
||||||
|
* ![Image Linear](README_files/Legend_Image_Linear.png "Image Linear") Image with LINEAR tiling.
|
||||||
|
* ![Image Unknown](README_files/Legend_Image_Unknown.png "Image Unknown") Image with tiling unknown to the allocator.
|
||||||
|
* ![Unknown](README_files/Legend_Unknown.png "Unknown") Allocation of unknown type.
|
||||||
|
* ![Details](README_files/Legend_Details.png "Details") Black bar - one or more allocations of any kind too small to be visualized as filled rectangles.
|
BIN
tools/GpuMemDumpVis/README_files/ExampleOutput.png
Normal file
After Width: | Height: | Size: 96 KiB |
BIN
tools/GpuMemDumpVis/README_files/Legend_Bkg.png
Normal file
After Width: | Height: | Size: 196 B |
BIN
tools/GpuMemDumpVis/README_files/Legend_Buffer_1.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
tools/GpuMemDumpVis/README_files/Legend_Buffer_2.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
tools/GpuMemDumpVis/README_files/Legend_Buffer_3.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
tools/GpuMemDumpVis/README_files/Legend_Buffer_4.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
tools/GpuMemDumpVis/README_files/Legend_Details.png
Normal file
After Width: | Height: | Size: 964 B |
BIN
tools/GpuMemDumpVis/README_files/Legend_Image_1.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
tools/GpuMemDumpVis/README_files/Legend_Image_2.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
tools/GpuMemDumpVis/README_files/Legend_Image_3.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
tools/GpuMemDumpVis/README_files/Legend_Image_4.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
tools/GpuMemDumpVis/README_files/Legend_Image_Linear.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
tools/GpuMemDumpVis/README_files/Legend_Image_Unknown.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
tools/GpuMemDumpVis/README_files/Legend_Texture_1.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
tools/GpuMemDumpVis/README_files/Legend_Texture_2.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
tools/GpuMemDumpVis/README_files/Legend_Texture_3.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
tools/GpuMemDumpVis/README_files/Legend_Texture_4.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
tools/GpuMemDumpVis/README_files/Legend_Unknown.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
426
tools/GpuMemDumpVis/Sample.json
Normal file
@ -0,0 +1,426 @@
|
|||||||
|
{
|
||||||
|
"General": {
|
||||||
|
"API": "Vulkan",
|
||||||
|
"apiVersion": "1.3.203",
|
||||||
|
"GPU": "AMD Radeon RX 6600 XT",
|
||||||
|
"deviceType": 2,
|
||||||
|
"maxMemoryAllocationCount": 4096,
|
||||||
|
"bufferImageGranularity": 1,
|
||||||
|
"nonCoherentAtomSize": 128,
|
||||||
|
"memoryHeapCount": 2,
|
||||||
|
"memoryTypeCount": 8
|
||||||
|
},
|
||||||
|
"Total": {
|
||||||
|
"BlockCount": 69,
|
||||||
|
"BlockBytes": 201392128,
|
||||||
|
"AllocationCount": 132,
|
||||||
|
"AllocationBytes": 73401500,
|
||||||
|
"UnusedRangeCount": 11,
|
||||||
|
"AllocationSizeMin": 60,
|
||||||
|
"AllocationSizeMax": 6095200,
|
||||||
|
"UnusedRangeSizeMin": 196,
|
||||||
|
"UnusedRangeSizeMax": 33550336
|
||||||
|
},
|
||||||
|
"MemoryInfo": {
|
||||||
|
"Heap 0": {
|
||||||
|
"Flags": [],
|
||||||
|
"Size": 16862150656,
|
||||||
|
"Budget": {
|
||||||
|
"BudgetBytes": 16325847040,
|
||||||
|
"UsageBytes": 122392576
|
||||||
|
},
|
||||||
|
"Stats": {
|
||||||
|
"BlockCount": 35,
|
||||||
|
"BlockBytes": 117473280,
|
||||||
|
"AllocationCount": 64,
|
||||||
|
"AllocationBytes": 33619968,
|
||||||
|
"UnusedRangeCount": 5,
|
||||||
|
"AllocationSizeMin": 1024,
|
||||||
|
"AllocationSizeMax": 2097152,
|
||||||
|
"UnusedRangeSizeMin": 49152,
|
||||||
|
"UnusedRangeSizeMax": 33550336
|
||||||
|
},
|
||||||
|
"MemoryPools": {
|
||||||
|
"Type 1": {
|
||||||
|
"Flags": ["HOST_VISIBLE", "HOST_COHERENT"],
|
||||||
|
"Stats": {
|
||||||
|
"BlockCount": 5,
|
||||||
|
"BlockBytes": 33558528,
|
||||||
|
"AllocationCount": 8,
|
||||||
|
"AllocationBytes": 8192,
|
||||||
|
"UnusedRangeCount": 1,
|
||||||
|
"AllocationSizeMin": 1024,
|
||||||
|
"AllocationSizeMax": 1024
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Type 3": {
|
||||||
|
"Flags": ["HOST_VISIBLE", "HOST_COHERENT", "HOST_CACHED"],
|
||||||
|
"Stats": {
|
||||||
|
"BlockCount": 30,
|
||||||
|
"BlockBytes": 83914752,
|
||||||
|
"AllocationCount": 56,
|
||||||
|
"AllocationBytes": 33611776,
|
||||||
|
"UnusedRangeCount": 4,
|
||||||
|
"AllocationSizeMin": 1024,
|
||||||
|
"AllocationSizeMax": 2097152,
|
||||||
|
"UnusedRangeSizeMin": 49152,
|
||||||
|
"UnusedRangeSizeMax": 25100288
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Type 5": {
|
||||||
|
"Flags": ["HOST_VISIBLE", "HOST_COHERENT", "DEVICE_COHERENT_AMD", "DEVICE_UNCACHED_AMD"],
|
||||||
|
"Stats": {
|
||||||
|
"BlockCount": 0,
|
||||||
|
"BlockBytes": 0,
|
||||||
|
"AllocationCount": 0,
|
||||||
|
"AllocationBytes": 0,
|
||||||
|
"UnusedRangeCount": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Type 7": {
|
||||||
|
"Flags": ["HOST_VISIBLE", "HOST_COHERENT", "HOST_CACHED", "DEVICE_COHERENT_AMD", "DEVICE_UNCACHED_AMD"],
|
||||||
|
"Stats": {
|
||||||
|
"BlockCount": 0,
|
||||||
|
"BlockBytes": 0,
|
||||||
|
"AllocationCount": 0,
|
||||||
|
"AllocationBytes": 0,
|
||||||
|
"UnusedRangeCount": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Heap 1": {
|
||||||
|
"Flags": ["DEVICE_LOCAL", "MULTI_INSTANCE"],
|
||||||
|
"Size": 8573157376,
|
||||||
|
"Budget": {
|
||||||
|
"BudgetBytes": 7737008128,
|
||||||
|
"UsageBytes": 155025408
|
||||||
|
},
|
||||||
|
"Stats": {
|
||||||
|
"BlockCount": 34,
|
||||||
|
"BlockBytes": 83918848,
|
||||||
|
"AllocationCount": 68,
|
||||||
|
"AllocationBytes": 39781532,
|
||||||
|
"UnusedRangeCount": 6,
|
||||||
|
"AllocationSizeMin": 60,
|
||||||
|
"AllocationSizeMax": 6095200,
|
||||||
|
"UnusedRangeSizeMin": 196,
|
||||||
|
"UnusedRangeSizeMax": 25100288
|
||||||
|
},
|
||||||
|
"MemoryPools": {
|
||||||
|
"Type 0": {
|
||||||
|
"Flags": ["DEVICE_LOCAL"],
|
||||||
|
"Stats": {
|
||||||
|
"BlockCount": 34,
|
||||||
|
"BlockBytes": 83918848,
|
||||||
|
"AllocationCount": 68,
|
||||||
|
"AllocationBytes": 39781532,
|
||||||
|
"UnusedRangeCount": 6,
|
||||||
|
"AllocationSizeMin": 60,
|
||||||
|
"AllocationSizeMax": 6095200,
|
||||||
|
"UnusedRangeSizeMin": 196,
|
||||||
|
"UnusedRangeSizeMax": 25100288
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Type 2": {
|
||||||
|
"Flags": ["DEVICE_LOCAL", "HOST_VISIBLE", "HOST_COHERENT"],
|
||||||
|
"Stats": {
|
||||||
|
"BlockCount": 0,
|
||||||
|
"BlockBytes": 0,
|
||||||
|
"AllocationCount": 0,
|
||||||
|
"AllocationBytes": 0,
|
||||||
|
"UnusedRangeCount": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Type 4": {
|
||||||
|
"Flags": ["DEVICE_LOCAL", "DEVICE_COHERENT_AMD", "DEVICE_UNCACHED_AMD"],
|
||||||
|
"Stats": {
|
||||||
|
"BlockCount": 0,
|
||||||
|
"BlockBytes": 0,
|
||||||
|
"AllocationCount": 0,
|
||||||
|
"AllocationBytes": 0,
|
||||||
|
"UnusedRangeCount": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Type 6": {
|
||||||
|
"Flags": ["DEVICE_LOCAL", "HOST_VISIBLE", "HOST_COHERENT", "DEVICE_COHERENT_AMD", "DEVICE_UNCACHED_AMD"],
|
||||||
|
"Stats": {
|
||||||
|
"BlockCount": 0,
|
||||||
|
"BlockBytes": 0,
|
||||||
|
"AllocationCount": 0,
|
||||||
|
"AllocationBytes": 0,
|
||||||
|
"UnusedRangeCount": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"DefaultPools": {
|
||||||
|
"Type 0": {
|
||||||
|
"PreferredBlockSize": 268435456,
|
||||||
|
"Blocks": {
|
||||||
|
"0": {
|
||||||
|
"MapRefCount": 0,
|
||||||
|
"TotalBytes": 33554432,
|
||||||
|
"UnusedBytes": 18987876,
|
||||||
|
"Allocations": 20,
|
||||||
|
"UnusedRanges": 4,
|
||||||
|
"Suballocations": [
|
||||||
|
{"Offset": 0, "Type": "IMAGE_OPTIMAL", "Size": 65536, "Usage": 6},
|
||||||
|
{"Offset": 65536, "Type": "BUFFER", "Size": 768, "Usage": 130},
|
||||||
|
{"Offset": 66304, "Type": "BUFFER", "Size": 60, "Usage": 66},
|
||||||
|
{"Offset": 66364, "Type": "UNKNOWN", "Size": 1024, "Usage": 0},
|
||||||
|
{"Offset": 67388, "Type": "UNKNOWN", "Size": 1024, "Usage": 0, "CustomData": "0000000000F5D987"},
|
||||||
|
{"Offset": 68412, "Type": "UNKNOWN", "Size": 1024, "Usage": 0, "Name": "SHEPURD"},
|
||||||
|
{"Offset": 69436, "Type": "UNKNOWN", "Size": 1024, "Usage": 0, "CustomData": "00000000018CE96A", "Name": "JOKER"},
|
||||||
|
{"Offset": 70460, "Type": "BUFFER", "Size": 1024, "Usage": 3},
|
||||||
|
{"Offset": 71484, "Type": "BUFFER", "Size": 1024, "Usage": 3, "CustomData": "0000000000F5D987"},
|
||||||
|
{"Offset": 72508, "Type": "BUFFER", "Size": 1024, "Usage": 3, "Name": "SHEPURD"},
|
||||||
|
{"Offset": 73532, "Type": "BUFFER", "Size": 1024, "Usage": 3, "CustomData": "00000000018CE96A", "Name": "JOKER"},
|
||||||
|
{"Offset": 74556, "Type": "FREE", "Size": 196},
|
||||||
|
{"Offset": 74752, "Type": "IMAGE_LINEAR", "Size": 2048, "Usage": 7},
|
||||||
|
{"Offset": 76800, "Type": "IMAGE_LINEAR", "Size": 2048, "Usage": 7, "CustomData": "0000000000F5D987"},
|
||||||
|
{"Offset": 78848, "Type": "IMAGE_LINEAR", "Size": 2048, "Usage": 7, "Name": "SHEPURD"},
|
||||||
|
{"Offset": 80896, "Type": "IMAGE_LINEAR", "Size": 2048, "Usage": 7, "CustomData": "00000000018CE96A", "Name": "JOKER"},
|
||||||
|
{"Offset": 82944, "Type": "FREE", "Size": 48128},
|
||||||
|
{"Offset": 131072, "Type": "IMAGE_OPTIMAL", "Size": 6095200, "Usage": 32},
|
||||||
|
{"Offset": 6226272, "Type": "FREE", "Size": 65184},
|
||||||
|
{"Offset": 6291456, "Type": "IMAGE_OPTIMAL", "Size": 2097152, "Usage": 7},
|
||||||
|
{"Offset": 8388608, "Type": "IMAGE_OPTIMAL", "Size": 2097152, "Usage": 7, "CustomData": "0000000000F5D987"},
|
||||||
|
{"Offset": 10485760, "Type": "IMAGE_OPTIMAL", "Size": 2097152, "Usage": 7, "Name": "SHEPURD"},
|
||||||
|
{"Offset": 12582912, "Type": "IMAGE_OPTIMAL", "Size": 2097152, "Usage": 7, "CustomData": "00000000018CE96A", "Name": "JOKER"},
|
||||||
|
{"Offset": 14680064, "Type": "FREE", "Size": 18874368}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"DedicatedAllocations": [
|
||||||
|
{"Type": "UNKNOWN", "Size": 1024, "Usage": 0},
|
||||||
|
{"Type": "UNKNOWN", "Size": 1024, "Usage": 0, "CustomData": "0000000000F5D987"},
|
||||||
|
{"Type": "UNKNOWN", "Size": 1024, "Usage": 0, "Name": "SHEPURD"},
|
||||||
|
{"Type": "UNKNOWN", "Size": 1024, "Usage": 0, "CustomData": "00000000018CE96A", "Name": "JOKER"},
|
||||||
|
{"Type": "BUFFER", "Size": 1024, "Usage": 3},
|
||||||
|
{"Type": "BUFFER", "Size": 1024, "Usage": 3, "CustomData": "0000000000F5D987"},
|
||||||
|
{"Type": "BUFFER", "Size": 1024, "Usage": 3, "Name": "SHEPURD"},
|
||||||
|
{"Type": "BUFFER", "Size": 1024, "Usage": 3, "CustomData": "00000000018CE96A", "Name": "JOKER"},
|
||||||
|
{"Type": "IMAGE_LINEAR", "Size": 2048, "Usage": 7},
|
||||||
|
{"Type": "IMAGE_LINEAR", "Size": 2048, "Usage": 7, "CustomData": "0000000000F5D987"},
|
||||||
|
{"Type": "IMAGE_LINEAR", "Size": 2048, "Usage": 7, "Name": "SHEPURD"},
|
||||||
|
{"Type": "IMAGE_LINEAR", "Size": 2048, "Usage": 7, "CustomData": "00000000018CE96A", "Name": "JOKER"},
|
||||||
|
{"Type": "IMAGE_OPTIMAL", "Size": 2097152, "Usage": 7},
|
||||||
|
{"Type": "IMAGE_OPTIMAL", "Size": 2097152, "Usage": 7, "CustomData": "0000000000F5D987"},
|
||||||
|
{"Type": "IMAGE_OPTIMAL", "Size": 2097152, "Usage": 7, "Name": "SHEPURD"},
|
||||||
|
{"Type": "IMAGE_OPTIMAL", "Size": 2097152, "Usage": 7, "CustomData": "00000000018CE96A", "Name": "JOKER"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Type 1": {
|
||||||
|
"PreferredBlockSize": 268435456,
|
||||||
|
"Blocks": {
|
||||||
|
"0": {
|
||||||
|
"MapRefCount": 0,
|
||||||
|
"TotalBytes": 33554432,
|
||||||
|
"UnusedBytes": 33550336,
|
||||||
|
"Allocations": 4,
|
||||||
|
"UnusedRanges": 1,
|
||||||
|
"Suballocations": [
|
||||||
|
{"Offset": 0, "Type": "UNKNOWN", "Size": 1024, "Usage": 0},
|
||||||
|
{"Offset": 1024, "Type": "UNKNOWN", "Size": 1024, "Usage": 0, "CustomData": "0000000000F5D987"},
|
||||||
|
{"Offset": 2048, "Type": "UNKNOWN", "Size": 1024, "Usage": 0, "Name": "SHEPURD"},
|
||||||
|
{"Offset": 3072, "Type": "UNKNOWN", "Size": 1024, "Usage": 0, "CustomData": "00000000018CE96A", "Name": "JOKER"},
|
||||||
|
{"Offset": 4096, "Type": "FREE", "Size": 33550336}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"DedicatedAllocations": [
|
||||||
|
{"Type": "UNKNOWN", "Size": 1024, "Usage": 0},
|
||||||
|
{"Type": "UNKNOWN", "Size": 1024, "Usage": 0, "CustomData": "0000000000F5D987"},
|
||||||
|
{"Type": "UNKNOWN", "Size": 1024, "Usage": 0, "Name": "SHEPURD"},
|
||||||
|
{"Type": "UNKNOWN", "Size": 1024, "Usage": 0, "CustomData": "00000000018CE96A", "Name": "JOKER"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Type 2": {
|
||||||
|
"PreferredBlockSize": 268435456,
|
||||||
|
"Blocks": {
|
||||||
|
},
|
||||||
|
"DedicatedAllocations": [
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Type 3": {
|
||||||
|
"PreferredBlockSize": 268435456,
|
||||||
|
"Blocks": {
|
||||||
|
"0": {
|
||||||
|
"MapRefCount": 0,
|
||||||
|
"TotalBytes": 33554432,
|
||||||
|
"UnusedBytes": 25153536,
|
||||||
|
"Allocations": 12,
|
||||||
|
"UnusedRanges": 2,
|
||||||
|
"Suballocations": [
|
||||||
|
{"Offset": 0, "Type": "BUFFER", "Size": 1024, "Usage": 3},
|
||||||
|
{"Offset": 1024, "Type": "BUFFER", "Size": 1024, "Usage": 3, "CustomData": "0000000000F5D987"},
|
||||||
|
{"Offset": 2048, "Type": "BUFFER", "Size": 1024, "Usage": 3, "Name": "SHEPURD"},
|
||||||
|
{"Offset": 3072, "Type": "BUFFER", "Size": 1024, "Usage": 3, "CustomData": "00000000018CE96A", "Name": "JOKER"},
|
||||||
|
{"Offset": 4096, "Type": "IMAGE_LINEAR", "Size": 2048, "Usage": 7},
|
||||||
|
{"Offset": 6144, "Type": "IMAGE_LINEAR", "Size": 2048, "Usage": 7, "CustomData": "0000000000F5D987"},
|
||||||
|
{"Offset": 8192, "Type": "IMAGE_LINEAR", "Size": 2048, "Usage": 7, "Name": "SHEPURD"},
|
||||||
|
{"Offset": 10240, "Type": "IMAGE_LINEAR", "Size": 2048, "Usage": 7, "CustomData": "00000000018CE96A", "Name": "JOKER"},
|
||||||
|
{"Offset": 12288, "Type": "FREE", "Size": 53248},
|
||||||
|
{"Offset": 65536, "Type": "IMAGE_OPTIMAL", "Size": 2097152, "Usage": 7},
|
||||||
|
{"Offset": 2162688, "Type": "IMAGE_OPTIMAL", "Size": 2097152, "Usage": 7, "CustomData": "0000000000F5D987"},
|
||||||
|
{"Offset": 4259840, "Type": "IMAGE_OPTIMAL", "Size": 2097152, "Usage": 7, "Name": "SHEPURD"},
|
||||||
|
{"Offset": 6356992, "Type": "IMAGE_OPTIMAL", "Size": 2097152, "Usage": 7, "CustomData": "00000000018CE96A", "Name": "JOKER"},
|
||||||
|
{"Offset": 8454144, "Type": "FREE", "Size": 25100288}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"DedicatedAllocations": [
|
||||||
|
{"Type": "BUFFER", "Size": 1024, "Usage": 3},
|
||||||
|
{"Type": "BUFFER", "Size": 1024, "Usage": 3, "CustomData": "0000000000F5D987"},
|
||||||
|
{"Type": "BUFFER", "Size": 1024, "Usage": 3, "Name": "SHEPURD"},
|
||||||
|
{"Type": "BUFFER", "Size": 1024, "Usage": 3, "CustomData": "00000000018CE96A", "Name": "JOKER"},
|
||||||
|
{"Type": "IMAGE_LINEAR", "Size": 2048, "Usage": 7},
|
||||||
|
{"Type": "IMAGE_LINEAR", "Size": 2048, "Usage": 7, "CustomData": "0000000000F5D987"},
|
||||||
|
{"Type": "IMAGE_LINEAR", "Size": 2048, "Usage": 7, "Name": "SHEPURD"},
|
||||||
|
{"Type": "IMAGE_LINEAR", "Size": 2048, "Usage": 7, "CustomData": "00000000018CE96A", "Name": "JOKER"},
|
||||||
|
{"Type": "IMAGE_OPTIMAL", "Size": 2097152, "Usage": 7},
|
||||||
|
{"Type": "IMAGE_OPTIMAL", "Size": 2097152, "Usage": 7, "CustomData": "0000000000F5D987"},
|
||||||
|
{"Type": "IMAGE_OPTIMAL", "Size": 2097152, "Usage": 7, "Name": "SHEPURD"},
|
||||||
|
{"Type": "IMAGE_OPTIMAL", "Size": 2097152, "Usage": 7, "CustomData": "00000000018CE96A", "Name": "JOKER"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Type 4": {
|
||||||
|
"PreferredBlockSize": 268435456,
|
||||||
|
"Blocks": {
|
||||||
|
},
|
||||||
|
"DedicatedAllocations": [
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Type 5": {
|
||||||
|
"PreferredBlockSize": 268435456,
|
||||||
|
"Blocks": {
|
||||||
|
},
|
||||||
|
"DedicatedAllocations": [
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Type 6": {
|
||||||
|
"PreferredBlockSize": 268435456,
|
||||||
|
"Blocks": {
|
||||||
|
},
|
||||||
|
"DedicatedAllocations": [
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Type 7": {
|
||||||
|
"PreferredBlockSize": 268435456,
|
||||||
|
"Blocks": {
|
||||||
|
},
|
||||||
|
"DedicatedAllocations": [
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"CustomPools": {
|
||||||
|
"Type 0": [
|
||||||
|
{
|
||||||
|
"Name": "0",
|
||||||
|
"PreferredBlockSize": 268435456,
|
||||||
|
"Blocks": {
|
||||||
|
"0": {
|
||||||
|
"MapRefCount": 0,
|
||||||
|
"TotalBytes": 33554432,
|
||||||
|
"UnusedBytes": 25149440,
|
||||||
|
"Allocations": 16,
|
||||||
|
"UnusedRanges": 2,
|
||||||
|
"Suballocations": [
|
||||||
|
{"Offset": 0, "Type": "UNKNOWN", "Size": 1024, "Usage": 0},
|
||||||
|
{"Offset": 1024, "Type": "UNKNOWN", "Size": 1024, "Usage": 0, "CustomData": "0000000000F5D987"},
|
||||||
|
{"Offset": 2048, "Type": "UNKNOWN", "Size": 1024, "Usage": 0, "Name": "SHEPURD"},
|
||||||
|
{"Offset": 3072, "Type": "UNKNOWN", "Size": 1024, "Usage": 0, "CustomData": "00000000018CE96A", "Name": "JOKER"},
|
||||||
|
{"Offset": 4096, "Type": "BUFFER", "Size": 1024, "Usage": 3},
|
||||||
|
{"Offset": 5120, "Type": "BUFFER", "Size": 1024, "Usage": 3, "CustomData": "0000000000F5D987"},
|
||||||
|
{"Offset": 6144, "Type": "BUFFER", "Size": 1024, "Usage": 3, "Name": "SHEPURD"},
|
||||||
|
{"Offset": 7168, "Type": "BUFFER", "Size": 1024, "Usage": 3, "CustomData": "00000000018CE96A", "Name": "JOKER"},
|
||||||
|
{"Offset": 8192, "Type": "IMAGE_LINEAR", "Size": 2048, "Usage": 7},
|
||||||
|
{"Offset": 10240, "Type": "IMAGE_LINEAR", "Size": 2048, "Usage": 7, "CustomData": "0000000000F5D987"},
|
||||||
|
{"Offset": 12288, "Type": "IMAGE_LINEAR", "Size": 2048, "Usage": 7, "Name": "SHEPURD"},
|
||||||
|
{"Offset": 14336, "Type": "IMAGE_LINEAR", "Size": 2048, "Usage": 7, "CustomData": "00000000018CE96A", "Name": "JOKER"},
|
||||||
|
{"Offset": 16384, "Type": "FREE", "Size": 49152},
|
||||||
|
{"Offset": 65536, "Type": "IMAGE_OPTIMAL", "Size": 2097152, "Usage": 7},
|
||||||
|
{"Offset": 2162688, "Type": "IMAGE_OPTIMAL", "Size": 2097152, "Usage": 7, "CustomData": "0000000000F5D987"},
|
||||||
|
{"Offset": 4259840, "Type": "IMAGE_OPTIMAL", "Size": 2097152, "Usage": 7, "Name": "SHEPURD"},
|
||||||
|
{"Offset": 6356992, "Type": "IMAGE_OPTIMAL", "Size": 2097152, "Usage": 7, "CustomData": "00000000018CE96A", "Name": "JOKER"},
|
||||||
|
{"Offset": 8454144, "Type": "FREE", "Size": 25100288}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"DedicatedAllocations": [
|
||||||
|
{"Type": "UNKNOWN", "Size": 1024, "Usage": 0},
|
||||||
|
{"Type": "UNKNOWN", "Size": 1024, "Usage": 0, "CustomData": "0000000000F5D987"},
|
||||||
|
{"Type": "UNKNOWN", "Size": 1024, "Usage": 0, "Name": "SHEPURD"},
|
||||||
|
{"Type": "UNKNOWN", "Size": 1024, "Usage": 0, "CustomData": "00000000018CE96A", "Name": "JOKER"},
|
||||||
|
{"Type": "BUFFER", "Size": 1024, "Usage": 3},
|
||||||
|
{"Type": "BUFFER", "Size": 1024, "Usage": 3, "CustomData": "0000000000F5D987"},
|
||||||
|
{"Type": "BUFFER", "Size": 1024, "Usage": 3, "Name": "SHEPURD"},
|
||||||
|
{"Type": "BUFFER", "Size": 1024, "Usage": 3, "CustomData": "00000000018CE96A", "Name": "JOKER"},
|
||||||
|
{"Type": "IMAGE_LINEAR", "Size": 2048, "Usage": 7},
|
||||||
|
{"Type": "IMAGE_LINEAR", "Size": 2048, "Usage": 7, "CustomData": "0000000000F5D987"},
|
||||||
|
{"Type": "IMAGE_LINEAR", "Size": 2048, "Usage": 7, "Name": "SHEPURD"},
|
||||||
|
{"Type": "IMAGE_LINEAR", "Size": 2048, "Usage": 7, "CustomData": "00000000018CE96A", "Name": "JOKER"},
|
||||||
|
{"Type": "IMAGE_OPTIMAL", "Size": 2097152, "Usage": 7},
|
||||||
|
{"Type": "IMAGE_OPTIMAL", "Size": 2097152, "Usage": 7, "CustomData": "0000000000F5D987"},
|
||||||
|
{"Type": "IMAGE_OPTIMAL", "Size": 2097152, "Usage": 7, "Name": "SHEPURD"},
|
||||||
|
{"Type": "IMAGE_OPTIMAL", "Size": 2097152, "Usage": 7, "CustomData": "00000000018CE96A", "Name": "JOKER"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Type 3": [
|
||||||
|
{
|
||||||
|
"Name": "0",
|
||||||
|
"PreferredBlockSize": 268435456,
|
||||||
|
"Blocks": {
|
||||||
|
"0": {
|
||||||
|
"MapRefCount": 0,
|
||||||
|
"TotalBytes": 33554432,
|
||||||
|
"UnusedBytes": 25149440,
|
||||||
|
"Allocations": 16,
|
||||||
|
"UnusedRanges": 2,
|
||||||
|
"Suballocations": [
|
||||||
|
{"Offset": 0, "Type": "UNKNOWN", "Size": 1024, "Usage": 0},
|
||||||
|
{"Offset": 1024, "Type": "UNKNOWN", "Size": 1024, "Usage": 0, "CustomData": "0000000000F5D987"},
|
||||||
|
{"Offset": 2048, "Type": "UNKNOWN", "Size": 1024, "Usage": 0, "Name": "SHEPURD"},
|
||||||
|
{"Offset": 3072, "Type": "UNKNOWN", "Size": 1024, "Usage": 0, "CustomData": "00000000018CE96A", "Name": "JOKER"},
|
||||||
|
{"Offset": 4096, "Type": "BUFFER", "Size": 1024, "Usage": 3},
|
||||||
|
{"Offset": 5120, "Type": "BUFFER", "Size": 1024, "Usage": 3, "CustomData": "0000000000F5D987"},
|
||||||
|
{"Offset": 6144, "Type": "BUFFER", "Size": 1024, "Usage": 3, "Name": "SHEPURD"},
|
||||||
|
{"Offset": 7168, "Type": "BUFFER", "Size": 1024, "Usage": 3, "CustomData": "00000000018CE96A", "Name": "JOKER"},
|
||||||
|
{"Offset": 8192, "Type": "IMAGE_LINEAR", "Size": 2048, "Usage": 7},
|
||||||
|
{"Offset": 10240, "Type": "IMAGE_LINEAR", "Size": 2048, "Usage": 7, "CustomData": "0000000000F5D987"},
|
||||||
|
{"Offset": 12288, "Type": "IMAGE_LINEAR", "Size": 2048, "Usage": 7, "Name": "SHEPURD"},
|
||||||
|
{"Offset": 14336, "Type": "IMAGE_LINEAR", "Size": 2048, "Usage": 7, "CustomData": "00000000018CE96A", "Name": "JOKER"},
|
||||||
|
{"Offset": 16384, "Type": "FREE", "Size": 49152},
|
||||||
|
{"Offset": 65536, "Type": "IMAGE_OPTIMAL", "Size": 2097152, "Usage": 7},
|
||||||
|
{"Offset": 2162688, "Type": "IMAGE_OPTIMAL", "Size": 2097152, "Usage": 7, "CustomData": "0000000000F5D987"},
|
||||||
|
{"Offset": 4259840, "Type": "IMAGE_OPTIMAL", "Size": 2097152, "Usage": 7, "Name": "SHEPURD"},
|
||||||
|
{"Offset": 6356992, "Type": "IMAGE_OPTIMAL", "Size": 2097152, "Usage": 7, "CustomData": "00000000018CE96A", "Name": "JOKER"},
|
||||||
|
{"Offset": 8454144, "Type": "FREE", "Size": 25100288}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"DedicatedAllocations": [
|
||||||
|
{"Type": "UNKNOWN", "Size": 1024, "Usage": 0},
|
||||||
|
{"Type": "UNKNOWN", "Size": 1024, "Usage": 0, "CustomData": "0000000000F5D987"},
|
||||||
|
{"Type": "UNKNOWN", "Size": 1024, "Usage": 0, "Name": "SHEPURD"},
|
||||||
|
{"Type": "UNKNOWN", "Size": 1024, "Usage": 0, "CustomData": "00000000018CE96A", "Name": "JOKER"},
|
||||||
|
{"Type": "BUFFER", "Size": 1024, "Usage": 3},
|
||||||
|
{"Type": "BUFFER", "Size": 1024, "Usage": 3, "CustomData": "0000000000F5D987"},
|
||||||
|
{"Type": "BUFFER", "Size": 1024, "Usage": 3, "Name": "SHEPURD"},
|
||||||
|
{"Type": "BUFFER", "Size": 1024, "Usage": 3, "CustomData": "00000000018CE96A", "Name": "JOKER"},
|
||||||
|
{"Type": "IMAGE_LINEAR", "Size": 2048, "Usage": 7},
|
||||||
|
{"Type": "IMAGE_LINEAR", "Size": 2048, "Usage": 7, "CustomData": "0000000000F5D987"},
|
||||||
|
{"Type": "IMAGE_LINEAR", "Size": 2048, "Usage": 7, "Name": "SHEPURD"},
|
||||||
|
{"Type": "IMAGE_LINEAR", "Size": 2048, "Usage": 7, "CustomData": "00000000018CE96A", "Name": "JOKER"},
|
||||||
|
{"Type": "IMAGE_OPTIMAL", "Size": 2097152, "Usage": 7},
|
||||||
|
{"Type": "IMAGE_OPTIMAL", "Size": 2097152, "Usage": 7, "CustomData": "0000000000F5D987"},
|
||||||
|
{"Type": "IMAGE_OPTIMAL", "Size": 2097152, "Usage": 7, "Name": "SHEPURD"},
|
||||||
|
{"Type": "IMAGE_OPTIMAL", "Size": 2097152, "Usage": 7, "CustomData": "00000000018CE96A", "Name": "JOKER"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|