Implement a specific case of alpha testing (depth discard) using extensions.

This commit is contained in:
Jean-Philip Desjardins 2021-04-15 13:30:23 -04:00
parent 8f201ab7c2
commit 3fddb1fe69
3 changed files with 63 additions and 7 deletions

View file

@ -313,6 +313,10 @@ void CGSH_OpenGL::CheckExtensions()
{
m_hasFramebufferFetchExtension = true;
}
else if(!strcmp(extensionName, "GL_ARM_shader_framebuffer_fetch_depth_stencil"))
{
m_hasFramebufferDepthFetchExtension = true;
}
}
}
@ -1125,6 +1129,7 @@ void CGSH_OpenGL::FillShaderCapsFromTest(SHADERCAPS& shaderCaps, const uint64& t
{
shaderCaps.hasAlphaTest = m_alphaTestingEnabled ? 1 : 0;
shaderCaps.alphaTestMethod = test.nAlphaMethod;
shaderCaps.alphaTestFailMethod = test.nAlphaFail;
}
}
else

View file

@ -85,10 +85,11 @@ private:
unsigned int hasFog : 1;
unsigned int hasAlphaTest : 1;
unsigned int alphaTestMethod : 3;
unsigned int alphaTestFailMethod : 2;
unsigned int hasDestAlphaTest : 1;
unsigned int destAlphaTestRef : 1;
unsigned int colorOutputWhite : 1;
unsigned int padding : 10;
unsigned int padding : 8;
bool isIndexedTextureSource() const
{
@ -316,7 +317,7 @@ private:
Framework::OpenGl::CShader GenerateVertexShader(const SHADERCAPS&);
Framework::OpenGl::CShader GenerateFragmentShader(const SHADERCAPS&);
std::string GenerateTexCoordClampingSection(TEXTURE_CLAMP_MODE, const char*);
std::string GenerateAlphaTestSection(ALPHA_TEST_METHOD);
std::string GenerateAlphaTestSection(ALPHA_TEST_METHOD, ALPHA_TEST_FAIL_METHOD);
Framework::OpenGl::ProgramPtr GeneratePresentProgram();
Framework::OpenGl::CBuffer GeneratePresentVertexBuffer();
@ -462,4 +463,5 @@ private:
VertexBuffer m_vertexBuffer;
bool m_hasFramebufferFetchExtension = false;
bool m_hasFramebufferDepthFetchExtension = false;
};

View file

@ -137,8 +137,35 @@ Framework::OpenGl::CShader CGSH_OpenGL::GenerateFragmentShader(const SHADERCAPS&
{
std::stringstream shaderBuilder;
bool useFramebufferFetch = false;
bool useFramebufferDepthFetch = false;
auto alphaTestFailMethod = static_cast<ALPHA_TEST_FAIL_METHOD>(caps.alphaTestFailMethod);
if(caps.hasAlphaTest)
{
switch(alphaTestFailMethod)
{
case ALPHA_TEST_FAIL_KEEP:
case ALPHA_TEST_FAIL_RGBONLY:
case ALPHA_TEST_FAIL_ZBONLY:
//TODO: Check how we can implement these correctly
alphaTestFailMethod = ALPHA_TEST_FAIL_KEEP;
break;
case ALPHA_TEST_FAIL_FBONLY:
if(!m_hasFramebufferDepthFetchExtension)
{
alphaTestFailMethod = ALPHA_TEST_FAIL_KEEP;
}
else
{
useFramebufferDepthFetch |= true;
}
break;
}
}
bool writeDestAlphaTest = caps.hasDestAlphaTest && m_hasFramebufferFetchExtension;
bool useFramebufferFetch = writeDestAlphaTest;
useFramebufferFetch |= writeDestAlphaTest;
shaderBuilder << GLSL_VERSION << std::endl;
@ -147,6 +174,11 @@ Framework::OpenGl::CShader CGSH_OpenGL::GenerateFragmentShader(const SHADERCAPS&
shaderBuilder << "#extension GL_EXT_shader_framebuffer_fetch : require" << std::endl;
}
if(useFramebufferDepthFetch)
{
shaderBuilder << "#extension GL_ARM_shader_framebuffer_fetch_depth_stencil : require" << std::endl;
}
shaderBuilder << "precision mediump float;" << std::endl;
shaderBuilder << "in highp float v_depth;" << std::endl;
@ -233,6 +265,8 @@ Framework::OpenGl::CShader CGSH_OpenGL::GenerateFragmentShader(const SHADERCAPS&
}
}
shaderBuilder << " highp float fragDepth = v_depth;" << std::endl;
shaderBuilder << " highp vec3 texCoord = v_texCoord;" << std::endl;
shaderBuilder << " texCoord.st /= texCoord.p;" << std::endl;
@ -348,7 +382,7 @@ Framework::OpenGl::CShader CGSH_OpenGL::GenerateFragmentShader(const SHADERCAPS&
if(caps.hasAlphaTest)
{
shaderBuilder << GenerateAlphaTestSection(static_cast<ALPHA_TEST_METHOD>(caps.alphaTestMethod));
shaderBuilder << GenerateAlphaTestSection(static_cast<ALPHA_TEST_METHOD>(caps.alphaTestMethod), alphaTestFailMethod);
}
if(caps.hasFog)
@ -374,7 +408,7 @@ Framework::OpenGl::CShader CGSH_OpenGL::GenerateFragmentShader(const SHADERCAPS&
shaderBuilder << " fragColor.xyz = vec3(1, 1, 1);" << std::endl;
}
shaderBuilder << " gl_FragDepth = v_depth;" << std::endl;
shaderBuilder << " gl_FragDepth = fragDepth;" << std::endl;
shaderBuilder << "}" << std::endl;
@ -418,7 +452,7 @@ std::string CGSH_OpenGL::GenerateTexCoordClampingSection(TEXTURE_CLAMP_MODE clam
return shaderSource;
}
std::string CGSH_OpenGL::GenerateAlphaTestSection(ALPHA_TEST_METHOD testMethod)
std::string CGSH_OpenGL::GenerateAlphaTestSection(ALPHA_TEST_METHOD testMethod, ALPHA_TEST_FAIL_METHOD testFailMethod)
{
std::stringstream shaderBuilder;
@ -456,10 +490,25 @@ std::string CGSH_OpenGL::GenerateAlphaTestSection(ALPHA_TEST_METHOD testMethod)
break;
}
const char* testFailOp = " discard;";
switch(testFailMethod)
{
case CGSHandler::ALPHA_TEST_FAIL_KEEP:
testFailOp = " discard;";
break;
case CGSHandler::ALPHA_TEST_FAIL_FBONLY:
//Depth is discarded
testFailOp = " fragDepth = gl_LastFragDepthARM;";
break;
default:
assert(false);
break;
}
shaderBuilder << "uint textureColorAlphaInt = uint(textureColor.a * 255.0);" << std::endl;
shaderBuilder << test << std::endl;
shaderBuilder << "{" << std::endl;
shaderBuilder << " discard;" << std::endl;
shaderBuilder << testFailOp << std::endl;
shaderBuilder << "}" << std::endl;
std::string shaderSource = shaderBuilder.str();