From de06321536d7dc67e6701c4d6beaecbcb6f45949 Mon Sep 17 00:00:00 2001 From: Jake Turner Date: Tue, 22 Aug 2023 08:23:06 +0100 Subject: [PATCH] Extend GL Depth Test Overlay Support shader exported depth by replaying using the capture pixel shader to determine passing pixels via a stencil mask --- renderdoc/CMakeLists.txt | 2 + renderdoc/data/embedded_files.h | 2 + renderdoc/data/glsl/depth_copy.frag | 41 ++++++++ renderdoc/data/glsl/depth_copyms.frag | 47 +++++++++ renderdoc/data/renderdoc.rc | 2 + renderdoc/data/resource.h | 2 + renderdoc/driver/gl/gl_debug.cpp | 15 +++ renderdoc/driver/gl/gl_overlay.cpp | 135 +++++++++++++++++++++++--- renderdoc/driver/gl/gl_replay.h | 4 + renderdoc/renderdoc.vcxproj | 2 + renderdoc/renderdoc.vcxproj.filters | 6 ++ 11 files changed, 245 insertions(+), 13 deletions(-) create mode 100644 renderdoc/data/glsl/depth_copy.frag create mode 100644 renderdoc/data/glsl/depth_copyms.frag diff --git a/renderdoc/CMakeLists.txt b/renderdoc/CMakeLists.txt index 693f86313..cff654c00 100644 --- a/renderdoc/CMakeLists.txt +++ b/renderdoc/CMakeLists.txt @@ -418,6 +418,8 @@ endif() set(data data/glsl/blit.vert data/glsl/checkerboard.frag + data/glsl/depth_copy.frag + data/glsl/depth_copyms.frag data/glsl/glsl_ubos.h data/glsl/glsl_globals.h data/glsl/fixedcol.frag diff --git a/renderdoc/data/embedded_files.h b/renderdoc/data/embedded_files.h index f517b281c..084cfee84 100644 --- a/renderdoc/data/embedded_files.h +++ b/renderdoc/data/embedded_files.h @@ -73,5 +73,7 @@ DECLARE_EMBED(glsl_vk_ms2buffer_comp); DECLARE_EMBED(glsl_vk_depthms2buffer_comp); DECLARE_EMBED(glsl_vk_buffer2ms_comp); DECLARE_EMBED(glsl_vk_depthbuf2ms_frag); +DECLARE_EMBED(glsl_depth_copy_frag); +DECLARE_EMBED(glsl_depth_copyms_frag); #undef DECLARE_EMBED diff --git a/renderdoc/data/glsl/depth_copy.frag b/renderdoc/data/glsl/depth_copy.frag new file mode 100644 index 000000000..237f43cf8 --- /dev/null +++ b/renderdoc/data/glsl/depth_copy.frag @@ -0,0 +1,41 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2020-2023 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 "glsl_globals.h" + +#if defined(VULKAN) + +layout(binding = 0) uniform sampler2D srcDepth; + +#else + +uniform PRECISION sampler2D srcDepth; + +#endif + +void main() +{ + ivec2 srcCoord = ivec2(int(gl_FragCoord.x), int(gl_FragCoord.y)); + gl_FragDepth = texelFetch(srcDepth, srcCoord, 0).x; +} diff --git a/renderdoc/data/glsl/depth_copyms.frag b/renderdoc/data/glsl/depth_copyms.frag new file mode 100644 index 000000000..76aed1ded --- /dev/null +++ b/renderdoc/data/glsl/depth_copyms.frag @@ -0,0 +1,47 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2020-2023 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. + ******************************************************************************/ + +#if defined(GLES) +#extension GL_OES_sample_variables : require +#elif defined(OPENGL_CORE) +#extension GL_ARB_sample_shading : require +#endif + +#include "glsl_globals.h" + +#if defined(VULKAN) + +layout(binding = 0) uniform sampler2DMS srcDepth; + +#else + +uniform PRECISION sampler2DMS srcDepth; + +#endif + +void main() +{ + ivec2 srcCoord = ivec2(int(gl_FragCoord.x), int(gl_FragCoord.y)); + gl_FragDepth = texelFetch(srcDepth, srcCoord, gl_SampleID).x; +} diff --git a/renderdoc/data/renderdoc.rc b/renderdoc/data/renderdoc.rc index 260d37e37..857fb2d27 100644 --- a/renderdoc/data/renderdoc.rc +++ b/renderdoc/data/renderdoc.rc @@ -148,6 +148,8 @@ RESOURCE_glsl_texdisplay_frag TYPE_EMBED "glsl/texdisplay.frag" RESOURCE_glsl_vktext_vert TYPE_EMBED "glsl/vktext.vert" RESOURCE_glsl_vktext_frag TYPE_EMBED "glsl/vktext.frag" RESOURCE_glsl_fixedcol_frag TYPE_EMBED "glsl/fixedcol.frag" +RESOURCE_glsl_depth_copy_frag TYPE_EMBED "glsl/depth_copy.frag" +RESOURCE_glsl_depth_copyms_frag TYPE_EMBED "glsl/depth_copyms.frag" RESOURCE_glsl_mesh_vert TYPE_EMBED "glsl/mesh.vert" RESOURCE_glsl_mesh_geom TYPE_EMBED "glsl/mesh.geom" RESOURCE_glsl_mesh_frag TYPE_EMBED "glsl/mesh.frag" diff --git a/renderdoc/data/resource.h b/renderdoc/data/resource.h index f5ebdc8a1..75dc2df92 100644 --- a/renderdoc/data/resource.h +++ b/renderdoc/data/resource.h @@ -66,6 +66,8 @@ #define RESOURCE_glsl_vk_depthms2buffer_comp 448 #define RESOURCE_glsl_vk_buffer2ms_comp 449 #define RESOURCE_glsl_vk_depthbuf2ms_frag 450 +#define RESOURCE_glsl_depth_copy_frag 451 +#define RESOURCE_glsl_depth_copyms_frag 452 // Next default values for new objects // diff --git a/renderdoc/driver/gl/gl_debug.cpp b/renderdoc/driver/gl/gl_debug.cpp index c00991e6b..5756fcf5c 100644 --- a/renderdoc/driver/gl/gl_debug.cpp +++ b/renderdoc/driver/gl/gl_debug.cpp @@ -444,6 +444,14 @@ void GLReplay::InitDebugData() DebugData.texDisplayVertexShader = CreateShader(eGL_VERTEX_SHADER, vs); vs = GenerateGLSLShader(GetEmbeddedResource(glsl_blit_vert), shaderType, glslBaseVer); + fs = GenerateGLSLShader(GetEmbeddedResource(glsl_fixedcol_frag), shaderType, glslBaseVer); + DebugData.fullScreenFixedColProg = CreateShaderProgram(vs, fs); + + fs = GenerateGLSLShader(GetEmbeddedResource(glsl_depth_copy_frag), shaderType, glslBaseVer); + DebugData.fullScreenCopyDepth = CreateShaderProgram(vs, fs); + + fs = GenerateGLSLShader(GetEmbeddedResource(glsl_depth_copyms_frag), shaderType, glslBaseVer); + DebugData.fullScreenCopyDepthMS = CreateShaderProgram(vs, fs); DebugData.fixedcolFragShaderSPIRV = DebugData.quadoverdrawFragShaderSPIRV = 0; @@ -1225,6 +1233,13 @@ void GLReplay::DeleteDebugData() drv.glDeleteFramebuffers(1, &DebugData.overlayFBO); drv.glDeleteTextures(1, &DebugData.overlayTex); + if(DebugData.fullScreenFixedColProg) + drv.glDeleteProgram(DebugData.fullScreenFixedColProg); + if(DebugData.fullScreenCopyDepth) + drv.glDeleteProgram(DebugData.fullScreenCopyDepth); + if(DebugData.fullScreenCopyDepthMS) + drv.glDeleteProgram(DebugData.fullScreenCopyDepthMS); + if(DebugData.quadoverdrawFragShader) drv.glDeleteShader(DebugData.quadoverdrawFragShader); if(DebugData.quadoverdrawFragShaderSPIRV) diff --git a/renderdoc/driver/gl/gl_overlay.cpp b/renderdoc/driver/gl/gl_overlay.cpp index ef5bd381e..2fcd28f2e 100644 --- a/renderdoc/driver/gl/gl_overlay.cpp +++ b/renderdoc/driver/gl/gl_overlay.cpp @@ -475,6 +475,9 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, Debug RDCWARN("Quad overdraw not supported on GLES", glslVer); } + GLuint prog = 0, pipe = 0; + drv.glGetIntegerv(eGL_CURRENT_PROGRAM, (GLint *)&prog); + drv.glGetIntegerv(eGL_PROGRAM_PIPELINE_BINDING, (GLint *)&pipe); // delete the old program if it exists if(DebugData.overlayProg != 0) drv.glDeleteProgram(DebugData.overlayProg); @@ -1008,6 +1011,7 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, Debug GLenum copyQueryEnum = texQueryEnum; GLuint depthCopy = 0, stencilCopy = 0; + bool useBlitFramebuffer = true; // create matching depth for existing FBO if(curDepth != 0) @@ -1046,6 +1050,22 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, Debug else if(depth == 0 && stencil == 8) fmt = eGL_STENCIL_INDEX8; } + // For depth overlay : need a stencil buffer + if(overlay == DebugOverlay::Depth) + { + GLenum oldFmt = fmt; + if((oldFmt == eGL_DEPTH_COMPONENT16) || (oldFmt == eGL_DEPTH_COMPONENT24) || + (oldFmt == eGL_DEPTH24_STENCIL8)) + fmt = eGL_DEPTH24_STENCIL8; + else + fmt = eGL_DEPTH32F_STENCIL8; + + if(oldFmt != fmt) + { + useBlitFramebuffer = false; + curStencil = curDepth; + } + } if(copyBindingEnum == eGL_TEXTURE_CUBE_MAP) { @@ -1127,18 +1147,18 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, Debug if(type != eGL_RENDERBUFFER) { - ResourceId id = m_pDriver->GetResourceManager()->GetResID(TextureRes(ctx, curDepth)); + ResourceId id = m_pDriver->GetResourceManager()->GetResID(TextureRes(ctx, curStencil)); fmt = m_pDriver->m_Textures[id].internalFormat; } else { - ResourceId id = m_pDriver->GetResourceManager()->GetResID(RenderbufferRes(ctx, curDepth)); + ResourceId id = m_pDriver->GetResourceManager()->GetResID(RenderbufferRes(ctx, curStencil)); fmt = m_pDriver->m_Textures[id].internalFormat; GLint depth = 0; GLint stencil = 0; - GL.glGetNamedRenderbufferParameterivEXT(curDepth, eGL_RENDERBUFFER_DEPTH_SIZE, &depth); - GL.glGetNamedRenderbufferParameterivEXT(curDepth, eGL_RENDERBUFFER_STENCIL_SIZE, &stencil); + GL.glGetNamedRenderbufferParameterivEXT(curStencil, eGL_RENDERBUFFER_DEPTH_SIZE, &depth); + GL.glGetNamedRenderbufferParameterivEXT(curStencil, eGL_RENDERBUFFER_STENCIL_SIZE, &stencil); if(depth == 16 && stencil == 0) fmt = eGL_DEPTH_COMPONENT16; @@ -1222,6 +1242,9 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, Debug drv.glBindTexture(copyBindingEnum, curTex); } + // bind the 'real' fbo to the read framebuffer, so we can blit from it + drv.glBindFramebuffer(eGL_READ_FRAMEBUFFER, rs.DrawFBO.name); + // bind depth/stencil to overlay FBO (currently bound to DRAW_FRAMEBUFFER) if(curDepth != 0 && curDepth == curStencil) { @@ -1239,11 +1262,46 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, Debug stencilCopy, sub.mip); } - // bind the 'real' fbo to the read framebuffer, so we can blit from it - drv.glBindFramebuffer(eGL_READ_FRAMEBUFFER, rs.DrawFBO.name); + if(useBlitFramebuffer) + { + // get latest depth/stencil from read FBO (existing FBO) into draw FBO (overlay FBO) + SafeBlitFramebuffer(0, 0, outWidth, outHeight, 0, 0, outWidth, outHeight, + GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, eGL_NEAREST); + } + else + { + GLRenderState savedRS; + savedRS.FetchState(&drv); - float green[] = {0.0f, 1.0f, 0.0f, 1.0f}; - drv.glProgramUniform4fv(DebugData.overlayProg, overlayFixedColLocation, 1, green); + // Fullscreen pass with shader to read from old depth buffer and write to new depth buffer + drv.glDisable(eGL_BLEND); + drv.glDisable(eGL_SCISSOR_TEST); + drv.glDisable(eGL_STENCIL_TEST); + drv.glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + drv.glEnable(eGL_DEPTH_TEST); + drv.glDepthFunc(eGL_ALWAYS); + drv.glDepthMask(GL_TRUE); + drv.glDisable(eGL_CULL_FACE); + if(!IsGLES) + drv.glPolygonMode(eGL_FRONT_AND_BACK, eGL_FILL); + + if(DebugData.overlayTexSamples > 1) + drv.glUseProgram(DebugData.fullScreenCopyDepthMS); + else + drv.glUseProgram(DebugData.fullScreenCopyDepth); + drv.glBindProgramPipeline(0); + + drv.glActiveTexture(eGL_TEXTURE0); + drv.glBindTexture(copyBindingEnum, curDepth); + + GLuint emptyVAO = 0; + drv.glGenVertexArrays(1, &emptyVAO); + drv.glBindVertexArray(emptyVAO); + drv.glDrawArrays(eGL_TRIANGLE_STRIP, 0, 4); + drv.glDeleteVertexArrays(1, &emptyVAO); + + savedRS.ApplyState(&drv); + } if(overlay == DebugOverlay::Depth) { @@ -1273,12 +1331,61 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, Debug if(!IsGLES && !rs.Enabled[GLRenderState::eEnabled_DepthClamp]) drv.glDisable(eGL_DEPTH_CLAMP); - // get latest depth/stencil from read FBO (existing FBO) into draw FBO (overlay FBO) - SafeBlitFramebuffer(0, 0, outWidth, outHeight, 0, 0, outWidth, outHeight, - GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, eGL_NEAREST); + bool useDepthStencilMask = (overlay == DebugOverlay::Depth) && (curDepth != 0); + if(useDepthStencilMask) + { + drv.glStencilMask(0xff); + GLint stencilClear = 0x0; + drv.glClearBufferiv(eGL_STENCIL, 0, &stencilClear); + drv.glEnable(eGL_STENCIL_TEST); + drv.glStencilFunc(eGL_ALWAYS, 1, 0xff); + drv.glStencilOp(eGL_KEEP, eGL_KEEP, eGL_REPLACE); + + drv.glBindProgramPipeline(pipe); + drv.glUseProgram(prog); + + drv.glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + } + else + { + float green[] = {0.0f, 1.0f, 0.0f, 1.0f}; + drv.glProgramUniform4fv(DebugData.overlayProg, overlayFixedColLocation, 1, green); + } ReplayLog(eventId, eReplay_OnlyDraw); + if(useDepthStencilMask) + { + float green[] = {0.0f, 1.0f, 0.0f, 1.0f}; + GLint fixedColLocation = 99; + if(!spirvOverlay) + fixedColLocation = + drv.glGetUniformLocation(DebugData.fullScreenFixedColProg, "RENDERDOC_Fixed_Color"); + drv.glProgramUniform4fv(DebugData.fullScreenFixedColProg, fixedColLocation, 1, green); + + drv.glDisable(eGL_BLEND); + drv.glDisable(eGL_SCISSOR_TEST); + drv.glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + drv.glDepthMask(GL_FALSE); + drv.glDisable(eGL_CULL_FACE); + if(!IsGLES) + drv.glPolygonMode(eGL_FRONT_AND_BACK, eGL_FILL); + drv.glDisable(eGL_DEPTH_TEST); + drv.glEnable(eGL_STENCIL_TEST); + drv.glStencilMask(0x0); + drv.glStencilFunc(eGL_EQUAL, 1, 0xff); + + drv.glUseProgram(DebugData.fullScreenFixedColProg); + drv.glBindProgramPipeline(0); + + GLuint emptyVAO = 0; + drv.glGenVertexArrays(1, &emptyVAO); + drv.glBindVertexArray(emptyVAO); + drv.glDrawArrays(eGL_TRIANGLE_STRIP, 0, 4); + drv.glBindVertexArray(0); + drv.glDeleteVertexArrays(1, &emptyVAO); + } + // unset depth/stencil textures from overlay FBO and delete temp depth/stencil if(curDepth != 0 && curDepth == curStencil) drv.glFramebufferTexture2D(eGL_DRAW_FRAMEBUFFER, eGL_DEPTH_STENCIL_ATTACHMENT, eGL_TEXTURE_2D, @@ -1681,7 +1788,8 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, Debug } } - GLuint prog = 0, pipe = 0; + prog = 0; + pipe = 0; drv.glGetIntegerv(eGL_CURRENT_PROGRAM, (GLint *)&prog); drv.glGetIntegerv(eGL_PROGRAM_PIPELINE_BINDING, (GLint *)&pipe); @@ -2060,7 +2168,8 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, FloatVector clearCol, Debug // bind image drv.glBindImageTexture(0, quadtexs[1], 0, GL_TRUE, 0, eGL_READ_WRITE, eGL_R32UI); - GLuint prog = 0, pipe = 0; + prog = 0; + pipe = 0; drv.glGetIntegerv(eGL_CURRENT_PROGRAM, (GLint *)&prog); drv.glGetIntegerv(eGL_PROGRAM_PIPELINE_BINDING, (GLint *)&pipe); diff --git a/renderdoc/driver/gl/gl_replay.h b/renderdoc/driver/gl/gl_replay.h index e957388e6..a3f3bf2b4 100644 --- a/renderdoc/driver/gl/gl_replay.h +++ b/renderdoc/driver/gl/gl_replay.h @@ -411,6 +411,10 @@ private: GLuint quadoverdrawFragShaderSPIRV; GLuint quadoverdrawResolveProg; + GLuint fullScreenFixedColProg; + GLuint fullScreenCopyDepth; + GLuint fullScreenCopyDepthMS; + GLuint discardProg[3][4]; GLuint discardPatternBuffer; diff --git a/renderdoc/renderdoc.vcxproj b/renderdoc/renderdoc.vcxproj index a56345ad2..98d3042e5 100644 --- a/renderdoc/renderdoc.vcxproj +++ b/renderdoc/renderdoc.vcxproj @@ -683,6 +683,8 @@ + + diff --git a/renderdoc/renderdoc.vcxproj.filters b/renderdoc/renderdoc.vcxproj.filters index 3571c74e0..76bc6413d 100644 --- a/renderdoc/renderdoc.vcxproj.filters +++ b/renderdoc/renderdoc.vcxproj.filters @@ -1130,6 +1130,12 @@ Resources\glsl + + Resources\glsl + + + Resources\glsl +