Fixes in JSON dump format. Fixes in GpuMemDumpVis.py regarding image height calculation.
Added GpuMemDump.schema.json.
diff --git a/src/D3D12MemAlloc.cpp b/src/D3D12MemAlloc.cpp
index d145c5c..2555ef6 100644
--- a/src/D3D12MemAlloc.cpp
+++ b/src/D3D12MemAlloc.cpp
@@ -27,6 +27,7 @@
#include <algorithm>
#include <utility>
#include <cstdlib>
+#include <cstdint>
#include <malloc.h> // for _aligned_malloc, _aligned_free
#ifndef _WIN32
#include <shared_mutex>
@@ -377,7 +378,15 @@
static T RoundDiv(T x, T y) { return (x + (y / (T)2)) / y; }
template <typename T>
static T DivideRoundingUp(T x, T y) { return (x + y - 1) / y; }
-
+
+static WCHAR HexDigitToChar(UINT8 digit)
+{
+ if(digit < 10)
+ return L'0' + digit;
+ else
+ return L'A' + (digit - 10);
+}
+
/*
Performs binary search and returns iterator to first element that is greater or
equal to `key`, according to comparison `cmp`.
@@ -1180,6 +1189,7 @@
void AddNewLine() { Add(L'\n'); }
void AddNumber(UINT num);
void AddNumber(UINT64 num);
+ void AddPointer(const void* ptr);
private:
Vector<WCHAR> m_Data;
@@ -1224,6 +1234,22 @@
while (num);
Add(p);
}
+
+void StringBuilder::AddPointer(const void* ptr)
+{
+ WCHAR buf[21];
+ uintptr_t num = (uintptr_t)ptr;
+ buf[20] = L'\0';
+ WCHAR *p = &buf[20];
+ do
+ {
+ *--p = HexDigitToChar((UINT8)(num & 0xF));
+ num >>= 4;
+ }
+ while (num);
+ Add(p);
+}
+
#endif // _D3D12MA_STRING_BUILDER_FUNCTIONS
#endif // _D3D12MA_STRING_BUILDER
@@ -1267,6 +1293,7 @@
// Posts next part of an open string. The number is converted to decimal characters.
void ContinueString(UINT num);
void ContinueString(UINT64 num);
+ void ContinueString_Pointer(const void* ptr);
// Posts next part of an open string. Pointer value is converted to characters
// using "%p" formatting - shown as hexadecimal number, e.g.: 000000081276Ad00
// void ContinueString_Pointer(const void* ptr);
@@ -1452,6 +1479,12 @@
m_SB.AddNumber(num);
}
+void JsonWriter::ContinueString_Pointer(const void* ptr)
+{
+ D3D12MA_ASSERT(m_InsideString);
+ m_SB.AddPointer(ptr);
+}
+
void JsonWriter::EndString(LPCWSTR pStr)
{
D3D12MA_ASSERT(m_InsideString);
@@ -1524,7 +1557,9 @@
if (privateData)
{
WriteString(L"CustomData");
- WriteNumber((uintptr_t)privateData);
+ BeginString();
+ ContinueString_Pointer(privateData);
+ EndString();
}
LPCWSTR name = alloc.GetName();
@@ -7196,9 +7231,6 @@
json.WriteString(L"DEFAULT");
json.BeginObject();
{
- json.WriteString(L"Flags");
- json.BeginArray(true);
- json.EndArray();
json.WriteString(L"Stats");
json.AddDetailedStatisticsInfoObject(stats.HeapType[0]);
}
@@ -7207,9 +7239,6 @@
json.WriteString(L"UPLOAD");
json.BeginObject();
{
- json.WriteString(L"Flags");
- json.BeginArray(true);
- json.EndArray();
json.WriteString(L"Stats");
json.AddDetailedStatisticsInfoObject(stats.HeapType[1]);
}
@@ -7218,9 +7247,6 @@
json.WriteString(L"READBACK");
json.BeginObject();
{
- json.WriteString(L"Flags");
- json.BeginArray(true);
- json.EndArray();
json.WriteString(L"Stats");
json.AddDetailedStatisticsInfoObject(stats.HeapType[2]);
}
@@ -7229,9 +7255,6 @@
json.WriteString(L"CUSTOM");
json.BeginObject();
{
- json.WriteString(L"Flags");
- json.BeginArray(true);
- json.EndArray();
json.WriteString(L"Stats");
json.AddDetailedStatisticsInfoObject(customHeaps[!IsUMA()]);
}
@@ -7245,13 +7268,6 @@
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);
@@ -7264,9 +7280,6 @@
json.WriteString(L"DEFAULT");
json.BeginObject();
{
- json.WriteString(L"Flags");
- json.BeginArray(true);
- json.EndArray();
json.WriteString(L"Stats");
json.AddDetailedStatisticsInfoObject(stats.HeapType[0]);
}
@@ -7275,9 +7288,6 @@
json.WriteString(L"CUSTOM");
json.BeginObject();
{
- json.WriteString(L"Flags");
- json.BeginArray(true);
- json.EndArray();
json.WriteString(L"Stats");
json.AddDetailedStatisticsInfoObject(customHeaps[0]);
}
diff --git a/src/Tests.cpp b/src/Tests.cpp
index 31804bb..1f77b87 100644
--- a/src/Tests.cpp
+++ b/src/Tests.cpp
@@ -322,10 +322,10 @@
}
}
-static void SaveStatsStringToFile(const TestContext& ctx, const wchar_t* dstFilePath)
+static void SaveStatsStringToFile(const TestContext& ctx, const wchar_t* dstFilePath, BOOL detailed = TRUE)
{
WCHAR* s = nullptr;
- ctx.allocator->BuildStatsString(&s, TRUE);
+ ctx.allocator->BuildStatsString(&s, detailed);
SaveFile(dstFilePath, s, wcslen(s) * sizeof(WCHAR));
ctx.allocator->FreeStatsString(s);
}
diff --git a/tools/GpuMemDumpVis/GpuMemDump.schema.json b/tools/GpuMemDumpVis/GpuMemDump.schema.json
new file mode 100644
index 0000000..4d3331c
--- /dev/null
+++ b/tools/GpuMemDumpVis/GpuMemDump.schema.json
@@ -0,0 +1,163 @@
+{
+ "$id": "https://gpuopen.com/vulkan-memory-allocator/schemas/GpuMemDump",
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "type": "object",
+ "properties": {
+ "General": {
+ "type": "object",
+ "properties": {
+ "API": {"type": "string", "enum": ["Vulkan", "Direct3D 12"]},
+ "GPU": {"type": "string"}
+ },
+ "required": ["API", "GPU"]
+ },
+ "Total": {"$ref": "#/$defs/Stats"},
+ "MemoryInfo": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "object",
+ "properties": {
+ "Flags": {
+ "type": "array",
+ "items": {"type": "string"}
+ },
+ "Size": {"type": "integer"},
+ "Budget": {
+ "type": "object",
+ "properties": {
+ "BudgetBytes": {"type": "integer"},
+ "UsageBytes": {"type": "integer"}
+ },
+ "additionalProperties": false
+ },
+ "Stats": {"$ref": "#/$defs/Stats"},
+ "MemoryPools": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "object",
+ "properties": {
+ "Flags": {
+ "type": "array",
+ "items": {"type": "string"}
+ },
+ "Stats": {"$ref": "#/$defs/Stats"}
+ },
+ "additionalProperties": false
+ }
+ }
+ },
+ "required": ["Budget", "Stats"],
+ "additionalProperties": false
+ }
+ },
+ "DefaultPools": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "object",
+ "properties": {
+ "PreferredBlockSize": {"type": "integer"},
+ "Blocks": {
+ "type": "object",
+ "propertyNames": {"pattern": "[0-9]+"},
+ "additionalProperties": {"$ref": "#/$defs/Block"}
+ },
+ "DedicatedAllocations": {
+ "type": "array",
+ "items": {"$ref": "#/$defs/DedicatedAllocation"}
+ }
+ }
+ }
+ },
+ "CustomPools": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "Name": {"type": "string"},
+ "Flags": {"type": "array"},
+ "PreferredBlockSize": {"type": "integer"},
+ "Blocks": {
+ "type": "object",
+ "additionalProperties": {"$ref": "#/$defs/Block"}
+ },
+ "DedicatedAllocations": {
+ "type": "array",
+ "items": {"$ref": "#/$defs/DedicatedAllocation"}
+ }
+ },
+ "required": ["PreferredBlockSize"],
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "required": ["General", "Total", "MemoryInfo"],
+ "additionalProperties": false,
+ "$defs": {
+ "CustomData": {
+ "type": "string",
+ "pattern": "^[0-9a-zA-Z]+$"
+ },
+ "Stats": {
+ "type": "object",
+ "properties": {
+ "BlockCount": {"type": "integer"},
+ "BlockBytes": {"type": "integer"},
+ "AllocationCount": {"type": "integer"},
+ "AllocationBytes": {"type": "integer"},
+ "UnusedRangeCount": {"type": "integer"},
+ "AllocationSizeMin": {"type": "integer"},
+ "AllocationSizeMax": {"type": "integer"},
+ "UnusedRangeSizeMin": {"type": "integer"},
+ "UnusedRangeSizeMax": {"type": "integer"}
+ },
+ "required": [
+ "BlockCount", "BlockBytes",
+ "AllocationCount", "AllocationBytes",
+ "UnusedRangeCount"
+ ],
+ "additionalProperties": false
+ },
+ "Block": {
+ "type": "object",
+ "properties": {
+ "MapRefCount": {"type": "integer"},
+ "TotalBytes": {"type": "integer"},
+ "UnusedBytes": {"type": "integer"},
+ "Allocations": {"type": "integer"},
+ "UnusedRanges": {"type": "integer"},
+ "Suballocations": {"type": "array", "items": {"$ref": "#/$defs/Suballocation"}}
+ },
+ "required": ["TotalBytes", "UnusedBytes", "Allocations", "UnusedRanges"]
+ },
+ "DedicatedAllocation": {
+ "type": "object",
+ "properties": {
+ "Type": {"type": "string"},
+ "Size": {"type": "integer"},
+ "Usage": {"type": "integer"},
+ "CustomData": {"$ref": "#/$defs/CustomData"},
+ "Name": {"type": "string"},
+ "Layout": {"type": "integer"}
+ },
+ "required": ["Type", "Size"],
+ "additionalProperties": false
+ },
+ "Suballocation": {
+ "type": "object",
+ "properties": {
+ "Offset": {"type": "integer"},
+ "Type": {"type": "string"},
+ "Size": {"type": "integer"},
+ "Usage": {"type": "integer"},
+ "CustomData": {"$ref": "#/$defs/CustomData"},
+ "Name": {"type": "string"},
+ "Layout": {"type": "integer"}
+ },
+ "required": ["Offset", "Type", "Size"],
+ "additionalProperties": false
+ }
+ }
+}
diff --git a/tools/GpuMemDumpVis/GpuMemDumpVis.py b/tools/GpuMemDumpVis/GpuMemDumpVis.py
index b225306..42800ea 100644
--- a/tools/GpuMemDumpVis/GpuMemDumpVis.py
+++ b/tools/GpuMemDumpVis/GpuMemDumpVis.py
@@ -106,9 +106,9 @@
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)
+ height += FONT_SIZE + IMG_MARGIN # Memory pool title
+ height += len(poolData['Blocks']) * (FONT_SIZE + MAP_SIZE + IMG_MARGIN * 2)
+ height += len(poolData['DedicatedAllocations']) * (FONT_SIZE + MAP_SIZE + IMG_MARGIN * 2)
# Get longest block size
for dedicatedAlloc in poolData['DedicatedAllocations']:
maxBlockSize = max(maxBlockSize, dedicatedAlloc['Size'])
@@ -116,16 +116,15 @@
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
+ height += len(customPoolData['Blocks']) * (FONT_SIZE + MAP_SIZE + IMG_MARGIN * 2)
+ height += len(customPoolData['DedicatedAllocations']) * (FONT_SIZE + MAP_SIZE + IMG_MARGIN * 2)
# 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)
+ return height, (IMG_WIDTH - IMG_MARGIN * 2) / float(maxBlockSize)
def BytesToStr(bytes):
if bytes < 1024:
@@ -306,7 +305,7 @@
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)
+ y += MAP_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)