diff --git a/renderdoc/driver/gl/gl_common.cpp b/renderdoc/driver/gl/gl_common.cpp index b21775d00..ab1130e69 100644 --- a/renderdoc/driver/gl/gl_common.cpp +++ b/renderdoc/driver/gl/gl_common.cpp @@ -1556,97 +1556,131 @@ 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) +struct SafeClearBlitState { - // only viewport 0's scissor should be used for blits, but Intel seems to require all scissors to - // be disabled. Since it's only a bit more work to disable them all, we push/pop all of them + SafeClearBlitState() + { + // only viewport 0's scissor should be used for blits, but Intel seems to require all scissors + // to be disabled. Since it's only a bit more work to disable them all, we push/pop all of them + GL.glGetIntegerv(eGL_MAX_VIEWPORTS, &maxViews); + + // fetch current state + { + if(HasExt[ARB_viewport_array]) + { + for(GLint v = 0; v < maxViews; v++) + scissorEnabled[v] = GL.glIsEnabledi(eGL_SCISSOR_TEST, v) != 0; + } + else + { + scissorEnabled[0] = 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); + } + + GL.glGetFloatv(eGL_COLOR_CLEAR_VALUE, ClearColor); + GL.glGetFloatv(eGL_DEPTH_CLEAR_VALUE, &ClearDepth); + GL.glGetIntegerv(eGL_STENCIL_CLEAR_VALUE, &ClearStencil); + + // apply safe state + { + if(HasExt[ARB_viewport_array]) + { + for(GLint v = 0; v < maxViews; v++) + GL.glDisablei(eGL_SCISSOR_TEST, v); + } + 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); + } + } + + ~SafeClearBlitState() + { + // restore original state + { + if(HasExt[ARB_viewport_array]) + { + for(GLint v = 0; v < maxViews; v++) + { + if(scissorEnabled[v]) + GL.glEnablei(eGL_SCISSOR_TEST, v); + else + GL.glDisablei(eGL_SCISSOR_TEST, v); + } + } + else + { + if(scissorEnabled[0]) + 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); + } + + GL.glClearColor(ClearColor[0], ClearColor[1], ClearColor[2], ClearColor[3]); + GL.glClearDepthf(ClearDepth); + GL.glClearStencil(ClearStencil); + } + bool scissorEnabled[16] = {}; GLboolean ColorMask[4] = {GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE}; GLboolean DepthMask = GL_TRUE; GLint StencilMask = 0xff, StencilBackMask = 0xff; + GLfloat ClearColor[4] = {}; + GLfloat ClearDepth = 1.0f; + GLint ClearStencil = 0; + GLint maxViews = 0; - GL.glGetIntegerv(eGL_MAX_VIEWPORTS, &maxViews); +}; - // fetch current state - { - if(HasExt[ARB_viewport_array]) - { - for(GLint v = 0; v < maxViews; v++) - scissorEnabled[v] = GL.glIsEnabledi(eGL_SCISSOR_TEST, v) != 0; - } - else - { - scissorEnabled[0] = 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]) - { - for(GLint v = 0; v < maxViews; v++) - GL.glDisablei(eGL_SCISSOR_TEST, v); - } - 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); - } +void SafeBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, + GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) +{ + SafeClearBlitState safe; GL.glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); +} - // restore original state - { - if(HasExt[ARB_viewport_array]) - { - for(GLint v = 0; v < maxViews; v++) - { - if(scissorEnabled[v]) - GL.glEnablei(eGL_SCISSOR_TEST, v); - else - GL.glDisablei(eGL_SCISSOR_TEST, v); - } - } - else - { - if(scissorEnabled[0]) - GL.glEnable(eGL_SCISSOR_TEST); - else - GL.glDisable(eGL_SCISSOR_TEST); - } +void SafeClearFramebuffer(GLbitfield clearMask, GLfloat rgba[4], GLfloat depth, GLint stencil) +{ + SafeClearBlitState safe; - 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); - } + GL.glClearColor(rgba[0], rgba[1], rgba[2], rgba[3]); + GL.glClearDepthf(0.0f); + GL.glClearStencil(0); + GL.glClear(clearMask); } BufferCategory MakeBufferCategory(GLenum bufferTarget) diff --git a/renderdoc/driver/gl/gl_common.h b/renderdoc/driver/gl/gl_common.h index 2f4fbc0ba..3cc4706fc 100644 --- a/renderdoc/driver/gl/gl_common.h +++ b/renderdoc/driver/gl/gl_common.h @@ -630,6 +630,7 @@ void GetCurrentBinding(GLuint curProg, ShaderReflection *refl, const ConstantBlo // 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); +void SafeClearFramebuffer(GLbitfield clearMask, GLfloat rgba[4], GLfloat depth, GLint stencil); enum UniformType { @@ -790,6 +791,8 @@ extern bool IsGLES; EXT_TO_CHECK(99, 99, EXT_texture_buffer) \ /* OpenGL ES extensions */ \ EXT_TO_CHECK(99, 32, EXT_color_buffer_float) \ + EXT_TO_CHECK(99, 99, EXT_color_buffer_half_float) \ + EXT_TO_CHECK(99, 99, EXT_render_snorm) \ EXT_TO_CHECK(99, 32, EXT_primitive_bounding_box) \ EXT_TO_CHECK(99, 32, OES_primitive_bounding_box) \ EXT_TO_CHECK(99, 32, OES_texture_border_color) \ diff --git a/renderdoc/driver/gl/wrappers/gl_emulated.cpp b/renderdoc/driver/gl/wrappers/gl_emulated.cpp index 6546fd991..b398f5393 100644 --- a/renderdoc/driver/gl/wrappers/gl_emulated.cpp +++ b/renderdoc/driver/gl/wrappers/gl_emulated.cpp @@ -1187,6 +1187,7 @@ void APIENTRY _glCopyImageSubData(GLuint srcName, GLenum srcTarget, GLint srcLev GLenum attach = eGL_COLOR_ATTACHMENT0; bool layered = false; + bool msaa = false; bool cpuTransfer = false; if(srcTarget == eGL_TEXTURE_CUBE_MAP || srcTarget == eGL_TEXTURE_CUBE_MAP_ARRAY || @@ -1206,8 +1207,87 @@ void APIENTRY _glCopyImageSubData(GLuint srcName, GLenum srcTarget, GLint srcLev GLenum fmt = eGL_NONE; GL.glGetTexLevelParameteriv(levelQueryType, 0, eGL_TEXTURE_INTERNAL_FORMAT, (GLint *)&fmt); + bool colorRenderable = true; + + if(IsCompressedFormat(fmt)) + colorRenderable = false; + + if(fmt == eGL_RGB9_E5) + colorRenderable = false; + + if(colorRenderable && IsGLES) + { + // before GLES 3 framebuffers basically weren't supported for the lack of formats you could + // use. We can turn some on based on extensions below + if(GLCoreVersion < 30) + colorRenderable = false; + + // GLES randomly excludes an inconsistent set of formats + switch(fmt) + { + // case eGL_RGB8: // valid?! + case eGL_SRGB8: + case eGL_RGB8I: + case eGL_RGB8UI: + case eGL_RGB8_SNORM: + + case eGL_RGB9_E5: + + case eGL_RGB10: + + case eGL_RGB16I: + case eGL_RGB16UI: + + case eGL_RGB32F: + case eGL_RGB32I: + case eGL_RGB32UI: colorRenderable = false; break; + default: break; + } + + // SRGB 1- and 2- channel formats aren't renderable + if(fmt == eGL_SR8_EXT || fmt == eGL_SRG8_EXT) + colorRenderable = false; + + // some extensions are required for other formats + switch(fmt) + { + case eGL_R8_SNORM: + case eGL_RG8_SNORM: + case eGL_RGBA8_SNORM: colorRenderable = HasExt[EXT_render_snorm]; + + case eGL_R16_SNORM: + case eGL_RG16_SNORM: + case eGL_RGBA16_SNORM: colorRenderable = HasExt[EXT_render_snorm]; + + case eGL_R16F: + case eGL_RG16F: + case eGL_RGBA16F: + colorRenderable = HasExt[EXT_color_buffer_half_float] || HasExt[EXT_color_buffer_float]; + + case eGL_RGB16F: colorRenderable = HasExt[EXT_color_buffer_half_float]; + + case eGL_R32F: + case eGL_RG32F: + case eGL_RGBA32F: + case eGL_R11F_G11F_B10F: colorRenderable = HasExt[EXT_color_buffer_float]; + + case eGL_RGB10_A2: + case eGL_RGB10_A2UI: colorRenderable = (GLCoreVersion >= 30); + + default: break; + } + } + + // can't blit or CPU-read MSAA textures. we treat these as 'color-renderable' but we will just clear to black + if(srcTarget == eGL_TEXTURE_2D_MULTISAMPLE || srcTarget == eGL_TEXTURE_2D_MULTISAMPLE_ARRAY) + { + colorRenderable = true; + msaa = true; + RDCDEBUG("Can't support image copy emulation on MSAA images, clearing to black"); + } + // non-color-renderable formats have to go through this path even though they are not compressed - if(IsCompressedFormat(fmt) || fmt == eGL_RGB9_E5) + if(!colorRenderable) { // have to do this via CPU readback, there's no alternative for GPU copies cpuTransfer = true; @@ -1332,6 +1412,8 @@ void APIENTRY _glCopyImageSubData(GLuint srcName, GLenum srcTarget, GLint srcLev } } + GLfloat black[4] = {}; + if(cpuTransfer) { // nothing to do! @@ -1348,8 +1430,16 @@ void APIENTRY _glCopyImageSubData(GLuint srcName, GLenum srcTarget, GLint srcLev if(status != eGL_FRAMEBUFFER_COMPLETE) RDCERR("glCopyImageSubData emulation read FBO is %s", ToStr(status).c_str()); - SafeBlitFramebuffer(srcX, srcY, srcX + srcWidth, srcY + srcHeight, dstX, dstY, - dstX + srcWidth, dstY + srcHeight, mask, eGL_NEAREST); + if(msaa) + { + SafeClearFramebuffer(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, + black, 0.0f, 0); + } + else + { + SafeBlitFramebuffer(srcX, srcY, srcX + srcWidth, srcY + srcHeight, dstX, dstY, + dstX + srcWidth, dstY + srcHeight, mask, eGL_NEAREST); + } } else if(srcTarget == eGL_TEXTURE_CUBE_MAP) { @@ -1381,8 +1471,16 @@ void APIENTRY _glCopyImageSubData(GLuint srcName, GLenum srcTarget, GLint srcLev RDCERR("glCopyImageSubData emulation read FBO is %s for slice 0", ToStr(status).c_str()); } - SafeBlitFramebuffer(srcX, srcY, srcX + srcWidth, srcY + srcHeight, dstX, dstY, - dstX + srcWidth, dstY + srcHeight, mask, eGL_NEAREST); + if(msaa) + { + SafeClearFramebuffer(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, + black, 0.0f, 0); + } + else + { + SafeBlitFramebuffer(srcX, srcY, srcX + srcWidth, srcY + srcHeight, dstX, dstY, + dstX + srcWidth, dstY + srcHeight, mask, eGL_NEAREST); + } } } else @@ -1405,8 +1503,16 @@ void APIENTRY _glCopyImageSubData(GLuint srcName, GLenum srcTarget, GLint srcLev RDCERR("glCopyImageSubData emulation read FBO is %s for slice 0", ToStr(status).c_str()); } - SafeBlitFramebuffer(srcX, srcY, srcX + srcWidth, srcY + srcHeight, dstX, dstY, - dstX + srcWidth, dstY + srcHeight, mask, eGL_NEAREST); + if(msaa) + { + SafeClearFramebuffer(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, + black, 0.0f, 0); + } + else + { + SafeBlitFramebuffer(srcX, srcY, srcX + srcWidth, srcY + srcHeight, dstX, dstY, + dstX + srcWidth, dstY + srcHeight, mask, eGL_NEAREST); + } } } }