diff --git a/renderdoc/Makefile b/renderdoc/Makefile index 6838afa2c..53e9a2d67 100644 --- a/renderdoc/Makefile +++ b/renderdoc/Makefile @@ -74,6 +74,7 @@ data/glsl/mesh.frago \ data/glsl/mesh.geomo \ data/glsl/text.verto \ data/glsl/text.frago \ +data/glsl/quadoverdraw.frago \ data/glsl/histogram.compo \ data/glsl/arraymscopy.compo \ data/sourcecodepro.ttfo diff --git a/renderdoc/data/embedded_files.h b/renderdoc/data/embedded_files.h index 463979b95..3152937fc 100644 --- a/renderdoc/data/embedded_files.h +++ b/renderdoc/data/embedded_files.h @@ -35,6 +35,7 @@ DECLARE_EMBED(blit_frag); DECLARE_EMBED(texdisplay_frag); DECLARE_EMBED(checkerboard_frag); DECLARE_EMBED(histogram_comp); +DECLARE_EMBED(quadoverdraw_frag); DECLARE_EMBED(arraymscopy_comp); DECLARE_EMBED(mesh_vert); DECLARE_EMBED(mesh_frag); diff --git a/renderdoc/data/glsl/quadoverdraw.frag b/renderdoc/data/glsl/quadoverdraw.frag new file mode 100644 index 000000000..cc7c0089c --- /dev/null +++ b/renderdoc/data/glsl/quadoverdraw.frag @@ -0,0 +1,96 @@ +/****************************************************************************** + * 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. + ******************************************************************************/ + +//////////////////////////////////////////////////////////////////////////////////////////// +// Below shaders courtesy of Stephen Hill (@self_shadow), converted to glsl trivially +// +// http://blog.selfshadow.com/2012/11/12/counting-quads/ +// https://github.com/selfshadow/demos/blob/master/QuadShading/QuadShading.fx +//////////////////////////////////////////////////////////////////////////////////////////// + +layout(binding = 0, r32ui) uniform coherent uimage2DArray overdrawImage; + + + +#ifdef RENDERDOC_QuadOverdrawPS + +layout(early_fragment_tests) in; + +void main() +{ + uint c0 = uint(gl_SampleMaskIn[0]); + + // Obtain coverage for all pixels in the quad, via 'message passing'*. + // (* For more details, see: + // "Shader Amortization using Pixel Quad Message Passing", Eric Penner, GPU Pro 2.) + uvec2 p = uvec2(uint(gl_FragCoord.x) & 1, uint(gl_FragCoord.y) & 1); + ivec2 sign = ivec2(p.x > 0 ? -1 : 1, p.y > 0 ? -1 : 1); + uint c1 = c0 + sign.x*int(dFdxFine(c0)); + uint c2 = c0 + sign.y*int(dFdyFine(c0)); + uint c3 = c2 + sign.x*int(dFdxFine(c2)); + + // Count the live pixels, minus 1 (zero indexing) + uint pixelCount = c0 + c1 + c2 + c3 - 1; + + ivec3 quad = ivec3(gl_FragCoord.xy*0.5, pixelCount); + imageAtomicAdd(overdrawImage, quad, 1); +} + +#endif // RENDERDOC_QuadOverdrawPS + + + + +#ifdef RENDERDOC_QOResolvePS + +#define NUM_RAMP_COLOURS 128 + +uniform vec4 overdrawRampColours[NUM_RAMP_COLOURS]; + +vec4 ToColour(uint v) +{ + return overdrawRampColours[min(v, uint(NUM_RAMP_COLOURS-1))]; +} + +layout (location = 0) out vec4 color_out; + +void main() +{ + ivec2 quad = ivec2(gl_FragCoord.xy*0.5f); + + uint overdraw = 0; + for(uint i = 0; i < 4; i++) + overdraw += imageLoad(overdrawImage, ivec3(quad, i)).x/(i + 1); + + color_out = ToColour(overdraw); +} + +#endif // RENDERDOC_QOResolvePS + +//////////////////////////////////////////////////////////////////////////////////////////// +// Above shaders courtesy of Stephen Hill (@self_shadow), converted to glsl trivially +// +// http://blog.selfshadow.com/2012/11/12/counting-quads/ +// https://github.com/selfshadow/demos/blob/master/QuadShading/QuadShading.fx +//////////////////////////////////////////////////////////////////////////////////////////// diff --git a/renderdoc/data/renderdoc.rc b/renderdoc/data/renderdoc.rc index f78a00075..b1f5e758e 100644 --- a/renderdoc/data/renderdoc.rc +++ b/renderdoc/data/renderdoc.rc @@ -124,6 +124,7 @@ RESOURCE_histogram_comp TYPE_EMBED "glsl/histogram.comp" RESOURCE_mesh_frag TYPE_EMBED "glsl/mesh.frag" RESOURCE_mesh_geom TYPE_EMBED "glsl/mesh.geom" RESOURCE_arraymscopy_comp TYPE_EMBED "glsl/arraymscopy.comp" +RESOURCE_quadoverdraw_frag TYPE_EMBED "glsl/quadoverdraw.frag" RESOURCE_sourcecodepro_ttf TYPE_EMBED "sourcecodepro.ttf" diff --git a/renderdoc/data/resource.h b/renderdoc/data/resource.h index 51ac4656f..f25cecaa3 100644 --- a/renderdoc/data/resource.h +++ b/renderdoc/data/resource.h @@ -26,6 +26,7 @@ #define RESOURCE_mesh_frag 213 #define RESOURCE_mesh_geom 214 #define RESOURCE_arraymscopy_comp 215 +#define RESOURCE_quadoverdraw_frag 216 #define RESOURCE_sourcecodepro_ttf 301 diff --git a/renderdoc/driver/gl/gl_debug.cpp b/renderdoc/driver/gl/gl_debug.cpp index c0a399add..4becab66f 100644 --- a/renderdoc/driver/gl/gl_debug.cpp +++ b/renderdoc/driver/gl/gl_debug.cpp @@ -180,6 +180,8 @@ void GLReplay::InitDebugData() MakeCurrentReplayContext(m_DebugCtx); } + WrappedOpenGL &gl = *m_pDriver; + DebugData.outWidth = 0.0f; DebugData.outHeight = 0.0f; string blitvsSource = GetEmbeddedResource(blit_vert); @@ -205,6 +207,54 @@ void GLReplay::InitDebugData() DebugData.texDisplayProg[i] = CreateShaderProgram(NULL, glsl.c_str()); } + GLint numsl = 0; + gl.glGetIntegerv(eGL_NUM_SHADING_LANGUAGE_VERSIONS, &numsl); + + bool support450 = false; + for(GLint i=0; i < numsl; i++) + { + const char *sl = (const char *)gl.glGetStringi(eGL_SHADING_LANGUAGE_VERSION, (GLuint)i); + + if(sl[0] == '4' && sl[1] == '5' && sl[2] == '0') + support450 = true; + if(sl[0] == '4' && sl[1] == '.' && sl[2] == '5') + support450 = true; + + if(support450) + break; + } + + if(support450) + { + DebugData.quadoverdraw420 = false; + + string glsl = "#version 450 core\n\n"; + glsl += "#define RENDERDOC_QuadOverdrawPS\n\n"; + glsl += GetEmbeddedResource(quadoverdraw_frag); + DebugData.quadoverdrawFSProg = CreateShaderProgram(NULL, glsl.c_str()); + + glsl = "#version 420 core\n\n"; + glsl += "#define RENDERDOC_QOResolvePS\n\n"; + glsl += GetEmbeddedResource(quadoverdraw_frag); + DebugData.quadoverdrawResolveProg = CreateShaderProgram(blitvsSource.c_str(), glsl.c_str()); + } + else + { + DebugData.quadoverdraw420 = true; + + string glsl = "#version 420 core\n\n"; + glsl += "#define RENDERDOC_QuadOverdrawPS\n\n"; + glsl += "#define dFdxFine dFdx\n\n"; // dFdx fine functions not available before GLSL 450 + glsl += "#define dFdyFine dFdy\n\n"; // use normal dFdx, which might be coarse, so won't show quad overdraw properly + glsl += GetEmbeddedResource(quadoverdraw_frag); + DebugData.quadoverdrawFSProg = CreateShaderProgram(NULL, glsl.c_str()); + + glsl = "#version 420 core\n\n"; + glsl += "#define RENDERDOC_QOResolvePS\n\n"; + glsl += GetEmbeddedResource(quadoverdraw_frag); + DebugData.quadoverdrawResolveProg = CreateShaderProgram(blitvsSource.c_str(), glsl.c_str()); + } + string checkerfs = GetEmbeddedResource(checkerboard_frag); DebugData.checkerProg = CreateShaderProgram(blitvsSource.c_str(), checkerfs.c_str()); @@ -223,8 +273,6 @@ void GLReplay::InitDebugData() DebugData.meshProg = CreateShaderProgram(meshvs.c_str(), meshfs.c_str()); DebugData.meshgsProg = CreateShaderProgram(meshvs.c_str(), meshfs.c_str(), meshgs.c_str()); - WrappedOpenGL &gl = *m_pDriver; - void *ctx = gl.GetCtx(); gl.glGenProgramPipelines(1, &DebugData.texDisplayPipe); @@ -496,6 +544,12 @@ void GLReplay::DeleteDebugData() } gl.glDeleteProgram(DebugData.blitProg); + + if(DebugData.quadoverdrawFSProg) + { + gl.glDeleteProgram(DebugData.quadoverdrawFSProg); + gl.glDeleteProgram(DebugData.quadoverdrawResolveProg); + } gl.glDeleteProgram(DebugData.texDisplayVSProg); for(int i=0; i < 3; i++) @@ -1355,34 +1409,21 @@ void GLReplay::RenderHighlightBox(float w, float h, float scale) gl.glDrawArrays(eGL_LINE_LOOP, 0, 4); } -ResourceId GLReplay::RenderOverlay(ResourceId texid, TextureDisplayOverlay overlay, uint32_t frameID, uint32_t eventID, const vector &passEvents) +void GLReplay::SetupOverlayPipeline(GLuint Program, GLuint Pipeline, GLuint fragProgram) { WrappedOpenGL &gl = *m_pDriver; - - MakeCurrentReplayContext(&m_ReplayCtx); void *ctx = m_ReplayCtx.ctx; - GLRenderState rs(&gl.GetHookset(), NULL, READING); - rs.FetchState(ctx, &gl); - - // use our overlay pipeline that we'll fill up with all the right - // shaders, then replace the fragment shader with our own. - gl.glUseProgram(0); - gl.glBindProgramPipeline(DebugData.overlayPipe); - - // we bind the separable program created for each shader, and copy - // uniforms and attrib bindings from the 'real' programs, wherever - // they are. - if(rs.Program == 0) + if(Program == 0) { - if(rs.Pipeline == 0) + if(Pipeline == 0) { - return ResourceId(); + return; } else { - ResourceId id = m_pDriver->GetResourceManager()->GetID(ProgramPipeRes(ctx, rs.Pipeline)); + ResourceId id = m_pDriver->GetResourceManager()->GetID(ProgramPipeRes(ctx, Pipeline)); auto &pipeDetails = m_pDriver->m_Pipelines[id]; for(size_t i=0; i < 4; i++) @@ -1404,8 +1445,8 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, TextureDisplayOverlay overl } else { - auto &progDetails = m_pDriver->m_Programs[m_pDriver->GetResourceManager()->GetID(ProgramRes(ctx, rs.Program))]; - + auto &progDetails = m_pDriver->m_Programs[m_pDriver->GetResourceManager()->GetID(ProgramRes(ctx, Program))]; + for(size_t i=0; i < 4; i++) { if(progDetails.stageShaders[i] != ResourceId()) @@ -1414,16 +1455,38 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, TextureDisplayOverlay overl gl.glUseProgramStages(DebugData.overlayPipe, ShaderBit(i), progdst); - CopyProgramUniforms(gl.GetHookset(), rs.Program, progdst); + CopyProgramUniforms(gl.GetHookset(), Program, progdst); if(i == 0) - CopyProgramAttribBindings(gl.GetHookset(), rs.Program, progdst, GetShader(progDetails.stageShaders[i])); + CopyProgramAttribBindings(gl.GetHookset(), Program, progdst, GetShader(progDetails.stageShaders[i])); } } } // use the generic FS program by default, can be overridden for specific overlays if needed - gl.glUseProgramStages(DebugData.overlayPipe, eGL_FRAGMENT_SHADER_BIT, DebugData.genericFSProg); + gl.glUseProgramStages(DebugData.overlayPipe, eGL_FRAGMENT_SHADER_BIT, fragProgram); +} + +ResourceId GLReplay::RenderOverlay(ResourceId texid, TextureDisplayOverlay overlay, uint32_t frameID, uint32_t eventID, const vector &passEvents) +{ + WrappedOpenGL &gl = *m_pDriver; + + MakeCurrentReplayContext(&m_ReplayCtx); + + void *ctx = m_ReplayCtx.ctx; + + GLRenderState rs(&gl.GetHookset(), NULL, READING); + rs.FetchState(ctx, &gl); + + // use our overlay pipeline that we'll fill up with all the right + // shaders, then replace the fragment shader with our own. + gl.glUseProgram(0); + gl.glBindProgramPipeline(DebugData.overlayPipe); + + // we bind the separable program created for each shader, and copy + // uniforms and attrib bindings from the 'real' programs, wherever + // they are. + SetupOverlayPipeline(rs.Program, rs.Pipeline, DebugData.genericFSProg); auto &texDetails = m_pDriver->m_Textures[texid]; @@ -1448,7 +1511,7 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, TextureDisplayOverlay overl DebugData.overlayTexWidth = texDetails.width; DebugData.overlayTexHeight = texDetails.height; - gl.glTexStorage2D(eGL_TEXTURE_2D, 1, eGL_SRGB8_ALPHA8, texDetails.width, texDetails.height); + gl.glTexStorage2D(eGL_TEXTURE_2D, 1, eGL_RGBA16, texDetails.width, texDetails.height); gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_MIN_FILTER, eGL_NEAREST); gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_MAG_FILTER, eGL_NEAREST); gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_WRAP_S, eGL_CLAMP_TO_EDGE); @@ -1669,8 +1732,205 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, TextureDisplayOverlay overl } else if(overlay == eTexOverlay_QuadOverdrawDraw || overlay == eTexOverlay_QuadOverdrawPass) { - float unknown[] = { 0.2f, 0.1f, 0.1f, 0.5f }; - gl.glClearBufferfv(eGL_COLOR, 0, unknown); + if(DebugData.quadoverdraw420) + { + RDCWARN("Quad overdraw requires GLSL 4.50 for dFd(xy)fine, using possibly coarse dFd(xy)."); + m_pDriver->AddDebugMessage(eDbgCategory_Portability, eDbgSeverity_Medium, eDbgSource_RuntimeWarning, + "Quad overdraw requires GLSL 4.50 for dFd(xy)fine, using possibly coarse dFd(xy)."); + } + + { + SCOPED_TIMER("Quad Overdraw"); + + float black[] = { 0.0f, 0.0f, 0.0f, 0.0f }; + gl.glClearBufferfv(eGL_COLOR, 0, black); + + vector events = passEvents; + + if(overlay == eTexOverlay_QuadOverdrawDraw) + events.clear(); + + events.push_back(eventID); + + if(!events.empty()) + { + GLuint replacefbo = 0; + GLuint quadtexs[3] = { 0 }; + gl.glGenFramebuffers(1, &replacefbo); + gl.glBindFramebuffer(eGL_FRAMEBUFFER, replacefbo); + + gl.glGenTextures(3, quadtexs); + + // image for quad usage + gl.glBindTexture(eGL_TEXTURE_2D_ARRAY, quadtexs[2]); + gl.glTexStorage3D(eGL_TEXTURE_2D_ARRAY, 1, eGL_R32UI, texDetails.width>>1, texDetails.height>>1, 4); + + // temporarily attach to FBO to clear it + GLint zero = 0; + gl.glFramebufferTextureLayer(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, quadtexs[2], 0, 0); + gl.glClearBufferiv(eGL_COLOR, 0, &zero); + gl.glFramebufferTextureLayer(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, quadtexs[2], 0, 1); + gl.glClearBufferiv(eGL_COLOR, 0, &zero); + gl.glFramebufferTextureLayer(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, quadtexs[2], 0, 2); + gl.glClearBufferiv(eGL_COLOR, 0, &zero); + gl.glFramebufferTextureLayer(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, quadtexs[2], 0, 3); + gl.glClearBufferiv(eGL_COLOR, 0, &zero); + + gl.glBindTexture(eGL_TEXTURE_2D, quadtexs[0]); + gl.glTexStorage2D(eGL_TEXTURE_2D, 1, eGL_RGBA8, texDetails.width, texDetails.height); + gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_MIN_FILTER, eGL_NEAREST); + gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_MAG_FILTER, eGL_NEAREST); + gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_WRAP_S, eGL_CLAMP_TO_EDGE); + gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_WRAP_T, eGL_CLAMP_TO_EDGE); + gl.glFramebufferTexture(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, quadtexs[0], 0); + + gl.glBindTexture(eGL_TEXTURE_2D, quadtexs[1]); + gl.glTexStorage2D(eGL_TEXTURE_2D, 1, eGL_DEPTH32F_STENCIL8, texDetails.width, texDetails.height); + gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_MIN_FILTER, eGL_NEAREST); + gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_MAG_FILTER, eGL_NEAREST); + gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_WRAP_S, eGL_CLAMP_TO_EDGE); + gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_WRAP_T, eGL_CLAMP_TO_EDGE); + gl.glFramebufferTexture(eGL_FRAMEBUFFER, eGL_DEPTH_STENCIL_ATTACHMENT, quadtexs[1], 0); + + if(overlay == eTexOverlay_QuadOverdrawPass) + ReplayLog(frameID, 0, events[0], eReplay_WithoutDraw); + else + rs.ApplyState(m_pDriver->GetCtx(), m_pDriver); + + GLuint lastProg = 0, lastPipe = 0; + for(size_t i=0; i < events.size(); i++) + { + GLint depthwritemask = 1; + GLint stencilfmask = 0xff, stencilbmask = 0xff; + GLuint curdrawfbo = 0, curreadfbo = 0; + struct + { + GLuint name; + GLuint level; + GLboolean layered; + GLuint layer; + GLenum access; + GLenum format; + } curimage0 = {0}; + + // save the state we're going to mess with + { + gl.glGetIntegerv(eGL_DEPTH_WRITEMASK, &depthwritemask); + gl.glGetIntegerv(eGL_STENCIL_WRITEMASK, &stencilfmask); + gl.glGetIntegerv(eGL_STENCIL_BACK_WRITEMASK, &stencilbmask); + + gl.glGetIntegerv(eGL_DRAW_FRAMEBUFFER_BINDING, (GLint *)&curdrawfbo); + gl.glGetIntegerv(eGL_READ_FRAMEBUFFER_BINDING, (GLint *)&curreadfbo); + + gl.glGetIntegeri_v(eGL_IMAGE_BINDING_NAME, 0, (GLint *)&curimage0.name); + gl.glGetIntegeri_v(eGL_IMAGE_BINDING_LEVEL, 0, (GLint*)&curimage0.level); + gl.glGetIntegeri_v(eGL_IMAGE_BINDING_ACCESS, 0, (GLint*)&curimage0.access); + gl.glGetIntegeri_v(eGL_IMAGE_BINDING_FORMAT, 0, (GLint*)&curimage0.format); + gl.glGetBooleani_v(eGL_IMAGE_BINDING_LAYERED, 0, &curimage0.layered); + if(curimage0.layered) + gl.glGetIntegeri_v(eGL_IMAGE_BINDING_LAYER, 0, (GLint*)&curimage0.layer); + } + + // disable depth and stencil writes + gl.glDepthMask(GL_FALSE); + gl.glStencilMask(GL_FALSE); + + // bind our FBO + gl.glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, replacefbo); + // bind image + gl.glBindImageTexture(0, quadtexs[2], 0, GL_TRUE, 0, eGL_READ_WRITE, eGL_R32UI); + + GLuint prog = 0, pipe = 0; + gl.glGetIntegerv(eGL_CURRENT_PROGRAM, (GLint *)&prog); + gl.glGetIntegerv(eGL_PROGRAM_PIPELINE_BINDING, (GLint *)&pipe); + + // replace fragment shader. This is exactly what we did + // at the start of this function for the single-event case, but now we have + // to do it for every event + SetupOverlayPipeline(prog, pipe, DebugData.quadoverdrawFSProg); + gl.glUseProgram(0); + gl.glBindProgramPipeline(DebugData.overlayPipe); + + lastProg = prog; + lastPipe = pipe; + + gl.glBindFramebuffer(eGL_READ_FRAMEBUFFER, curdrawfbo); + gl.glBlitFramebuffer(0, 0, texDetails.width, texDetails.height, + 0, 0, texDetails.width, texDetails.height, + GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, eGL_NEAREST); + + ReplayLog(frameID, events[i], events[i], eReplay_OnlyDraw); + + // pop the state that we messed with + { + gl.glBindProgramPipeline(pipe); + gl.glUseProgram(prog); + + if(curimage0.name) + gl.glBindImageTexture(0, curimage0.name, curimage0.level, curimage0.layered ? GL_TRUE : GL_FALSE, curimage0.layer, curimage0.access, curimage0.format); + else + gl.glBindImageTexture(0, 0, 0, GL_FALSE, 0, eGL_READ_ONLY, eGL_R32UI); + + gl.glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, curdrawfbo); + gl.glBindFramebuffer(eGL_READ_FRAMEBUFFER, curreadfbo); + + gl.glDepthMask(depthwritemask ? GL_TRUE : GL_FALSE); + gl.glStencilMaskSeparate(eGL_FRONT, (GLuint)stencilfmask); + gl.glStencilMaskSeparate(eGL_BACK, (GLuint)stencilbmask); + } + + if(overlay == eTexOverlay_QuadOverdrawPass) + { + ReplayLog(frameID, events[i], events[i], eReplay_OnlyDraw); + + if(i+1 < events.size()) + ReplayLog(frameID, events[i], events[i+1], eReplay_WithoutDraw); + } + } + + // resolve pass + { + gl.glUseProgram(DebugData.quadoverdrawResolveProg); + gl.glBindProgramPipeline(0); + + GLint rampLoc = gl.glGetUniformLocation(DebugData.quadoverdrawResolveProg, "overdrawRampColours"); + gl.glProgramUniform4fv(DebugData.quadoverdrawResolveProg, rampLoc, ARRAY_COUNT(overdrawRamp), (float *)&overdrawRamp[0].x); + + // modify our fbo to attach the overlay texture instead + gl.glBindFramebuffer(eGL_FRAMEBUFFER, replacefbo); + gl.glFramebufferTexture(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, DebugData.overlayTex, 0); + gl.glFramebufferTexture(eGL_FRAMEBUFFER, eGL_DEPTH_STENCIL_ATTACHMENT, 0, 0); + + gl.glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + gl.glDisable(eGL_BLEND); + gl.glDisable(eGL_SCISSOR_TEST); + gl.glDepthMask(GL_FALSE); + gl.glDisable(eGL_CULL_FACE); + gl.glPolygonMode(eGL_FRONT_AND_BACK, eGL_FILL); + gl.glDisable(eGL_DEPTH_TEST); + gl.glDisable(eGL_STENCIL_TEST); + gl.glStencilMask(0); + gl.glViewport(0, 0, texDetails.width, texDetails.height); + + gl.glBindImageTexture(0, quadtexs[2], 0, GL_FALSE, 0, eGL_READ_WRITE, eGL_R32UI); + + GLuint emptyVAO = 0; + gl.glGenVertexArrays(1, &emptyVAO); + gl.glBindVertexArray(emptyVAO); + gl.glDrawArrays(eGL_TRIANGLE_STRIP, 0, 4); + gl.glBindVertexArray(0); + gl.glDeleteVertexArrays(1, &emptyVAO); + + gl.glFramebufferTexture(eGL_FRAMEBUFFER, eGL_COLOR_ATTACHMENT0, quadtexs[0], 0); + } + + gl.glDeleteFramebuffers(1, &replacefbo); + gl.glDeleteTextures(3, quadtexs); + + if(overlay == eTexOverlay_QuadOverdrawPass) + ReplayLog(frameID, 0, eventID, eReplay_WithoutDraw); + } + } } else { diff --git a/renderdoc/driver/gl/gl_driver.cpp b/renderdoc/driver/gl/gl_driver.cpp index d1f3c5845..322ade015 100644 --- a/renderdoc/driver/gl/gl_driver.cpp +++ b/renderdoc/driver/gl/gl_driver.cpp @@ -1928,6 +1928,21 @@ void WrappedOpenGL::FinishCapture() //m_SuccessfulCapture = false; } +void WrappedOpenGL::AddDebugMessage(DebugMessageCategory c, DebugMessageSeverity sv, DebugMessageSource src, std::string d) +{ + if(m_State == READING || src == eDbgSource_RuntimeWarning) + { + DebugMessage msg; + msg.eventID = m_CurEventID; + msg.messageID = 0; + msg.source = src; + msg.category = c; + msg.severity = sv; + msg.description = d; + m_DebugMessages.push_back(msg); + } +} + vector WrappedOpenGL::GetDebugMessages() { vector ret; diff --git a/renderdoc/driver/gl/gl_driver.h b/renderdoc/driver/gl/gl_driver.h index 36a27db32..cc4604944 100644 --- a/renderdoc/driver/gl/gl_driver.h +++ b/renderdoc/driver/gl/gl_driver.h @@ -373,6 +373,9 @@ class WrappedOpenGL void SetDebugMsgContext(const char *context) { m_DebugMsgContext = context; } + void AddDebugMessage(DebugMessage msg) { if(m_State < WRITING) m_DebugMessages.push_back(msg); } + void AddDebugMessage(DebugMessageCategory c, DebugMessageSeverity sv, DebugMessageSource src, std::string d); + // replay interface void Initialise(GLInitParams ¶ms); void ReplayLog(uint32_t frameID, uint32_t startEventID, uint32_t endEventID, ReplayLogType replayType); diff --git a/renderdoc/driver/gl/gl_replay.h b/renderdoc/driver/gl/gl_replay.h index cbf29b4ab..aa54c3ba2 100644 --- a/renderdoc/driver/gl/gl_replay.h +++ b/renderdoc/driver/gl/gl_replay.h @@ -195,6 +195,7 @@ class GLReplay : public IReplayDriver const vector &data); void CreateCustomShaderTex(uint32_t w, uint32_t h); + void SetupOverlayPipeline(GLuint Program, GLuint Pipeline, GLuint fragProgram); void GetMapping(WrappedOpenGL &gl, GLuint curProg, int shadIdx, ShaderReflection *refl, ShaderBindpointMapping &mapping); @@ -289,6 +290,10 @@ class GLReplay : public IReplayDriver GLuint pickPixelTex; GLuint pickPixelFBO; + GLuint quadoverdrawFSProg; + GLuint quadoverdrawResolveProg; + bool quadoverdraw420; + GLuint overlayTex; GLuint overlayFBO; GLuint overlayPipe; diff --git a/renderdoc/renderdoc.vcxproj b/renderdoc/renderdoc.vcxproj index 9196f8a32..86027f458 100644 --- a/renderdoc/renderdoc.vcxproj +++ b/renderdoc/renderdoc.vcxproj @@ -376,6 +376,7 @@ + diff --git a/renderdoc/renderdoc.vcxproj.filters b/renderdoc/renderdoc.vcxproj.filters index c4bef7d36..d8101bf4f 100644 --- a/renderdoc/renderdoc.vcxproj.filters +++ b/renderdoc/renderdoc.vcxproj.filters @@ -610,6 +610,9 @@ Resources\glsl + + Resources\glsl +