mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-11-14 18:00:54 +00:00
Implement GPU duration counters on OpenGL
This commit is contained in:
1 parent
96d0f472e0
commit
c5fafbed5d
9 files changed
+267
-23
No files matched your search
@@ -38,6 +38,7 @@ driver/gl/gl_common.o \
|
||||
driver/gl/gl_driver.o \
|
||||
driver/gl/gl_manager.o \
|
||||
driver/gl/gl_debug.o \
|
||||
driver/gl/gl_counters.o \
|
||||
driver/gl/gl_replay.o \
|
||||
driver/gl/gl_replay_linux.o \
|
||||
driver/gl/gl_shader_refl.o \
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
/******************************************************************************
|
||||
* 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 "gl_replay.h"
|
||||
#include "gl_driver.h"
|
||||
#include "gl_resources.h"
|
||||
|
||||
void GLReplay::PreContextInitCounters()
|
||||
{
|
||||
}
|
||||
|
||||
void GLReplay::PostContextInitCounters()
|
||||
{
|
||||
}
|
||||
|
||||
void GLReplay::PreContextShutdownCounters()
|
||||
{
|
||||
}
|
||||
|
||||
void GLReplay::PostContextShutdownCounters()
|
||||
{
|
||||
}
|
||||
|
||||
vector<uint32_t> GLReplay::EnumerateCounters()
|
||||
{
|
||||
vector<uint32_t> ret;
|
||||
|
||||
ret.push_back(eCounter_EventGPUDuration);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void GLReplay::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
|
||||
{
|
||||
GLuint obj;
|
||||
uint32_t eventID;
|
||||
};
|
||||
|
||||
struct CounterContext
|
||||
{
|
||||
uint32_t frameID;
|
||||
uint32_t minEID;
|
||||
uint32_t maxEID;
|
||||
uint32_t eventStart;
|
||||
vector<GPUTimer> timers;
|
||||
int reuseIdx;
|
||||
};
|
||||
|
||||
void GLReplay::FillTimers(CounterContext &ctx, const DrawcallTreeNode &drawnode)
|
||||
{
|
||||
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;
|
||||
|
||||
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->obj = 0;
|
||||
|
||||
m_pDriver->glGenQueries(1, &timer->obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
timer = &ctx.timers[ctx.reuseIdx++];
|
||||
}
|
||||
}
|
||||
|
||||
m_pDriver->ReplayLog(ctx.frameID, ctx.eventStart, d.eventID, eReplay_WithoutDraw);
|
||||
|
||||
if(includeEvent && timer->obj)
|
||||
{
|
||||
m_pDriver->glBeginQuery(eGL_TIME_ELAPSED, timer->obj);
|
||||
m_pDriver->ReplayLog(ctx.frameID, ctx.eventStart, d.eventID, eReplay_OnlyDraw);
|
||||
m_pDriver->glEndQuery(eGL_TIME_ELAPSED);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pDriver->ReplayLog(ctx.frameID, ctx.eventStart, d.eventID, eReplay_OnlyDraw);
|
||||
}
|
||||
|
||||
ctx.eventStart = d.eventID+1;
|
||||
}
|
||||
}
|
||||
|
||||
vector<CounterResult> GLReplay::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;
|
||||
}
|
||||
|
||||
MakeCurrentReplayContext(&m_ReplayCtx);
|
||||
|
||||
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);
|
||||
|
||||
CounterContext ctx;
|
||||
ctx.frameID = frameID;
|
||||
ctx.minEID = minEventID;
|
||||
ctx.maxEID = maxEventID;
|
||||
|
||||
for(int loop=0; loop < 1; loop++)
|
||||
{
|
||||
ctx.eventStart = 0;
|
||||
ctx.reuseIdx = loop == 0 ? -1 : 0;
|
||||
FillTimers(ctx, m_pDriver->GetRootDraw());
|
||||
|
||||
double nanosToSecs = 1.0/1000000000.0;
|
||||
|
||||
GLuint prevbind = 0;
|
||||
m_pDriver->glGetIntegerv(eGL_QUERY_BUFFER_BINDING, (GLint *)&prevbind);
|
||||
m_pDriver->glBindBuffer(eGL_QUERY_BUFFER, 0);
|
||||
|
||||
for(size_t i=0; i < ctx.timers.size(); i++)
|
||||
{
|
||||
if(ctx.timers[i].obj)
|
||||
{
|
||||
GLuint elapsed = 0;
|
||||
m_pDriver->glGetQueryObjectuiv(ctx.timers[i].obj, eGL_QUERY_RESULT, &elapsed);
|
||||
|
||||
double duration = double(elapsed)*nanosToSecs;
|
||||
|
||||
ret.push_back(CounterResult(ctx.timers[i].eventID, counterID, duration));
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.push_back(CounterResult(ctx.timers[i].eventID, counterID, 0.0));
|
||||
}
|
||||
}
|
||||
|
||||
m_pDriver->glBindBuffer(eGL_QUERY_BUFFER, prevbind);
|
||||
}
|
||||
|
||||
for(size_t i=0; i < ctx.timers.size(); i++)
|
||||
m_pDriver->glDeleteQueries(1, &ctx.timers[i].obj);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -373,6 +373,8 @@ class WrappedOpenGL
|
||||
vector<FetchFrameRecord> &GetFrameRecord() { return m_FrameRecord; }
|
||||
FetchAPIEvent GetEvent(uint32_t eventID);
|
||||
|
||||
const DrawcallTreeNode &GetRootDraw() { return m_ParentDrawcall; }
|
||||
|
||||
const FetchDrawcall *GetDrawcall(uint32_t frameID, uint32_t eventID);
|
||||
|
||||
void CreateContext(GLWindowingData winData, void *shareContext, GLInitParams initParams, bool core);
|
||||
|
||||
@@ -44,6 +44,8 @@ GLReplay::GLReplay()
|
||||
|
||||
void GLReplay::Shutdown()
|
||||
{
|
||||
PreContextShutdownCounters();
|
||||
|
||||
DeleteDebugData();
|
||||
|
||||
DestroyOutputWindow(m_DebugID);
|
||||
@@ -51,6 +53,8 @@ void GLReplay::Shutdown()
|
||||
CloseReplayContext();
|
||||
|
||||
delete m_pDriver;
|
||||
|
||||
GLReplay::PostContextShutdownCounters();
|
||||
}
|
||||
|
||||
#pragma region Implemented
|
||||
@@ -122,6 +126,8 @@ void GLReplay::SetReplayData(GLWindowingData data)
|
||||
m_ReplayCtx = data;
|
||||
|
||||
InitDebugData();
|
||||
|
||||
PostContextInitCounters();
|
||||
}
|
||||
|
||||
void GLReplay::InitCallstackResolver()
|
||||
@@ -2199,28 +2205,6 @@ void GLReplay::RemoveReplacement(ResourceId id)
|
||||
RDCUNIMPLEMENTED("RemoveReplacement");
|
||||
}
|
||||
|
||||
vector<uint32_t> GLReplay::EnumerateCounters()
|
||||
{
|
||||
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)
|
||||
{
|
||||
RDCUNIMPLEMENTED("BuildTargetShader");
|
||||
|
||||
@@ -34,6 +34,8 @@ using std::pair;
|
||||
using std::map;
|
||||
|
||||
class WrappedOpenGL;
|
||||
struct CounterContext;
|
||||
struct DrawcallTreeNode;
|
||||
|
||||
struct GLPostVSData
|
||||
{
|
||||
@@ -177,7 +179,12 @@ class GLReplay : public IReplayDriver
|
||||
void InitCallstackResolver();
|
||||
bool HasCallstacks();
|
||||
Callstack::StackResolver *GetCallstackResolver();
|
||||
|
||||
|
||||
// called before any context is created, to init any counters
|
||||
static void PreContextInitCounters();
|
||||
// called after any context is destroyed, to do corresponding shutdown of counters
|
||||
static void PostContextShutdownCounters();
|
||||
|
||||
void SetReplayData(GLWindowingData data);
|
||||
private:
|
||||
void FillCBufferValue(WrappedOpenGL &gl, GLuint prog, bool bufferBacked, bool rowMajor, uint32_t offs, uint32_t matStride,
|
||||
@@ -305,6 +312,13 @@ class GLReplay : public IReplayDriver
|
||||
void InitDebugData();
|
||||
void DeleteDebugData();
|
||||
|
||||
// called after the context is created, to init any counters
|
||||
void PostContextInitCounters();
|
||||
// called before the context is destroyed, to shutdown any counters
|
||||
void PreContextShutdownCounters();
|
||||
|
||||
void FillTimers(CounterContext &ctx, const DrawcallTreeNode &drawnode);
|
||||
|
||||
GLuint CreateShaderProgram(const char *vs, const char *ps, const char *gs = NULL);
|
||||
GLuint CreateCShaderProgram(const char *cs);
|
||||
|
||||
|
||||
@@ -248,6 +248,8 @@ ReplayCreateStatus GL_CreateReplayDevice(const char *logfile, IReplayDriver **dr
|
||||
int attribs[64] = {0};
|
||||
int i=0;
|
||||
|
||||
GLReplay::PreContextInitCounters();
|
||||
|
||||
attribs[i++] = GLX_CONTEXT_MAJOR_VERSION_ARB;
|
||||
attribs[i++] = 4;
|
||||
attribs[i++] = GLX_CONTEXT_MINOR_VERSION_ARB;
|
||||
@@ -273,6 +275,7 @@ ReplayCreateStatus GL_CreateReplayDevice(const char *logfile, IReplayDriver **dr
|
||||
if(fbcfg == NULL)
|
||||
{
|
||||
XCloseDisplay(dpy);
|
||||
GLReplay::PostContextShutdownCounters();
|
||||
RDCERR("Couldn't choose default framebuffer config");
|
||||
return eReplayCreate_APIInitFailed;
|
||||
}
|
||||
@@ -281,7 +284,9 @@ ReplayCreateStatus GL_CreateReplayDevice(const char *logfile, IReplayDriver **dr
|
||||
|
||||
if(ctx == NULL)
|
||||
{
|
||||
XFree(fbcfg);
|
||||
XCloseDisplay(dpy);
|
||||
GLReplay::PostContextShutdownCounters();
|
||||
RDCERR("Couldn't create 4.3 context - RenderDoc requires OpenGL 4.3 availability");
|
||||
return eReplayCreate_APIHardwareUnsupported;
|
||||
}
|
||||
@@ -299,7 +304,9 @@ ReplayCreateStatus GL_CreateReplayDevice(const char *logfile, IReplayDriver **dr
|
||||
{
|
||||
glXDestroyPbufferProc(dpy, pbuffer);
|
||||
glXDestroyCtxProc(dpy, ctx);
|
||||
XFree(fbcfg);
|
||||
XCloseDisplay(dpy);
|
||||
GLReplay::PostContextShutdownCounters();
|
||||
RDCERR("Couldn't make pbuffer & context current");
|
||||
return eReplayCreate_APIInitFailed;
|
||||
}
|
||||
@@ -310,6 +317,11 @@ ReplayCreateStatus GL_CreateReplayDevice(const char *logfile, IReplayDriver **dr
|
||||
if(getInt == NULL || getStr == NULL)
|
||||
{
|
||||
RDCERR("Couldn't get glGetIntegerv (%p) or glGetStringi (%p) entry points", getInt, getStr);
|
||||
glXDestroyPbufferProc(dpy, pbuffer);
|
||||
glXDestroyCtxProc(dpy, ctx);
|
||||
XFree(fbcfg);
|
||||
XCloseDisplay(dpy);
|
||||
GLReplay::PostContextShutdownCounters();
|
||||
return eReplayCreate_APIInitFailed;
|
||||
}
|
||||
else
|
||||
@@ -334,6 +346,11 @@ ReplayCreateStatus GL_CreateReplayDevice(const char *logfile, IReplayDriver **dr
|
||||
if(!found)
|
||||
{
|
||||
RDCERR("RenderDoc requires EXT_direct_state_access availability, and it is not reported. Try updating your drivers.");
|
||||
glXDestroyPbufferProc(dpy, pbuffer);
|
||||
glXDestroyCtxProc(dpy, ctx);
|
||||
XFree(fbcfg);
|
||||
XCloseDisplay(dpy);
|
||||
GLReplay::PostContextShutdownCounters();
|
||||
return eReplayCreate_APIHardwareUnsupported;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -343,6 +343,8 @@ ReplayCreateStatus GL_CreateReplayDevice(const char *logfile, IReplayDriver **dr
|
||||
wglDeleteRC(rc);
|
||||
ReleaseDC(w, dc);
|
||||
DestroyWindow(w);
|
||||
|
||||
GLReplay::PreContextInitCounters();
|
||||
|
||||
// we don't use the default framebuffer (backbuffer) for anything, so we make it
|
||||
// tiny and with no depth/stencil bits
|
||||
@@ -361,6 +363,8 @@ ReplayCreateStatus GL_CreateReplayDevice(const char *logfile, IReplayDriver **dr
|
||||
if(pf == 0)
|
||||
{
|
||||
RDCERR("Couldn't choose pixel format");
|
||||
ReleaseDC(w, dc);
|
||||
GLReplay::PostContextShutdownCounters();
|
||||
return eReplayCreate_APIInitFailed;
|
||||
}
|
||||
|
||||
@@ -368,6 +372,8 @@ ReplayCreateStatus GL_CreateReplayDevice(const char *logfile, IReplayDriver **dr
|
||||
if(res == FALSE)
|
||||
{
|
||||
RDCERR("Couldn't set pixel format");
|
||||
ReleaseDC(w, dc);
|
||||
GLReplay::PostContextShutdownCounters();
|
||||
return eReplayCreate_APIInitFailed;
|
||||
}
|
||||
|
||||
@@ -387,6 +393,8 @@ ReplayCreateStatus GL_CreateReplayDevice(const char *logfile, IReplayDriver **dr
|
||||
if(rc == NULL)
|
||||
{
|
||||
RDCERR("Couldn't create 4.3 RC - RenderDoc requires OpenGL 4.3 availability");
|
||||
ReleaseDC(w, dc);
|
||||
GLReplay::PostContextShutdownCounters();
|
||||
return eReplayCreate_APIHardwareUnsupported;
|
||||
}
|
||||
|
||||
@@ -394,6 +402,10 @@ ReplayCreateStatus GL_CreateReplayDevice(const char *logfile, IReplayDriver **dr
|
||||
if(res == FALSE)
|
||||
{
|
||||
RDCERR("Couldn't make 4.3 RC current");
|
||||
wglMakeCurrentProc(NULL, NULL);
|
||||
wglDeleteRC(rc);
|
||||
ReleaseDC(w, dc);
|
||||
GLReplay::PostContextShutdownCounters();
|
||||
return eReplayCreate_APIInitFailed;
|
||||
}
|
||||
|
||||
@@ -403,6 +415,10 @@ ReplayCreateStatus GL_CreateReplayDevice(const char *logfile, IReplayDriver **dr
|
||||
if(getInt == NULL || getStr == NULL)
|
||||
{
|
||||
RDCERR("Couldn't get glGetIntegerv (%p) or glGetStringi (%p) entry points", getInt, getStr);
|
||||
wglMakeCurrentProc(NULL, NULL);
|
||||
wglDeleteRC(rc);
|
||||
ReleaseDC(w, dc);
|
||||
GLReplay::PostContextShutdownCounters();
|
||||
return eReplayCreate_APIInitFailed;
|
||||
}
|
||||
else
|
||||
@@ -427,6 +443,10 @@ ReplayCreateStatus GL_CreateReplayDevice(const char *logfile, IReplayDriver **dr
|
||||
if(!found)
|
||||
{
|
||||
RDCERR("RenderDoc requires EXT_direct_state_access availability, and it is not reported. Try updating your drivers.");
|
||||
wglMakeCurrentProc(NULL, NULL);
|
||||
wglDeleteRC(rc);
|
||||
ReleaseDC(w, dc);
|
||||
GLReplay::PostContextShutdownCounters();
|
||||
return eReplayCreate_APIHardwareUnsupported;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,6 +316,7 @@
|
||||
<ClCompile Include="driver\d3d11\shaders\dxbc_inspect.cpp" />
|
||||
<ClCompile Include="driver\dxgi\dxgi_wrapped.cpp" />
|
||||
<ClCompile Include="driver\gl\gl_common.cpp" />
|
||||
<ClCompile Include="driver\gl\gl_counters.cpp" />
|
||||
<ClCompile Include="driver\gl\gl_debug.cpp" />
|
||||
<ClCompile Include="driver\gl\gl_driver.cpp" />
|
||||
<ClCompile Include="driver\gl\gl_manager.cpp" />
|
||||
|
||||
@@ -548,6 +548,9 @@
|
||||
<ClCompile Include="driver\d3d11\d3d11_counters.cpp">
|
||||
<Filter>Drivers\D3D11</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="driver\gl\gl_counters.cpp">
|
||||
<Filter>Drivers\OpenGL</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="os\win32\comexport.def">
|
||||
|
||||
Reference in new issue
Block a user