Commit 5f0246ca by Kimmo Kinnunen Committed by Geoff Lang

Implement gl_FragDepth for GLES SL 3.0

Makes it an error to access gl_FragDepthEXT in #version 300 es shader. TODO: Lacks the feature to make "#extension GL_EXT_frag_depth : require" an error for #version 300 es. Reland of: https://chromium-review.googlesource.com/#/c/287570 BUG=angleproject:1102 TEST=angle_unittest Change-Id: I064d918d65f37539cb1e14f12173ca5591a4ea3f Reviewed-on: https://chromium-review.googlesource.com/301711Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Tested-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent ddf4d392
...@@ -164,6 +164,7 @@ int main(int argc, char *argv[]) ...@@ -164,6 +164,7 @@ int main(int argc, char *argv[])
case 'x': case 'x':
if (argv[0][2] == '=') if (argv[0][2] == '=')
{ {
// clang-format off
switch (argv[0][3]) switch (argv[0][3])
{ {
case 'i': resources.OES_EGL_image_external = 1; break; case 'i': resources.OES_EGL_image_external = 1; break;
...@@ -191,15 +192,14 @@ int main(int argc, char *argv[]) ...@@ -191,15 +192,14 @@ int main(int argc, char *argv[])
failCode = EFailUsage; failCode = EFailUsage;
} }
break; break;
case 'g': case 'g': resources.EXT_frag_depth = 1; break;
resources.EXT_frag_depth = 1;
break;
case 'l': resources.EXT_shader_texture_lod = 1; break; case 'l': resources.EXT_shader_texture_lod = 1; break;
case 'f': resources.EXT_shader_framebuffer_fetch = 1; break; case 'f': resources.EXT_shader_framebuffer_fetch = 1; break;
case 'n': resources.NV_shader_framebuffer_fetch = 1; break; case 'n': resources.NV_shader_framebuffer_fetch = 1; break;
case 'a': resources.ARM_shader_framebuffer_fetch = 1; break; case 'a': resources.ARM_shader_framebuffer_fetch = 1; break;
default: failCode = EFailUsage; default: failCode = EFailUsage;
} }
// clang-format on
} }
else else
{ {
...@@ -287,6 +287,7 @@ int main(int argc, char *argv[]) ...@@ -287,6 +287,7 @@ int main(int argc, char *argv[])
// //
void usage() void usage()
{ {
// clang-format off
printf( printf(
"Usage: translate [-i -o -u -l -e -t -d -p -b=e -b=g -b=h9 -x=i -x=d] file1 file2 ...\n" "Usage: translate [-i -o -u -l -e -t -d -p -b=e -b=g -b=h9 -x=i -x=d] file1 file2 ...\n"
"Where: filename : filename ending in .frag or .vert\n" "Where: filename : filename ending in .frag or .vert\n"
...@@ -314,10 +315,12 @@ void usage() ...@@ -314,10 +315,12 @@ void usage()
" -x=r : enable ARB_texture_rectangle\n" " -x=r : enable ARB_texture_rectangle\n"
" -x=b[NUM]: enable EXT_blend_func_extended (NUM default 1)\n" " -x=b[NUM]: enable EXT_blend_func_extended (NUM default 1)\n"
" -x=w[NUM]: enable EXT_draw_buffers (NUM default 1)\n" " -x=w[NUM]: enable EXT_draw_buffers (NUM default 1)\n"
" -x=g : enable EXT_frag_depth\n"
" -x=l : enable EXT_shader_texture_lod\n" " -x=l : enable EXT_shader_texture_lod\n"
" -x=f : enable EXT_shader_framebuffer_fetch\n" " -x=f : enable EXT_shader_framebuffer_fetch\n"
" -x=n : enable NV_shader_framebuffer_fetch\n" " -x=n : enable NV_shader_framebuffer_fetch\n"
" -x=a : enable ARM_shader_framebuffer_fetch\n"); " -x=a : enable ARM_shader_framebuffer_fetch\n");
// clang-format on
} }
// //
......
...@@ -324,7 +324,10 @@ enum TQualifier ...@@ -324,7 +324,10 @@ enum TQualifier
// built-ins written by fragment shader // built-ins written by fragment shader
EvqFragColor, EvqFragColor,
EvqFragData, EvqFragData,
EvqFragDepth,
EvqFragDepth, // gl_FragDepth for ESSL300.
EvqFragDepthEXT, // gl_FragDepthEXT for ESSL100, EXT_frag_depth.
EvqSecondaryFragColorEXT, // EXT_blend_func_extended EvqSecondaryFragColorEXT, // EXT_blend_func_extended
EvqSecondaryFragDataEXT, // EXT_blend_func_extended EvqSecondaryFragDataEXT, // EXT_blend_func_extended
...@@ -389,48 +392,47 @@ struct TLayoutQualifier ...@@ -389,48 +392,47 @@ struct TLayoutQualifier
// //
inline const char* getQualifierString(TQualifier q) inline const char* getQualifierString(TQualifier q)
{ {
// clang-format off
switch(q) switch(q)
{ {
case EvqTemporary: return "Temporary"; break; case EvqTemporary: return "Temporary";
case EvqGlobal: return "Global"; break; case EvqGlobal: return "Global";
case EvqConst: return "const"; break; case EvqConst: return "const";
case EvqAttribute: return "attribute"; break; case EvqAttribute: return "attribute";
case EvqVaryingIn: return "varying"; break; case EvqVaryingIn: return "varying";
case EvqVaryingOut: return "varying"; break; case EvqVaryingOut: return "varying";
case EvqUniform: return "uniform"; break; case EvqUniform: return "uniform";
case EvqVertexIn: return "in"; break; case EvqVertexIn: return "in";
case EvqFragmentOut: return "out"; break; case EvqFragmentOut: return "out";
case EvqVertexOut: return "out"; break; case EvqVertexOut: return "out";
case EvqFragmentIn: return "in"; break; case EvqFragmentIn: return "in";
case EvqIn: return "in"; break; case EvqIn: return "in";
case EvqOut: return "out"; break; case EvqOut: return "out";
case EvqInOut: return "inout"; break; case EvqInOut: return "inout";
case EvqConstReadOnly: return "const"; break; case EvqConstReadOnly: return "const";
case EvqInstanceID: return "InstanceID"; break; case EvqInstanceID: return "InstanceID";
case EvqPosition: return "Position"; break; case EvqPosition: return "Position";
case EvqPointSize: return "PointSize"; break; case EvqPointSize: return "PointSize";
case EvqFragCoord: return "FragCoord"; break; case EvqFragCoord: return "FragCoord";
case EvqFrontFacing: return "FrontFacing"; break; case EvqFrontFacing: return "FrontFacing";
case EvqPointCoord: return "PointCoord"; break; case EvqPointCoord: return "PointCoord";
case EvqFragColor: return "FragColor"; break; case EvqFragColor: return "FragColor";
case EvqFragData: return "FragData"; break; case EvqFragData: return "FragData";
case EvqFragDepth: return "FragDepth"; break; case EvqFragDepthEXT: return "FragDepth";
case EvqSecondaryFragColorEXT: case EvqFragDepth: return "FragDepth";
return "SecondaryFragColorEXT"; case EvqSecondaryFragColorEXT: return "SecondaryFragColorEXT";
break; case EvqSecondaryFragDataEXT: return "SecondaryFragDataEXT";
case EvqSecondaryFragDataEXT: case EvqLastFragColor: return "LastFragColor";
return "SecondaryFragDataEXT"; case EvqLastFragData: return "LastFragData";
break; case EvqSmoothOut: return "smooth out";
case EvqLastFragColor: return "LastFragColor"; break; case EvqCentroidOut: return "centroid out";
case EvqLastFragData: return "LastFragData"; break; case EvqFlatOut: return "flat out";
case EvqSmoothOut: return "smooth out"; break; case EvqSmoothIn: return "smooth in";
case EvqCentroidOut: return "centroid out"; break; case EvqFlatIn: return "flat in";
case EvqFlatOut: return "flat out"; break; case EvqCentroidIn: return "centroid in";
case EvqSmoothIn: return "smooth in"; break; default: UNREACHABLE(); return "unknown qualifier";
case EvqFlatIn: return "flat in"; break;
case EvqCentroidIn: return "centroid in"; break;
default: UNREACHABLE(); return "unknown qualifier";
} }
// clang-format on
} }
inline const char* getMatrixPackingString(TLayoutMatrixPacking mpq) inline const char* getMatrixPackingString(TLayoutMatrixPacking mpq)
......
...@@ -523,10 +523,18 @@ void IdentifyBuiltIns(sh::GLenum type, ShShaderSpec spec, ...@@ -523,10 +523,18 @@ void IdentifyBuiltIns(sh::GLenum type, ShShaderSpec spec,
if (resources.EXT_frag_depth) if (resources.EXT_frag_depth)
{ {
symbolTable.insert(ESSL1_BUILTINS, "GL_EXT_frag_depth", new TVariable(NewPoolTString("gl_FragDepthEXT"), symbolTable.insert(
TType(EbtFloat, resources.FragmentPrecisionHigh ? EbpHigh : EbpMedium, EvqFragDepth, 1))); ESSL1_BUILTINS, "GL_EXT_frag_depth",
new TVariable(
NewPoolTString("gl_FragDepthEXT"),
TType(EbtFloat, resources.FragmentPrecisionHigh ? EbpHigh : EbpMedium,
EvqFragDepthEXT, 1)));
} }
symbolTable.insert(ESSL3_BUILTINS,
new TVariable(NewPoolTString("gl_FragDepth"),
TType(EbtFloat, EbpHigh, EvqFragDepth, 1)));
if (resources.EXT_shader_framebuffer_fetch || resources.NV_shader_framebuffer_fetch) if (resources.EXT_shader_framebuffer_fetch || resources.NV_shader_framebuffer_fetch)
{ {
TType lastFragData(EbtFloat, EbpMedium, EvqLastFragData, 4, 1, true); TType lastFragData(EbtFloat, EbpMedium, EvqLastFragData, 4, 1, true);
......
...@@ -1386,7 +1386,7 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node) ...@@ -1386,7 +1386,7 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node)
mUsesInstanceID = true; mUsesInstanceID = true;
out << name; out << name;
} }
else if (name == "gl_FragDepthEXT") else if (name == "gl_FragDepthEXT" || name == "gl_FragDepth")
{ {
mUsesFragDepth = true; mUsesFragDepth = true;
out << "gl_Depth"; out << "gl_Depth";
......
...@@ -151,6 +151,7 @@ CollectVariables::CollectVariables(std::vector<sh::Attribute> *attribs, ...@@ -151,6 +151,7 @@ CollectVariables::CollectVariables(std::vector<sh::Attribute> *attribs,
mLastFragDataAdded(false), mLastFragDataAdded(false),
mFragColorAdded(false), mFragColorAdded(false),
mFragDataAdded(false), mFragDataAdded(false),
mFragDepthEXTAdded(false),
mFragDepthAdded(false), mFragDepthAdded(false),
mSecondaryFragColorEXTAdded(false), mSecondaryFragColorEXTAdded(false),
mSecondaryFragDataEXTAdded(false), mSecondaryFragDataEXTAdded(false),
...@@ -405,8 +406,8 @@ void CollectVariables::visitSymbol(TIntermSymbol *symbol) ...@@ -405,8 +406,8 @@ void CollectVariables::visitSymbol(TIntermSymbol *symbol)
mFragDataAdded = true; mFragDataAdded = true;
} }
return; return;
case EvqFragDepth: case EvqFragDepthEXT:
if (!mFragDepthAdded) if (!mFragDepthEXTAdded)
{ {
OutputVariable info; OutputVariable info;
const char kName[] = "gl_FragDepthEXT"; const char kName[] = "gl_FragDepthEXT";
...@@ -420,6 +421,21 @@ void CollectVariables::visitSymbol(TIntermSymbol *symbol) ...@@ -420,6 +421,21 @@ void CollectVariables::visitSymbol(TIntermSymbol *symbol)
->getType()); ->getType());
info.staticUse = true; info.staticUse = true;
mOutputVariables->push_back(info); mOutputVariables->push_back(info);
mFragDepthEXTAdded = true;
}
return;
case EvqFragDepth:
if (!mFragDepthAdded)
{
OutputVariable info;
const char kName[] = "gl_FragDepth";
info.name = kName;
info.mappedName = kName;
info.type = GL_FLOAT;
info.arraySize = 0;
info.precision = GL_HIGH_FLOAT;
info.staticUse = true;
mOutputVariables->push_back(info);
mFragDepthAdded = true; mFragDepthAdded = true;
} }
return; return;
......
...@@ -58,6 +58,7 @@ class CollectVariables : public TIntermTraverser ...@@ -58,6 +58,7 @@ class CollectVariables : public TIntermTraverser
bool mLastFragDataAdded; bool mLastFragDataAdded;
bool mFragColorAdded; bool mFragColorAdded;
bool mFragDataAdded; bool mFragDataAdded;
bool mFragDepthEXTAdded;
bool mFragDepthAdded; bool mFragDepthAdded;
bool mSecondaryFragColorEXTAdded; bool mSecondaryFragColorEXTAdded;
bool mSecondaryFragDataEXTAdded; bool mSecondaryFragDataEXTAdded;
......
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
'<(angle_path)/src/tests/compiler_tests/DebugShaderPrecision_test.cpp', '<(angle_path)/src/tests/compiler_tests/DebugShaderPrecision_test.cpp',
'<(angle_path)/src/tests/compiler_tests/ExpressionLimit_test.cpp', '<(angle_path)/src/tests/compiler_tests/ExpressionLimit_test.cpp',
'<(angle_path)/src/tests/compiler_tests/EXT_blend_func_extended_test.cpp', '<(angle_path)/src/tests/compiler_tests/EXT_blend_func_extended_test.cpp',
'<(angle_path)/src/tests/compiler_tests/FragDepth_test.cpp',
'<(angle_path)/src/tests/compiler_tests/IntermNode_test.cpp', '<(angle_path)/src/tests/compiler_tests/IntermNode_test.cpp',
'<(angle_path)/src/tests/compiler_tests/MalformedShader_test.cpp', '<(angle_path)/src/tests/compiler_tests/MalformedShader_test.cpp',
'<(angle_path)/src/tests/compiler_tests/NV_draw_buffers_test.cpp', '<(angle_path)/src/tests/compiler_tests/NV_draw_buffers_test.cpp',
......
...@@ -557,6 +557,30 @@ TEST_F(CollectFragmentVariablesTest, OutputVarESSL1FragDepthHighp) ...@@ -557,6 +557,30 @@ TEST_F(CollectFragmentVariablesTest, OutputVarESSL1FragDepthHighp)
EXPECT_GLENUM_EQ(GL_FLOAT, outputVariable->type); EXPECT_GLENUM_EQ(GL_FLOAT, outputVariable->type);
EXPECT_GLENUM_EQ(GL_HIGH_FLOAT, outputVariable->precision); EXPECT_GLENUM_EQ(GL_HIGH_FLOAT, outputVariable->precision);
} }
// Test that gl_FragData built-in usage in ESSL3 fragment shader is reflected in the output
// variables list. Also test that the precision is highp.
TEST_F(CollectFragmentVariablesTest, OutputVarESSL3FragDepthHighp)
{
const std::string &fragDepthHighShader =
"#version 300 es\n"
"precision mediump float;\n"
"void main() {\n"
" gl_FragDepth = 0.7;"
"}\n";
ShBuiltInResources resources = mTranslator->getResources();
resources.EXT_frag_depth = 1;
initTranslator(resources);
const sh::OutputVariable *outputVariable = nullptr;
validateOutputVariableForShader(fragDepthHighShader, 0u, "gl_FragDepth", &outputVariable);
ASSERT_NE(outputVariable, nullptr);
EXPECT_EQ(0u, outputVariable->arraySize);
EXPECT_GLENUM_EQ(GL_FLOAT, outputVariable->type);
EXPECT_GLENUM_EQ(GL_HIGH_FLOAT, outputVariable->precision);
}
// Test that gl_SecondaryFragColorEXT built-in usage in ESSL1 fragment shader is reflected in the // Test that gl_SecondaryFragColorEXT built-in usage in ESSL1 fragment shader is reflected in the
// output variables list. // output variables list.
TEST_F(CollectFragmentVariablesTest, OutputVarESSL1EXTBlendFuncExtendedSecondaryFragColor) TEST_F(CollectFragmentVariablesTest, OutputVarESSL1EXTBlendFuncExtendedSecondaryFragColor)
......
//
// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// FragDepth_test.cpp:
// Test for GLES SL 3.0 gl_FragDepth variable implementation.
//
#include "angle_gl.h"
#include "gtest/gtest.h"
#include "GLSLANG/ShaderLang.h"
namespace
{
const char ESSLVersion100[] = "#version 100\n";
const char ESSLVersion300[] = "#version 300 es\n";
const char EXTFDPragma[] = "#extension GL_EXT_frag_depth : require\n";
} // namespace
class FragDepthTest : public testing::TestWithParam<bool>
{
protected:
void SetUp() override
{
ShInitBuiltInResources(&mResources);
mCompiler = nullptr;
mResources.EXT_frag_depth = GetParam();
}
void TearDown() override { DestroyCompiler(); }
void DestroyCompiler()
{
if (mCompiler)
{
ShDestruct(mCompiler);
mCompiler = nullptr;
}
}
void InitializeCompiler()
{
DestroyCompiler();
mCompiler =
ShConstructCompiler(GL_FRAGMENT_SHADER, SH_GLES3_SPEC, SH_GLSL_OUTPUT, &mResources);
ASSERT_TRUE(mCompiler != nullptr) << "Compiler could not be constructed.";
}
testing::AssertionResult TestShaderCompile(const char *version,
const char *pragma,
const char *shader)
{
const char *shaderStrings[] = {version, pragma, shader};
bool success = ShCompile(mCompiler, shaderStrings, 3, 0);
if (success)
{
return ::testing::AssertionSuccess() << "Compilation success";
}
return ::testing::AssertionFailure() << ShGetInfoLog(mCompiler);
}
protected:
ShBuiltInResources mResources;
ShHandle mCompiler;
};
// The GLES SL 3.0 built-in variable gl_FragDepth fails to compile with GLES SL 1.0.
TEST_P(FragDepthTest, CompileFailsESSL100)
{
static const char shaderString[] =
"precision mediump float;\n"
"void main() { \n"
" gl_FragDepth = 1.0;\n"
"}\n";
InitializeCompiler();
EXPECT_FALSE(TestShaderCompile(ESSLVersion100, "", shaderString));
EXPECT_FALSE(TestShaderCompile("", "", shaderString));
EXPECT_FALSE(TestShaderCompile("", EXTFDPragma, shaderString));
}
// The GLES SL 3.0 built-in variable gl_FragDepth compiles with GLES SL 3.0.
TEST_P(FragDepthTest, CompileSucceedsESSL300)
{
static const char shaderString[] =
"precision mediump float;\n"
"void main() { \n"
" gl_FragDepth = 1.0;\n"
"}\n";
InitializeCompiler();
EXPECT_TRUE(TestShaderCompile(ESSLVersion300, "", shaderString));
}
// Using #extension GL_EXT_frag_depth in GLSL ES 3.0 shader fails to compile.
TEST_P(FragDepthTest, ExtensionFDFailsESSL300)
{
static const char shaderString[] =
"precision mediump float;\n"
"out vec4 fragColor;\n"
"void main() { \n"
" fragColor = vec4(1.0);\n"
"}\n";
InitializeCompiler();
if (mResources.EXT_frag_depth == 1)
{
// TODO(kkinnunen, geofflang): this should fail. Extensions need to have similar level
// system to SymbolTable. The biggest task is to implement version-aware preprocessor, so
// that the extension defines can be defined depending on the version that the preprocessor
// saw or did not see.
EXPECT_TRUE(TestShaderCompile(ESSLVersion300, EXTFDPragma, shaderString));
}
else
{
EXPECT_FALSE(TestShaderCompile(ESSLVersion300, EXTFDPragma, shaderString));
}
}
// The tests should pass regardless whether the EXT_frag_depth is on or not.
INSTANTIATE_TEST_CASE_P(FragDepthTests, FragDepthTest, testing::Values(false, true));
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment