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]); }); }); }