diff --git a/renderdoc/driver/gl/gl_common.cpp b/renderdoc/driver/gl/gl_common.cpp index 97db51027..5b9762ddf 100644 --- a/renderdoc/driver/gl/gl_common.cpp +++ b/renderdoc/driver/gl/gl_common.cpp @@ -1335,6 +1335,81 @@ GLuint GetBoundVertexBuffer(GLuint i) return buffer; } +void SafeBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, + GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) +{ + bool scissorEnabled = false; + GLboolean ColorMask[4] = {GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE}; + GLboolean DepthMask = GL_TRUE; + GLint StencilMask = 0xff, StencilBackMask = 0xff; + + // fetch current state + { + if(HasExt[ARB_viewport_array]) + scissorEnabled = GL.glIsEnabledi(eGL_SCISSOR_TEST, 0) != 0; + else + scissorEnabled = GL.glIsEnabled(eGL_SCISSOR_TEST) != 0; + + if(HasExt[EXT_draw_buffers2] || HasExt[ARB_draw_buffers_blend]) + GL.glGetBooleani_v(eGL_COLOR_WRITEMASK, 0, ColorMask); + else + GL.glGetBooleanv(eGL_COLOR_WRITEMASK, ColorMask); + + GL.glGetBooleanv(eGL_DEPTH_WRITEMASK, &DepthMask); + + GL.glGetIntegerv(eGL_STENCIL_WRITEMASK, &StencilMask); + GL.glGetIntegerv(eGL_STENCIL_BACK_WRITEMASK, &StencilBackMask); + } + + // apply safe state + { + if(HasExt[ARB_viewport_array]) + GL.glDisablei(eGL_SCISSOR_TEST, 0); + else + GL.glDisable(eGL_SCISSOR_TEST); + + if(HasExt[EXT_draw_buffers2] || HasExt[ARB_draw_buffers_blend]) + GL.glColorMaski(0, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + else + GL.glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + + GL.glDepthMask(GL_TRUE); + + GL.glStencilMaskSeparate(eGL_FRONT, 0xff); + GL.glStencilMaskSeparate(eGL_BACK, 0xff); + } + + GL.glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); + + // restore original state + { + if(HasExt[ARB_viewport_array]) + { + if(scissorEnabled) + GL.glEnablei(eGL_SCISSOR_TEST, 0); + else + GL.glDisablei(eGL_SCISSOR_TEST, 0); + } + else + { + if(scissorEnabled) + GL.glEnable(eGL_SCISSOR_TEST); + else + GL.glDisable(eGL_SCISSOR_TEST); + } + + if(HasExt[EXT_draw_buffers2] || HasExt[ARB_draw_buffers_blend]) + GL.glColorMaski(0, ColorMask[0], ColorMask[1], ColorMask[2], ColorMask[3]); + else + GL.glColorMask(ColorMask[0], ColorMask[1], ColorMask[2], ColorMask[3]); + + GL.glDepthMask(DepthMask); + + GL.glStencilMaskSeparate(eGL_FRONT, StencilMask); + GL.glStencilMaskSeparate(eGL_BACK, StencilBackMask); + } +} + BufferCategory MakeBufferCategory(GLenum bufferTarget) { switch(bufferTarget) diff --git a/renderdoc/driver/gl/gl_common.h b/renderdoc/driver/gl/gl_common.h index 41ddafb5c..9e45dbe34 100644 --- a/renderdoc/driver/gl/gl_common.h +++ b/renderdoc/driver/gl/gl_common.h @@ -499,6 +499,11 @@ void GetBindpointMapping(GLuint curProg, int shadIdx, ShaderReflection *refl, void ResortBindings(ShaderReflection *refl, ShaderBindpointMapping *mapping); +// calls glBlitFramebuffer but ensures no state can interfere like scissor or color mask +// pops state for only a single drawbuffer! +void SafeBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, + GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); + enum UniformType { UNIFORM_UNKNOWN, diff --git a/renderdoc/driver/gl/gl_debug.cpp b/renderdoc/driver/gl/gl_debug.cpp index ab23cf2fa..f23da5f20 100644 --- a/renderdoc/driver/gl/gl_debug.cpp +++ b/renderdoc/driver/gl/gl_debug.cpp @@ -877,7 +877,7 @@ bool GLReplay::GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, uin GL.glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, texDetails.renderbufferFBOs[1]); GL.glBindFramebuffer(eGL_READ_FRAMEBUFFER, texDetails.renderbufferFBOs[0]); - GL.glBlitFramebuffer( + SafeBlitFramebuffer( 0, 0, texDetails.width, texDetails.height, 0, 0, texDetails.width, texDetails.height, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, eGL_NEAREST); @@ -1049,7 +1049,7 @@ bool GLReplay::GetHistogram(ResourceId texid, uint32_t sliceFace, uint32_t mip, GL.glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, texDetails.renderbufferFBOs[1]); GL.glBindFramebuffer(eGL_READ_FRAMEBUFFER, texDetails.renderbufferFBOs[0]); - GL.glBlitFramebuffer( + SafeBlitFramebuffer( 0, 0, texDetails.width, texDetails.height, 0, 0, texDetails.width, texDetails.height, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, eGL_NEAREST); diff --git a/renderdoc/driver/gl/gl_overlay.cpp b/renderdoc/driver/gl/gl_overlay.cpp index 1a8526178..1e4d1623a 100644 --- a/renderdoc/driver/gl/gl_overlay.cpp +++ b/renderdoc/driver/gl/gl_overlay.cpp @@ -699,9 +699,9 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, CompType typeHint, DebugOve } // get latest depth/stencil from read FBO (existing FBO) into draw FBO (overlay FBO) - drv.glBlitFramebuffer(0, 0, DebugData.overlayTexWidth, DebugData.overlayTexHeight, 0, 0, - DebugData.overlayTexWidth, DebugData.overlayTexHeight, - GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, eGL_NEAREST); + SafeBlitFramebuffer(0, 0, DebugData.overlayTexWidth, DebugData.overlayTexHeight, 0, 0, + DebugData.overlayTexWidth, DebugData.overlayTexHeight, + GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, eGL_NEAREST); ReplayLog(eventId, eReplay_OnlyDraw); @@ -1317,9 +1317,9 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, CompType typeHint, DebugOve drv.glBindProgramPipeline(0); drv.glBindFramebuffer(eGL_READ_FRAMEBUFFER, curdrawfbo); - drv.glBlitFramebuffer(0, 0, texDetails.width, texDetails.height, 0, 0, texDetails.width, - texDetails.height, GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, - eGL_NEAREST); + SafeBlitFramebuffer(0, 0, texDetails.width, texDetails.height, 0, 0, texDetails.width, + texDetails.height, GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, + eGL_NEAREST); m_pDriver->ReplayLog(0, events[i], eReplay_OnlyDraw); diff --git a/renderdoc/driver/gl/gl_rendertexture.cpp b/renderdoc/driver/gl/gl_rendertexture.cpp index 6aa871cac..114784d41 100644 --- a/renderdoc/driver/gl/gl_rendertexture.cpp +++ b/renderdoc/driver/gl/gl_rendertexture.cpp @@ -94,7 +94,7 @@ bool GLReplay::RenderTextureInternal(TextureDisplay cfg, int flags) drv.glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, texDetails.renderbufferFBOs[1]); drv.glBindFramebuffer(eGL_READ_FRAMEBUFFER, texDetails.renderbufferFBOs[0]); - drv.glBlitFramebuffer( + SafeBlitFramebuffer( 0, 0, texDetails.width, texDetails.height, 0, 0, texDetails.width, texDetails.height, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, eGL_NEAREST); diff --git a/renderdoc/driver/gl/gl_replay.cpp b/renderdoc/driver/gl/gl_replay.cpp index 28606504e..0ddf8f30c 100644 --- a/renderdoc/driver/gl/gl_replay.cpp +++ b/renderdoc/driver/gl/gl_replay.cpp @@ -2317,7 +2317,7 @@ void GLReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, float col[] = {0.3f, 0.4f, 0.5f, 1.0f}; drv.glClearBufferfv(eGL_COLOR, 0, col); - drv.glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, eGL_NEAREST); + SafeBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, eGL_NEAREST); // rewrite the variables to temporary texture texType = eGL_TEXTURE_2D; @@ -2380,8 +2380,8 @@ void GLReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, else if(b == eGL_DEPTH_STENCIL) mask = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; - drv.glBlitFramebuffer(0, 0, texDetails.width, texDetails.height, 0, 0, texDetails.width, - texDetails.height, mask, eGL_NEAREST); + SafeBlitFramebuffer(0, 0, texDetails.width, texDetails.height, 0, 0, texDetails.width, + texDetails.height, mask, eGL_NEAREST); drv.glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, curDrawFBO); drv.glBindFramebuffer(eGL_READ_FRAMEBUFFER, curReadFBO); diff --git a/renderdoc/driver/gl/wrappers/gl_emulated.cpp b/renderdoc/driver/gl/wrappers/gl_emulated.cpp index e8f27a4a7..4ce2192fc 100644 --- a/renderdoc/driver/gl/wrappers/gl_emulated.cpp +++ b/renderdoc/driver/gl/wrappers/gl_emulated.cpp @@ -1198,8 +1198,8 @@ void APIENTRY _glCopyImageSubData(GLuint srcName, GLenum srcTarget, GLint srcLev } else if(!layered) { - GL.glBlitFramebuffer(srcX, srcY, srcX + srcWidth, srcY + srcHeight, dstX, dstY, - dstX + srcWidth, dstY + srcHeight, mask, eGL_NEAREST); + SafeBlitFramebuffer(srcX, srcY, srcX + srcWidth, srcY + srcHeight, dstX, dstY, + dstX + srcWidth, dstY + srcHeight, mask, eGL_NEAREST); } else if(srcTarget == eGL_TEXTURE_CUBE_MAP) { @@ -1218,8 +1218,8 @@ void APIENTRY _glCopyImageSubData(GLuint srcName, GLenum srcTarget, GLint srcLev GL.glFramebufferTexture2D(eGL_DRAW_FRAMEBUFFER, attach, textargets[dstZ + slice], dstName, dstLevel); - GL.glBlitFramebuffer(srcX, srcY, srcX + srcWidth, srcY + srcHeight, dstX, dstY, - dstX + srcWidth, dstY + srcHeight, mask, eGL_NEAREST); + SafeBlitFramebuffer(srcX, srcY, srcX + srcWidth, srcY + srcHeight, dstX, dstY, + dstX + srcWidth, dstY + srcHeight, mask, eGL_NEAREST); } } else @@ -1229,8 +1229,8 @@ void APIENTRY _glCopyImageSubData(GLuint srcName, GLenum srcTarget, GLint srcLev GL.glFramebufferTextureLayer(eGL_READ_FRAMEBUFFER, attach, srcName, srcLevel, srcZ + slice); GL.glFramebufferTextureLayer(eGL_DRAW_FRAMEBUFFER, attach, dstName, dstLevel, dstZ + slice); - GL.glBlitFramebuffer(srcX, srcY, srcX + srcWidth, srcY + srcHeight, dstX, dstY, - dstX + srcWidth, dstY + srcHeight, mask, eGL_NEAREST); + SafeBlitFramebuffer(srcX, srcY, srcX + srcWidth, srcY + srcHeight, dstX, dstY, + dstX + srcWidth, dstY + srcHeight, mask, eGL_NEAREST); } } }