Commit 7c8567a3 by Olli Etuaho Committed by Commit Bot

Always add most extension symbols to symbol table

An error will be generated either way if the extension symbols are used incorrectly since each use of an extension function or variable checks whether the extension is enabled. We now also track extension in unmangled built-in names, so that redefining built-ins of extensions that are not enabled can be supported. This includes refactoring the shader extension tests to share a common helper class ShaderExtensionTest. BUG=angleproject:2267 TEST=angle_unittests Change-Id: I9cc5e9bd62fa07796e69256a6a9a493531a62446 Reviewed-on: https://chromium-review.googlesource.com/926526 Commit-Queue: Olli Etuaho <oetuaho@nvidia.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent a953b527
......@@ -3228,7 +3228,7 @@ TIntermFunctionPrototype *TParseContext::addFunctionPrototypeDeclaration(
// first declaration. Either way the instance in the symbol table is used to track whether the
// function is declared multiple times.
bool hadPrototypeDeclaration = false;
const TFunction *function = symbolTable.markUserDefinedFunctionHasPrototypeDeclaration(
const TFunction *function = symbolTable.markFunctionHasPrototypeDeclaration(
parsedFunction.getMangledName(), &hadPrototypeDeclaration);
if (hadPrototypeDeclaration && mShaderVersion == 100)
......@@ -3282,22 +3282,12 @@ void TParseContext::parseFunctionDefinitionHeader(const TSourceLoc &location,
TIntermFunctionPrototype **prototypeOut)
{
ASSERT(function);
const TSymbol *builtIn =
symbolTable.findBuiltIn(ImmutableString(function->getMangledName()), getShaderVersion());
if (builtIn)
bool wasDefined = false;
function = symbolTable.setFunctionParameterNamesFromDefinition(function, &wasDefined);
if (wasDefined)
{
error(location, "built-in functions cannot be redefined", function->name());
}
else
{
bool wasDefined = false;
function =
symbolTable.setUserDefinedFunctionParameterNamesFromDefinition(function, &wasDefined);
if (wasDefined)
{
error(location, "function already has a body", function->name());
}
error(location, "function already has a body", function->name());
}
// Remember the return type for later checking for return statements.
......@@ -3315,11 +3305,6 @@ TFunction *TParseContext::parseFunctionDeclarator(const TSourceLoc &location, TF
// The definition production code will check for redefinitions.
// In the case of ESSL 1.00 the prototype production code will also check for redeclarations.
//
// Return types and parameter qualifiers must match in all redeclarations, so those are checked
// here.
//
const TFunction *prevDec = static_cast<const TFunction *>(
symbolTable.find(ImmutableString(function->getMangledName()), getShaderVersion()));
for (size_t i = 0u; i < function->getParamCount(); ++i)
{
......@@ -3332,15 +3317,36 @@ TFunction *TParseContext::parseFunctionDeclarator(const TSourceLoc &location, TF
}
}
if (getShaderVersion() >= 300 && symbolTable.hasUnmangledBuiltInForShaderVersion(
function->name().data(), getShaderVersion()))
if (getShaderVersion() >= 300)
{
// With ESSL 3.00 and above, names of built-in functions cannot be redeclared as functions.
// Therefore overloading or redefining builtin functions is an error.
error(location, "Name of a built-in function cannot be redeclared as function",
function->name());
const UnmangledBuiltIn *builtIn =
symbolTable.getUnmangledBuiltInForShaderVersion(function->name(), getShaderVersion());
if (builtIn &&
(builtIn->extension == TExtension::UNDEFINED || isExtensionEnabled(builtIn->extension)))
{
// With ESSL 3.00 and above, names of built-in functions cannot be redeclared as
// functions. Therefore overloading or redefining builtin functions is an error.
error(location, "Name of a built-in function cannot be redeclared as function",
function->name());
}
}
else if (prevDec)
else
{
// ESSL 1.00.17 section 4.2.6: built-ins can be overloaded but not redefined. We assume that
// this applies to redeclarations as well.
const TSymbol *builtIn =
symbolTable.findBuiltIn(function->getMangledName(), getShaderVersion());
if (builtIn)
{
error(location, "built-in functions cannot be redefined", function->name());
}
}
// Return types and parameter qualifiers must match in all redeclarations, so those are checked
// here.
const TFunction *prevDec =
static_cast<const TFunction *>(symbolTable.findGlobal(function->getMangledName()));
if (prevDec)
{
if (prevDec->getReturnType() != function->getReturnType())
{
......
......@@ -57,6 +57,15 @@ const int GLSL_BUILTINS = 4;
const int LAST_BUILTIN_LEVEL = GLSL_BUILTINS;
const int GLOBAL_LEVEL = 5;
struct UnmangledBuiltIn
{
constexpr UnmangledBuiltIn() : extension(TExtension::UNDEFINED) {}
constexpr UnmangledBuiltIn(TExtension extension) : extension(extension) {}
TExtension extension;
};
class TSymbolTable : angle::NonCopyable
{
public:
......@@ -87,11 +96,10 @@ class TSymbolTable : angle::NonCopyable
void declareUserDefinedFunction(TFunction *function, bool insertUnmangledName);
// These return the TFunction pointer to keep using to refer to this function.
const TFunction *markUserDefinedFunctionHasPrototypeDeclaration(
const ImmutableString &mangledName,
bool *hadPrototypeDeclarationOut);
const TFunction *setUserDefinedFunctionParameterNamesFromDefinition(const TFunction *function,
bool *wasDefinedOut);
const TFunction *markFunctionHasPrototypeDeclaration(const ImmutableString &mangledName,
bool *hadPrototypeDeclarationOut);
const TFunction *setFunctionParameterNamesFromDefinition(const TFunction *function,
bool *wasDefinedOut);
// find() is guaranteed not to retain a reference to the ImmutableString, so an ImmutableString
// with a reference to a short-lived char * is fine to pass here.
......@@ -125,8 +133,9 @@ class TSymbolTable : angle::NonCopyable
const TSymbolUniqueId nextUniqueId() { return TSymbolUniqueId(this); }
// Checks whether there is a built-in accessible by a shader with the specified version.
bool hasUnmangledBuiltInForShaderVersion(const char *name, int shaderVersion);
// Gets the built-in accessible by a shader with the specified version, if any.
const UnmangledBuiltIn *getUnmangledBuiltInForShaderVersion(const ImmutableString &name,
int shaderVersion);
void initializeBuiltIns(sh::GLenum type,
ShShaderSpec spec,
......@@ -195,7 +204,7 @@ class TSymbolTable : angle::NonCopyable
const TType *ptype4 = 0,
const TType *ptype5 = 0)
{
insertUnmangledBuiltInName(name, level);
insertUnmangledBuiltIn(name, TExtension::UNDEFINED, level);
insertBuiltIn(level, EOpCallBuiltInFunction, TExtension::UNDEFINED, rvalue, name, ptype1,
ptype2, ptype3, ptype4, ptype5);
}
......@@ -210,7 +219,7 @@ class TSymbolTable : angle::NonCopyable
const TType *ptype4 = 0,
const TType *ptype5 = 0)
{
insertUnmangledBuiltInName(name, level);
insertUnmangledBuiltIn(name, ext, level);
insertBuiltIn(level, EOpCallBuiltInFunction, ext, rvalue, name, ptype1, ptype2, ptype3,
ptype4, ptype5);
}
......@@ -256,15 +265,13 @@ class TSymbolTable : angle::NonCopyable
// Used to insert unmangled functions to check redeclaration of built-ins in ESSL 3.00 and
// above.
void insertUnmangledBuiltInName(const char *name, ESymbolLevel level);
void insertUnmangledBuiltIn(const char *name, TExtension ext, ESymbolLevel level);
bool hasUnmangledBuiltInAtLevel(const char *name, ESymbolLevel level);
void initSamplerDefaultPrecision(TBasicType samplerType);
void initializeBuiltInFunctions(sh::GLenum type,
ShShaderSpec spec,
const ShBuiltInResources &resources);
void initializeBuiltInFunctions(sh::GLenum type);
void initializeBuiltInVariables(sh::GLenum type,
ShShaderSpec spec,
const ShBuiltInResources &resources);
......
......@@ -64,14 +64,18 @@
'<(angle_path)/src/tests/compiler_tests/ExpressionLimit_test.cpp',
'<(angle_path)/src/tests/compiler_tests/EXT_YUV_target_test.cpp',
'<(angle_path)/src/tests/compiler_tests/EXT_blend_func_extended_test.cpp',
'<(angle_path)/src/tests/compiler_tests/EXT_frag_depth_test.cpp',
'<(angle_path)/src/tests/compiler_tests/EXT_shader_texture_lod_test.cpp',
'<(angle_path)/src/tests/compiler_tests/ExtensionDirective_test.cpp',
'<(angle_path)/src/tests/compiler_tests/FloatLex_test.cpp',
'<(angle_path)/src/tests/compiler_tests/FragDepth_test.cpp',
'<(angle_path)/src/tests/compiler_tests/GLSLCompatibilityOutput_test.cpp',
'<(angle_path)/src/tests/compiler_tests/GlFragDataNotModified_test.cpp',
'<(angle_path)/src/tests/compiler_tests/GeometryShader_test.cpp',
'<(angle_path)/src/tests/compiler_tests/InitOutputVariables_test.cpp',
'<(angle_path)/src/tests/compiler_tests/IntermNode_test.cpp',
'<(angle_path)/src/tests/compiler_tests/NV_draw_buffers_test.cpp',
'<(angle_path)/src/tests/compiler_tests/OES_standard_derivatives_test.cpp',
'<(angle_path)/src/tests/compiler_tests/Pack_Unpack_test.cpp',
'<(angle_path)/src/tests/compiler_tests/PruneEmptyDeclarations_test.cpp',
'<(angle_path)/src/tests/compiler_tests/PrunePureLiteralStatements_test.cpp',
......@@ -85,7 +89,6 @@
'<(angle_path)/src/tests/compiler_tests/RewriteDoWhile_test.cpp',
'<(angle_path)/src/tests/compiler_tests/SamplerMultisample_test.cpp',
'<(angle_path)/src/tests/compiler_tests/ScalarizeVecAndMatConstructorArgs_test.cpp',
'<(angle_path)/src/tests/compiler_tests/ShaderExtension_test.cpp',
'<(angle_path)/src/tests/compiler_tests/ShaderImage_test.cpp',
'<(angle_path)/src/tests/compiler_tests/ShaderValidation_test.cpp',
'<(angle_path)/src/tests/compiler_tests/ShaderVariable_test.cpp',
......@@ -121,6 +124,7 @@
'<(angle_path)/src/tests/test_utils/ConstantFoldingTest.cpp',
'<(angle_path)/src/tests/test_utils/ShaderCompileTreeTest.h',
'<(angle_path)/src/tests/test_utils/ShaderCompileTreeTest.cpp',
'<(angle_path)/src/tests/test_utils/ShaderExtensionTest.h',
],
# TODO(jmadill): should probably call this windows sources
'angle_unittests_hlsl_sources':
......
......@@ -30,6 +30,46 @@ class ARBTextureRectangleTest : public ARBTextureRectangleTestNoExt
}
};
// Check that if the extension is not supported, trying to use the features without having an
// extension directive fails.
TEST_F(ARBTextureRectangleTestNoExt, NewTypeAndBuiltinsWithoutExtensionDirective)
{
const std::string &shaderString =
R"(
precision mediump float;
uniform sampler2DRect tex;
void main()
{
vec4 color = texture2DRect(tex, vec2(1.0));
color = texture2DRectProj(tex, vec3(1.0));
color = texture2DRectProj(tex, vec4(1.0));
})";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Check that if the extension is not supported, trying to use the features fails.
TEST_F(ARBTextureRectangleTestNoExt, NewTypeAndBuiltinsWithExtensionDirective)
{
const std::string &shaderString =
R"(
#extension GL_ARB_texture_rectangle : enable
precision mediump float;
uniform sampler2DRect tex;
void main()
{
vec4 color = texture2DRect(tex, vec2(1.0));
color = texture2DRectProj(tex, vec3(1.0));
color = texture2DRectProj(tex, vec4(1.0));
})";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Check that new types and builtins are usable even with the #extension directive
// Issue #15 of ARB_texture_rectangle explains that the extension was specified before the
// #extension mechanism was in place so it doesn't require explicit enabling.
......
......@@ -7,16 +7,12 @@
// Test for EXT_YUV_target implementation.
//
#include "angle_gl.h"
#include "gtest/gtest.h"
#include "GLSLANG/ShaderLang.h"
#include "tests/test_utils/ShaderExtensionTest.h"
using testing::Combine;
using testing::Values;
using EXTYUVTargetTest = sh::ShaderExtensionTest;
namespace
{
const char ESSLVersion300[] = "#version 300 es\n";
const char EXTYTPragma[] = "#extension GL_EXT_YUV_target : require\n";
const char ESSL300_SimpleShader[] =
......@@ -220,60 +216,29 @@ const char ESSL300_BuiltInFunctionsShader[] =
my_color = vec4(rgb, 1.0);
})";
class EXTYUVTargetTest : public testing::TestWithParam<testing::tuple<const char *, const char *>>
{
protected:
virtual void SetUp()
{
sh::InitBuiltInResources(&mResources);
mResources.EXT_YUV_target = 1;
const char ESSL300_OverloadRgb2Yuv[] =
R"(precision mediump float;
float rgb_2_yuv(float x) { return x + 1.0; }
mCompiler = nullptr;
}
in float i;
out float o;
virtual void TearDown() { DestroyCompiler(); }
void DestroyCompiler()
void main()
{
if (mCompiler)
{
sh::Destruct(mCompiler);
mCompiler = nullptr;
}
}
o = rgb_2_yuv(i);
})";
void InitializeCompiler()
{
DestroyCompiler();
mCompiler =
sh::ConstructCompiler(GL_FRAGMENT_SHADER, SH_GLES3_SPEC, SH_ESSL_OUTPUT, &mResources);
ASSERT_TRUE(mCompiler != nullptr) << "Compiler could not be constructed.";
}
const char ESSL300_OverloadYuv2Rgb[] =
R"(precision mediump float;
float yuv_2_rgb(float x) { return x + 1.0; }
testing::AssertionResult TestShaderCompile(const char *pragma)
{
return TestShaderCompile(testing::get<0>(GetParam()), // Version.
pragma,
testing::get<1>(GetParam()) // Shader.
);
}
in float i;
out float o;
testing::AssertionResult TestShaderCompile(const char *version,
const char *pragma,
const char *shader)
void main()
{
const char *shaderStrings[] = {version, pragma, shader};
bool success = sh::Compile(mCompiler, shaderStrings, 3, 0);
if (success)
{
return ::testing::AssertionSuccess() << "Compilation success";
}
return ::testing::AssertionFailure() << sh::GetInfoLog(mCompiler);
}
protected:
ShBuiltInResources mResources;
ShHandle mCompiler;
};
o = yuv_2_rgb(i);
})";
// Extension flag is required to compile properly. Expect failure when it is
// not present.
......@@ -307,7 +272,8 @@ TEST_P(EXTYUVTargetTest, CompileSucceedsWithExtensionAndPragma)
INSTANTIATE_TEST_CASE_P(CorrectVariantsWithExtensionAndPragma,
EXTYUVTargetTest,
Combine(Values(ESSLVersion300),
Combine(Values(SH_GLES3_SPEC),
Values(sh::ESSLVersion300),
Values(ESSL300_SimpleShader, ESSL300_FragColorShader)));
class EXTYUVTargetCompileSuccessTest : public EXTYUVTargetTest
......@@ -324,7 +290,8 @@ TEST_P(EXTYUVTargetCompileSuccessTest, CompileSucceeds)
INSTANTIATE_TEST_CASE_P(CorrectESSL300Shaders,
EXTYUVTargetCompileSuccessTest,
Combine(Values(ESSLVersion300),
Combine(Values(SH_GLES3_SPEC),
Values(sh::ESSLVersion300),
Values(ESSL300_FragColorShader,
ESSL300_YUVQualifierMultipleTimesShader,
ESSL300_YuvCscStandardEXTShader,
......@@ -344,7 +311,8 @@ TEST_P(EXTYUVTargetCompileFailureTest, CompileFails)
INSTANTIATE_TEST_CASE_P(IncorrectESSL300Shaders,
EXTYUVTargetCompileFailureTest,
Combine(Values(ESSLVersion300),
Combine(Values(SH_GLES3_SPEC),
Values(sh::ESSLVersion300),
Values(ESSL300_YUVQualifierFailureShader1,
ESSL300_YUVQualifierFailureShader2,
ESSL300_LocationAndYUVFailureShader,
......@@ -363,4 +331,23 @@ INSTANTIATE_TEST_CASE_P(IncorrectESSL300Shaders,
ESSL300_YuvCscStandartdEXTQualifiersFailureShader2,
ESSL300_YuvCscStandartdEXTQualifiersFailureShader3)));
class EXTYUVNotEnabledTest : public EXTYUVTargetTest
{
};
TEST_P(EXTYUVNotEnabledTest, CanOverloadConversions)
{
// Expect compile success with a shader that overloads functions in the EXT_YUV_target
// extension.
mResources.EXT_YUV_target = 0;
InitializeCompiler();
EXPECT_TRUE(TestShaderCompile(""));
}
INSTANTIATE_TEST_CASE_P(CoreESSL300Shaders,
EXTYUVNotEnabledTest,
Combine(Values(SH_GLES3_SPEC),
Values(sh::ESSLVersion300),
Values(ESSL300_OverloadRgb2Yuv, ESSL300_OverloadYuv2Rgb)));
} // namespace
......@@ -7,19 +7,10 @@
// Test for EXT_blend_func_extended_test
//
#include "angle_gl.h"
#include "gtest/gtest.h"
#include "GLSLANG/ShaderLang.h"
using testing::Combine;
using testing::Values;
using testing::make_tuple;
#include "tests/test_utils/ShaderExtensionTest.h"
namespace
{
const char ESSLVersion100[] = "#version 100\n";
const char ESSLVersion300[] = "#version 300 es\n";
const char ESSLVersion310[] = "#version 310 es\n";
const char EXTBFEPragma[] = "#extension GL_EXT_blend_func_extended : require\n";
const char ESSL100_SimpleShader1[] =
......@@ -118,62 +109,16 @@ const char ESSL310_LocationIndexFailureShader[] =
" secondaryFragColor = vec4(1.0);\n"
"}\n";
class EXTBlendFuncExtendedTest
: public testing::TestWithParam<testing::tuple<ShShaderSpec, const char *, const char *>>
class EXTBlendFuncExtendedTest : public sh::ShaderExtensionTest
{
protected:
virtual void SetUp()
void SetUp() override
{
sh::InitBuiltInResources(&mResources);
sh::ShaderExtensionTest::SetUp();
// EXT_draw_buffers is used in some of the shaders for test purposes.
mResources.EXT_draw_buffers = 1;
mResources.NV_draw_buffers = 2;
mCompiler = nullptr;
}
virtual void TearDown() { DestroyCompiler(); }
void DestroyCompiler()
{
if (mCompiler)
{
sh::Destruct(mCompiler);
mCompiler = nullptr;
}
}
void InitializeCompiler()
{
DestroyCompiler();
mCompiler = sh::ConstructCompiler(GL_FRAGMENT_SHADER, testing::get<0>(GetParam()),
SH_GLSL_COMPATIBILITY_OUTPUT, &mResources);
ASSERT_TRUE(mCompiler != nullptr) << "Compiler could not be constructed.";
}
testing::AssertionResult TestShaderCompile(const char *pragma)
{
return TestShaderCompile(testing::get<1>(GetParam()), // Version.
pragma,
testing::get<2>(GetParam()) // Shader.
);
}
testing::AssertionResult TestShaderCompile(const char *version,
const char *pragma,
const char *shader)
{
const char *shaderStrings[] = {version, pragma, shader};
bool success = sh::Compile(mCompiler, shaderStrings, 3, 0);
if (success)
{
return ::testing::AssertionSuccess() << "Compilation success";
}
return ::testing::AssertionFailure() << sh::GetInfoLog(mCompiler);
}
protected:
ShBuiltInResources mResources;
ShHandle mCompiler;
};
// Extension flag is required to compile properly. Expect failure when it is
......@@ -213,7 +158,7 @@ TEST_P(EXTBlendFuncExtendedTest, CompileSucceedsWithExtensionAndPragma)
INSTANTIATE_TEST_CASE_P(CorrectESSL100Shaders,
EXTBlendFuncExtendedTest,
Combine(Values(SH_GLES2_SPEC, SH_GLES3_SPEC),
Values("", ESSLVersion100),
Values("", sh::ESSLVersion100),
Values(ESSL100_SimpleShader1,
ESSL100_MaxDualSourceAccessShader,
ESSL100_FragDataShader)));
......@@ -221,7 +166,7 @@ INSTANTIATE_TEST_CASE_P(CorrectESSL100Shaders,
INSTANTIATE_TEST_CASE_P(CorrectESSL300Shaders,
EXTBlendFuncExtendedTest,
Combine(Values(SH_GLES3_SPEC),
Values(ESSLVersion300),
Values(sh::ESSLVersion300),
Values(ESSL300_MaxDualSourceAccessShader,
ESSL300_LocationAndUnspecifiedOutputShader,
ESSL300_TwoUnspecifiedLocationOutputsShader)));
......@@ -243,7 +188,7 @@ TEST_P(EXTBlendFuncExtendedCompileFailureTest, CompileFails)
INSTANTIATE_TEST_CASE_P(IncorrectESSL100Shaders,
EXTBlendFuncExtendedCompileFailureTest,
Combine(Values(SH_GLES2_SPEC),
Values(ESSLVersion100),
Values(sh::ESSLVersion100),
Values(ESSL100_ColorAndDataWriteFailureShader1,
ESSL100_ColorAndDataWriteFailureShader2,
ESSL100_ColorAndDataWriteFailureShader3)));
......@@ -252,7 +197,7 @@ INSTANTIATE_TEST_CASE_P(IncorrectESSL100Shaders,
INSTANTIATE_TEST_CASE_P(CorrectESSL300Shaders,
EXTBlendFuncExtendedCompileFailureTest,
Combine(Values(SH_GLES2_SPEC),
Values("", ESSLVersion100, ESSLVersion300),
Values("", sh::ESSLVersion100, sh::ESSLVersion300),
Values(ESSL300_LocationAndUnspecifiedOutputShader,
ESSL300_TwoUnspecifiedLocationOutputsShader)));
......@@ -260,26 +205,26 @@ INSTANTIATE_TEST_CASE_P(CorrectESSL300Shaders,
INSTANTIATE_TEST_CASE_P(CorrectESSL100Shaders,
EXTBlendFuncExtendedCompileFailureTest,
Combine(Values(SH_GLES3_SPEC),
Values(ESSLVersion300),
Values(sh::ESSLVersion300),
Values(ESSL100_SimpleShader1, ESSL100_FragDataShader)));
// Incorrect #version 310 es always fails.
INSTANTIATE_TEST_CASE_P(IncorrectESSL310Shaders,
EXTBlendFuncExtendedCompileFailureTest,
Combine(Values(SH_GLES3_SPEC),
Values(ESSLVersion300, ESSLVersion310),
Values(sh::ESSLVersion300, sh::ESSLVersion310),
Values(ESSL310_LocationIndexFailureShader)));
// Correct #version 310 es fails in #version 300 es.
INSTANTIATE_TEST_CASE_P(
CorrectESSL310ShadersInESSL300,
EXTBlendFuncExtendedCompileFailureTest,
Values(make_tuple(SH_GLES3_SPEC, &ESSLVersion300[0], &ESSL310_LocationIndexShader[0])));
Values(make_tuple(SH_GLES3_SPEC, &sh::ESSLVersion300[0], &ESSL310_LocationIndexShader[0])));
// Correct #version 310 es fails in #version 310 es, due to 3.1 not being supported.
INSTANTIATE_TEST_CASE_P(
CorrectESSL310Shaders,
EXTBlendFuncExtendedCompileFailureTest,
Values(make_tuple(SH_GLES3_SPEC, &ESSLVersion310[0], &ESSL310_LocationIndexShader[0])));
Values(make_tuple(SH_GLES3_SPEC, &sh::ESSLVersion310[0], &ESSL310_LocationIndexShader[0])));
} // namespace
//
// Copyright (c) 2018 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.
//
// EXT_frag_depth_test.cpp:
// Test for EXT_frag_depth
//
#include "tests/test_utils/ShaderExtensionTest.h"
using EXTFragDepthTest = sh::ShaderExtensionTest;
namespace
{
const char EXTPragma[] = "#extension GL_EXT_frag_depth : require\n";
// Shader setting gl_FragDepthEXT
const char ESSL100_FragDepthShader[] =
R"(
precision mediump float;
void main()
{
gl_FragDepthEXT = 1.0;
})";
// Extension flag is required to compile properly. Expect failure when it is
// not present.
TEST_P(EXTFragDepthTest, CompileFailsWithoutExtension)
{
mResources.EXT_frag_depth = 0;
InitializeCompiler();
EXPECT_FALSE(TestShaderCompile(EXTPragma));
}
// Extension directive is required to compile properly. Expect failure when
// it is not present.
TEST_P(EXTFragDepthTest, CompileFailsWithExtensionWithoutPragma)
{
mResources.EXT_frag_depth = 1;
InitializeCompiler();
EXPECT_FALSE(TestShaderCompile(""));
}
// With extension flag and extension directive, compiling succeeds.
// Also test that the extension directive state is reset correctly.
TEST_P(EXTFragDepthTest, CompileSucceedsWithExtensionAndPragma)
{
mResources.EXT_frag_depth = 1;
InitializeCompiler();
EXPECT_TRUE(TestShaderCompile(EXTPragma));
// Test reset functionality.
EXPECT_FALSE(TestShaderCompile(""));
EXPECT_TRUE(TestShaderCompile(EXTPragma));
}
// The SL #version 100 shaders that are correct work similarly
// in both GL2 and GL3, with and without the version string.
INSTANTIATE_TEST_CASE_P(CorrectESSL100Shaders,
EXTFragDepthTest,
Combine(Values(SH_GLES2_SPEC),
Values(sh::ESSLVersion100),
Values(ESSL100_FragDepthShader)));
} // anonymous namespace
//
// Copyright (c) 2018 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.
//
// EXT_shader_texture_lod_test.cpp:
// Test for EXT_shader_texture_lod
//
#include "tests/test_utils/ShaderExtensionTest.h"
using EXTShaderTextureLodTest = sh::ShaderExtensionTest;
namespace
{
const char EXTPragma[] = "#extension GL_EXT_shader_texture_lod : require\n";
// Shader calling texture2DLodEXT()
const char ESSL100_TextureLodShader[] =
R"(
precision mediump float;
varying vec2 texCoord0v;
uniform float lod;
uniform sampler2D tex;
void main()
{
vec4 color = texture2DLodEXT(tex, texCoord0v, lod);
})";
// Extension flag is required to compile properly. Expect failure when it is
// not present.
TEST_P(EXTShaderTextureLodTest, CompileFailsWithoutExtension)
{
mResources.EXT_shader_texture_lod = 0;
InitializeCompiler();
EXPECT_FALSE(TestShaderCompile(EXTPragma));
}
// Extension directive is required to compile properly. Expect failure when
// it is not present.
TEST_P(EXTShaderTextureLodTest, CompileFailsWithExtensionWithoutPragma)
{
mResources.EXT_shader_texture_lod = 1;
InitializeCompiler();
EXPECT_FALSE(TestShaderCompile(""));
}
// With extension flag and extension directive, compiling succeeds.
// Also test that the extension directive state is reset correctly.
TEST_P(EXTShaderTextureLodTest, CompileSucceedsWithExtensionAndPragma)
{
mResources.EXT_shader_texture_lod = 1;
InitializeCompiler();
EXPECT_TRUE(TestShaderCompile(EXTPragma));
// Test reset functionality.
EXPECT_FALSE(TestShaderCompile(""));
EXPECT_TRUE(TestShaderCompile(EXTPragma));
}
// The SL #version 100 shaders that are correct work similarly
// in both GL2 and GL3, with and without the version string.
INSTANTIATE_TEST_CASE_P(CorrectESSL100Shaders,
EXTShaderTextureLodTest,
Combine(Values(SH_GLES2_SPEC),
Values(sh::ESSLVersion100),
Values(ESSL100_TextureLodShader)));
} // anonymous namespace
//
// Copyright (c) 2018 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.
//
// GlFragDataNotModified_test.cpp:
// Test that the properties of built-in gl_FragData are not modified when a shader is compiled
// multiple times.
//
#include "tests/test_utils/ShaderCompileTreeTest.h"
namespace
{
class GlFragDataNotModifiedTest : public sh::ShaderCompileTreeTest
{
public:
GlFragDataNotModifiedTest() {}
protected:
void initResources(ShBuiltInResources *resources) override
{
resources->MaxDrawBuffers = 4;
resources->EXT_draw_buffers = 1;
}
::GLenum getShaderType() const override { return GL_FRAGMENT_SHADER; }
ShShaderSpec getShaderSpec() const override { return SH_GLES2_SPEC; }
};
// Test a bug where we could modify the value of a builtin variable.
TEST_F(GlFragDataNotModifiedTest, BuiltinRewritingBug)
{
const std::string &shaderString =
"#extension GL_EXT_draw_buffers : require\n"
"precision mediump float;\n"
"void main() {\n"
" gl_FragData[gl_MaxDrawBuffers] = vec4(0.0);\n"
"}";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure\n";
}
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure\n";
}
}
} // anonymous namespace
//
// Copyright (c) 2018 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.
//
// OES_standard_derivatives_test.cpp:
// Test for OES_standard_derivatives
//
#include "tests/test_utils/ShaderExtensionTest.h"
using OESStandardDerivativesTest = sh::ShaderExtensionTest;
namespace
{
const char OESPragma[] = "#extension GL_OES_standard_derivatives : require\n";
// Shader calling dFdx()
const char ESSL100_DfdxShader[] =
R"(
precision mediump float;
varying float x;
void main()
{
gl_FragColor = vec4(dFdx(x));
})";
// Shader calling dFdy()
const char ESSL100_DfdyShader[] =
R"(
precision mediump float;
varying float x;
void main()
{
gl_FragColor = vec4(dFdy(x));
})";
// Shader calling fwidth()
const char ESSL100_FwidthShader[] =
R"(
precision mediump float;
varying float x;
void main()
{
gl_FragColor = vec4(fwidth(x));
})";
// Extension flag is required to compile properly. Expect failure when it is
// not present.
TEST_P(OESStandardDerivativesTest, CompileFailsWithoutExtension)
{
mResources.OES_standard_derivatives = 0;
InitializeCompiler();
EXPECT_FALSE(TestShaderCompile(OESPragma));
}
// Extension directive is required to compile properly. Expect failure when
// it is not present.
TEST_P(OESStandardDerivativesTest, CompileFailsWithExtensionWithoutPragma)
{
mResources.OES_standard_derivatives = 1;
InitializeCompiler();
EXPECT_FALSE(TestShaderCompile(""));
}
// With extension flag and extension directive, compiling succeeds.
// Also test that the extension directive state is reset correctly.
TEST_P(OESStandardDerivativesTest, CompileSucceedsWithExtensionAndPragma)
{
mResources.OES_standard_derivatives = 1;
InitializeCompiler();
EXPECT_TRUE(TestShaderCompile(OESPragma));
// Test reset functionality.
EXPECT_FALSE(TestShaderCompile(""));
EXPECT_TRUE(TestShaderCompile(OESPragma));
}
// The SL #version 100 shaders that are correct work similarly
// in both GL2 and GL3, with and without the version string.
INSTANTIATE_TEST_CASE_P(
CorrectESSL100Shaders,
OESStandardDerivativesTest,
Combine(Values(SH_GLES2_SPEC),
Values(sh::ESSLVersion100),
Values(ESSL100_DfdxShader, ESSL100_DfdyShader, ESSL100_FwidthShader)));
} // anonymous namespace
//
// 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.
//
// Extension_test.cpp
// Test that shaders need various extensions to be compiled.
//
#include "angle_gl.h"
#include "gtest/gtest.h"
#include "GLSLANG/ShaderLang.h"
static const char *FragDepthExtShdr[] =
{
// First string of the shader. The required pragma declaration.
"#extension GL_EXT_frag_depth : enable\n",
// Second string of the shader. The rest of the shader body.
"void main() { gl_FragDepthEXT = 1.0; }\n"
};
static const char *StandDerivExtShdr[] =
{
// First string of the shader. The required pragma declaration.
"#extension GL_OES_standard_derivatives : enable\n",
// Second string of the shader. The rest of the shader body.
"precision mediump float;\n"
"varying vec2 texCoord;\n"
"void main() { gl_FragColor = vec4(dFdx(texCoord.x), dFdy(texCoord.y), fwidth(texCoord.x), 1.0); }\n"
};
static const char *TextureLODShdr[] =
{
// First string of the shader. The required pragma declaration.
"#extension GL_EXT_shader_texture_lod : enable\n",
// Second string of the shader. The rest of the shader body.
"precision mediump float;\n"
"varying vec2 texCoord0v;\n"
"uniform float lod;\n"
"uniform sampler2D tex;\n"
"void main() { vec4 color = texture2DLodEXT(tex, texCoord0v, lod); }\n"
};
class ShaderExtensionTest : public testing::Test
{
public:
ShaderExtensionTest() {}
protected:
virtual void SetUp()
{
sh::InitBuiltInResources(&mResources);
mCompiler = nullptr;
}
virtual void TearDown()
{
DestroyCompiler();
}
void DestroyCompiler()
{
if (mCompiler)
{
sh::Destruct(mCompiler);
mCompiler = nullptr;
}
}
void InitializeCompiler()
{
DestroyCompiler();
mCompiler = sh::ConstructCompiler(GL_FRAGMENT_SHADER, SH_WEBGL_SPEC,
SH_GLSL_COMPATIBILITY_OUTPUT, &mResources);
ASSERT_TRUE(mCompiler != nullptr) << "Compiler could not be constructed.";
}
void TestShaderExtension(const char **shaderStrings, int stringCount, bool expectation)
{
bool success = sh::Compile(mCompiler, shaderStrings, stringCount, 0);
const std::string &compileLog = sh::GetInfoLog(mCompiler);
EXPECT_EQ(expectation, success) << compileLog;
}
protected:
ShBuiltInResources mResources;
ShHandle mCompiler;
};
TEST_F(ShaderExtensionTest, FragDepthExtRequiresExt)
{
// Extension is required to compile properly.
mResources.EXT_frag_depth = 0;
InitializeCompiler();
TestShaderExtension(FragDepthExtShdr, 2, false);
}
TEST_F(ShaderExtensionTest, FragDepthExtRequiresPragma)
{
// Pragma is required to compile properly.
mResources.EXT_frag_depth = 1;
InitializeCompiler();
TestShaderExtension(&FragDepthExtShdr[1], 1, false);
}
TEST_F(ShaderExtensionTest, FragDepthExtCompiles)
{
// Test that it compiles properly with extension enabled.
mResources.EXT_frag_depth = 1;
InitializeCompiler();
TestShaderExtension(FragDepthExtShdr, 2, true);
}
TEST_F(ShaderExtensionTest, FragDepthExtResetsInternalStates)
{
// Test that extension internal states are reset properly between compiles.
mResources.EXT_frag_depth = 1;
InitializeCompiler();
TestShaderExtension(FragDepthExtShdr, 2, true);
TestShaderExtension(&FragDepthExtShdr[1], 1, false);
TestShaderExtension(FragDepthExtShdr, 2, true);
}
TEST_F(ShaderExtensionTest, StandDerivExtRequiresExt)
{
// Extension is required to compile properly.
mResources.OES_standard_derivatives = 0;
InitializeCompiler();
TestShaderExtension(StandDerivExtShdr, 2, false);
}
TEST_F(ShaderExtensionTest, StandDerivExtRequiresPragma)
{
// Pragma is required to compile properly.
mResources.OES_standard_derivatives = 1;
InitializeCompiler();
TestShaderExtension(&StandDerivExtShdr[1], 1, false);
}
TEST_F(ShaderExtensionTest, StandDerivExtCompiles)
{
// Test that it compiles properly with extension enabled.
mResources.OES_standard_derivatives = 1;
InitializeCompiler();
TestShaderExtension(StandDerivExtShdr, 2, true);
}
TEST_F(ShaderExtensionTest, StandDerivExtResetsInternalStates)
{
// Test that extension internal states are reset properly between compiles.
mResources.OES_standard_derivatives = 1;
InitializeCompiler();
TestShaderExtension(StandDerivExtShdr, 2, true);
TestShaderExtension(&StandDerivExtShdr[1], 1, false);
TestShaderExtension(StandDerivExtShdr, 2, true);
TestShaderExtension(&StandDerivExtShdr[1], 1, false);
}
TEST_F(ShaderExtensionTest, TextureLODExtRequiresExt)
{
// Extension is required to compile properly.
mResources.EXT_shader_texture_lod = 0;
InitializeCompiler();
TestShaderExtension(TextureLODShdr, 2, false);
}
TEST_F(ShaderExtensionTest, TextureLODExtRequiresPragma)
{
// Pragma is required to compile properly.
mResources.EXT_shader_texture_lod = 1;
InitializeCompiler();
TestShaderExtension(&TextureLODShdr[1], 1, false);
}
TEST_F(ShaderExtensionTest, TextureLODExtCompiles)
{
// Test that it compiles properly with extension enabled.
mResources.EXT_shader_texture_lod = 1;
InitializeCompiler();
TestShaderExtension(TextureLODShdr, 2, true);
}
TEST_F(ShaderExtensionTest, TextureLODExtResetsInternalStates)
{
// Test that extension internal states are reset properly between compiles.
mResources.EXT_shader_texture_lod = 1;
InitializeCompiler();
TestShaderExtension(&TextureLODShdr[1], 1, false);
TestShaderExtension(TextureLODShdr, 2, true);
TestShaderExtension(&TextureLODShdr[1], 1, false);
TestShaderExtension(TextureLODShdr, 2, true);
}
// Test a bug where we could modify the value of a builtin variable.
TEST_F(ShaderExtensionTest, BuiltinRewritingBug)
{
mResources.MaxDrawBuffers = 4;
mResources.EXT_draw_buffers = 1;
InitializeCompiler();
const std::string &shaderString =
"#extension GL_EXT_draw_buffers : require\n"
"precision mediump float;\n"
"void main() {\n"
" gl_FragData[gl_MaxDrawBuffers] = vec4(0.0);\n"
"}";
const char *shaderStrings[] = { shaderString.c_str() };
TestShaderExtension(shaderStrings, 1, false);
TestShaderExtension(shaderStrings, 1, false);
}
......@@ -5719,3 +5719,24 @@ TEST_F(FragmentShaderValidationTest, ConstantInitializerTypeMismatch)
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test that redeclaring a built-in is an error in ESSL 1.00. ESSL 1.00.17 section 4.2.6 disallows
// "redefinition" of built-ins - it's not very explicit about redeclaring them, but we treat this as
// an error. The redeclaration cannot serve any purpose since it can't be accompanied by a
// definition.
TEST_F(FragmentShaderValidationTest, RedeclaringBuiltIn)
{
const std::string &shaderString =
R"(
precision mediump float;
float sin(float x);
void main()
{
gl_FragColor = vec4(0.0);
})";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
//
// Copyright (c) 2018 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.
//
// ShaderExtensionTest.cpp:
// Utilities for testing that GLSL extension pragma and changing the extension flag in compiler
// resources has the correct effect.
//
#include "GLSLANG/ShaderLang.h"
#include "angle_gl.h"
#include "gtest/gtest.h"
using testing::Combine;
using testing::Values;
using testing::make_tuple;
namespace sh
{
const char ESSLVersion100[] = "#version 100\n";
const char ESSLVersion300[] = "#version 300 es\n";
const char ESSLVersion310[] = "#version 310 es\n";
class ShaderExtensionTest
: public testing::TestWithParam<testing::tuple<ShShaderSpec, const char *, const char *>>
{
protected:
void SetUp() override
{
sh::InitBuiltInResources(&mResources);
mCompiler = nullptr;
}
void TearDown() override { DestroyCompiler(); }
void DestroyCompiler()
{
if (mCompiler)
{
sh::Destruct(mCompiler);
mCompiler = nullptr;
}
}
void InitializeCompiler()
{
DestroyCompiler();
mCompiler = sh::ConstructCompiler(GL_FRAGMENT_SHADER, testing::get<0>(GetParam()),
SH_GLSL_COMPATIBILITY_OUTPUT, &mResources);
ASSERT_TRUE(mCompiler != nullptr) << "Compiler could not be constructed.";
}
testing::AssertionResult TestShaderCompile(const char *pragma)
{
return TestShaderCompile(testing::get<1>(GetParam()), // Version.
pragma,
testing::get<2>(GetParam()) // Shader.
);
}
testing::AssertionResult TestShaderCompile(const char *version,
const char *pragma,
const char *shader)
{
const char *shaderStrings[] = {version, pragma, shader};
bool success = sh::Compile(mCompiler, shaderStrings, 3, 0);
if (success)
{
return ::testing::AssertionSuccess() << "Compilation success";
}
return ::testing::AssertionFailure() << sh::GetInfoLog(mCompiler);
}
protected:
ShBuiltInResources mResources;
ShHandle mCompiler;
};
} // namespace sh
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