From fba0de59c10a51dd43bfdc838f9c8562d93cb2c0 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 29 Jul 2018 11:03:55 -0700 Subject: [PATCH 1/3] GPU: Restrict alpha test to zero for dest blend. We could end up with the wrong blending in other cases, because the exiting color will get multiplied. Luckily, this is still the common case. --- GPU/Common/GPUStateUtils.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index 9da2049d61..47605f64b7 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -125,7 +125,12 @@ bool NeedsTestDiscard() { return true; if (gstate.getBlendFuncA() != GE_SRCBLEND_SRCALPHA && gstate.getBlendFuncA() != GE_DSTBLEND_DOUBLESRCALPHA) return true; - if (!safeDestFactors[(int)gstate.getBlendFuncB()]) + // GE_DSTBLEND_DOUBLEINVSRCALPHA is actually inverse double src alpha, and doubling zero is still zero. + if (gstate.getBlendFuncB() != GE_DSTBLEND_INVSRCALPHA && gstate.getBlendFuncB() != GE_DSTBLEND_DOUBLEINVSRCALPHA) { + if (gstate.getBlendFuncB() != GE_DSTBLEND_FIXB || gstate.getFixB() != 0xFFFFFF) + return true; + } + if (gstate.getBlendEq() != GE_BLENDMODE_MUL_AND_ADD && gstate.getBlendEq() != GE_BLENDMODE_MUL_AND_SUBTRACT_REVERSE) return true; return false; From 78dc07e7a3af43147944f4f3be87a25dc2c69ef1 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 29 Jul 2018 11:07:29 -0700 Subject: [PATCH 2/3] Headless: Fix graphics tests for Vulkan/Direct3D. Otherwise we hang because there's no thread to ever end. --- GPU/GLES/TextureCacheGLES.cpp | 1 + headless/WindowsHeadlessHost.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/GPU/GLES/TextureCacheGLES.cpp b/GPU/GLES/TextureCacheGLES.cpp index 555160352c..659f9540fe 100644 --- a/GPU/GLES/TextureCacheGLES.cpp +++ b/GPU/GLES/TextureCacheGLES.cpp @@ -862,6 +862,7 @@ bool TextureCacheGLES::GetCurrentTextureDebug(GPUDebugBuffer &buffer, int level) GLRenderManager *renderManager = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); // Not a framebuffer, so let's assume these are right. + // TODO: But they may definitely not be, if the texture was scaled. int w = gstate.getTextureWidth(level); int h = gstate.getTextureHeight(level); diff --git a/headless/WindowsHeadlessHost.cpp b/headless/WindowsHeadlessHost.cpp index 9bfe3d7832..f2172f7238 100644 --- a/headless/WindowsHeadlessHost.cpp +++ b/headless/WindowsHeadlessHost.cpp @@ -163,7 +163,7 @@ bool WindowsHeadlessHost::InitGraphics(std::string *error_message, GraphicsConte void WindowsHeadlessHost::ShutdownGraphics() { gfx_->StopThread(); - while (threadState_ != RenderThreadState::STOPPED) + while (threadState_ != RenderThreadState::STOPPED && threadState_ != RenderThreadState::IDLE) sleep_ms(1); gfx_->Shutdown(); From 7885a88c0ca408039e3645d51b823dd67baaa9ce Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 29 Jul 2018 11:37:04 -0700 Subject: [PATCH 3/3] GPU: Optimize > 0 alpha test using discard rules. It should be equally unsafe to use src color as dest blend factor, or use blending with a subtract or min/max equation. --- GPU/Common/GPUStateUtils.cpp | 82 ++++++++++++------------------------ 1 file changed, 26 insertions(+), 56 deletions(-) diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index 47605f64b7..0353e3ac96 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -40,20 +40,28 @@ bool CanUseHardwareTransform(int prim) { return !gstate.isModeThrough() && prim != GE_PRIM_RECTANGLES; } -// Dest factors where it's safe to eliminate the alpha test under certain conditions -static const bool safeDestFactors[16] = { - true, // GE_DSTBLEND_SRCCOLOR, - true, // GE_DSTBLEND_INVSRCCOLOR, - false, // GE_DSTBLEND_SRCALPHA, - true, // GE_DSTBLEND_INVSRCALPHA, - true, // GE_DSTBLEND_DSTALPHA, - true, // GE_DSTBLEND_INVDSTALPHA, - false, // GE_DSTBLEND_DOUBLESRCALPHA, - false, // GE_DSTBLEND_DOUBLEINVSRCALPHA, - true, // GE_DSTBLEND_DOUBLEDSTALPHA, - true, // GE_DSTBLEND_DOUBLEINVDSTALPHA, - true, //GE_DSTBLEND_FIXB, -}; +bool NeedsTestDiscard() { + // We assume this is called only when enabled and not trivially true (may also be for color testing.) + if (gstate.isStencilTestEnabled() && (gstate.pmska & 0xFF) != 0xFF) + return true; + if (gstate.isDepthTestEnabled() && gstate.isDepthWriteEnabled()) + return true; + if (!gstate.isAlphaBlendEnabled()) + return true; + if (gstate.getBlendFuncA() != GE_SRCBLEND_SRCALPHA && gstate.getBlendFuncA() != GE_DSTBLEND_DOUBLESRCALPHA) + return true; + // GE_DSTBLEND_DOUBLEINVSRCALPHA is actually inverse double src alpha, and doubling zero is still zero. + if (gstate.getBlendFuncB() != GE_DSTBLEND_INVSRCALPHA && gstate.getBlendFuncB() != GE_DSTBLEND_DOUBLEINVSRCALPHA) { + if (gstate.getBlendFuncB() != GE_DSTBLEND_FIXB || gstate.getFixB() != 0xFFFFFF) + return true; + } + if (gstate.getBlendEq() != GE_BLENDMODE_MUL_AND_ADD && gstate.getBlendEq() != GE_BLENDMODE_MUL_AND_SUBTRACT_REVERSE) + return true; + if (gstate.isLogicOpEnabled() && gstate.getLogicOp() != GE_LOGIC_COPY) + return true; + + return false; +} bool IsAlphaTestTriviallyTrue() { switch (gstate.getAlphaTestFunction()) { @@ -80,25 +88,10 @@ bool IsAlphaTestTriviallyTrue() { case GE_COMP_GREATER: { -#if 0 - // Easy way to check the values in the debugger without ruining && early-out - bool doTextureAlpha = gstate.isTextureAlphaUsed(); - bool stencilTest = gstate.isStencilTestEnabled(); - bool depthTest = gstate.isDepthTestEnabled(); - GEComparison depthTestFunc = gstate.getDepthTestFunction(); - int alphaRef = gstate.getAlphaTestRef(); - int blendA = gstate.getBlendFuncA(); - bool blendEnabled = gstate.isAlphaBlendEnabled(); - int blendB = gstate.getBlendFuncA(); -#endif - return (gstate_c.vertexFullAlpha && (gstate_c.textureFullAlpha || !gstate.isTextureAlphaUsed())) || ( - (!gstate.isStencilTestEnabled() && - !gstate.isDepthTestEnabled() && - (!gstate.isLogicOpEnabled() || gstate.getLogicOp() == GE_LOGIC_COPY) && - gstate.getAlphaTestRef() == 0 && - gstate.isAlphaBlendEnabled() && - gstate.getBlendFuncA() == GE_SRCBLEND_SRCALPHA && - safeDestFactors[(int)gstate.getBlendFuncB()])); + // If the texture and vertex only use 1.0 alpha, then the ref value doesn't matter. + if (gstate_c.vertexFullAlpha && (gstate_c.textureFullAlpha || !gstate.isTextureAlphaUsed())) + return true; + return gstate.getAlphaTestRef() == 0 && !NeedsTestDiscard(); } case GE_COMP_LEQUAL: @@ -113,29 +106,6 @@ bool IsAlphaTestTriviallyTrue() { } } -bool NeedsTestDiscard() { - // We assume this is called only when enabled and not trivially true (may also be for color testing.) - if (gstate.isStencilTestEnabled() && (gstate.pmska & 0xFF) != 0xFF) - return true; - if (gstate.isDepthTestEnabled() && gstate.isDepthWriteEnabled()) - return true; - if (!gstate.isAlphaBlendEnabled()) - return true; - if (gstate.isLogicOpEnabled() && gstate.getLogicOp() != GE_LOGIC_COPY) - return true; - if (gstate.getBlendFuncA() != GE_SRCBLEND_SRCALPHA && gstate.getBlendFuncA() != GE_DSTBLEND_DOUBLESRCALPHA) - return true; - // GE_DSTBLEND_DOUBLEINVSRCALPHA is actually inverse double src alpha, and doubling zero is still zero. - if (gstate.getBlendFuncB() != GE_DSTBLEND_INVSRCALPHA && gstate.getBlendFuncB() != GE_DSTBLEND_DOUBLEINVSRCALPHA) { - if (gstate.getBlendFuncB() != GE_DSTBLEND_FIXB || gstate.getFixB() != 0xFFFFFF) - return true; - } - if (gstate.getBlendEq() != GE_BLENDMODE_MUL_AND_ADD && gstate.getBlendEq() != GE_BLENDMODE_MUL_AND_SUBTRACT_REVERSE) - return true; - - return false; -} - bool IsAlphaTestAgainstZero() { return gstate.getAlphaTestRef() == 0 && gstate.getAlphaTestMask() == 0xFF; }