From acb692677babb56105e402ebef836c69b0c3079e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 18 Jan 2018 22:17:29 -0800 Subject: [PATCH] GLES: Accept a color mask for clears. Otherwise, we end up clearing RGB when we try to only clear alpha, which is fairly common. Makes Valkyria Chronicles 3 action mode visible again. --- GPU/GLES/DrawEngineGLES.cpp | 4 +++- GPU/GLES/StencilBufferGLES.cpp | 7 ++----- ext/native/thin3d/GLQueueRunner.cpp | 8 ++++---- ext/native/thin3d/GLQueueRunner.h | 1 + ext/native/thin3d/GLRenderManager.cpp | 1 + ext/native/thin3d/GLRenderManager.h | 3 ++- ext/native/thin3d/thin3d_gl.cpp | 2 +- 7 files changed, 14 insertions(+), 12 deletions(-) diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index 1aa3a0dd66..d5cf5ae824 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -709,11 +709,13 @@ rotateVBO: } GLbitfield target = 0; + // Without this, we will clear RGB when clearing stencil, which breaks games. + uint8_t rgbaMask = (colorMask ? 7 : 0) | (alphaMask ? 8 : 0); if (colorMask || alphaMask) target |= GL_COLOR_BUFFER_BIT; if (alphaMask) target |= GL_STENCIL_BUFFER_BIT; if (depthMask) target |= GL_DEPTH_BUFFER_BIT; - render_->Clear(clearColor, clearDepth, clearColor >> 24, target); + render_->Clear(clearColor, clearDepth, clearColor >> 24, target, rgbaMask); framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason); int scissorX1 = gstate.getScissorX1(); diff --git a/GPU/GLES/StencilBufferGLES.cpp b/GPU/GLES/StencilBufferGLES.cpp index 980c3d4406..0f3a19b881 100644 --- a/GPU/GLES/StencilBufferGLES.cpp +++ b/GPU/GLES/StencilBufferGLES.cpp @@ -113,10 +113,7 @@ bool FramebufferManagerGLES::NotifyStencilUpload(u32 addr, int size, bool skipZe if (dstBuffer->fbo) { draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }); } - // TODO: This incorrectly does not apply to the clear currently. - render_->SetNoBlendAndMask(0x8); - render_->Clear(0, 0, 0, GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); - render_->SetNoBlendAndMask(0xF); + render_->Clear(0, 0, 0, GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT, 0x8); gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE); return true; } @@ -172,7 +169,7 @@ bool FramebufferManagerGLES::NotifyStencilUpload(u32 addr, int size, bool skipZe textureCacheGL_->ForgetLastTexture(); // We must bind the program after starting the render pass, and set the color mask after clearing. - render_->Clear(0, 0, 0, GL_STENCIL_BUFFER_BIT); + render_->Clear(0, 0, 0, GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, 0x8); render_->SetStencilFunc(GL_TRUE, GL_ALWAYS, 0xFF, 0xFF); render_->BindProgram(stencilUploadProgram_); render_->SetNoBlendAndMask(0x8); diff --git a/ext/native/thin3d/GLQueueRunner.cpp b/ext/native/thin3d/GLQueueRunner.cpp index 92320161ce..1fcd63fdac 100644 --- a/ext/native/thin3d/GLQueueRunner.cpp +++ b/ext/native/thin3d/GLQueueRunner.cpp @@ -498,10 +498,10 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step) { break; case GLRRenderCommand::CLEAR: glDisable(GL_SCISSOR_TEST); - // TODO: We sometimes pass a color mask in that we want to respect (StencilBufferGLES.) - // We want to clear to only clear alpha, in that case. - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - colorMask = 0xF; + if (c.clear.colorMask != colorMask) { + glColorMask(c.clear.colorMask & 1, (c.clear.colorMask >> 1) & 1, (c.clear.colorMask >> 2) & 1, (c.clear.colorMask >> 3) & 1); + colorMask = c.clear.colorMask; + } if (c.clear.clearMask & GL_COLOR_BUFFER_BIT) { float color[4]; Uint8x4ToFloat4(color, c.clear.clearColor); diff --git a/ext/native/thin3d/GLQueueRunner.h b/ext/native/thin3d/GLQueueRunner.h index f11e9fec44..22dfbaef84 100644 --- a/ext/native/thin3d/GLQueueRunner.h +++ b/ext/native/thin3d/GLQueueRunner.h @@ -117,6 +117,7 @@ struct GLRRenderData { float clearZ; int clearStencil; int clearMask; // VK_IMAGE_ASPECT_COLOR_BIT etc + int colorMask; // Like blend, but for the clear. } clear; struct { int slot; diff --git a/ext/native/thin3d/GLRenderManager.cpp b/ext/native/thin3d/GLRenderManager.cpp index 3cbc3a2dd8..7989f0b662 100644 --- a/ext/native/thin3d/GLRenderManager.cpp +++ b/ext/native/thin3d/GLRenderManager.cpp @@ -193,6 +193,7 @@ void GLRenderManager::BindFramebufferAsRenderTarget(GLRFramebuffer *fb, GLRRende } if (clearMask) { data.clear.clearMask = clearMask; + data.clear.colorMask = 0xF; step->commands.push_back(data); } diff --git a/ext/native/thin3d/GLRenderManager.h b/ext/native/thin3d/GLRenderManager.h index 711aa143fb..c5d728505e 100644 --- a/ext/native/thin3d/GLRenderManager.h +++ b/ext/native/thin3d/GLRenderManager.h @@ -571,13 +571,14 @@ public: curRenderStep_->commands.push_back(data); } - void Clear(uint32_t clearColor, float clearZ, int clearStencil, int clearMask) { + void Clear(uint32_t clearColor, float clearZ, int clearStencil, int clearMask, int colorMask = 0xF) { _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); GLRRenderData data{ GLRRenderCommand::CLEAR }; data.clear.clearMask = clearMask; data.clear.clearColor = clearColor; data.clear.clearZ = clearZ; data.clear.clearStencil = clearStencil; + data.clear.colorMask = colorMask; curRenderStep_->commands.push_back(data); } diff --git a/ext/native/thin3d/thin3d_gl.cpp b/ext/native/thin3d/thin3d_gl.cpp index 82d66dd0e1..a16411fbe7 100644 --- a/ext/native/thin3d/thin3d_gl.cpp +++ b/ext/native/thin3d/thin3d_gl.cpp @@ -186,7 +186,7 @@ public: bool depthWriteEnabled; GLuint depthComp; // TODO: Two-sided - GLboolean stencilEnabled; + bool stencilEnabled; GLuint stencilFail; GLuint stencilZFail; GLuint stencilPass;