diff --git a/GPU/Common/FragmentShaderGenerator.cpp b/GPU/Common/FragmentShaderGenerator.cpp index decdd26d5c..5339ecb26b 100644 --- a/GPU/Common/FragmentShaderGenerator.cpp +++ b/GPU/Common/FragmentShaderGenerator.cpp @@ -155,7 +155,9 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu shading = doFlatShading ? "flat" : ""; } - bool useDiscardStencilBugWorkaround = id.Bit(FS_BIT_NO_DEPTH_CANNOT_DISCARD_STENCIL); + bool forceDepthWritesOff = id.Bit(FS_BIT_DEPTH_TEST_NEVER); + + bool useDiscardStencilBugWorkaround = id.Bit(FS_BIT_NO_DEPTH_CANNOT_DISCARD_STENCIL) && !forceDepthWritesOff; GEBlendSrcFactor replaceBlendFuncA = (GEBlendSrcFactor)id.Bits(FS_BIT_BLENDFUNC_A, 4); GEBlendDstFactor replaceBlendFuncB = (GEBlendDstFactor)id.Bits(FS_BIT_BLENDFUNC_B, 4); @@ -177,7 +179,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu } bool needFragCoord = readFramebufferTex || gstate_c.Use(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT); - bool writeDepth = gstate_c.Use(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT); + bool writeDepth = gstate_c.Use(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT) && !forceDepthWritesOff; // TODO: We could have a separate mechanism to support more ops using the shader blending mechanism, // on hardware that can do proper bit math in fragment shaders. diff --git a/GPU/Common/ShaderId.cpp b/GPU/Common/ShaderId.cpp index 492b2d8e48..71efcfa683 100644 --- a/GPU/Common/ShaderId.cpp +++ b/GPU/Common/ShaderId.cpp @@ -196,6 +196,7 @@ std::string FragmentShaderDesc(const FShaderID &id) { if (id.Bit(FS_BIT_FLATSHADE)) desc << "Flat "; if (id.Bit(FS_BIT_BGRA_TEXTURE)) desc << "BGRA "; if (id.Bit(FS_BIT_UBERSHADER)) desc << "FragUber "; + if (id.Bit(FS_BIT_DEPTH_TEST_NEVER)) desc << "DepthNever "; switch ((ShaderDepalMode)id.Bits(FS_BIT_SHADER_DEPAL_MODE, 2)) { case ShaderDepalMode::OFF: break; case ShaderDepalMode::NORMAL: desc << "Depal "; break; @@ -397,6 +398,14 @@ void ComputeFragmentShaderID(FShaderID *id_out, const ComputedPipelineState &pip } } + // Forcibly disable NEVER + depth-write on Mali. + // TODO: Take this from computed depth test instead of directly from the gstate. + // That will take more refactoring though. + if (bugs.Has(Draw::Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL_MALI) && + gstate.getDepthTestFunction() == GE_COMP_NEVER && gstate.isDepthTestEnabled()) { + id.SetBit(FS_BIT_DEPTH_TEST_NEVER); + } + // In case the USE flag changes (for example, in multisampling we might disable input attachments), // we don't want to accidentally use the wrong cached shader here. So moved it to a bit. if (FragmentIdNeedsFramebufferRead(id)) { diff --git a/GPU/Common/ShaderId.h b/GPU/Common/ShaderId.h index 830abd0440..8141cac442 100644 --- a/GPU/Common/ShaderId.h +++ b/GPU/Common/ShaderId.h @@ -102,6 +102,7 @@ enum FShaderBit : uint8_t { FS_BIT_STEREO = 58, FS_BIT_USE_FRAMEBUFFER_FETCH = 59, FS_BIT_UBERSHADER = 60, + FS_BIT_DEPTH_TEST_NEVER = 61, // Only used on Mali. Set when depth == NEVER. We forcibly avoid writing to depth in this case, since it crashes the driver. }; static inline FShaderBit operator +(FShaderBit bit, int i) { diff --git a/GPU/GPUCommonHW.cpp b/GPU/GPUCommonHW.cpp index e6e894a96a..144fd8276b 100644 --- a/GPU/GPUCommonHW.cpp +++ b/GPU/GPUCommonHW.cpp @@ -124,7 +124,7 @@ const CommonCommandTableEntry commonCommandTable[] = { { GE_CMD_BLENDFIXEDB, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_FRAGMENTSHADER_STATE }, { GE_CMD_MASKRGB, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_COLORWRITEMASK }, { GE_CMD_MASKALPHA, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_COLORWRITEMASK }, - { GE_CMD_ZTEST, FLAG_FLUSHBEFOREONCHANGE, DIRTY_DEPTHSTENCIL_STATE }, + { GE_CMD_ZTEST, FLAG_FLUSHBEFOREONCHANGE, DIRTY_DEPTHSTENCIL_STATE | DIRTY_FRAGMENTSHADER_STATE }, { GE_CMD_ZTESTENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_DEPTHSTENCIL_STATE | DIRTY_FRAGMENTSHADER_STATE }, { GE_CMD_ZWRITEDISABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_DEPTHSTENCIL_STATE | DIRTY_FRAGMENTSHADER_STATE }, { GE_CMD_LOGICOP, FLAG_FLUSHBEFOREONCHANGE, DIRTY_BLEND_STATE | DIRTY_FRAGMENTSHADER_STATE },