diff --git a/renderdoc/Makefile b/renderdoc/Makefile index 6ce0c2fcc..573e9ec77 100644 --- a/renderdoc/Makefile +++ b/renderdoc/Makefile @@ -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 \ diff --git a/renderdoc/driver/gl/gl_counters.cpp b/renderdoc/driver/gl/gl_counters.cpp new file mode 100644 index 000000000..3821e2be8 --- /dev/null +++ b/renderdoc/driver/gl/gl_counters.cpp @@ -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 GLReplay::EnumerateCounters() +{ + vector 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 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 GLReplay::FetchCounters(uint32_t frameID, uint32_t minEventID, uint32_t maxEventID, const vector &counters) +{ + vector ret; + + if(counters.empty()) + { + RDCERR("No counters specified to FetchCounters"); + return ret; + } + + 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; +} diff --git a/renderdoc/driver/gl/gl_driver.h b/renderdoc/driver/gl/gl_driver.h index fe29b5b8b..301667dbb 100644 --- a/renderdoc/driver/gl/gl_driver.h +++ b/renderdoc/driver/gl/gl_driver.h @@ -373,6 +373,8 @@ class WrappedOpenGL vector &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); diff --git a/renderdoc/driver/gl/gl_replay.cpp b/renderdoc/driver/gl/gl_replay.cpp index 57b991d00..f68709ced 100644 --- a/renderdoc/driver/gl/gl_replay.cpp +++ b/renderdoc/driver/gl/gl_replay.cpp @@ -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 GLReplay::EnumerateCounters() -{ - GLNOTIMP("EnumerateCounters"); - return vector(); -} - -void GLReplay::DescribeCounter(uint32_t counterID, CounterDescription &desc) -{ - desc.counterID = counterID; - desc.name = "Unsupported"; - desc.description = "Counters are not implemented on OpenGL yet"; - desc.resultByteWidth = 0; - desc.resultCompType = eCompType_None; - desc.units = eUnits_Absolute; -} - -vector GLReplay::FetchCounters(uint32_t frameID, uint32_t minEventID, uint32_t maxEventID, const vector &counters) -{ - RDCUNIMPLEMENTED("FetchCounters"); - return vector(); -} - void GLReplay::BuildTargetShader(string source, string entry, const uint32_t compileFlags, ShaderStageType type, ResourceId *id, string *errors) { RDCUNIMPLEMENTED("BuildTargetShader"); diff --git a/renderdoc/driver/gl/gl_replay.h b/renderdoc/driver/gl/gl_replay.h index 4feb2c2eb..304a51109 100644 --- a/renderdoc/driver/gl/gl_replay.h +++ b/renderdoc/driver/gl/gl_replay.h @@ -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); diff --git a/renderdoc/driver/gl/gl_replay_linux.cpp b/renderdoc/driver/gl/gl_replay_linux.cpp index 3df589656..452333597 100644 --- a/renderdoc/driver/gl/gl_replay_linux.cpp +++ b/renderdoc/driver/gl/gl_replay_linux.cpp @@ -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; } } diff --git a/renderdoc/driver/gl/gl_replay_win32.cpp b/renderdoc/driver/gl/gl_replay_win32.cpp index 54f5d2aca..60ee46ff6 100644 --- a/renderdoc/driver/gl/gl_replay_win32.cpp +++ b/renderdoc/driver/gl/gl_replay_win32.cpp @@ -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; } } diff --git a/renderdoc/renderdoc.vcxproj b/renderdoc/renderdoc.vcxproj index bd2656870..89e71749d 100644 --- a/renderdoc/renderdoc.vcxproj +++ b/renderdoc/renderdoc.vcxproj @@ -316,6 +316,7 @@ + diff --git a/renderdoc/renderdoc.vcxproj.filters b/renderdoc/renderdoc.vcxproj.filters index d2a788469..3b9b6dc13 100644 --- a/renderdoc/renderdoc.vcxproj.filters +++ b/renderdoc/renderdoc.vcxproj.filters @@ -548,6 +548,9 @@ Drivers\D3D11 + + Drivers\OpenGL +