D3D12: Added pipeline stats. (#3534)

This commit is contained in:
Branimir Karadžić
2026-01-06 20:44:12 -08:00
committed by GitHub
parent 80370936d0
commit d9d99f51ad
2 changed files with 150 additions and 29 deletions

View File

@@ -656,6 +656,8 @@ namespace bgfx { namespace d3d12
}
}
typedef HRESULT (WINAPI* PFN_D3D12_ENABLE_EXPERIMENTAL_FEATURES)(uint32_t _numFeatures, const IID* _iids, void* _configurationStructs, uint32_t* _configurationStructSizes);
#if USE_D3D12_DYNAMIC_LIB
static PFN_D3D12_ENABLE_EXPERIMENTAL_FEATURES D3D12EnableExperimentalFeatures;
static PFN_D3D12_CREATE_DEVICE D3D12CreateDevice;
@@ -4108,22 +4110,25 @@ namespace bgfx { namespace d3d12
queueDesc.Priority = 0;
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
queueDesc.NodeMask = 1;
DX_CHECK(_device->CreateCommandQueue(&queueDesc
DX_CHECK(_device->CreateCommandQueue(
&queueDesc
, IID_ID3D12CommandQueue
, (void**)&m_commandQueue
) );
m_completedFence = 0;
m_currentFence = 0;
DX_CHECK(_device->CreateFence(0
DX_CHECK(_device->CreateFence(
0
, D3D12_FENCE_FLAG_NONE
, IID_ID3D12Fence
, (void**)&m_fence
) );
for (uint32_t ii = 0; ii < BX_COUNTOF(m_commandList); ++ii)
for (uint32_t ii = 0; ii < kMaxCommandLists; ++ii)
{
DX_CHECK(_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT
DX_CHECK(_device->CreateCommandAllocator(
D3D12_COMMAND_LIST_TYPE_DIRECT
, IID_ID3D12CommandAllocator
, (void**)&m_commandList[ii].m_commandAllocator
) );
@@ -4138,6 +4143,30 @@ namespace bgfx { namespace d3d12
DX_CHECK(m_commandList[ii].m_commandList->Close() );
}
const D3D12_QUERY_HEAP_DESC queryHeapDesc =
{
.Type = D3D12_QUERY_HEAP_TYPE_PIPELINE_STATISTICS,
.Count = kMaxCommandLists,
.NodeMask = 1,
};
DX_CHECK(_device->CreateQueryHeap(
&queryHeapDesc
, IID_ID3D12QueryHeap
, (void**)&m_pipelineStatsQueryHeap
) );
setDebugObjectName(m_pipelineStatsQueryHeap, "Pipeline Statistics Query Heap");
m_pipelineStatsReadBack = createCommittedResource(_device, HeapProperty::ReadBack, kMaxCommandLists*sizeof(D3D12_QUERY_DATA_PIPELINE_STATISTICS) );
setDebugObjectName(m_pipelineStatsReadBack, "Pipeline Statistics Read-Back");
const D3D12_RANGE range =
{
.Begin = 0,
.End = kMaxCommandLists*sizeof(D3D12_QUERY_DATA_PIPELINE_STATISTICS),
};
m_pipelineStatsReadBack->Map(0, &range, (void**)&m_pipelineStats);
}
void CommandQueueD3D12::shutdown()
@@ -4146,13 +4175,22 @@ namespace bgfx { namespace d3d12
DX_RELEASE(m_fence, 0);
for (uint32_t ii = 0; ii < BX_COUNTOF(m_commandList); ++ii)
for (uint32_t ii = 0; ii < kMaxCommandLists; ++ii)
{
DX_RELEASE(m_commandList[ii].m_commandAllocator, 0);
DX_RELEASE(m_commandList[ii].m_commandList, 0);
}
DX_RELEASE(m_commandQueue, 0);
const D3D12_RANGE range =
{
.Begin = 0,
.End = kMaxCommandLists*sizeof(D3D12_QUERY_DATA_PIPELINE_STATISTICS),
};
m_pipelineStatsReadBack->Unmap(0, &range);
DX_RELEASE(m_pipelineStatsQueryHeap, 0);
DX_RELEASE(m_pipelineStatsReadBack, 0);
}
ID3D12GraphicsCommandList* CommandQueueD3D12::alloc()
@@ -4165,12 +4203,33 @@ namespace bgfx { namespace d3d12
CommandList& commandList = m_commandList[m_control.m_current];
DX_CHECK(commandList.m_commandAllocator->Reset() );
DX_CHECK(commandList.m_commandList->Reset(commandList.m_commandAllocator, NULL) );
commandList.m_commandList->BeginQuery(
m_pipelineStatsQueryHeap
, D3D12_QUERY_TYPE_PIPELINE_STATISTICS
, m_control.m_current
);
return commandList.m_commandList;
}
uint64_t CommandQueueD3D12::kick()
{
CommandList& commandList = m_commandList[m_control.m_current];
const uint32_t currentIdx = m_control.m_current;
CommandList& commandList = m_commandList[currentIdx];
commandList.m_commandList->EndQuery(
m_pipelineStatsQueryHeap
, D3D12_QUERY_TYPE_PIPELINE_STATISTICS
, currentIdx
);
commandList.m_commandList->ResolveQueryData(
m_pipelineStatsQueryHeap
, D3D12_QUERY_TYPE_PIPELINE_STATISTICS
, currentIdx
, 1
, m_pipelineStatsReadBack
, currentIdx*sizeof(D3D12_QUERY_DATA_PIPELINE_STATISTICS)
);
DX_CHECK(commandList.m_commandList->Close() );
ID3D12CommandList* commandLists[] = { commandList.m_commandList };
@@ -4247,6 +4306,8 @@ namespace bgfx { namespace d3d12
}
ra.clear();
m_pipelineStatsSum.add(m_pipelineStats[m_control.m_read]);
m_control.consume(1);
return true;
@@ -6138,24 +6199,32 @@ namespace bgfx { namespace d3d12
void TimerQueryD3D12::init()
{
D3D12_QUERY_HEAP_DESC queryHeapDesc;
queryHeapDesc.Count = m_control.m_size * 2;
queryHeapDesc.NodeMask = 1;
queryHeapDesc.Type = D3D12_QUERY_HEAP_TYPE_TIMESTAMP;
DX_CHECK(s_renderD3D12->m_device->CreateQueryHeap(&queryHeapDesc
ID3D12Device* device = s_renderD3D12->m_device;
D3D12_QUERY_HEAP_DESC queryHeapDesc =
{
.Type = D3D12_QUERY_HEAP_TYPE_TIMESTAMP,
.Count = m_control.m_size * 2,
.NodeMask = 1,
};
DX_CHECK(device->CreateQueryHeap(
&queryHeapDesc
, IID_ID3D12QueryHeap
, (void**)&m_queryHeap
) );
setDebugObjectName(m_queryHeap, "Timer Query Heap");
const uint32_t size = queryHeapDesc.Count*sizeof(uint64_t);
m_readback = createCommittedResource(s_renderD3D12->m_device
m_readback = createCommittedResource(device
, HeapProperty::ReadBack
, size
);
setDebugObjectName(m_readback, "Timer Query Read-Back");
DX_CHECK(s_renderD3D12->m_cmd.m_commandQueue->GetTimestampFrequency(&m_frequency) );
D3D12_RANGE range = { 0, size };
D3D12_RANGE range = { .Begin = 0, .End = size };
m_readback->Map(0, &range, (void**)&m_queryResult);
for (uint32_t ii = 0; ii < BX_COUNTOF(m_result); ++ii)
@@ -6178,6 +6247,8 @@ namespace bgfx { namespace d3d12
uint32_t TimerQueryD3D12::begin(uint32_t _resultIdx, uint32_t _frameNum)
{
ID3D12GraphicsCommandList* commandList = s_renderD3D12->m_commandList;
while (0 == m_control.reserve(1) )
{
m_control.consume(1);
@@ -6192,8 +6263,6 @@ namespace bgfx { namespace d3d12
query.m_ready = false;
query.m_frameNum = _frameNum;
ID3D12GraphicsCommandList* commandList = s_renderD3D12->m_commandList;
uint32_t offset = idx * 2 + 0;
commandList->EndQuery(m_queryHeap
, D3D12_QUERY_TYPE_TIMESTAMP
@@ -6207,13 +6276,13 @@ namespace bgfx { namespace d3d12
void TimerQueryD3D12::end(uint32_t _idx)
{
ID3D12GraphicsCommandList* commandList = s_renderD3D12->m_commandList;
Query& query = m_query[_idx];
query.m_ready = true;
query.m_fence = s_renderD3D12->m_cmd.m_currentFence - 1;
uint32_t offset = _idx * 2;
ID3D12GraphicsCommandList* commandList = s_renderD3D12->m_commandList;
commandList->EndQuery(m_queryHeap
, D3D12_QUERY_TYPE_TIMESTAMP
, offset + 1
@@ -6276,10 +6345,11 @@ namespace bgfx { namespace d3d12
) );
const uint32_t size = BX_COUNTOF(m_handle)*sizeof(uint64_t);
m_readback = createCommittedResource(s_renderD3D12->m_device
, HeapProperty::ReadBack
, size
);
m_readback = createCommittedResource(
s_renderD3D12->m_device
, HeapProperty::ReadBack
, size
);
D3D12_RANGE range = { 0, size };
m_readback->Map(0, &range, (void**)&m_result);
@@ -6527,9 +6597,6 @@ namespace bgfx { namespace d3d12
static ViewState viewState;
viewState.reset(_render);
// bool wireframe = !!(_render->m_debug&BGFX_DEBUG_WIREFRAME);
// setDebugWireframe(wireframe);
uint16_t currentSamplerStateIdx = kInvalidHandle;
ProgramHandle currentProgram = BGFX_INVALID_HANDLE;
uint32_t currentBindHash = 0;
@@ -7389,7 +7456,6 @@ namespace bgfx { namespace d3d12
{
BGFX_D3D12_PROFILER_BEGIN_LITERAL("debugstats", kColorFrame);
// m_needPresent = true;
TextVideoMem& tvm = m_textVideoMem;
static int64_t next = timeEnd;
@@ -7548,6 +7614,17 @@ namespace bgfx { namespace d3d12
);
pos++;
tvm.printf(10, pos++, 0x8b, " Pipeline Statistics:");
const CommandQueueD3D12::PipelineStats& pipelineStats = m_cmd.m_pipelineStatsSum;
tvm.printf(10, pos++, 0x8b, " IAVertices: %llu", pipelineStats.IAVertices);
tvm.printf(10, pos++, 0x8b, " IAPrimitives: %llu", pipelineStats.IAPrimitives);
tvm.printf(10, pos++, 0x8b, " VSInvocations: %llu", pipelineStats.VSInvocations);
tvm.printf(10, pos++, 0x8b, " CInvocations: %llu", pipelineStats.CInvocations);
tvm.printf(10, pos++, 0x8b, " CPrimitives: %llu", pipelineStats.CPrimitives);
tvm.printf(10, pos++, 0x8b, " PSInvocations: %llu", pipelineStats.PSInvocations);
tvm.printf(10, pos++, 0x8b, " CSInvocations: %llu", pipelineStats.CSInvocations);
pos++;
double captureMs = double(captureElapsed)*toMs;
tvm.printf(10, pos++, 0x8b, " Capture: %7.4f [ms] ", captureMs);
@@ -7616,6 +7693,7 @@ namespace bgfx { namespace d3d12
#endif // BX_PLATFORM_WINDOWS
m_backBufferColorFence[m_backBufferColorIdx] = kick();
m_cmd.m_pipelineStatsSum.reset();
}
} /* namespace d3d12 */ } // namespace bgfx

View File

@@ -77,8 +77,6 @@ extern "C" uint64_t WINAPI bgfx_PIXEventsReplaceBlock(PIXEven
namespace bgfx { namespace d3d12
{
typedef HRESULT (WINAPI* PFN_D3D12_ENABLE_EXPERIMENTAL_FEATURES)(uint32_t _numFeatures, const IID* _iids, void* _configurationStructs, uint32_t* _configurationStructSizes);
struct Rdt
{
enum Enum
@@ -372,6 +370,8 @@ namespace bgfx { namespace d3d12
struct CommandQueueD3D12
{
static constexpr uint32_t kMaxCommandLists = 256;
CommandQueueD3D12()
: m_currentFence(0)
, m_completedFence(0)
@@ -396,14 +396,57 @@ namespace bgfx { namespace d3d12
HANDLE m_event;
};
struct PipelineStats
{
PipelineStats()
{
reset();
}
void reset()
{
IAVertices = 0;
IAPrimitives = 0;
VSInvocations = 0;
CInvocations = 0;
CPrimitives = 0;
PSInvocations = 0;
CSInvocations = 0;
}
void add(const D3D12_QUERY_DATA_PIPELINE_STATISTICS& _stats)
{
IAVertices += _stats.IAVertices;
IAPrimitives += _stats.IAPrimitives;
VSInvocations += _stats.VSInvocations;
CInvocations += _stats.CInvocations;
CPrimitives += _stats.CPrimitives;
PSInvocations += _stats.PSInvocations;
CSInvocations += _stats.CSInvocations;
}
uint64_t IAVertices;
uint64_t IAPrimitives;
uint64_t VSInvocations;
uint64_t CInvocations;
uint64_t CPrimitives;
uint64_t PSInvocations;
uint64_t CSInvocations;
};
ID3D12CommandQueue* m_commandQueue;
uint64_t m_currentFence;
uint64_t m_completedFence;
ID3D12Fence* m_fence;
CommandList m_commandList[256];
CommandList m_commandList[kMaxCommandLists];
typedef stl::vector<ID3D12Resource*> ResourceArray;
ResourceArray m_release[256];
ResourceArray m_release[kMaxCommandLists];
bx::RingBufferControl m_control;
ID3D12Resource* m_pipelineStatsReadBack;
ID3D12QueryHeap* m_pipelineStatsQueryHeap;
D3D12_QUERY_DATA_PIPELINE_STATISTICS* m_pipelineStats;
PipelineStats m_pipelineStatsSum;
};
struct BatchD3D12