mirror of
https://github.com/jpd002/Play-.git
synced 2025-04-28 13:47:57 +03:00
Use framebuffer fetch depth extension to better handle alpha testing.
This commit is contained in:
parent
5627084a1e
commit
99770a53b3
3 changed files with 80 additions and 9 deletions
|
@ -312,6 +312,10 @@ void CGSH_OpenGL::CheckExtensions()
|
|||
{
|
||||
m_hasFramebufferFetchExtension = true;
|
||||
}
|
||||
else if(!strcmp(extensionName, "GL_ARM_shader_framebuffer_fetch_depth_stencil"))
|
||||
{
|
||||
m_hasFramebufferFetchDepthExtension = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1060,6 +1064,20 @@ bool CGSH_OpenGL::CanRegionRepeatClampModeSimplified(uint32 clampMin, uint32 cla
|
|||
return false;
|
||||
}
|
||||
|
||||
bool CGSH_OpenGL::RequiresAlphaTestDepthTest_DepthFetch(const TEST& test) const
|
||||
{
|
||||
if(!m_hasFramebufferFetchDepthExtension) return false;
|
||||
//If alpha test is not enabled, bail
|
||||
if(!test.nAlphaEnabled) return false;
|
||||
//If depth test not enabled, bail
|
||||
if(!test.nDepthEnabled) return false;
|
||||
//If depth test doesn't need depth value to compare, bail
|
||||
if(!((test.nDepthMethod == DEPTH_TEST_GEQUAL) || (test.nDepthMethod == DEPTH_TEST_GREATER))) return false;
|
||||
//If alpha test doesn't discard depth (independently of other channels), bail
|
||||
if(!((test.nAlphaFail == ALPHA_TEST_FAIL_FBONLY) || (test.nAlphaFail == ALPHA_TEST_FAIL_RGBONLY))) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CGSH_OpenGL::FillShaderCapsFromTexture(SHADERCAPS& shaderCaps, const uint64& tex0Reg, const uint64& tex1Reg, const uint64& texAReg, const uint64& clampReg)
|
||||
{
|
||||
auto tex0 = make_convertible<TEX0>(tex0Reg);
|
||||
|
@ -1143,6 +1161,17 @@ void CGSH_OpenGL::FillShaderCapsFromTest(SHADERCAPS& shaderCaps, const uint64& t
|
|||
shaderCaps.alphaTestMethod = test.nAlphaMethod;
|
||||
shaderCaps.alphaFailMethod = test.nAlphaFail;
|
||||
}
|
||||
|
||||
if(RequiresAlphaTestDepthTest_DepthFetch(test))
|
||||
{
|
||||
//If we use depthbuffer fetch to reject depth writes on alpha test fail,
|
||||
//we need to handle depth test ourselves since we still need to potentially
|
||||
//discard the fragment based on its depth value. Since our strategy for rejecting
|
||||
//depth writes relies on providing the previous depth value to the current
|
||||
//fragment, the built-in depth test won't be able to give proper results.
|
||||
shaderCaps.alphaTestDepthTest_DepthFetch = 1;
|
||||
shaderCaps.alphaTestDepthTestEqual_DepthFetch = (test.nDepthMethod == DEPTH_TEST_GEQUAL);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -95,6 +95,8 @@ private:
|
|||
unsigned int hasDestAlphaTest : 1;
|
||||
unsigned int destAlphaTestRef : 1;
|
||||
unsigned int alphaFailMethod : 2;
|
||||
unsigned int alphaTestDepthTest_DepthFetch : 1;
|
||||
unsigned int alphaTestDepthTestEqual_DepthFetch : 1;
|
||||
|
||||
bool isIndexedTextureSource() const
|
||||
{
|
||||
|
@ -356,6 +358,7 @@ private:
|
|||
void SetupFogColor(uint64);
|
||||
|
||||
static bool CanRegionRepeatClampModeSimplified(uint32, uint32);
|
||||
bool RequiresAlphaTestDepthTest_DepthFetch(const TEST&) const;
|
||||
void FillShaderCapsFromTexture(SHADERCAPS&, const uint64&, const uint64&, const uint64&, const uint64&);
|
||||
void FillShaderCapsFromTest(SHADERCAPS&, const uint64&);
|
||||
void FillShaderCapsFromAlpha(SHADERCAPS&, bool, const uint64&);
|
||||
|
@ -474,4 +477,5 @@ private:
|
|||
//If GPU has framebuffer fetch extension, some things will be done
|
||||
//within the shader, such alpha blending
|
||||
bool m_hasFramebufferFetchExtension = false;
|
||||
bool m_hasFramebufferFetchDepthExtension = false;
|
||||
};
|
||||
|
|
|
@ -135,7 +135,9 @@ Framework::OpenGl::CShader CGSH_OpenGL::GenerateVertexShader(const SHADERCAPS& c
|
|||
|
||||
Framework::OpenGl::CShader CGSH_OpenGL::GenerateFragmentShader(const SHADERCAPS& caps)
|
||||
{
|
||||
bool alphaTestCanDiscardDepth = (caps.hasAlphaTest) && ((caps.alphaFailMethod == ALPHA_TEST_FAIL_FBONLY) || (caps.alphaFailMethod == ALPHA_TEST_FAIL_RGBONLY));
|
||||
bool useFramebufferFetch = (caps.hasAlphaBlend || caps.hasAlphaTest || caps.hasDestAlphaTest) && m_hasFramebufferFetchExtension;
|
||||
bool useFramebufferFetchDepth = alphaTestCanDiscardDepth && m_hasFramebufferFetchDepthExtension;
|
||||
|
||||
std::stringstream shaderBuilder;
|
||||
shaderBuilder << GLSL_VERSION << std::endl;
|
||||
|
@ -144,6 +146,10 @@ Framework::OpenGl::CShader CGSH_OpenGL::GenerateFragmentShader(const SHADERCAPS&
|
|||
{
|
||||
shaderBuilder << "#extension GL_EXT_shader_framebuffer_fetch : require" << std::endl;
|
||||
}
|
||||
if(useFramebufferFetchDepth)
|
||||
{
|
||||
shaderBuilder << "#extension GL_ARM_shader_framebuffer_fetch_depth_stencil : require" << std::endl;
|
||||
}
|
||||
|
||||
shaderBuilder << "precision mediump float;" << std::endl;
|
||||
|
||||
|
@ -354,6 +360,10 @@ Framework::OpenGl::CShader CGSH_OpenGL::GenerateFragmentShader(const SHADERCAPS&
|
|||
shaderBuilder << " bool outputColor = true;" << std::endl;
|
||||
shaderBuilder << " bool outputAlpha = true;" << std::endl;
|
||||
}
|
||||
if(useFramebufferFetchDepth)
|
||||
{
|
||||
shaderBuilder << " bool outputDepth = true;" << std::endl;
|
||||
}
|
||||
|
||||
if(caps.hasAlphaTest)
|
||||
{
|
||||
|
@ -420,7 +430,33 @@ Framework::OpenGl::CShader CGSH_OpenGL::GenerateFragmentShader(const SHADERCAPS&
|
|||
|
||||
// ----------------------
|
||||
|
||||
shaderBuilder << " gl_FragDepth = v_depth;" << std::endl;
|
||||
if(useFramebufferFetchDepth)
|
||||
{
|
||||
shaderBuilder << " if(outputDepth)" << std::endl;
|
||||
shaderBuilder << " {" << std::endl;
|
||||
shaderBuilder << " gl_FragDepth = v_depth;" << std::endl;
|
||||
shaderBuilder << " }" << std::endl;
|
||||
shaderBuilder << " else" << std::endl;
|
||||
shaderBuilder << " {" << std::endl;
|
||||
shaderBuilder << " highp float dstDepth = gl_LastFragDepthARM;" << std::endl;
|
||||
if(caps.alphaTestDepthTest_DepthFetch)
|
||||
{
|
||||
if(caps.alphaTestDepthTestEqual_DepthFetch)
|
||||
{
|
||||
shaderBuilder << " if(!(v_depth >= dstDepth)) discard;" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
shaderBuilder << " if(!(v_depth > dstDepth)) discard;" << std::endl;
|
||||
}
|
||||
}
|
||||
shaderBuilder << " gl_FragDepth = dstDepth;" << std::endl;
|
||||
shaderBuilder << " }" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
shaderBuilder << " gl_FragDepth = v_depth;" << std::endl;
|
||||
}
|
||||
|
||||
// ----------------------
|
||||
|
||||
|
@ -526,6 +562,11 @@ std::string CGSH_OpenGL::GenerateAlphaTestSection(ALPHA_TEST_METHOD testMethod,
|
|||
// Failure note: We rather accept writing depth here, than discarding the
|
||||
// whole pixel, as most games work better with this hack.
|
||||
// Breaks foliage in some games (Grandia X/3, Naruto, etc.)
|
||||
// If we have depth buffer fetch, we can properly handle it.
|
||||
if(m_hasFramebufferFetchDepthExtension)
|
||||
{
|
||||
shaderBuilder << " outputDepth = false;" << std::endl;
|
||||
}
|
||||
break;
|
||||
case ALPHA_TEST_FAIL_ZBONLY:
|
||||
// Only write depth
|
||||
|
@ -546,17 +587,14 @@ std::string CGSH_OpenGL::GenerateAlphaTestSection(ALPHA_TEST_METHOD testMethod,
|
|||
if(m_hasFramebufferFetchExtension)
|
||||
{
|
||||
shaderBuilder << " outputAlpha = false;" << std::endl;
|
||||
|
||||
// TODO: Prevent depth writing
|
||||
// Failure note: We rather accept writing depth here, than discarding the
|
||||
// whole pixel, as most games work better with this hack.
|
||||
}
|
||||
else
|
||||
if(m_hasFramebufferFetchDepthExtension)
|
||||
{
|
||||
// TODO: Prevent color and depth writing without extension
|
||||
// Failure note: We are somewhat out of luck, and just draw the pixel as is.
|
||||
// This is completely wrong, but nothing we can do about it at this point.
|
||||
shaderBuilder << " outputDepth = false;" << std::endl;
|
||||
}
|
||||
// TODO: Prevent alpha and depth writing without extension
|
||||
// Failure note: We are somewhat out of luck, and just draw the pixel as is.
|
||||
// This is completely wrong, but nothing we can do about it at this point.
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue