From b7f9d5b6d0d5e2e5c4be320c0f15998a90663576 Mon Sep 17 00:00:00 2001 From: baldurk Date: Wed, 28 Jan 2015 21:15:19 +0000 Subject: [PATCH] Generalise drawcall timing to get arbitrary sets of counter values * Client code can enumerate the IDs of counters that are supported - some of these will be general, some will be IHV specific. It can also request descriptions of the counters to determine the type of data or units. This can be used to 'discover' counters that aren't hard coded into renderdoc. I'll want to at least reserve IHV ranges so that counter IDs are globally unique, and ideally IHV counters will also be predeclared where possible. * Also the refactor removes some ugly rdctype::array use outside of the replay layer and replaces it just with std::vector, which is a nice bonus. --- renderdoc/api/replay/data_types.h | 32 +- renderdoc/api/replay/renderdoc_replay.h | 5 +- renderdoc/api/replay/replay_enums.h | 26 ++ renderdoc/core/image_viewer.cpp | 17 +- renderdoc/core/replay_proxy.cpp | 118 +++++-- renderdoc/core/replay_proxy.h | 9 +- renderdoc/driver/d3d11/d3d11_analyse.cpp | 148 -------- renderdoc/driver/d3d11/d3d11_context.cpp | 2 - renderdoc/driver/d3d11/d3d11_context.h | 12 +- .../driver/d3d11/d3d11_context1_wrap.cpp | 2 - renderdoc/driver/d3d11/d3d11_counters.cpp | 320 ++++++++++++++++++ renderdoc/driver/d3d11/d3d11_debug.cpp | 4 + renderdoc/driver/d3d11/d3d11_debug.h | 33 +- renderdoc/driver/d3d11/d3d11_device.cpp | 74 +--- renderdoc/driver/d3d11/d3d11_replay.cpp | 21 +- renderdoc/driver/d3d11/d3d11_replay.h | 6 +- renderdoc/driver/gl/gl_driver.cpp | 10 +- renderdoc/driver/gl/gl_driver.h | 12 +- renderdoc/driver/gl/gl_replay.cpp | 21 +- renderdoc/driver/gl/gl_replay.h | 6 +- renderdoc/renderdoc.vcxproj | 1 + renderdoc/renderdoc.vcxproj.filters | 3 + renderdoc/replay/replay_driver.h | 8 +- renderdoc/replay/replay_renderer.cpp | 55 ++- renderdoc/replay/replay_renderer.h | 5 +- renderdocui/Code/Core.cs | 14 +- renderdocui/Interop/CustomMarshaling.cs | 8 + renderdocui/Interop/Enums.cs | 24 ++ renderdocui/Interop/FetchInfo.cs | 34 +- renderdocui/Interop/ReplayRenderer.cs | 85 ++++- renderdocui/Windows/EventBrowser.cs | 26 +- 31 files changed, 794 insertions(+), 347 deletions(-) create mode 100644 renderdoc/driver/d3d11/d3d11_counters.cpp diff --git a/renderdoc/api/replay/data_types.h b/renderdoc/api/replay/data_types.h index 1755db23c..5ec1cc0a0 100644 --- a/renderdoc/api/replay/data_types.h +++ b/renderdoc/api/replay/data_types.h @@ -171,7 +171,6 @@ struct FetchDrawcall indexByteWidth = 0; flags = 0; context = ResourceId(); - duration = -1.0f; parent = 0; previous = 0; next = 0; @@ -196,8 +195,6 @@ struct FetchDrawcall ResourceId context; - double duration; - int64_t parent; int64_t previous; @@ -215,6 +212,35 @@ struct APIProperties APIPipelineStateType pipelineType; }; +struct CounterDescription +{ + uint32_t counterID; + rdctype::str name; + rdctype::str description; + FormatComponentType resultCompType; + uint32_t resultByteWidth; + CounterUnits units; +}; + +struct CounterResult +{ + CounterResult() : eventID(0) , u64( 0) {} + CounterResult(uint32_t EID, uint32_t c, float data) : eventID(EID), counterID(c), f (data) {} + CounterResult(uint32_t EID, uint32_t c, double data) : eventID(EID), counterID(c), d (data) {} + CounterResult(uint32_t EID, uint32_t c, uint32_t data) : eventID(EID), counterID(c), u32(data) {} + CounterResult(uint32_t EID, uint32_t c, uint64_t data) : eventID(EID), counterID(c), u64(data) {} + + uint32_t eventID; + uint32_t counterID; + union + { + float f; + double d; + uint32_t u32; + uint64_t u64; + }; +}; + struct PixelValue { union diff --git a/renderdoc/api/replay/renderdoc_replay.h b/renderdoc/api/replay/renderdoc_replay.h index df761fe34..fa6a9bc3c 100644 --- a/renderdoc/api/replay/renderdoc_replay.h +++ b/renderdoc/api/replay/renderdoc_replay.h @@ -146,7 +146,10 @@ extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_RemoveReplacement(Re extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_FreeTargetResource(ReplayRenderer *rend, ResourceId id); extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetFrameInfo(ReplayRenderer *rend, rdctype::array *frame); -extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetDrawcalls(ReplayRenderer *rend, uint32_t frameID, bool32 includeTimes, rdctype::array *draws); +extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetDrawcalls(ReplayRenderer *rend, uint32_t frameID, rdctype::array *draws); +extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_FetchCounters(ReplayRenderer *rend, uint32_t frameID, uint32_t minEventID, uint32_t maxEventID, uint32_t *counters, uint32_t numCounters, rdctype::array *results); +extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_EnumerateCounters(ReplayRenderer *rend, rdctype::array *counters); +extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_DescribeCounter(ReplayRenderer *rend, uint32_t counterID, CounterDescription *desc); extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetTextures(ReplayRenderer *rend, rdctype::array *texs); extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetBuffers(ReplayRenderer *rend, rdctype::array *bufs); extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetResolve(ReplayRenderer *rend, uint64_t *callstack, uint32_t callstackLen, rdctype::array *trace); diff --git a/renderdoc/api/replay/replay_enums.h b/renderdoc/api/replay/replay_enums.h index e5b105bc7..721ae0ce4 100644 --- a/renderdoc/api/replay/replay_enums.h +++ b/renderdoc/api/replay/replay_enums.h @@ -389,6 +389,32 @@ enum TriangleCullMode eCull_FrontAndBack, }; +enum GPUCounters +{ + eCounter_FirstGeneric = 1, + eCounter_EventGPUDuration = eCounter_FirstGeneric, + eCounter_InputVerticesRead, + eCounter_VSInvocations, + eCounter_PSInvocations, + eCounter_RasterizedPrimitives, + eCounter_SamplesWritten, + + // IHV specific counters can be set above this point + // with ranges reserved for each IHV + eCounter_FirstAMD = 1000000, + + eCounter_FirstIntel = 2000000, + + eCounter_FirstNvidia = 3000000, +}; + +enum CounterUnits +{ + eUnits_Absolute, + eUnits_Seconds, + eUnits_Percentage, +}; + enum ReplayCreateStatus { eReplayCreate_Success = 0, diff --git a/renderdoc/core/image_viewer.cpp b/renderdoc/core/image_viewer.cpp index daf83b379..6a62357a6 100644 --- a/renderdoc/core/image_viewer.cpp +++ b/renderdoc/core/image_viewer.cpp @@ -46,12 +46,13 @@ class ImageViewer : public IReplayDriver record.frameInfo.frameNumber = 1; record.frameInfo.immContextId = ResourceId(); - create_array_uninit(record.drawcallList, 1); - RDCEraseEl(record.drawcallList[0]); - record.drawcallList[0].context = record.frameInfo.immContextId; - record.drawcallList[0].drawcallID = 1; - record.drawcallList[0].eventID = 1; - record.drawcallList[0].name = filename; + FetchDrawcall d; + d.context = record.frameInfo.immContextId; + d.drawcallID = 1; + d.eventID = 1; + d.name = filename; + + record.drawcallList.push_back(d); create_array_uninit(m_PipelineState.m_OM.RenderTargets, 1); m_PipelineState.m_OM.RenderTargets[0].Resource = texID; @@ -114,7 +115,9 @@ class ImageViewer : public IReplayDriver vector GetUsage(ResourceId id) { return vector(); } bool IsRenderOutput(ResourceId id) { return false; } ResourceId GetLiveID(ResourceId id) { return id; } - void TimeDrawcalls(rdctype::array &arr) {} + vector EnumerateCounters() { return vector(); } + void DescribeCounter(uint32_t counterID, CounterDescription &desc) { RDCEraseEl(desc); desc.counterID = counterID; } + vector FetchCounters(uint32_t frameID, uint32_t minEventID, uint32_t maxEventID, const vector &counters) { return vector(); } void FillCBufferVariables(ResourceId shader, uint32_t cbufSlot, vector &outvars, const vector &data) {} vector GetBufferData(ResourceId buff, uint32_t offset, uint32_t len) { return vector(); } void InitPostVSBuffers(uint32_t frameID, uint32_t eventID) {} diff --git a/renderdoc/core/replay_proxy.cpp b/renderdoc/core/replay_proxy.cpp index e85e98214..821146769 100644 --- a/renderdoc/core/replay_proxy.cpp +++ b/renderdoc/core/replay_proxy.cpp @@ -769,8 +769,6 @@ void Serialiser::Serialise(const char *name, FetchDrawcall &el) Serialise("", el.context); - Serialise("", el.duration); - Serialise("", el.parent); Serialise("", el.previous); Serialise("", el.next); @@ -781,7 +779,7 @@ void Serialiser::Serialise(const char *name, FetchDrawcall &el) Serialise("", el.events); Serialise("", el.children); - SIZE_CHECK(FetchDrawcall, 176); + SIZE_CHECK(FetchDrawcall, 168); } template<> @@ -790,7 +788,7 @@ void Serialiser::Serialise(const char *name, FetchFrameRecord &el) Serialise("", el.frameInfo); Serialise("", el.drawcallList); - SIZE_CHECK(FetchFrameRecord, 48); + SIZE_CHECK(FetchFrameRecord, 56); } template<> @@ -816,6 +814,19 @@ void Serialiser::Serialise(const char *name, MeshFormat &el) SIZE_CHECK(MeshFormat, 72); } +template<> +void Serialiser::Serialise(const char *name, CounterDescription &el) +{ + Serialise("", el.counterID); + Serialise("", el.name); + Serialise("", el.description); + Serialise("", el.resultCompType); + Serialise("", el.resultByteWidth); + Serialise("", el.units); + + SIZE_CHECK(CounterDescription, 32); +} + template<> void Serialiser::Serialise(const char *name, PixelModification &el) { @@ -856,6 +867,8 @@ string ToStrHelper::Get(const SpecialFormat &el) { return template<> string ToStrHelper::Get(const FormatComponentType &el) { return "<...>"; } template<> +string ToStrHelper::Get(const CounterUnits &el) { return "<...>"; } +template<> string ToStrHelper::Get(const PrimitiveTopology &el) { return "<...>"; } template<> string ToStrHelper::Get(const ShaderStageType &el) { return "<...>"; } @@ -914,6 +927,8 @@ string ToStrHelper::Get(const GLPipelineState::Hi template<> string ToStrHelper::Get(const EventUsage &el) { return "<...>"; } template<> +string ToStrHelper::Get(const CounterResult &el) { return "<...>"; } +template<> string ToStrHelper::Get(const FetchFrameInfo &el) { return "<...>"; } template<> string ToStrHelper::Get(const ReplayLogType &el) { return "<...>"; } @@ -1066,10 +1081,19 @@ bool ProxySerialiser::Tick() case eCommand_FreeResource: FreeTargetResource(ResourceId()); break; - case eCommand_TimeDrawcalls: + case eCommand_FetchCounters: { - rdctype::array l; - TimeDrawcalls(l); + vector counters; + FetchCounters(0, 0, 0, counters); + break; + } + case eCommand_EnumerateCounters: + EnumerateCounters(); + break; + case eCommand_DescribeCounter: + { + CounterDescription desc; + DescribeCounter(0, desc); break; } case eCommand_FillCBufferVariables: @@ -1432,44 +1456,64 @@ ResourceId ProxySerialiser::GetLiveID(ResourceId id) return ret; } -void ProxySerialiser::CopyDrawcallTimes(rdctype::array &src, rdctype::array &dst) +vector ProxySerialiser::FetchCounters(uint32_t frameID, uint32_t minEventID, uint32_t maxEventID, const vector &counters) { - RDCASSERT(src.count == dst.count); - - if(src.count == 0 || dst.count == 0) - return; - - for(int32_t i=0; i < dst.count && i < src.count; i++) - { - CopyDrawcallTimes(src[i].children, dst[i].children); - dst[i].duration = src[i].duration; - } -} - -void ProxySerialiser::TimeDrawcalls(rdctype::array &arr) -{ - m_ToReplaySerialiser->Serialise("", arr); + vector ret; + + m_ToReplaySerialiser->Serialise("", frameID); + m_ToReplaySerialiser->Serialise("", minEventID); + m_ToReplaySerialiser->Serialise("", maxEventID); + m_ToReplaySerialiser->Serialise("", (vector &)counters); if(m_ReplayHost) { - m_Remote->TimeDrawcalls(arr); - - m_FromReplaySerialiser->Serialise("", arr); + ret = m_Remote->FetchCounters(frameID, minEventID, maxEventID, counters); } else { - if(!SendReplayCommand(eCommand_TimeDrawcalls)) - return; - - // need to serialise into a dummy list then copy the times as TimeDrawcalls - // expects to modify only the times of the drawcalls in place, whereas - // serialise would completely trash the list! - rdctype::array dummy; - - m_FromReplaySerialiser->Serialise("", dummy); - - CopyDrawcallTimes(dummy, arr); + if(!SendReplayCommand(eCommand_FetchCounters)) + return ret; } + + m_FromReplaySerialiser->Serialise("", ret); + + return ret; +} + +vector ProxySerialiser::EnumerateCounters() +{ + vector ret; + + if(m_ReplayHost) + { + ret = m_Remote->EnumerateCounters(); + } + else + { + if(!SendReplayCommand(eCommand_EnumerateCounters)) + return ret; + } + + m_FromReplaySerialiser->Serialise("", ret); + + return ret; +} + +void ProxySerialiser::DescribeCounter(uint32_t counterID, CounterDescription &desc) +{ + m_ToReplaySerialiser->Serialise("", counterID); + + if(m_ReplayHost) + { + m_Remote->DescribeCounter(counterID, desc); + } + else + { + if(!SendReplayCommand(eCommand_DescribeCounter)) + return; + } + + m_FromReplaySerialiser->Serialise("", desc); return; } diff --git a/renderdoc/core/replay_proxy.h b/renderdoc/core/replay_proxy.h index 881c2dbf3..5a5c01f25 100644 --- a/renderdoc/core/replay_proxy.h +++ b/renderdoc/core/replay_proxy.h @@ -53,7 +53,9 @@ enum CommandPacketType eCommand_FreeResource, eCommand_HasResolver, - eCommand_TimeDrawcalls, + eCommand_FetchCounters, + eCommand_EnumerateCounters, + eCommand_DescribeCounter, eCommand_FillCBufferVariables, eCommand_InitPostVS, @@ -313,7 +315,9 @@ class ProxySerialiser : public IReplayDriver, Callstack::StackResolver ResourceId GetLiveID(ResourceId id); - void TimeDrawcalls(rdctype::array &arr); + vector EnumerateCounters(); + void DescribeCounter(uint32_t counterID, CounterDescription &desc); + vector FetchCounters(uint32_t frameID, uint32_t minEventID, uint32_t maxEventID, const vector &counterID); void FillCBufferVariables(ResourceId shader, uint32_t cbufSlot, vector &outvars, const vector &data); @@ -369,7 +373,6 @@ class ProxySerialiser : public IReplayDriver, Callstack::StackResolver private: bool SendReplayCommand(CommandPacketType type); - void CopyDrawcallTimes(rdctype::array &src, rdctype::array &dst); void EnsureTexCached(ResourceId texid, uint32_t arrayIdx, uint32_t mip); void EnsureBufCached(ResourceId bufid); diff --git a/renderdoc/driver/d3d11/d3d11_analyse.cpp b/renderdoc/driver/d3d11/d3d11_analyse.cpp index 716944282..51f5939cc 100644 --- a/renderdoc/driver/d3d11/d3d11_analyse.cpp +++ b/renderdoc/driver/d3d11/d3d11_analyse.cpp @@ -2310,154 +2310,6 @@ byte *D3D11DebugManager::GetTextureData(ResourceId id, uint32_t arrayIdx, uint32 return ret; } -void D3D11DebugManager::FillTimers(uint32_t frameID, uint32_t &eventStart, rdctype::array &draws, vector &timers, int &reuseIdx) -{ - const D3D11_QUERY_DESC qdesc = { D3D11_QUERY_TIMESTAMP, 0 }; - - if(draws.count == 0) return; - - for(int32_t i=0; i < draws.count; i++) - { - FetchDrawcall &d = draws[i]; - FillTimers(frameID, eventStart, d.children, timers, reuseIdx); - - if(d.events.count == 0) continue; - - GPUTimer *timer = NULL; - - if(reuseIdx == -1) - { - timers.push_back(GPUTimer()); - - timer = &timers.back(); - timer->drawcall = &d; - } - else - { - timer = &timers[reuseIdx++]; - } - - HRESULT hr = S_OK; - - if(reuseIdx == -1) - { - timer->before = timer->after = NULL; - - hr = m_pDevice->CreateQuery(&qdesc, &timer->before); - RDCASSERT(SUCCEEDED(hr)); - hr = m_pDevice->CreateQuery(&qdesc, &timer->after); - RDCASSERT(SUCCEEDED(hr)); - } - - m_WrappedDevice->ReplayLog(frameID, eventStart, d.eventID, eReplay_WithoutDraw); - - m_pImmediateContext->Flush(); - - if(timer->before && timer->after) - { - m_pImmediateContext->End(timer->before); - m_WrappedDevice->ReplayLog(frameID, eventStart, d.eventID, eReplay_OnlyDraw); - m_pImmediateContext->End(timer->after); - } - else - { - m_WrappedDevice->ReplayLog(frameID, eventStart, d.eventID, eReplay_OnlyDraw); - } - - eventStart = d.eventID+1; - } -} - -void D3D11DebugManager::TimeDrawcalls(rdctype::array &arr) -{ - SCOPED_TIMER("Drawcall timing"); - - vector timers; - - D3D11_QUERY_DESC disjointdesc = { D3D11_QUERY_TIMESTAMP_DISJOINT, 0 }; - ID3D11Query *disjoint = NULL; - - D3D11_QUERY_DESC qdesc = { D3D11_QUERY_TIMESTAMP, 0 }; - ID3D11Query *start = NULL; - - HRESULT hr = S_OK; - - hr = m_pDevice->CreateQuery(&disjointdesc, &disjoint); - if(FAILED(hr)) - { - RDCERR("Failed to create disjoint query %08x", hr); - return; - } - - hr = m_pDevice->CreateQuery(&qdesc, &start); - if(FAILED(hr)) - { - RDCERR("Failed to create start query %08x", hr); - return; - } - - for(int loop=0; loop < 1; loop++) - { - { - m_pImmediateContext->Begin(disjoint); - - m_pImmediateContext->End(start); - - uint32_t ev = 0; - int reuse = loop == 0 ? -1 : 0; - FillTimers(0, ev, arr, timers, reuse); - - m_pImmediateContext->End(disjoint); - } - - { - D3D11_QUERY_DATA_TIMESTAMP_DISJOINT disjointData; - do - { - hr = m_pImmediateContext->GetData(disjoint, &disjointData, sizeof(D3D11_QUERY_DATA_TIMESTAMP_DISJOINT), 0); - } while(hr == S_FALSE); - RDCASSERT(hr == S_OK); - - RDCASSERT(!disjointData.Disjoint); - - double ticksToSecs = double(disjointData.Frequency); - - UINT64 a=0; - m_pImmediateContext->GetData(start, &a, sizeof(UINT64), 0); - - for(size_t i=0; i < timers.size(); i++) - { - if(timers[i].before && timers[i].after) - { - hr = m_pImmediateContext->GetData(timers[i].before, &a, sizeof(UINT64), 0); - RDCASSERT(hr == S_OK); - - UINT64 b=0; - hr = m_pImmediateContext->GetData(timers[i].after, &b, sizeof(UINT64), 0); - RDCASSERT(hr == S_OK); - - timers[i].drawcall->duration = (double(b-a)/ticksToSecs); - - a = b; - } - else - { - timers[i].drawcall->duration = 0.0; - } - } - } - } - - for(size_t i=0; i < timers.size(); i++) - { - SAFE_RELEASE(timers[i].before); - SAFE_RELEASE(timers[i].after); - } - - SAFE_RELEASE(disjoint); - SAFE_RELEASE(start); -} - ResourceId D3D11DebugManager::ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip) { TextureShaderDetails details = GetShaderDetails(texid, false); diff --git a/renderdoc/driver/d3d11/d3d11_context.cpp b/renderdoc/driver/d3d11/d3d11_context.cpp index 1f52a915e..61422ba4c 100644 --- a/renderdoc/driver/d3d11/d3d11_context.cpp +++ b/renderdoc/driver/d3d11/d3d11_context.cpp @@ -1242,8 +1242,6 @@ void WrappedID3D11DeviceContext::ReplayLog(LogState readType, uint32_t startEven m_pDevice->GetFrameRecord().back().drawcallList = m_ParentDrawcall.Bake(); m_pDevice->GetFrameRecord().back().frameInfo.debugMessages = m_pDevice->GetDebugMessages(); - m_ParentDrawcall.children.clear(); - int initialSkips = 0; for(auto it=WrappedID3D11Buffer::m_BufferList.begin(); it != WrappedID3D11Buffer::m_BufferList.end(); ++it) diff --git a/renderdoc/driver/d3d11/d3d11_context.h b/renderdoc/driver/d3d11/d3d11_context.h index c0184288b..483a89e97 100644 --- a/renderdoc/driver/d3d11/d3d11_context.h +++ b/renderdoc/driver/d3d11/d3d11_context.h @@ -114,16 +114,16 @@ struct DrawcallTreeNode FetchDrawcall draw; vector children; - rdctype::array Bake() + vector Bake() { - rdctype::array ret; + vector ret; if(children.empty()) return ret; - create_array_uninit(ret, children.size()); + ret.resize(children.size()); for(size_t i=0; i < children.size(); i++) { - ret.elems[i] = children[i].draw; - ret.elems[i].children = children[i].Bake(); + ret[i] = children[i].draw; + ret[i].children = children[i].Bake(); } return ret; @@ -287,6 +287,8 @@ public: uint32_t GetEventID() { return m_CurEventID; } FetchAPIEvent GetEvent(uint32_t eventID); + + const DrawcallTreeNode &GetRootDraw() { return m_ParentDrawcall; } void ThreadSafe_SetMarker(uint32_t col, const wchar_t *name); int ThreadSafe_BeginEvent(uint32_t col, const wchar_t *name); diff --git a/renderdoc/driver/d3d11/d3d11_context1_wrap.cpp b/renderdoc/driver/d3d11/d3d11_context1_wrap.cpp index cb77e3951..ece717e65 100644 --- a/renderdoc/driver/d3d11/d3d11_context1_wrap.cpp +++ b/renderdoc/driver/d3d11/d3d11_context1_wrap.cpp @@ -410,8 +410,6 @@ bool WrappedID3D11DeviceContext::Serialise_ClearView(ID3D11View *pView, const FL draw.flags |= eDraw_Clear; - draw.duration = 0.1f; - AddDrawcall(draw, true); } diff --git a/renderdoc/driver/d3d11/d3d11_counters.cpp b/renderdoc/driver/d3d11/d3d11_counters.cpp new file mode 100644 index 000000000..573e37b86 --- /dev/null +++ b/renderdoc/driver/d3d11/d3d11_counters.cpp @@ -0,0 +1,320 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2015 Baldur Karlsson + * + * 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. + ******************************************************************************/ + +#include "common/common.h" +#include "d3d11_debug.h" +#include "d3d11_device.h" +#include "d3d11_context.h" + +#if defined(ENABLE_NVIDIA_PERFKIT) +#define NVPM_INITGUID +#include STRINGIZE(CONCAT(NVIDIA_PERFKIT_DIR, inc\\NvPmApi.h)) + +NvPmApi *nvAPI = NULL; + +int enumFunc(NVPMCounterID id, const char *name) +{ + RDCLOG("(% 4d): %s", id, name); + + return NVPM_OK; +} +#endif + +void D3D11DebugManager::PreDeviceInitCounters() +{ +} + +void D3D11DebugManager::PostDeviceInitCounters() +{ +#if defined(ENABLE_NVIDIA_PERFKIT) + HMODULE nvapi = LoadLibraryA(STRINGIZE(CONCAT(NVIDIA_PERFKIT_DIR, bin\\win7_x86\\NvPmApi.Core.dll))); + if(nvapi == NULL) + { + RDCERR("Couldn't load perfkit"); + return; + } + + NVPMGetExportTable_Pfn NVPMGetExportTable = (NVPMGetExportTable_Pfn)GetProcAddress(nvapi, "NVPMGetExportTable"); + if(NVPMGetExportTable == NULL) + { + RDCERR("Couldn't Get Symbol 'NVPMGetExportTable'"); + return; + } + + NVPMRESULT nvResult = NVPMGetExportTable(&ETID_NvPmApi, (void **)&nvAPI); + if(nvResult != NVPM_OK) + { + RDCERR("Couldn't NVPMGetExportTable"); + return; + } + + nvResult = nvAPI->Init(); + + if(nvResult != NVPM_OK) + { + RDCERR("Couldn't nvAPI->Init"); + return; + } + + NVPMContext context(0); + nvResult = nvAPI->CreateContextFromD3D11Device(m_pDevice, &context); + + if(nvResult != NVPM_OK) + { + RDCERR("Couldn't nvAPI->CreateContextFromD3D11Device"); + return; + } + + nvAPI->EnumCountersByContext(context, &enumFunc); + + nvAPI->DestroyContext(context); + nvAPI->Shutdown(); + nvAPI = NULL; + FreeLibrary(nvapi); +#endif +} + +void D3D11DebugManager::PreDeviceShutdownCounters() +{ +} + +void D3D11DebugManager::PostDeviceShutdownCounters() +{ +} + +vector D3D11DebugManager::EnumerateCounters() +{ + vector ret; + + ret.push_back(eCounter_EventGPUDuration); + + return ret; +} + +void D3D11DebugManager::DescribeCounter(uint32_t counterID, CounterDescription &desc) +{ + desc.counterID = counterID; + + if(counterID == eCounter_EventGPUDuration) + { + desc.name = "GPU Duration"; + desc.description = "Time taken for this event on the GPU, as measured by delta between two GPU timestamps."; + desc.resultByteWidth = 8; + desc.resultCompType = eCompType_Double; + desc.units = eUnits_Seconds; + } + else + { + desc.name = "Unknown"; + desc.description = "Unknown counter ID"; + desc.resultByteWidth = 0; + desc.resultCompType = eCompType_None; + desc.units = eUnits_Absolute; + } +} + +struct GPUTimer +{ + ID3D11Query *before; + ID3D11Query *after; + uint32_t eventID; +}; + +struct CounterContext +{ + uint32_t frameID; + uint32_t minEID; + uint32_t maxEID; + uint32_t eventStart; + vector timers; + int reuseIdx; +}; + +void D3D11DebugManager::FillTimers(CounterContext &ctx, const DrawcallTreeNode &drawnode) +{ + const D3D11_QUERY_DESC qdesc = { D3D11_QUERY_TIMESTAMP, 0 }; + + if(drawnode.children.empty()) return; + + for(size_t i=0; i < drawnode.children.size(); i++) + { + const FetchDrawcall &d = drawnode.children[i].draw; + FillTimers(ctx, drawnode.children[i]); + + if(d.events.count == 0) continue; + + GPUTimer *timer = NULL; + + HRESULT hr = S_OK; + + bool includeEvent = (d.eventID >= ctx.minEID && d.eventID <= ctx.maxEID); + + if(includeEvent) + { + if(ctx.reuseIdx == -1) + { + ctx.timers.push_back(GPUTimer()); + + timer = &ctx.timers.back(); + timer->eventID = d.eventID; + timer->before = timer->after = NULL; + + hr = m_pDevice->CreateQuery(&qdesc, &timer->before); + RDCASSERT(SUCCEEDED(hr)); + hr = m_pDevice->CreateQuery(&qdesc, &timer->after); + RDCASSERT(SUCCEEDED(hr)); + } + else + { + timer = &ctx.timers[ctx.reuseIdx++]; + } + } + + m_WrappedDevice->ReplayLog(ctx.frameID, ctx.eventStart, d.eventID, eReplay_WithoutDraw); + + m_pImmediateContext->Flush(); + + if(includeEvent && timer->before && timer->after) + { + m_pImmediateContext->End(timer->before); + m_WrappedDevice->ReplayLog(ctx.frameID, ctx.eventStart, d.eventID, eReplay_OnlyDraw); + m_pImmediateContext->End(timer->after); + } + else + { + m_WrappedDevice->ReplayLog(ctx.frameID, ctx.eventStart, d.eventID, eReplay_OnlyDraw); + } + + ctx.eventStart = d.eventID+1; + } +} + +vector D3D11DebugManager::FetchCounters(uint32_t frameID, uint32_t minEventID, uint32_t maxEventID, const vector &counters) +{ + vector ret; + + if(counters.empty()) + { + RDCERR("No counters specified to FetchCounters"); + return ret; + } + + uint32_t counterID = counters[0]; + RDCASSERT(counters.size() == 1); + RDCASSERT(counterID == eCounter_EventGPUDuration); + + SCOPED_TIMER("Fetch Counters over %u-%u for %u", minEventID, maxEventID, counterID); + + D3D11_QUERY_DESC disjointdesc = { D3D11_QUERY_TIMESTAMP_DISJOINT, 0 }; + ID3D11Query *disjoint = NULL; + + D3D11_QUERY_DESC qdesc = { D3D11_QUERY_TIMESTAMP, 0 }; + ID3D11Query *start = NULL; + + HRESULT hr = S_OK; + + hr = m_pDevice->CreateQuery(&disjointdesc, &disjoint); + if(FAILED(hr)) + { + RDCERR("Failed to create disjoint query %08x", hr); + return ret; + } + + hr = m_pDevice->CreateQuery(&qdesc, &start); + if(FAILED(hr)) + { + RDCERR("Failed to create start query %08x", hr); + return ret; + } + + CounterContext ctx; + ctx.frameID = frameID; + ctx.minEID = minEventID; + ctx.maxEID = maxEventID; + + for(int loop=0; loop < 1; loop++) + { + { + m_pImmediateContext->Begin(disjoint); + + m_pImmediateContext->End(start); + + ctx.eventStart = 0; + ctx.reuseIdx = loop == 0 ? -1 : 0; + FillTimers(ctx, m_WrappedContext->GetRootDraw()); + + m_pImmediateContext->End(disjoint); + } + + { + D3D11_QUERY_DATA_TIMESTAMP_DISJOINT disjointData; + do + { + hr = m_pImmediateContext->GetData(disjoint, &disjointData, sizeof(D3D11_QUERY_DATA_TIMESTAMP_DISJOINT), 0); + } while(hr == S_FALSE); + RDCASSERT(hr == S_OK); + + RDCASSERT(!disjointData.Disjoint); + + double ticksToSecs = double(disjointData.Frequency); + + UINT64 a=0; + m_pImmediateContext->GetData(start, &a, sizeof(UINT64), 0); + + for(size_t i=0; i < ctx.timers.size(); i++) + { + if(ctx.timers[i].before && ctx.timers[i].after) + { + hr = m_pImmediateContext->GetData(ctx.timers[i].before, &a, sizeof(UINT64), 0); + RDCASSERT(hr == S_OK); + + UINT64 b=0; + hr = m_pImmediateContext->GetData(ctx.timers[i].after, &b, sizeof(UINT64), 0); + RDCASSERT(hr == S_OK); + + double duration = (double(b-a)/ticksToSecs); + + ret.push_back(CounterResult(ctx.timers[i].eventID, counterID, duration)); + + a = b; + } + else + { + ret.push_back(CounterResult(ctx.timers[i].eventID, counterID, 0.0)); + } + } + } + } + + for(size_t i=0; i < ctx.timers.size(); i++) + { + SAFE_RELEASE(ctx.timers[i].before); + SAFE_RELEASE(ctx.timers[i].after); + } + + SAFE_RELEASE(disjoint); + SAFE_RELEASE(start); + + return ret; +} \ No newline at end of file diff --git a/renderdoc/driver/d3d11/d3d11_debug.cpp b/renderdoc/driver/d3d11/d3d11_debug.cpp index 1ebd44577..e2be42738 100644 --- a/renderdoc/driver/d3d11/d3d11_debug.cpp +++ b/renderdoc/driver/d3d11/d3d11_debug.cpp @@ -273,12 +273,16 @@ D3D11DebugManager::D3D11DebugManager(WrappedID3D11Device *wrapper) InitFontRendering(); m_CacheShaders = false; + + PostDeviceInitCounters(); RenderDoc::Inst().SetProgress(DebugManagerInit, 1.0f); } D3D11DebugManager::~D3D11DebugManager() { + PreDeviceShutdownCounters(); + if(m_ShaderCacheDirty) { string shadercache = FileIO::GetAppFolderFilename("shaders.cache"); diff --git a/renderdoc/driver/d3d11/d3d11_debug.h b/renderdoc/driver/d3d11/d3d11_debug.h index 512881e24..02276e5a0 100644 --- a/renderdoc/driver/d3d11/d3d11_debug.h +++ b/renderdoc/driver/d3d11/d3d11_debug.h @@ -27,6 +27,10 @@ #include +#include +#include +#include +using std::map; using std::pair; #include "api/replay/renderdoc_replay.h" @@ -39,17 +43,14 @@ class Vec3f; class WrappedID3D11Device; class WrappedID3D11DeviceContext; +struct DrawcallTreeNode; + +struct CounterContext; + class D3D11ResourceManager; namespace ShaderDebug { struct GlobalState; } -struct GPUTimer -{ - ID3D11Query *before; - ID3D11Query *after; - FetchDrawcall *drawcall; -}; - struct PostVSData { struct StageData @@ -131,8 +132,16 @@ class D3D11DebugManager void CopyArrayToTex2DMS(ID3D11Texture2D *destMS, ID3D11Texture2D *srcArray); void CopyTex2DMSToArray(ID3D11Texture2D *destArray, ID3D11Texture2D *srcMS); + + // called before any device is created, to init any counters + static void PreDeviceInitCounters(); - void TimeDrawcalls(rdctype::array &arr); + // called after any device is destroyed, to do corresponding shutdown of counters + static void PostDeviceShutdownCounters(); + + vector EnumerateCounters(); + void DescribeCounter(uint32_t counterID, CounterDescription &desc); + vector FetchCounters(uint32_t frameID, uint32_t minEventID, uint32_t maxEventID, const vector &counters); void RenderText(float x, float y, const char *textfmt, ...); void RenderMesh(uint32_t frameID, uint32_t eventID, const vector &secondaryDraws, MeshDisplay cfg); @@ -527,7 +536,13 @@ class D3D11DebugManager const vector &data); friend struct ShaderDebugState; - void FillTimers(uint32_t frameID, uint32_t &eventStart, rdctype::array &draws, vector &timers, int &reuseIdx); + // called after the device is created, to init any counters + void PostDeviceInitCounters(); + + // called before the device is shutdown, to shutdown any counters + void PreDeviceShutdownCounters(); + + void FillTimers(CounterContext &ctx, const DrawcallTreeNode &drawnode); void FillCBuffer(ID3D11Buffer *buf, float *data, size_t size); }; \ No newline at end of file diff --git a/renderdoc/driver/d3d11/d3d11_device.cpp b/renderdoc/driver/d3d11/d3d11_device.cpp index fac3b664a..698ec3ea3 100644 --- a/renderdoc/driver/d3d11/d3d11_device.cpp +++ b/renderdoc/driver/d3d11/d3d11_device.cpp @@ -630,22 +630,6 @@ HRESULT WrappedID3D11Device::QueryInterface(REFIID riid, void **ppvObject) return m_RefCounter.QueryInterface(riid, ppvObject); } -#if defined(ENABLE_NVIDIA_PERFKIT) -#define NVPM_INITGUID -#include STRINGIZE(CONCAT(NVIDIA_PERFKIT_DIR, inc\\NvPmApi.h)) - -NvPmApi *nvAPI = NULL; -#endif - -#if defined(ENABLE_NVIDIA_PERFKIT) -int enumFunc(NVPMCounterID id, const char *name) -{ - RDCLOG("(% 4d): %s", id, name); - - return NVPM_OK; -} -#endif - const char *WrappedID3D11Device::GetChunkName(uint32_t idx) { if(idx < FIRST_CHUNK_ID || idx >= NUM_D3D11_CHUNKS) @@ -656,57 +640,7 @@ const char *WrappedID3D11Device::GetChunkName(uint32_t idx) void WrappedID3D11Device::LazyInit() { if(m_DebugManager == NULL) - { m_DebugManager = new D3D11DebugManager(this); - -#if defined(ENABLE_NVIDIA_PERFKIT) - - HMODULE nvapi = LoadLibraryA(STRINGIZE(CONCAT(NVIDIA_PERFKIT_DIR, bin\\win7_x86\\NvPmApi.Core.dll))); - if(nvapi == NULL) - { - RDCERR("Couldn't load perfkit"); - return; - } - - NVPMGetExportTable_Pfn NVPMGetExportTable = (NVPMGetExportTable_Pfn)GetProcAddress(nvapi, "NVPMGetExportTable"); - if(NVPMGetExportTable == NULL) - { - RDCERR("Couldn't Get Symbol 'NVPMGetExportTable'"); - return; - } - - NVPMRESULT nvResult = NVPMGetExportTable(&ETID_NvPmApi, (void **)&nvAPI); - if(nvResult != NVPM_OK) - { - RDCERR("Couldn't NVPMGetExportTable"); - return; - } - - nvResult = nvAPI->Init(); - - if(nvResult != NVPM_OK) - { - RDCERR("Couldn't nvAPI->Init"); - return; - } - - NVPMContext context(0); - nvResult = nvAPI->CreateContextFromD3D11Device(m_pDevice, &context); - - if(nvResult != NVPM_OK) - { - RDCERR("Couldn't nvAPI->CreateContextFromD3D11Device"); - return; - } - - nvAPI->EnumCountersByContext(context, &enumFunc); - - nvAPI->DestroyContext(context); - nvAPI->Shutdown(); - nvAPI = NULL; - FreeLibrary(nvapi); -#endif - } } void WrappedID3D11Device::AddDebugMessage(DebugMessageCategory c, DebugMessageSeverity sv, DebugMessageSource src, std::string d) @@ -3482,11 +3416,11 @@ const FetchDrawcall *WrappedID3D11Device::GetDrawcall(uint32_t frameID, uint32_t if(frameID >= m_FrameRecord.size()) return NULL; - int32_t count = m_FrameRecord[frameID].drawcallList.count; - for(int32_t i=0; i < count; i++) + size_t count = m_FrameRecord[frameID].drawcallList.size(); + for(size_t i=0; i < count; i++) { - const FetchDrawcall *cur = &m_FrameRecord[frameID].drawcallList.elems[i]; - const FetchDrawcall *next = i+1 < count ? &m_FrameRecord[frameID].drawcallList.elems[i+1] : NULL; + const FetchDrawcall *cur = &m_FrameRecord[frameID].drawcallList[i]; + const FetchDrawcall *next = i+1 < count ? &m_FrameRecord[frameID].drawcallList[i+1] : NULL; if(next && next->eventID <= eventID) continue; diff --git a/renderdoc/driver/d3d11/d3d11_replay.cpp b/renderdoc/driver/d3d11/d3d11_replay.cpp index 1090d6767..6cebc28f0 100644 --- a/renderdoc/driver/d3d11/d3d11_replay.cpp +++ b/renderdoc/driver/d3d11/d3d11_replay.cpp @@ -24,6 +24,7 @@ #include "d3d11_device.h" +#include "d3d11_debug.h" #include "d3d11_context.h" #include "d3d11_resources.h" #include "d3d11_renderstate.h" @@ -44,6 +45,8 @@ D3D11Replay::D3D11Replay() void D3D11Replay::Shutdown() { m_pDevice->Release(); + + D3D11DebugManager::PostDeviceShutdownCounters(); } FetchTexture D3D11Replay::GetTexture(ResourceId id) @@ -1287,9 +1290,19 @@ void D3D11Replay::RemoveReplacement(ResourceId id) m_pDevice->GetResourceManager()->RemoveReplacement(id); } -void D3D11Replay::TimeDrawcalls(rdctype::array &arr) +vector D3D11Replay::EnumerateCounters() { - return m_pDevice->GetDebugManager()->TimeDrawcalls(arr); + return m_pDevice->GetDebugManager()->EnumerateCounters(); +} + +void D3D11Replay::DescribeCounter(uint32_t counterID, CounterDescription &desc) +{ + m_pDevice->GetDebugManager()->DescribeCounter(counterID, desc); +} + +vector D3D11Replay::FetchCounters(uint32_t frameID, uint32_t minEventID, uint32_t maxEventID, const vector &counters) +{ + return m_pDevice->GetDebugManager()->FetchCounters(frameID, minEventID, maxEventID, counters); } void D3D11Replay::RenderMesh(uint32_t frameID, uint32_t eventID, const vector &secondaryDraws, MeshDisplay cfg) @@ -1803,6 +1816,8 @@ ReplayCreateStatus D3D11_CreateReplayDevice(const char *logfile, IReplayDriver * return eReplayCreate_APIHardwareUnsupported; } + D3D11DebugManager::PreDeviceInitCounters(); + hr = E_FAIL; while(1) { @@ -1853,6 +1868,8 @@ ReplayCreateStatus D3D11_CreateReplayDevice(const char *logfile, IReplayDriver * } } + D3D11DebugManager::PostDeviceShutdownCounters(); + RDCERR("Couldn't create any compatible d3d11 device :(."); return eReplayCreate_APIHardwareUnsupported; diff --git a/renderdoc/driver/d3d11/d3d11_replay.h b/renderdoc/driver/d3d11/d3d11_replay.h index 433d4fafe..72699dd4f 100644 --- a/renderdoc/driver/d3d11/d3d11_replay.h +++ b/renderdoc/driver/d3d11/d3d11_replay.h @@ -95,8 +95,10 @@ class D3D11Replay : public IReplayDriver void BuildTargetShader(string source, string entry, const uint32_t compileFlags, ShaderStageType type, ResourceId *id, string *errors); void ReplaceResource(ResourceId from, ResourceId to); void RemoveReplacement(ResourceId id); - - void TimeDrawcalls(rdctype::array &arr); + + vector EnumerateCounters(); + void DescribeCounter(uint32_t counterID, CounterDescription &desc); + vector FetchCounters(uint32_t frameID, uint32_t minEventID, uint32_t maxEventID, const vector &counters); ResourceId CreateProxyTexture(FetchTexture templateTex); void SetProxyTextureData(ResourceId texid, uint32_t arrayIdx, uint32_t mip, byte *data, size_t dataSize); diff --git a/renderdoc/driver/gl/gl_driver.cpp b/renderdoc/driver/gl/gl_driver.cpp index bcafb1095..55c424347 100644 --- a/renderdoc/driver/gl/gl_driver.cpp +++ b/renderdoc/driver/gl/gl_driver.cpp @@ -2938,8 +2938,6 @@ void WrappedOpenGL::ContextReplayLog(LogState readType, uint32_t startEventID, u { GetFrameRecord().back().drawcallList = m_ParentDrawcall.Bake(); GetFrameRecord().back().frameInfo.debugMessages = GetDebugMessages(); - - m_ParentDrawcall.children.clear(); } GetResourceManager()->MarkInFrame(false); @@ -3151,11 +3149,11 @@ const FetchDrawcall *WrappedOpenGL::GetDrawcall(uint32_t frameID, uint32_t event if(frameID >= m_FrameRecord.size()) return NULL; - int32_t count = m_FrameRecord[frameID].drawcallList.count; - for(int32_t i=0; i < count; i++) + size_t count = m_FrameRecord[frameID].drawcallList.size(); + for(size_t i=0; i < count; i++) { - const FetchDrawcall *cur = &m_FrameRecord[frameID].drawcallList.elems[i]; - const FetchDrawcall *next = i+1 < count ? &m_FrameRecord[frameID].drawcallList.elems[i+1] : NULL; + const FetchDrawcall *cur = &m_FrameRecord[frameID].drawcallList[i]; + const FetchDrawcall *next = i+1 < count ? &m_FrameRecord[frameID].drawcallList[i+1] : NULL; if(next && next->eventID <= eventID) continue; diff --git a/renderdoc/driver/gl/gl_driver.h b/renderdoc/driver/gl/gl_driver.h index 46cb63943..fe29b5b8b 100644 --- a/renderdoc/driver/gl/gl_driver.h +++ b/renderdoc/driver/gl/gl_driver.h @@ -69,17 +69,17 @@ struct DrawcallTreeNode vector children; DrawcallTreeNode &operator =(FetchDrawcall d) { *this = DrawcallTreeNode(d); return *this; } - - rdctype::array Bake() + + vector Bake() { - rdctype::array ret; + vector ret; if(children.empty()) return ret; - create_array_uninit(ret, children.size()); + ret.resize(children.size()); for(size_t i=0; i < children.size(); i++) { - ret.elems[i] = children[i].draw; - ret.elems[i].children = children[i].Bake(); + ret[i] = children[i].draw; + ret[i].children = children[i].Bake(); } return ret; diff --git a/renderdoc/driver/gl/gl_replay.cpp b/renderdoc/driver/gl/gl_replay.cpp index 70d05a457..57b991d00 100644 --- a/renderdoc/driver/gl/gl_replay.cpp +++ b/renderdoc/driver/gl/gl_replay.cpp @@ -2199,9 +2199,26 @@ void GLReplay::RemoveReplacement(ResourceId id) RDCUNIMPLEMENTED("RemoveReplacement"); } -void GLReplay::TimeDrawcalls(rdctype::array &arr) +vector GLReplay::EnumerateCounters() { - RDCUNIMPLEMENTED("TimeDrawcalls"); + GLNOTIMP("EnumerateCounters"); + return vector(); +} + +void GLReplay::DescribeCounter(uint32_t counterID, CounterDescription &desc) +{ + desc.counterID = counterID; + desc.name = "Unsupported"; + desc.description = "Counters are not implemented on OpenGL yet"; + desc.resultByteWidth = 0; + desc.resultCompType = eCompType_None; + desc.units = eUnits_Absolute; +} + +vector GLReplay::FetchCounters(uint32_t frameID, uint32_t minEventID, uint32_t maxEventID, const vector &counters) +{ + RDCUNIMPLEMENTED("FetchCounters"); + return vector(); } void GLReplay::BuildTargetShader(string source, string entry, const uint32_t compileFlags, ShaderStageType type, ResourceId *id, string *errors) diff --git a/renderdoc/driver/gl/gl_replay.h b/renderdoc/driver/gl/gl_replay.h index 93e38cdcc..4feb2c2eb 100644 --- a/renderdoc/driver/gl/gl_replay.h +++ b/renderdoc/driver/gl/gl_replay.h @@ -138,8 +138,10 @@ class GLReplay : public IReplayDriver void ReplaceResource(ResourceId from, ResourceId to); void RemoveReplacement(ResourceId id); - - void TimeDrawcalls(rdctype::array &arr); + + vector EnumerateCounters(); + void DescribeCounter(uint32_t counterID, CounterDescription &desc); + vector FetchCounters(uint32_t frameID, uint32_t minEventID, uint32_t maxEventID, const vector &counters); void RenderMesh(uint32_t frameID, uint32_t eventID, const vector &secondaryDraws, MeshDisplay cfg); diff --git a/renderdoc/renderdoc.vcxproj b/renderdoc/renderdoc.vcxproj index a1b6c5f18..bd2656870 100644 --- a/renderdoc/renderdoc.vcxproj +++ b/renderdoc/renderdoc.vcxproj @@ -302,6 +302,7 @@ + diff --git a/renderdoc/renderdoc.vcxproj.filters b/renderdoc/renderdoc.vcxproj.filters index e8a767bfa..d2a788469 100644 --- a/renderdoc/renderdoc.vcxproj.filters +++ b/renderdoc/renderdoc.vcxproj.filters @@ -545,6 +545,9 @@ 3rdparty\tinyexr + + Drivers\D3D11 + diff --git a/renderdoc/replay/replay_driver.h b/renderdoc/replay/replay_driver.h index 228115609..733061682 100644 --- a/renderdoc/replay/replay_driver.h +++ b/renderdoc/replay/replay_driver.h @@ -34,7 +34,7 @@ struct FetchFrameRecord { FetchFrameInfo frameInfo; - rdctype::array drawcallList; + vector drawcallList; }; // these two interfaces define what an API driver implementation must provide @@ -90,8 +90,10 @@ class IRemoteDriver virtual void ReplaceResource(ResourceId from, ResourceId to) = 0; virtual void RemoveReplacement(ResourceId id) = 0; virtual void FreeTargetResource(ResourceId id) = 0; - - virtual void TimeDrawcalls(rdctype::array &arr) = 0; + + virtual vector EnumerateCounters() = 0; + virtual void DescribeCounter(uint32_t counterID, CounterDescription &desc) = 0; + virtual vector FetchCounters(uint32_t frameID, uint32_t minEventID, uint32_t maxEventID, const vector &counterID) = 0; virtual void FillCBufferVariables(ResourceId shader, uint32_t cbufSlot, vector &outvars, const vector &data) = 0; diff --git a/renderdoc/replay/replay_renderer.cpp b/renderdoc/replay/replay_renderer.cpp index f9a82015d..feb9b807e 100644 --- a/renderdoc/replay/replay_renderer.cpp +++ b/renderdoc/replay/replay_renderer.cpp @@ -253,22 +253,51 @@ FetchDrawcall *ReplayRenderer::GetDrawcallByEID(uint32_t eventID, uint32_t defEv return m_Drawcalls[ev]; } -bool ReplayRenderer::GetDrawcalls(uint32_t frameID, bool includeTimes, rdctype::array *draws) +bool ReplayRenderer::GetDrawcalls(uint32_t frameID, rdctype::array *draws) { if(frameID >= (uint32_t)m_FrameRecord.size() || draws == NULL) return false; - if(includeTimes) - { - RDCDEBUG("Timing drawcalls..."); - - m_pDevice->TimeDrawcalls(m_FrameRecord[frameID].m_DrawCallList); - } - *draws = m_FrameRecord[frameID].m_DrawCallList; return true; } +bool ReplayRenderer::FetchCounters(uint32_t frameID, uint32_t minEventID, uint32_t maxEventID, + uint32_t *counters, uint32_t numCounters, rdctype::array *results) +{ + if(frameID >= (uint32_t)m_FrameRecord.size() || results == NULL) + return false; + + vector counterArray; + counterArray.reserve(numCounters); + for(uint32_t i=0; i < numCounters; i++) + counterArray.push_back(counters[i]); + + *results = m_pDevice->FetchCounters(frameID, minEventID, maxEventID, counterArray); + + return true; +} + +bool ReplayRenderer::EnumerateCounters(rdctype::array *counters) +{ + if(counters == NULL) + return false; + + *counters = m_pDevice->EnumerateCounters(); + + return true; +} + +bool ReplayRenderer::DescribeCounter(uint32_t counterID, CounterDescription *desc) +{ + if(desc == NULL) + return false; + + m_pDevice->DescribeCounter(counterID, *desc); + + return true; +} + bool ReplayRenderer::GetBuffers(rdctype::array *out) { if(m_Buffers.empty()) @@ -1492,8 +1521,14 @@ extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_FreeTargetResource(R extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetFrameInfo(ReplayRenderer *rend, rdctype::array *frame) { return rend->GetFrameInfo(frame); } -extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetDrawcalls(ReplayRenderer *rend, uint32_t frameID, bool32 includeTimes, rdctype::array *draws) -{ return rend->GetDrawcalls(frameID, includeTimes != 0, draws); } +extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetDrawcalls(ReplayRenderer *rend, uint32_t frameID, rdctype::array *draws) +{ return rend->GetDrawcalls(frameID, draws); } +extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_FetchCounters(ReplayRenderer *rend, uint32_t frameID, uint32_t minEventID, uint32_t maxEventID, uint32_t *counters, uint32_t numCounters, rdctype::array *results) +{ return rend->FetchCounters(frameID, minEventID, maxEventID, counters, numCounters, results); } +extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_EnumerateCounters(ReplayRenderer *rend, rdctype::array *counters) +{ return rend->EnumerateCounters(counters); } +extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_DescribeCounter(ReplayRenderer *rend, uint32_t counterID, CounterDescription *desc) +{ return rend->DescribeCounter(counterID, desc); } extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetTextures(ReplayRenderer *rend, rdctype::array *texs) { return rend->GetTextures(texs); } extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetBuffers(ReplayRenderer *rend, rdctype::array *bufs) diff --git a/renderdoc/replay/replay_renderer.h b/renderdoc/replay/replay_renderer.h index ae8207488..1cb7a45cd 100644 --- a/renderdoc/replay/replay_renderer.h +++ b/renderdoc/replay/replay_renderer.h @@ -154,7 +154,10 @@ struct ReplayRenderer bool FreeTargetResource(ResourceId id); bool GetFrameInfo(rdctype::array *frame); - bool GetDrawcalls(uint32_t frameID, bool includeTimes, rdctype::array *draws); + bool GetDrawcalls(uint32_t frameID, rdctype::array *draws); + bool FetchCounters(uint32_t frameID, uint32_t minEventID, uint32_t maxEventID, uint32_t *counters, uint32_t numCounters, rdctype::array *results); + bool EnumerateCounters(rdctype::array *counters); + bool DescribeCounter(uint32_t counterID, CounterDescription *desc); bool GetTextures(rdctype::array *texs); bool GetBuffers(rdctype::array *bufs); bool GetResolve(uint64_t *callstack, uint32_t callstackLen, rdctype::array *trace); diff --git a/renderdocui/Code/Core.cs b/renderdocui/Code/Core.cs index 5cb3278d3..31c8ad034 100644 --- a/renderdocui/Code/Core.cs +++ b/renderdocui/Code/Core.cs @@ -488,9 +488,7 @@ namespace renderdocui.Code postloadProgress = 0.4f; for (int i = 0; i < m_FrameInfo.Length; i++) - m_DrawCalls[i] = FakeProfileMarkers(i, r.GetDrawcalls((UInt32)i, false)); - - m_TimedDrawcalls = false; + m_DrawCalls[i] = FakeProfileMarkers(i, r.GetDrawcalls((UInt32)i)); postloadProgress = 0.7f; @@ -608,16 +606,6 @@ namespace renderdocui.Code #region Log drawcalls - private bool m_TimedDrawcalls = false; - public void TimeDrawcalls(ReplayRenderer r) - { - if (m_TimedDrawcalls) return; - m_TimedDrawcalls = true; - - for (int i = 0; i < m_FrameInfo.Length; i++) - m_DrawCalls[i] = FakeProfileMarkers(i, r.GetDrawcalls((UInt32)i, true)); - } - public FetchDrawcall[] GetDrawcalls(UInt32 frameIdx) { if (m_DrawCalls == null) return null; diff --git a/renderdocui/Interop/CustomMarshaling.cs b/renderdocui/Interop/CustomMarshaling.cs index 8e203e23f..438e395ca 100644 --- a/renderdocui/Interop/CustomMarshaling.cs +++ b/renderdocui/Interop/CustomMarshaling.cs @@ -107,6 +107,14 @@ namespace renderdoc return mem; } + public static IntPtr Alloc(Type T, int arraylen) + { + IntPtr mem = Marshal.AllocHGlobal(CustomMarshal.SizeOf(T)*arraylen); + FillMemory(mem, CustomMarshal.SizeOf(T) * arraylen, 0); + + return mem; + } + public static IntPtr MakeUTF8String(string s) { int len = System.Text.Encoding.UTF8.GetByteCount(s); diff --git a/renderdocui/Interop/Enums.cs b/renderdocui/Interop/Enums.cs index 0e41e9392..ff0febdbc 100644 --- a/renderdocui/Interop/Enums.cs +++ b/renderdocui/Interop/Enums.cs @@ -387,6 +387,30 @@ namespace renderdoc FrontAndBack, }; + public enum GPUCounters + { + FirstGeneric = 1, + EventGPUDuration = FirstGeneric, + InputVerticesRead, + VSInvocations, + PSInvocations, + RasterizedPrimitives, + SamplesWritten, + + FirstAMD = 1000000, + + FirstIntel = 2000000, + + FirstNvidia = 3000000, + }; + + public enum CounterUnits + { + Absolute, + Seconds, + Percentage, + }; + public enum ReplayCreateStatus { Success = 0, diff --git a/renderdocui/Interop/FetchInfo.cs b/renderdocui/Interop/FetchInfo.cs index a43335b77..b36e79476 100644 --- a/renderdocui/Interop/FetchInfo.cs +++ b/renderdocui/Interop/FetchInfo.cs @@ -335,8 +335,6 @@ namespace renderdoc public ResourceId context; - public double duration; - public Int64 parentDrawcall; public Int64 previousDrawcall; public Int64 nextDrawcall; @@ -491,6 +489,38 @@ namespace renderdoc public APIPipelineStateType pipelineType; }; + [StructLayout(LayoutKind.Sequential)] + public class CounterDescription + { + public UInt32 counterID; + [CustomMarshalAs(CustomUnmanagedType.UTF8TemplatedString)] + public string name; + [CustomMarshalAs(CustomUnmanagedType.UTF8TemplatedString)] + public string description; + public FormatComponentType resultCompType; + public UInt32 resultByteWidth; + public CounterUnits units; + }; + + [StructLayout(LayoutKind.Sequential)] + public class CounterResult + { + public UInt32 eventID; + public UInt32 counterID; + + [StructLayout(LayoutKind.Sequential)] + public struct ValueUnion + { + public float f; + public double d; + public UInt32 u32; + public UInt64 u64; + }; + + [CustomMarshalAs(CustomUnmanagedType.Union)] + public ValueUnion value; + }; + [StructLayout(LayoutKind.Sequential)] public class PixelValue { diff --git a/renderdocui/Interop/ReplayRenderer.cs b/renderdocui/Interop/ReplayRenderer.cs index 77783eff9..4f681d17e 100644 --- a/renderdocui/Interop/ReplayRenderer.cs +++ b/renderdocui/Interop/ReplayRenderer.cs @@ -209,7 +209,13 @@ namespace renderdoc [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayRenderer_GetFrameInfo(IntPtr real, IntPtr outframe); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] - private static extern bool ReplayRenderer_GetDrawcalls(IntPtr real, UInt32 frameID, bool includeTimes, IntPtr outdraws); + private static extern bool ReplayRenderer_GetDrawcalls(IntPtr real, UInt32 frameID, IntPtr outdraws); + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayRenderer_FetchCounters(IntPtr real, UInt32 frameID, UInt32 minEventID, UInt32 maxEventID, IntPtr counters, UInt32 numCounters, IntPtr outresults); + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayRenderer_EnumerateCounters(IntPtr real, IntPtr outcounters); + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern bool ReplayRenderer_DescribeCounter(IntPtr real, UInt32 counter, IntPtr outdesc); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern bool ReplayRenderer_GetTextures(IntPtr real, IntPtr outtexs); [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] @@ -428,11 +434,84 @@ namespace renderdoc } } - public FetchDrawcall[] GetDrawcalls(UInt32 frameID, bool includeTimes) + public Dictionary> FetchCounters(UInt32 frameID, UInt32 minEventID, UInt32 maxEventID, UInt32[] counters) { IntPtr mem = CustomMarshal.Alloc(typeof(templated_array)); - bool success = ReplayRenderer_GetDrawcalls(m_Real, frameID, includeTimes, mem); + IntPtr countersmem = CustomMarshal.Alloc(typeof(UInt32), counters.Length); + + // there's no Marshal.Copy for uint[], which is stupid. + for (int i = 0; i < counters.Length; i++) + Marshal.WriteInt32(countersmem, sizeof(UInt32) * i, (int)counters[i]); + + bool success = ReplayRenderer_FetchCounters(m_Real, frameID, minEventID, maxEventID, countersmem, (uint)counters.Length, mem); + + CustomMarshal.Free(countersmem); + + Dictionary> ret = null; + + if (success) + { + CounterResult[] resultArray = (CounterResult[])CustomMarshal.GetTemplatedArray(mem, typeof(CounterResult), true); + + // fixup previous/next/parent pointers + ret = new Dictionary>(); + + foreach (var result in resultArray) + { + if (!ret.ContainsKey(result.eventID)) + ret.Add(result.eventID, new List()); + + ret[result.eventID].Add(result); + } + } + + CustomMarshal.Free(mem); + + return ret; + } + + public UInt32[] EnumerateCounters() + { + IntPtr mem = CustomMarshal.Alloc(typeof(templated_array)); + + bool success = ReplayRenderer_EnumerateCounters(m_Real, mem); + + UInt32[] ret = null; + + if (success) + { + ret = (UInt32[])CustomMarshal.GetTemplatedArray(mem, typeof(UInt32), true); + } + + CustomMarshal.Free(mem); + + return ret; + } + + public CounterDescription DescribeCounter(UInt32 counterID) + { + IntPtr mem = CustomMarshal.Alloc(typeof(CounterDescription)); + + bool success = ReplayRenderer_DescribeCounter(m_Real, counterID, mem); + + CounterDescription ret = null; + + if (success) + { + ret = (CounterDescription)CustomMarshal.PtrToStructure(mem, typeof(CounterDescription), false); + } + + CustomMarshal.Free(mem); + + return ret; + } + + public FetchDrawcall[] GetDrawcalls(UInt32 frameID) + { + IntPtr mem = CustomMarshal.Alloc(typeof(templated_array)); + + bool success = ReplayRenderer_GetDrawcalls(m_Real, frameID, mem); FetchDrawcall[] ret = null; diff --git a/renderdocui/Windows/EventBrowser.cs b/renderdocui/Windows/EventBrowser.cs index 2f4135ea8..6b5fffffc 100644 --- a/renderdocui/Windows/EventBrowser.cs +++ b/renderdocui/Windows/EventBrowser.cs @@ -222,7 +222,7 @@ namespace renderdocui.Windows return new TreelistView.Node(new object[] { EID, draw, text, duration }); } - private TreelistView.Node AddDrawcall(TreelistView.Node existing, FetchDrawcall drawcall, TreelistView.Node root) + private TreelistView.Node AddDrawcall(TreelistView.Node existing, FetchDrawcall drawcall, TreelistView.Node root, Dictionary> times) { if (m_Core.Config.EventBrowser_HideEmpty) { @@ -231,7 +231,9 @@ namespace renderdocui.Windows } UInt32 eventNum = drawcall.eventID; - double duration = drawcall.duration; + double duration = 0.0; + if (times != null && times.ContainsKey(eventNum)) + duration = times[eventNum][0].value.d; TreelistView.Node drawNode = MakeNode(eventNum, drawcall.drawcallID, drawcall.name, duration); if (existing != null) @@ -272,7 +274,7 @@ namespace renderdocui.Windows { TreelistView.Node d = drawNode.Nodes.Count > i ? drawNode.Nodes[i] : null; - AddDrawcall(d, drawcall.children[i], drawNode); + AddDrawcall(d, drawcall.children[i], drawNode, times); if (i > 0 && (drawcall.children[i-1].flags & DrawcallFlags.SetMarker) > 0) { @@ -302,7 +304,7 @@ namespace renderdocui.Windows return drawNode; } - private void AddFrameDrawcalls(TreelistView.Node frame, FetchDrawcall[] drawcalls) + private void AddFrameDrawcalls(TreelistView.Node frame, FetchDrawcall[] drawcalls, Dictionary> times) { eventView.BeginUpdate(); @@ -319,7 +321,7 @@ namespace renderdocui.Windows { TreelistView.Node d = frame.Nodes.Count > (i + 1) ? frame.Nodes[i + 1] : null; - TreelistView.Node newD = AddDrawcall(d, drawcalls[i], frame); + TreelistView.Node newD = AddDrawcall(d, drawcalls[i], frame, times); if (newD != null) { @@ -371,7 +373,7 @@ namespace renderdocui.Windows eventView.EndUpdate(); for (int curFrame = 0; curFrame < frameList.Length; curFrame++) - AddFrameDrawcalls(m_FrameNodes[curFrame], m_Core.GetDrawcalls((UInt32)curFrame)); + AddFrameDrawcalls(m_FrameNodes[curFrame], m_Core.GetDrawcalls((UInt32)curFrame), null); if (frameList.Length > 0) { @@ -680,7 +682,15 @@ namespace renderdocui.Windows { m_Core.Renderer.BeginInvoke((ReplayRenderer r) => { - m_Core.TimeDrawcalls(r); + uint[] counters = { (uint)GPUCounters.EventGPUDuration }; + + var avail = r.EnumerateCounters(); + + var desc = r.DescribeCounter(counters[0]); + + Dictionary>[] times = new Dictionary>[m_Core.FrameInfo.Length]; + for (int curFrame = 0; curFrame < m_Core.FrameInfo.Length; curFrame++) + times[curFrame] = r.FetchCounters((UInt32)curFrame, 0, ~0U, counters); BeginInvoke((MethodInvoker)delegate { @@ -691,7 +701,7 @@ namespace renderdocui.Windows } for (int curFrame = 0; curFrame < m_FrameNodes.Count; curFrame++) - AddFrameDrawcalls(m_FrameNodes[curFrame], m_Core.GetDrawcalls((UInt32)curFrame)); + AddFrameDrawcalls(m_FrameNodes[curFrame], m_Core.GetDrawcalls((UInt32)curFrame), times[curFrame]); }); }); }