mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-08-28 09:26:52 +00:00
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:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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) {}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user