diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 664d26fa7..c2e5222dd 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -922,36 +922,23 @@ void Graphics::clear(OptionalColorD c, OptionalInt stencil, OptionalDouble depth flags |= GL_COLOR_BUFFER_BIT; } - uint32 stencilwrites = gl.getStencilWriteMask(); - if (stencil.hasValue) { - if (stencilwrites != LOVE_UINT32_MAX) - gl.setStencilWriteMask(LOVE_UINT32_MAX); - glClearStencil(stencil.value); flags |= GL_STENCIL_BUFFER_BIT; } - bool hadDepthWrites = gl.hasDepthWrites(); - if (depth.hasValue) { - if (!hadDepthWrites) // glDepthMask also affects glClear. - gl.setDepthWrites(true); - gl.clearDepth(depth.value); flags |= GL_DEPTH_BUFFER_BIT; } if (flags != 0) + { + OpenGL::CleanClearState cs(flags); glClear(flags); - - if (stencil.hasValue && stencilwrites != LOVE_UINT32_MAX) - gl.setStencilWriteMask(stencilwrites); - - if (depth.hasValue && !hadDepthWrites) - gl.setDepthWrites(hadDepthWrites); + } if (c.hasValue && gl.bugs.clearRequiresDriverTextureStateUpdate && Shader::current) { @@ -1041,36 +1028,23 @@ void Graphics::clear(const std::vector &colors, OptionalInt sten GLbitfield flags = 0; - uint32 stencilwrites = gl.getStencilWriteMask(); - if (stencil.hasValue) { - if (stencilwrites != LOVE_UINT32_MAX) - gl.setStencilWriteMask(LOVE_UINT32_MAX); - glClearStencil(stencil.value); flags |= GL_STENCIL_BUFFER_BIT; } - bool hadDepthWrites = gl.hasDepthWrites(); - if (depth.hasValue) { - if (!hadDepthWrites) // glDepthMask also affects glClear. - gl.setDepthWrites(true); - gl.clearDepth(depth.value); flags |= GL_DEPTH_BUFFER_BIT; } if (flags != 0) + { + OpenGL::CleanClearState cs(flags); glClear(flags); - - if (stencil.hasValue && stencilwrites != LOVE_UINT32_MAX) - gl.setStencilWriteMask(stencilwrites); - - if (depth.hasValue && !hadDepthWrites) - gl.setDepthWrites(hadDepthWrites); + } if (gl.bugs.clearRequiresDriverTextureStateUpdate && Shader::current) { @@ -1568,7 +1542,11 @@ void Graphics::setColorMask(ColorChannelMask mask) { flushBatchedDraws(); - glColorMask(mask.r, mask.g, mask.b, mask.a); + uint32 maskbits = + ((mask.r ? 1 : 0) << 1) | ((mask.g ? 1 : 0) << 2) | + ((mask.g ? 1 : 0) << 3) | ((mask.a ? 1 : 0) << 4); + + gl.setColorWriteMask(maskbits); states.back().colorMask = mask; } diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index b169a06a9..df3a0b9b8 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -91,12 +91,49 @@ OpenGL::TempDebugGroup::~TempDebugGroup() } } +OpenGL::CleanClearState::CleanClearState(GLbitfield clearFlags) + : clearFlags(clearFlags) + , colorWriteMask(gl.getColorWriteMask()) + , stencilWriteMask(gl.getStencilWriteMask()) + , depthWrites(gl.hasDepthWrites()) + , scissor(gl.isStateEnabled(ENABLE_SCISSOR_TEST)) +{ + if (clearFlags & GL_COLOR_BUFFER_BIT) + gl.setColorWriteMask(LOVE_UINT32_MAX); + + if (clearFlags & GL_DEPTH_BUFFER_BIT) + gl.setDepthWrites(false); + + if (clearFlags & GL_STENCIL_BUFFER_BIT) + gl.setStencilWriteMask(LOVE_UINT32_MAX); + + if (clearFlags != 0) + gl.setEnableState(ENABLE_SCISSOR_TEST, false); +} + +OpenGL::CleanClearState::~CleanClearState() +{ + if (clearFlags & GL_COLOR_BUFFER_BIT) + gl.setColorWriteMask(colorWriteMask); + + if (clearFlags & GL_DEPTH_BUFFER_BIT) + gl.setDepthWrites(depthWrites); + + if (clearFlags & GL_STENCIL_BUFFER_BIT) + gl.setStencilWriteMask(stencilWriteMask); + + if (clearFlags != 0) + gl.setEnableState(ENABLE_SCISSOR_TEST, scissor); +} + OpenGL::OpenGL() : stats() + , bugs() , contextInitialized(false) , pixelShaderHighpSupported(false) , baseVertexSupported(false) , maxAnisotropy(1.0f) + , maxLODBias(0.0f) , max2DTextureSize(0) , max3DTextureSize(0) , maxCubeTextureSize(0) @@ -284,6 +321,7 @@ void OpenGL::setupContext() setDepthWrites(state.depthWritesEnabled); setStencilWriteMask(state.stencilWriteMask); + setColorWriteMask(state.colorWriteMask); createDefaultTexture(); @@ -1125,6 +1163,17 @@ uint32 OpenGL::getStencilWriteMask() const return state.stencilWriteMask; } +void OpenGL::setColorWriteMask(uint32 mask) +{ + glColorMask(mask & (1 << 0), mask & (1 << 1), mask & (1 << 2), mask & (1 << 3)); + state.colorWriteMask = mask; +} + +uint32 OpenGL::getColorWriteMask() const +{ + return state.colorWriteMask; +} + void OpenGL::useProgram(GLuint program) { glUseProgram(program); diff --git a/src/modules/graphics/opengl/OpenGL.h b/src/modules/graphics/opengl/OpenGL.h index 6f2d26746..3690c6baa 100644 --- a/src/modules/graphics/opengl/OpenGL.h +++ b/src/modules/graphics/opengl/OpenGL.h @@ -124,6 +124,21 @@ public: ~TempDebugGroup(); }; + // glClear() is affected by various OpenGL state... + class CleanClearState + { + public: + CleanClearState(GLbitfield clearFlags); + ~CleanClearState(); + + private: + GLenum clearFlags; + uint32 colorWriteMask; + uint32 stencilWriteMask; + bool depthWrites; + bool scissor; + }; + struct Stats { int shaderSwitches; @@ -301,6 +316,9 @@ public: void setStencilWriteMask(uint32 mask); uint32 getStencilWriteMask() const; + void setColorWriteMask(uint32 mask); + uint32 getColorWriteMask() const; + /** * Calls glUseProgram. **/ @@ -528,6 +546,7 @@ private: bool depthWritesEnabled = true; uint32 stencilWriteMask = LOVE_UINT32_MAX; + uint32 colorWriteMask = LOVE_UINT32_MAX; GLuint boundFramebuffers[2]; diff --git a/src/modules/graphics/opengl/Texture.cpp b/src/modules/graphics/opengl/Texture.cpp index 70fdbd344..01a451e8f 100644 --- a/src/modules/graphics/opengl/Texture.cpp +++ b/src/modules/graphics/opengl/Texture.cpp @@ -80,31 +80,22 @@ static GLenum createFBO(GLuint &framebuffer, TextureType texType, PixelFormat fo if (clear) { - if (isPixelFormatDepthStencil(format)) + bool ds = isPixelFormatDepthStencil(format); + + GLbitfield clearflags = ds ? GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT : GL_COLOR_BUFFER_BIT; + OpenGL::CleanClearState cleanClearState(clearflags); + + if (ds) { - bool hadDepthWrites = gl.hasDepthWrites(); - if (!hadDepthWrites) // glDepthMask also affects glClear. - gl.setDepthWrites(true); - - uint32 stencilwrite = gl.getStencilWriteMask(); - if (stencilwrite != LOVE_UINT32_MAX) - gl.setStencilWriteMask(LOVE_UINT32_MAX); - gl.clearDepth(1.0); glClearStencil(0); - glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - - if (!hadDepthWrites) - gl.setDepthWrites(hadDepthWrites); - - if (stencilwrite != LOVE_UINT32_MAX) - gl.setStencilWriteMask(stencilwrite); } else { glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT); } + + glClear(clearflags); } } } @@ -167,25 +158,23 @@ static GLenum newRenderbuffer(int width, int height, int &samples, PixelFormat p if (status == GL_FRAMEBUFFER_COMPLETE) { - if (isPixelFormatDepthStencil(pixelformat)) - { - bool hadDepthWrites = gl.hasDepthWrites(); - if (!hadDepthWrites) // glDepthMask also affects glClear. - gl.setDepthWrites(true); + bool ds = isPixelFormatDepthStencil(pixelformat); + GLbitfield clearflags = ds ? GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT : GL_COLOR_BUFFER_BIT; + OpenGL::CleanClearState cleanClearState(clearflags); + + if (ds) + { gl.clearDepth(1.0); glClearStencil(0); - glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - - if (!hadDepthWrites) - gl.setDepthWrites(hadDepthWrites); } else { // Initialize the buffer to transparent black. glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT); } + + glClear(clearflags); } else {