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.
This commit is contained in:
baldurk
2015-01-28 21:15:19 +00:00
parent 50e571e7d4
commit b7f9d5b6d0
31 changed files with 794 additions and 347 deletions
+29 -3
View File
@@ -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
+4 -1
View File
@@ -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<FetchFrameInfo> *frame);
extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetDrawcalls(ReplayRenderer *rend, uint32_t frameID, bool32 includeTimes, rdctype::array<FetchDrawcall> *draws);
extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetDrawcalls(ReplayRenderer *rend, uint32_t frameID, rdctype::array<FetchDrawcall> *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<CounterResult> *results);
extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_EnumerateCounters(ReplayRenderer *rend, rdctype::array<uint32_t> *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<FetchTexture> *texs);
extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetBuffers(ReplayRenderer *rend, rdctype::array<FetchBuffer> *bufs);
extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetResolve(ReplayRenderer *rend, uint64_t *callstack, uint32_t callstackLen, rdctype::array<rdctype::str> *trace);
+26
View File
@@ -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,
+10 -7
View File
@@ -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<EventUsage> GetUsage(ResourceId id) { return vector<EventUsage>(); }
bool IsRenderOutput(ResourceId id) { return false; }
ResourceId GetLiveID(ResourceId id) { return id; }
void TimeDrawcalls(rdctype::array<FetchDrawcall> &arr) {}
vector<uint32_t> EnumerateCounters() { return vector<uint32_t>(); }
void DescribeCounter(uint32_t counterID, CounterDescription &desc) { RDCEraseEl(desc); desc.counterID = counterID; }
vector<CounterResult> FetchCounters(uint32_t frameID, uint32_t minEventID, uint32_t maxEventID, const vector<uint32_t> &counters) { return vector<CounterResult>(); }
void FillCBufferVariables(ResourceId shader, uint32_t cbufSlot, vector<ShaderVariable> &outvars, const vector<byte> &data) {}
vector<byte> GetBufferData(ResourceId buff, uint32_t offset, uint32_t len) { return vector<byte>(); }
void InitPostVSBuffers(uint32_t frameID, uint32_t eventID) {}
+81 -37
View File
@@ -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<false, SpecialFormat>::Get(const SpecialFormat &el) { return
template<>
string ToStrHelper<false, FormatComponentType>::Get(const FormatComponentType &el) { return "<...>"; }
template<>
string ToStrHelper<false, CounterUnits>::Get(const CounterUnits &el) { return "<...>"; }
template<>
string ToStrHelper<false, PrimitiveTopology>::Get(const PrimitiveTopology &el) { return "<...>"; }
template<>
string ToStrHelper<false, ShaderStageType>::Get(const ShaderStageType &el) { return "<...>"; }
@@ -914,6 +927,8 @@ string ToStrHelper<false, GLPipelineState::Hints>::Get(const GLPipelineState::Hi
template<>
string ToStrHelper<false, EventUsage>::Get(const EventUsage &el) { return "<...>"; }
template<>
string ToStrHelper<false, CounterResult>::Get(const CounterResult &el) { return "<...>"; }
template<>
string ToStrHelper<false, FetchFrameInfo>::Get(const FetchFrameInfo &el) { return "<...>"; }
template<>
string ToStrHelper<false, ReplayLogType>::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<FetchDrawcall> l;
TimeDrawcalls(l);
vector<uint32_t> 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<FetchDrawcall> &src, rdctype::array<FetchDrawcall> &dst)
vector<CounterResult> ProxySerialiser::FetchCounters(uint32_t frameID, uint32_t minEventID, uint32_t maxEventID, const vector<uint32_t> &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<FetchDrawcall> &arr)
{
m_ToReplaySerialiser->Serialise("", arr);
vector<CounterResult> ret;
m_ToReplaySerialiser->Serialise("", frameID);
m_ToReplaySerialiser->Serialise("", minEventID);
m_ToReplaySerialiser->Serialise("", maxEventID);
m_ToReplaySerialiser->Serialise("", (vector<uint32_t> &)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<FetchDrawcall> dummy;
m_FromReplaySerialiser->Serialise("", dummy);
CopyDrawcallTimes(dummy, arr);
if(!SendReplayCommand(eCommand_FetchCounters))
return ret;
}
m_FromReplaySerialiser->Serialise("", ret);
return ret;
}
vector<uint32_t> ProxySerialiser::EnumerateCounters()
{
vector<uint32_t> 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;
}
+6 -3
View File
@@ -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<FetchDrawcall> &arr);
vector<uint32_t> EnumerateCounters();
void DescribeCounter(uint32_t counterID, CounterDescription &desc);
vector<CounterResult> FetchCounters(uint32_t frameID, uint32_t minEventID, uint32_t maxEventID, const vector<uint32_t> &counterID);
void FillCBufferVariables(ResourceId shader, uint32_t cbufSlot, vector<ShaderVariable> &outvars, const vector<byte> &data);
@@ -369,7 +373,6 @@ class ProxySerialiser : public IReplayDriver, Callstack::StackResolver
private:
bool SendReplayCommand(CommandPacketType type);
void CopyDrawcallTimes(rdctype::array<FetchDrawcall> &src, rdctype::array<FetchDrawcall> &dst);
void EnsureTexCached(ResourceId texid, uint32_t arrayIdx, uint32_t mip);
void EnsureBufCached(ResourceId bufid);
-148
View File
@@ -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<FetchDrawcall> &draws, vector<GPUTimer> &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<FetchDrawcall> &arr)
{
SCOPED_TIMER("Drawcall timing");
vector<GPUTimer> 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);
-2
View File
@@ -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)
+7 -5
View File
@@ -114,16 +114,16 @@ struct DrawcallTreeNode
FetchDrawcall draw;
vector<DrawcallTreeNode> children;
rdctype::array<FetchDrawcall> Bake()
vector<FetchDrawcall> Bake()
{
rdctype::array<FetchDrawcall> ret;
vector<FetchDrawcall> 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);
@@ -410,8 +410,6 @@ bool WrappedID3D11DeviceContext::Serialise_ClearView(ID3D11View *pView, const FL
draw.flags |= eDraw_Clear;
draw.duration = 0.1f;
AddDrawcall(draw, true);
}
+320
View File
@@ -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<uint32_t> D3D11DebugManager::EnumerateCounters()
{
vector<uint32_t> 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<GPUTimer> 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<CounterResult> D3D11DebugManager::FetchCounters(uint32_t frameID, uint32_t minEventID, uint32_t maxEventID, const vector<uint32_t> &counters)
{
vector<CounterResult> 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;
}
+4
View File
@@ -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");
+24 -9
View File
@@ -27,6 +27,10 @@
#include <d3d11.h>
#include <utility>
#include <list>
#include <map>
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<FetchDrawcall> &arr);
// called after any device is destroyed, to do corresponding shutdown of counters
static void PostDeviceShutdownCounters();
vector<uint32_t> EnumerateCounters();
void DescribeCounter(uint32_t counterID, CounterDescription &desc);
vector<CounterResult> FetchCounters(uint32_t frameID, uint32_t minEventID, uint32_t maxEventID, const vector<uint32_t> &counters);
void RenderText(float x, float y, const char *textfmt, ...);
void RenderMesh(uint32_t frameID, uint32_t eventID, const vector<MeshFormat> &secondaryDraws, MeshDisplay cfg);
@@ -527,7 +536,13 @@ class D3D11DebugManager
const vector<byte> &data);
friend struct ShaderDebugState;
void FillTimers(uint32_t frameID, uint32_t &eventStart, rdctype::array<FetchDrawcall> &draws, vector<GPUTimer> &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);
};
+4 -70
View File
@@ -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;
+19 -2
View File
@@ -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<FetchDrawcall> &arr)
vector<uint32_t> 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<CounterResult> D3D11Replay::FetchCounters(uint32_t frameID, uint32_t minEventID, uint32_t maxEventID, const vector<uint32_t> &counters)
{
return m_pDevice->GetDebugManager()->FetchCounters(frameID, minEventID, maxEventID, counters);
}
void D3D11Replay::RenderMesh(uint32_t frameID, uint32_t eventID, const vector<MeshFormat> &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;
+4 -2
View File
@@ -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<FetchDrawcall> &arr);
vector<uint32_t> EnumerateCounters();
void DescribeCounter(uint32_t counterID, CounterDescription &desc);
vector<CounterResult> FetchCounters(uint32_t frameID, uint32_t minEventID, uint32_t maxEventID, const vector<uint32_t> &counters);
ResourceId CreateProxyTexture(FetchTexture templateTex);
void SetProxyTextureData(ResourceId texid, uint32_t arrayIdx, uint32_t mip, byte *data, size_t dataSize);
+4 -6
View File
@@ -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;
+6 -6
View File
@@ -69,17 +69,17 @@ struct DrawcallTreeNode
vector<DrawcallTreeNode> children;
DrawcallTreeNode &operator =(FetchDrawcall d) { *this = DrawcallTreeNode(d); return *this; }
rdctype::array<FetchDrawcall> Bake()
vector<FetchDrawcall> Bake()
{
rdctype::array<FetchDrawcall> ret;
vector<FetchDrawcall> 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;
+19 -2
View File
@@ -2199,9 +2199,26 @@ void GLReplay::RemoveReplacement(ResourceId id)
RDCUNIMPLEMENTED("RemoveReplacement");
}
void GLReplay::TimeDrawcalls(rdctype::array<FetchDrawcall> &arr)
vector<uint32_t> GLReplay::EnumerateCounters()
{
RDCUNIMPLEMENTED("TimeDrawcalls");
GLNOTIMP("EnumerateCounters");
return vector<uint32_t>();
}
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<CounterResult> GLReplay::FetchCounters(uint32_t frameID, uint32_t minEventID, uint32_t maxEventID, const vector<uint32_t> &counters)
{
RDCUNIMPLEMENTED("FetchCounters");
return vector<CounterResult>();
}
void GLReplay::BuildTargetShader(string source, string entry, const uint32_t compileFlags, ShaderStageType type, ResourceId *id, string *errors)
+4 -2
View File
@@ -138,8 +138,10 @@ class GLReplay : public IReplayDriver
void ReplaceResource(ResourceId from, ResourceId to);
void RemoveReplacement(ResourceId id);
void TimeDrawcalls(rdctype::array<FetchDrawcall> &arr);
vector<uint32_t> EnumerateCounters();
void DescribeCounter(uint32_t counterID, CounterDescription &desc);
vector<CounterResult> FetchCounters(uint32_t frameID, uint32_t minEventID, uint32_t maxEventID, const vector<uint32_t> &counters);
void RenderMesh(uint32_t frameID, uint32_t eventID, const vector<MeshFormat> &secondaryDraws, MeshDisplay cfg);
+1
View File
@@ -302,6 +302,7 @@
<ClCompile Include="driver\d3d11\d3d11_context1_wrap.cpp" />
<ClCompile Include="driver\d3d11\d3d11_context2_wrap.cpp" />
<ClCompile Include="driver\d3d11\d3d11_context_wrap.cpp" />
<ClCompile Include="driver\d3d11\d3d11_counters.cpp" />
<ClCompile Include="driver\d3d11\d3d11_debug.cpp" />
<ClCompile Include="driver\d3d11\d3d11_device.cpp" />
<ClCompile Include="driver\d3d11\d3d11_device1_wrap.cpp" />
+3
View File
@@ -545,6 +545,9 @@
<ClCompile Include="3rdparty\tinyexr\tinyexr.cpp">
<Filter>3rdparty\tinyexr</Filter>
</ClCompile>
<ClCompile Include="driver\d3d11\d3d11_counters.cpp">
<Filter>Drivers\D3D11</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="os\win32\comexport.def">
+5 -3
View File
@@ -34,7 +34,7 @@ struct FetchFrameRecord
{
FetchFrameInfo frameInfo;
rdctype::array<FetchDrawcall> drawcallList;
vector<FetchDrawcall> 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<FetchDrawcall> &arr) = 0;
virtual vector<uint32_t> EnumerateCounters() = 0;
virtual void DescribeCounter(uint32_t counterID, CounterDescription &desc) = 0;
virtual vector<CounterResult> FetchCounters(uint32_t frameID, uint32_t minEventID, uint32_t maxEventID, const vector<uint32_t> &counterID) = 0;
virtual void FillCBufferVariables(ResourceId shader, uint32_t cbufSlot, vector<ShaderVariable> &outvars, const vector<byte> &data) = 0;
+45 -10
View File
@@ -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<FetchDrawcall> *draws)
bool ReplayRenderer::GetDrawcalls(uint32_t frameID, rdctype::array<FetchDrawcall> *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<CounterResult> *results)
{
if(frameID >= (uint32_t)m_FrameRecord.size() || results == NULL)
return false;
vector<uint32_t> 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<uint32_t> *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<FetchBuffer> *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<FetchFrameInfo> *frame)
{ return rend->GetFrameInfo(frame); }
extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetDrawcalls(ReplayRenderer *rend, uint32_t frameID, bool32 includeTimes, rdctype::array<FetchDrawcall> *draws)
{ return rend->GetDrawcalls(frameID, includeTimes != 0, draws); }
extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetDrawcalls(ReplayRenderer *rend, uint32_t frameID, rdctype::array<FetchDrawcall> *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<CounterResult> *results)
{ return rend->FetchCounters(frameID, minEventID, maxEventID, counters, numCounters, results); }
extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_EnumerateCounters(ReplayRenderer *rend, rdctype::array<uint32_t> *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<FetchTexture> *texs)
{ return rend->GetTextures(texs); }
extern "C" RENDERDOC_API bool32 RENDERDOC_CC ReplayRenderer_GetBuffers(ReplayRenderer *rend, rdctype::array<FetchBuffer> *bufs)
+4 -1
View File
@@ -154,7 +154,10 @@ struct ReplayRenderer
bool FreeTargetResource(ResourceId id);
bool GetFrameInfo(rdctype::array<FetchFrameInfo> *frame);
bool GetDrawcalls(uint32_t frameID, bool includeTimes, rdctype::array<FetchDrawcall> *draws);
bool GetDrawcalls(uint32_t frameID, rdctype::array<FetchDrawcall> *draws);
bool FetchCounters(uint32_t frameID, uint32_t minEventID, uint32_t maxEventID, uint32_t *counters, uint32_t numCounters, rdctype::array<CounterResult> *results);
bool EnumerateCounters(rdctype::array<uint32_t> *counters);
bool DescribeCounter(uint32_t counterID, CounterDescription *desc);
bool GetTextures(rdctype::array<FetchTexture> *texs);
bool GetBuffers(rdctype::array<FetchBuffer> *bufs);
bool GetResolve(uint64_t *callstack, uint32_t callstackLen, rdctype::array<rdctype::str> *trace);
+1 -13
View File
@@ -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;
+8
View File
@@ -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);
+24
View File
@@ -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,
+32 -2
View File
@@ -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
{
+82 -3
View File
@@ -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<uint, List<CounterResult>> 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<uint, List<CounterResult>> ret = null;
if (success)
{
CounterResult[] resultArray = (CounterResult[])CustomMarshal.GetTemplatedArray(mem, typeof(CounterResult), true);
// fixup previous/next/parent pointers
ret = new Dictionary<uint, List<CounterResult>>();
foreach (var result in resultArray)
{
if (!ret.ContainsKey(result.eventID))
ret.Add(result.eventID, new List<CounterResult>());
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;
+18 -8
View File
@@ -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<uint, List<CounterResult>> 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<uint, List<CounterResult>> 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<uint, List<CounterResult>>[] times = new Dictionary<uint, List<CounterResult>>[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]);
});
});
}