blob: 4ce945897fc0b06404effba77a58e7120aff649a [file] [log] [blame]
//
// 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.
//
// ShaderValidation_test.cpp:
// Tests that malformed shaders fail compilation, and that correct shaders pass compilation.
//
#include "angle_gl.h"
#include "gtest/gtest.h"
#include "GLSLANG/ShaderLang.h"
#include "tests/test_utils/ShaderCompileTreeTest.h"
using namespace sh;
// Tests that don't target a specific version of the API spec (sometimes there are minor
// differences). They choose the shader spec version with version directives.
class FragmentShaderValidationTest : public ShaderCompileTreeTest
{
public:
FragmentShaderValidationTest() {}
protected:
::GLenum getShaderType() const override { return GL_FRAGMENT_SHADER; }
ShShaderSpec getShaderSpec() const override { return SH_GLES3_1_SPEC; }
};
// Tests that don't target a specific version of the API spec (sometimes there are minor
// differences). They choose the shader spec version with version directives.
class VertexShaderValidationTest : public ShaderCompileTreeTest
{
public:
VertexShaderValidationTest() {}
protected:
::GLenum getShaderType() const override { return GL_VERTEX_SHADER; }
ShShaderSpec getShaderSpec() const override { return SH_GLES3_1_SPEC; }
};
class WebGL2FragmentShaderValidationTest : public ShaderCompileTreeTest
{
public:
WebGL2FragmentShaderValidationTest() {}
protected:
::GLenum getShaderType() const override { return GL_FRAGMENT_SHADER; }
ShShaderSpec getShaderSpec() const override { return SH_WEBGL2_SPEC; }
};
class WebGL1FragmentShaderValidationTest : public ShaderCompileTreeTest
{
public:
WebGL1FragmentShaderValidationTest() {}
protected:
::GLenum getShaderType() const override { return GL_FRAGMENT_SHADER; }
ShShaderSpec getShaderSpec() const override { return SH_WEBGL_SPEC; }
};
class ComputeShaderValidationTest : public ShaderCompileTreeTest
{
public:
ComputeShaderValidationTest() {}
private:
::GLenum getShaderType() const override { return GL_COMPUTE_SHADER; }
ShShaderSpec getShaderSpec() const override { return SH_GLES3_1_SPEC; }
};
// This is a test for a bug that used to exist in ANGLE:
// Calling a function with all parameters missing should not succeed.
TEST_F(FragmentShaderValidationTest, FunctionParameterMismatch)
{
const std::string &shaderString =
"precision mediump float;\n"
"float fun(float a) {\n"
" return a * 2.0;\n"
"}\n"
"void main() {\n"
" float ff = fun();\n"
" gl_FragColor = vec4(ff);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Functions can't be redeclared as variables in the same scope (ESSL 1.00 section 4.2.7)
TEST_F(FragmentShaderValidationTest, RedeclaringFunctionAsVariable)
{
const std::string &shaderString =
"precision mediump float;\n"
"float fun(float a) {\n"
" return a * 2.0;\n"
"}\n"
"float fun;\n"
"void main() {\n"
" gl_FragColor = vec4(0.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Functions can't be redeclared as structs in the same scope (ESSL 1.00 section 4.2.7)
TEST_F(FragmentShaderValidationTest, RedeclaringFunctionAsStruct)
{
const std::string &shaderString =
"precision mediump float;\n"
"float fun(float a) {\n"
" return a * 2.0;\n"
"}\n"
"struct fun { float a; };\n"
"void main() {\n"
" gl_FragColor = vec4(0.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Functions can't be redeclared with different qualifiers (ESSL 1.00 section 6.1.0)
TEST_F(FragmentShaderValidationTest, RedeclaringFunctionWithDifferentQualifiers)
{
const std::string &shaderString =
"precision mediump float;\n"
"float fun(out float a);\n"
"float fun(float a) {\n"
" return a * 2.0;\n"
"}\n"
"void main() {\n"
" gl_FragColor = vec4(0.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Assignment and equality are undefined for structures containing arrays (ESSL 1.00 section 5.7)
TEST_F(FragmentShaderValidationTest, CompareStructsContainingArrays)
{
const std::string &shaderString =
"precision mediump float;\n"
"struct s { float a[3]; };\n"
"void main() {\n"
" s a;\n"
" s b;\n"
" bool c = (a == b);\n"
" gl_FragColor = vec4(c ? 1.0 : 0.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Assignment and equality are undefined for structures containing arrays (ESSL 1.00 section 5.7)
TEST_F(FragmentShaderValidationTest, AssignStructsContainingArrays)
{
const std::string &shaderString =
"precision mediump float;\n"
"struct s { float a[3]; };\n"
"void main() {\n"
" s a;\n"
" s b;\n"
" b.a[0] = 0.0;\n"
" a = b;\n"
" gl_FragColor = vec4(a.a[0]);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Assignment and equality are undefined for structures containing samplers (ESSL 1.00 sections 5.7
// and 5.9)
TEST_F(FragmentShaderValidationTest, CompareStructsContainingSamplers)
{
const std::string &shaderString =
"precision mediump float;\n"
"struct s { sampler2D foo; };\n"
"uniform s a;\n"
"uniform s b;\n"
"void main() {\n"
" bool c = (a == b);\n"
" gl_FragColor = vec4(c ? 1.0 : 0.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Samplers are not allowed as l-values (ESSL 3.00 section 4.1.7), our interpretation is that this
// extends to structs containing samplers. ESSL 1.00 spec is clearer about this.
TEST_F(FragmentShaderValidationTest, AssignStructsContainingSamplers)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"struct s { sampler2D foo; };\n"
"uniform s a;\n"
"out vec4 my_FragColor;\n"
"void main() {\n"
" s b;\n"
" b = a;\n"
" my_FragColor = vec4(1.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// This is a regression test for a particular bug that was in ANGLE.
// It also verifies that ESSL3 functionality doesn't leak to ESSL1.
TEST_F(FragmentShaderValidationTest, ArrayWithNoSizeInInitializerList)
{
const std::string &shaderString =
"precision mediump float;\n"
"void main() {\n"
" float a[2], b[];\n"
" gl_FragColor = vec4(1.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Const variables need an initializer.
TEST_F(FragmentShaderValidationTest, ConstVarNotInitialized)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 my_FragColor;\n"
"void main() {\n"
" const float a;\n"
" my_FragColor = vec4(1.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Const variables need an initializer. In ESSL1 const structs containing
// arrays are not allowed at all since it's impossible to initialize them.
// Even though this test is for ESSL3 the only thing that's critical for
// ESSL1 is the non-initialization check that's used for both language versions.
// Whether ESSL1 compilation generates the most helpful error messages is a
// secondary concern.
TEST_F(FragmentShaderValidationTest, ConstStructNotInitialized)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"struct S {\n"
" float a[3];\n"
"};\n"
"out vec4 my_FragColor;\n"
"void main() {\n"
" const S b;\n"
" my_FragColor = vec4(1.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Const variables need an initializer. In ESSL1 const arrays are not allowed
// at all since it's impossible to initialize them.
// Even though this test is for ESSL3 the only thing that's critical for
// ESSL1 is the non-initialization check that's used for both language versions.
// Whether ESSL1 compilation generates the most helpful error messages is a
// secondary concern.
TEST_F(FragmentShaderValidationTest, ConstArrayNotInitialized)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 my_FragColor;\n"
"void main() {\n"
" const float a[3];\n"
" my_FragColor = vec4(1.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Block layout qualifiers can't be used on non-block uniforms (ESSL 3.00 section 4.3.8.3)
TEST_F(FragmentShaderValidationTest, BlockLayoutQualifierOnRegularUniform)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"layout(packed) uniform mat2 x;\n"
"out vec4 my_FragColor;\n"
"void main() {\n"
" my_FragColor = vec4(1.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Block layout qualifiers can't be used on non-block uniforms (ESSL 3.00 section 4.3.8.3)
TEST_F(FragmentShaderValidationTest, BlockLayoutQualifierOnUniformWithEmptyDecl)
{
// Yes, the comma in the declaration below is not a typo.
// Empty declarations are allowed in GLSL.
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"layout(packed) uniform mat2, x;\n"
"out vec4 my_FragColor;\n"
"void main() {\n"
" my_FragColor = vec4(1.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Arrays of arrays are not allowed (ESSL 3.00 section 4.1.9)
TEST_F(FragmentShaderValidationTest, ArraysOfArrays1)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 my_FragColor;\n"
"void main() {\n"
" float[5] a[3];\n"
" my_FragColor = vec4(1.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Arrays of arrays are not allowed (ESSL 3.00 section 4.1.9)
TEST_F(FragmentShaderValidationTest, ArraysOfArrays2)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 my_FragColor;\n"
"void main() {\n"
" float[2] a, b[3];\n"
" my_FragColor = vec4(1.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Implicitly sized arrays need to be initialized (ESSL 3.00 section 4.1.9)
TEST_F(FragmentShaderValidationTest, UninitializedImplicitArraySize)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 my_FragColor;\n"
"void main() {\n"
" float[] a;\n"
" my_FragColor = vec4(1.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// An operator can only form a constant expression if all the operands are constant expressions
// - even operands of ternary operator that are never evaluated. (ESSL 3.00 section 4.3.3)
TEST_F(FragmentShaderValidationTest, TernaryOperatorNotConstantExpression)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 my_FragColor;\n"
"uniform bool u;\n"
"void main() {\n"
" const bool a = true ? true : u;\n"
" my_FragColor = vec4(1.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Ternary operator can't operate on arrays (ESSL 3.00 section 5.7)
TEST_F(FragmentShaderValidationTest, TernaryOperatorOnArrays)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 my_FragColor;\n"
"void main() {\n"
" float[1] a = float[1](0.0);\n"
" float[1] b = float[1](1.0);\n"
" float[1] c = true ? a : b;\n"
" my_FragColor = vec4(1.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Ternary operator can't operate on structs (ESSL 3.00 section 5.7)
TEST_F(FragmentShaderValidationTest, TernaryOperatorOnStructs)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 my_FragColor;\n"
"struct S { float foo; };\n"
"void main() {\n"
" S a = S(0.0);\n"
" S b = S(1.0);\n"
" S c = true ? a : b;\n"
" my_FragColor = vec4(1.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Array length() returns a constant signed integral expression (ESSL 3.00 section 4.1.9)
// Assigning it to unsigned should result in an error.
TEST_F(FragmentShaderValidationTest, AssignArrayLengthToUnsigned)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 my_FragColor;\n"
"void main() {\n"
" int[1] arr;\n"
" uint l = arr.length();\n"
" my_FragColor = vec4(float(l));\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Global variable initializers need to be constant expressions (ESSL 1.00 section 4.3)
// Initializing with a varying should be an error.
TEST_F(FragmentShaderValidationTest, AssignVaryingToGlobal)
{
const std::string &shaderString =
"precision mediump float;\n"
"varying float a;\n"
"float b = a * 2.0;\n"
"void main() {\n"
" gl_FragColor = vec4(b);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Global variable initializers need to be constant expressions (ESSL 3.00 section 4.3)
// Initializing with an uniform should be an error.
TEST_F(FragmentShaderValidationTest, AssignUniformToGlobalESSL3)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"uniform float a;\n"
"float b = a * 2.0;\n"
"out vec4 my_FragColor;\n"
"void main() {\n"
" my_FragColor = vec4(b);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Global variable initializers need to be constant expressions (ESSL 1.00 section 4.3)
// Initializing with an uniform should generate a warning
// (we don't generate an error on ESSL 1.00 because of legacy compatibility)
TEST_F(FragmentShaderValidationTest, AssignUniformToGlobalESSL1)
{
const std::string &shaderString =
"precision mediump float;\n"
"uniform float a;\n"
"float b = a * 2.0;\n"
"void main() {\n"
" gl_FragColor = vec4(b);\n"
"}\n";
if (compile(shaderString))
{
if (!hasWarning())
{
FAIL() << "Shader compilation succeeded without warnings, expecting warning:\n"
<< mInfoLog;
}
}
else
{
FAIL() << "Shader compilation failed, expecting success with warning:\n" << mInfoLog;
}
}
// Global variable initializers need to be constant expressions (ESSL 1.00 section 4.3)
// Initializing with an user-defined function call should be an error.
TEST_F(FragmentShaderValidationTest, AssignFunctionCallToGlobal)
{
const std::string &shaderString =
"precision mediump float;\n"
"float foo() { return 1.0; }\n"
"float b = foo();\n"
"void main() {\n"
" gl_FragColor = vec4(b);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Global variable initializers need to be constant expressions (ESSL 1.00 section 4.3)
// Initializing with an assignment to another global should be an error.
TEST_F(FragmentShaderValidationTest, AssignAssignmentToGlobal)
{
const std::string &shaderString =
"precision mediump float;\n"
"float c = 1.0;\n"
"float b = (c = 0.0);\n"
"void main() {\n"
" gl_FragColor = vec4(b);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Global variable initializers need to be constant expressions (ESSL 1.00 section 4.3)
// Initializing with incrementing another global should be an error.
TEST_F(FragmentShaderValidationTest, AssignIncrementToGlobal)
{
const std::string &shaderString =
"precision mediump float;\n"
"float c = 1.0;\n"
"float b = (c++);\n"
"void main() {\n"
" gl_FragColor = vec4(b);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Global variable initializers need to be constant expressions (ESSL 1.00 section 4.3)
// Initializing with a texture lookup function call should be an error.
TEST_F(FragmentShaderValidationTest, AssignTexture2DToGlobal)
{
const std::string &shaderString =
"precision mediump float;\n"
"uniform mediump sampler2D s;\n"
"float b = texture2D(s, vec2(0.5, 0.5)).x;\n"
"void main() {\n"
" gl_FragColor = vec4(b);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Global variable initializers need to be constant expressions (ESSL 3.00 section 4.3)
// Initializing with a non-constant global should be an error.
TEST_F(FragmentShaderValidationTest, AssignNonConstGlobalToGlobal)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"float a = 1.0;\n"
"float b = a * 2.0;\n"
"out vec4 my_FragColor;\n"
"void main() {\n"
" my_FragColor = vec4(b);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Global variable initializers need to be constant expressions (ESSL 3.00 section 4.3)
// Initializing with a constant global should be fine.
TEST_F(FragmentShaderValidationTest, AssignConstGlobalToGlobal)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"const float a = 1.0;\n"
"float b = a * 2.0;\n"
"out vec4 my_FragColor;\n"
"void main() {\n"
" my_FragColor = vec4(b);\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Statically assigning to both gl_FragData and gl_FragColor is forbidden (ESSL 1.00 section 7.2)
TEST_F(FragmentShaderValidationTest, WriteBothFragDataAndFragColor)
{
const std::string &shaderString =
"precision mediump float;\n"
"void foo() {\n"
" gl_FragData[0].a++;\n"
"}\n"
"void main() {\n"
" gl_FragColor.x += 0.0;\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Version directive must be on the first line (ESSL 3.00 section 3.3)
TEST_F(FragmentShaderValidationTest, VersionOnSecondLine)
{
const std::string &shaderString =
"\n"
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 my_FragColor;\n"
"void main() {\n"
" my_FragColor = vec4(0.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Layout qualifier can only appear in global scope (ESSL 3.00 section 4.3.8)
TEST_F(FragmentShaderValidationTest, LayoutQualifierInCondition)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"uniform vec4 u;\n"
"out vec4 my_FragColor;\n"
"void main() {\n"
" int i = 0;\n"
" for (int j = 0; layout(location = 0) bool b = false; ++j) {\n"
" ++i;\n"
" }\n"
" my_FragColor = u;\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Layout qualifier can only appear where specified (ESSL 3.00 section 4.3.8)
TEST_F(FragmentShaderValidationTest, LayoutQualifierInFunctionReturnType)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"uniform vec4 u;\n"
"out vec4 my_FragColor;\n"
"layout(location = 0) vec4 foo() {\n"
" return u;\n"
"}\n"
"void main() {\n"
" my_FragColor = foo();\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// If there is more than one output, the location must be specified for all outputs.
// (ESSL 3.00.04 section 4.3.8.2)
TEST_F(FragmentShaderValidationTest, TwoOutputsNoLayoutQualifiers)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"uniform vec4 u;\n"
"out vec4 my_FragColor;\n"
"out vec4 my_SecondaryFragColor;\n"
"void main() {\n"
" my_FragColor = vec4(1.0);\n"
" my_SecondaryFragColor = vec4(0.5);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// (ESSL 3.00.04 section 4.3.8.2)
TEST_F(FragmentShaderValidationTest, TwoOutputsFirstLayoutQualifier)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"uniform vec4 u;\n"
"layout(location = 0) out vec4 my_FragColor;\n"
"out vec4 my_SecondaryFragColor;\n"
"void main() {\n"
" my_FragColor = vec4(1.0);\n"
" my_SecondaryFragColor = vec4(0.5);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// (ESSL 3.00.04 section 4.3.8.2)
TEST_F(FragmentShaderValidationTest, TwoOutputsSecondLayoutQualifier)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"uniform vec4 u;\n"
"out vec4 my_FragColor;\n"
"layout(location = 0) out vec4 my_SecondaryFragColor;\n"
"void main() {\n"
" my_FragColor = vec4(1.0);\n"
" my_SecondaryFragColor = vec4(0.5);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Uniforms can be arrays (ESSL 3.00 section 4.3.5)
TEST_F(FragmentShaderValidationTest, UniformArray)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"uniform vec4[2] u;\n"
"out vec4 my_FragColor;\n"
"void main() {\n"
" my_FragColor = u[0];\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Fragment shader input variables cannot be arrays of structs (ESSL 3.00 section 4.3.4)
TEST_F(FragmentShaderValidationTest, FragmentInputArrayOfStructs)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"struct S {\n"
" vec4 foo;\n"
"};\n"
"in S i[2];\n"
"out vec4 my_FragColor;\n"
"void main() {\n"
" my_FragColor = i[0].foo;\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Vertex shader inputs can't be arrays (ESSL 3.00 section 4.3.4)
// This test is testing the case where the array brackets are after the variable name, so
// the arrayness isn't known when the type and qualifiers are initially parsed.
TEST_F(VertexShaderValidationTest, VertexShaderInputArray)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"in vec4 i[2];\n"
"void main() {\n"
" gl_Position = i[0];\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Vertex shader inputs can't be arrays (ESSL 3.00 section 4.3.4)
// This test is testing the case where the array brackets are after the type.
TEST_F(VertexShaderValidationTest, VertexShaderInputArrayType)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"in vec4[2] i;\n"
"void main() {\n"
" gl_Position = i[0];\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Fragment shader inputs can't contain booleans (ESSL 3.00 section 4.3.4)
TEST_F(FragmentShaderValidationTest, FragmentShaderInputStructWithBool)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"struct S {\n"
" bool foo;\n"
"};\n"
"in S s;\n"
"out vec4 my_FragColor;\n"
"void main() {\n"
" my_FragColor = vec4(0.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Fragment shader inputs without a flat qualifier can't contain integers (ESSL 3.00 section 4.3.4)
TEST_F(FragmentShaderValidationTest, FragmentShaderInputStructWithInt)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"struct S {\n"
" int foo;\n"
"};\n"
"in S s;\n"
"out vec4 my_FragColor;\n"
"void main() {\n"
" my_FragColor = vec4(0.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Selecting a field of a vector that's the result of dynamic indexing a constant array should work.
TEST_F(FragmentShaderValidationTest, ShaderSelectingFieldOfVectorIndexedFromArray)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 my_FragColor;\n"
"uniform int i;\n"
"void main() {\n"
" float f = vec2[1](vec2(0.0, 0.1))[i].x;\n"
" my_FragColor = vec4(f);\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Passing an array into a function and then passing a value from that array into another function
// should work. This is a regression test for a bug where the mangled name of a TType was not
// properly updated when determining the type resulting from array indexing.
TEST_F(FragmentShaderValidationTest, ArrayValueFromFunctionParameterAsParameter)
{
const std::string &shaderString =
"precision mediump float;\n"
"uniform float u;\n"
"float foo(float f) {\n"
" return f * 2.0;\n"
"}\n"
"float bar(float[2] f) {\n"
" return foo(f[0]);\n"
"}\n"
"void main()\n"
"{\n"
" float arr[2];\n"
" arr[0] = u;\n"
" gl_FragColor = vec4(bar(arr));\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Test that out-of-range integer literal generates an error in ESSL 3.00.
TEST_F(FragmentShaderValidationTest, OutOfRangeIntegerLiteral)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"precision highp int;\n"
"out vec4 my_FragColor;\n"
"void main() {\n"
" my_FragColor = vec4(0x100000000);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test that vector field selection from a value taken from an array constructor is accepted as a
// constant expression.
TEST_F(FragmentShaderValidationTest, FieldSelectionFromVectorArrayConstructorIsConst)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 my_FragColor;\n"
"void main()\n"
"{\n"
" const float f = vec2[1](vec2(0.0, 1.0))[0].x;\n"
" my_FragColor = vec4(f);\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Test that structure field selection from a value taken from an array constructor is accepted as a
// constant expression.
TEST_F(FragmentShaderValidationTest, FieldSelectionFromStructArrayConstructorIsConst)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 my_FragColor;\n"
"struct S { float member; };\n"
"void main()\n"
"{\n"
" const float f = S[1](S(0.0))[0].member;\n"
" my_FragColor = vec4(f);\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Test that a reference to a const array is accepted as a constant expression.
TEST_F(FragmentShaderValidationTest, ArraySymbolIsConst)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 my_FragColor;\n"
"void main()\n"
"{\n"
" const float[2] arr = float[2](0.0, 1.0);\n"
" const float f = arr[0];\n"
" my_FragColor = vec4(f);\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Test that using an array constructor in a parameter to a built-in function is accepted as a
// constant expression.
TEST_F(FragmentShaderValidationTest, BuiltInFunctionAppliedToArrayConstructorIsConst)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 my_FragColor;\n"
"void main()\n"
"{\n"
" const float f = sin(float[2](0.0, 1.0)[0]);\n"
" my_FragColor = vec4(f);\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Test that using an array constructor in a parameter to a built-in function is accepted as a
// constant expression.
TEST_F(FragmentShaderValidationTest,
BuiltInFunctionWithMultipleParametersAppliedToArrayConstructorIsConst)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 my_FragColor;\n"
"void main()\n"
"{\n"
" const float f = pow(1.0, float[2](0.0, 1.0)[0]);\n"
" my_FragColor = vec4(f);\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Test that using an array constructor in a parameter to a constructor is accepted as a constant
// expression.
TEST_F(FragmentShaderValidationTest,
ConstructorWithMultipleParametersAppliedToArrayConstructorIsConst)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 my_FragColor;\n"
"void main()\n"
"{\n"
" const vec2 f = vec2(1.0, float[2](0.0, 1.0)[0]);\n"
" my_FragColor = vec4(f.x);\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Test that using an array constructor in an operand of the ternary selection operator is accepted
// as a constant expression.
TEST_F(FragmentShaderValidationTest, TernaryOperatorAppliedToArrayConstructorIsConst)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 my_FragColor;\n"
"void main()\n"
"{\n"
" const float f = true ? float[2](0.0, 1.0)[0] : 1.0;\n"
" my_FragColor = vec4(f);\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Test that a ternary operator with one unevaluated non-constant operand is not a constant
// expression.
TEST_F(FragmentShaderValidationTest, TernaryOperatorNonConstantOperand)
{
const std::string &shaderString =
"precision mediump float;\n"
"uniform float u;\n"
"void main()\n"
"{\n"
" const float f = true ? 1.0 : u;\n"
" gl_FragColor = vec4(f);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test that a sampler can't be used in constructor argument list
TEST_F(FragmentShaderValidationTest, SamplerInConstructorArguments)
{
const std::string &shaderString =
"precision mediump float;\n"
"uniform sampler2D s;\n"
"void main()\n"
"{\n"
" vec2 v = vec2(0.0, s);\n"
" gl_FragColor = vec4(v, 0.0, 0.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test that void can't be used in constructor argument list
TEST_F(FragmentShaderValidationTest, VoidInConstructorArguments)
{
const std::string &shaderString =
"precision mediump float;\n"
"void foo() {}\n"
"void main()\n"
"{\n"
" vec2 v = vec2(0.0, foo());\n"
" gl_FragColor = vec4(v, 0.0, 0.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test that a shader passing a struct into a constructor of array of structs with 1 element works.
TEST_F(FragmentShaderValidationTest, SingleStructArrayConstructor)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 my_FragColor;\n"
"uniform float u;\n"
"struct S { float member; };\n"
"void main()\n"
"{\n"
" S[1] sarr = S[1](S(u));\n"
" my_FragColor = vec4(sarr[0].member);\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Test that a shader with empty constructor parameter list is not accepted.
TEST_F(FragmentShaderValidationTest, EmptyArrayConstructor)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 my_FragColor;\n"
"uniform float u;\n"
"const float[] f = f[]();\n"
"void main()\n"
"{\n"
" my_FragColor = vec4(0.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test that indexing fragment outputs with a non-constant expression is forbidden, even if ANGLE
// is able to constant fold the index expression. ESSL 3.00 section 4.3.6.
TEST_F(FragmentShaderValidationTest, DynamicallyIndexedFragmentOutput)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"uniform int a;\n"
"out vec4[2] my_FragData;\n"
"void main()\n"
"{\n"
" my_FragData[true ? 0 : a] = vec4(0.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test that indexing an interface block array with a non-constant expression is forbidden, even if
// ANGLE is able to constant fold the index expression. ESSL 3.00 section 4.3.7.
TEST_F(FragmentShaderValidationTest, DynamicallyIndexedInterfaceBlock)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"uniform int a;\n"
"uniform B\n"
"{\n"
" vec4 f;\n"
"}\n"
"blocks[2];\n"
"out vec4 my_FragColor;\n"
"void main()\n"
"{\n"
" my_FragColor = blocks[true ? 0 : a].f;\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test that a shader that uses a struct definition in place of a struct constructor does not
// compile. See GLSL ES 1.00 section 5.4.3.
TEST_F(FragmentShaderValidationTest, StructConstructorWithStructDefinition)
{
const std::string &shaderString =
"precision mediump float;\n"
"void main()\n"
"{\n"
" struct s { float f; } (0.0);\n"
" gl_FragColor = vec4(0.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test that indexing gl_FragData with a non-constant expression is forbidden in WebGL 2.0, even
// when ANGLE is able to constant fold the index.
// WebGL 2.0 spec section 'GLSL ES 1.00 Fragment Shader Output'
TEST_F(WebGL2FragmentShaderValidationTest, IndexFragDataWithNonConstant)
{
const std::string &shaderString =
"precision mediump float;\n"
"void main()\n"
"{\n"
" for (int i = 0; i < 2; ++i) {\n"
" gl_FragData[true ? 0 : i] = vec4(0.0);\n"
" }\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test that a non-constant texture offset is not accepted for textureOffset.
// ESSL 3.00 section 8.8
TEST_F(FragmentShaderValidationTest, TextureOffsetNonConst)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 my_FragColor;\n"
"uniform vec3 u_texCoord;\n"
"uniform mediump sampler3D u_sampler;\n"
"uniform int x;\n"
"void main()\n"
"{\n"
" my_FragColor = textureOffset(u_sampler, u_texCoord, ivec3(x, 3, -8));\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test that a non-constant texture offset is not accepted for textureProjOffset with bias.
// ESSL 3.00 section 8.8
TEST_F(FragmentShaderValidationTest, TextureProjOffsetNonConst)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 my_FragColor;\n"
"uniform vec4 u_texCoord;\n"
"uniform mediump sampler3D u_sampler;\n"
"uniform int x;\n"
"void main()\n"
"{\n"
" my_FragColor = textureProjOffset(u_sampler, u_texCoord, ivec3(x, 3, -8), 0.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test that an out-of-range texture offset is not accepted.
// GLES 3.0.4 section 3.8.10 specifies that out-of-range offset has undefined behavior.
TEST_F(FragmentShaderValidationTest, TextureLodOffsetOutOfRange)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 my_FragColor;\n"
"uniform vec3 u_texCoord;\n"
"uniform mediump sampler3D u_sampler;\n"
"void main()\n"
"{\n"
" my_FragColor = textureLodOffset(u_sampler, u_texCoord, 0.0, ivec3(0, 0, 8));\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test that default precision qualifier for uint is not accepted.
// ESSL 3.00.4 section 4.5.4: Only allowed for float, int and sampler types.
TEST_F(FragmentShaderValidationTest, DefaultPrecisionUint)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"precision mediump uint;\n"
"out vec4 my_FragColor;\n"
"void main()\n"
"{\n"
" my_FragColor = vec4(0.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test that sampler3D needs to be precision qualified.
// ESSL 3.00.4 section 4.5.4: New ESSL 3.00 sampler types don't have predefined precision.
TEST_F(FragmentShaderValidationTest, NoPrecisionSampler3D)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"uniform sampler3D s;\n"
"out vec4 my_FragColor;\n"
"void main()\n"
"{\n"
" my_FragColor = vec4(0.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test that using a non-constant expression in a for loop initializer is forbidden in WebGL 1.0,
// even when ANGLE is able to constant fold the initializer.
// ESSL 1.00 Appendix A.
TEST_F(WebGL1FragmentShaderValidationTest, NonConstantLoopIndex)
{
const std::string &shaderString =
"precision mediump float;\n"
"uniform int u;\n"
"void main()\n"
"{\n"
" for (int i = (true ? 1 : u); i < 5; ++i) {\n"
" gl_FragColor = vec4(0.0);\n"
" }\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Check that indices that are not integers are rejected.
// The check should be done even if ESSL 1.00 Appendix A limitations are not applied.
TEST_F(FragmentShaderValidationTest, NonIntegerIndex)
{
const std::string &shaderString =
"precision mediump float;\n"
"void main()\n"
"{\n"
" float f[3];\n"
" const float i = 2.0;\n"
" gl_FragColor = vec4(f[i]);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// ESSL1 shaders with a duplicate function prototype should be rejected.
// ESSL 1.00.17 section 4.2.7.
TEST_F(FragmentShaderValidationTest, DuplicatePrototypeESSL1)
{
const std::string &shaderString =
"precision mediump float;\n"
"void foo();\n"
"void foo();\n"
"void foo() {}\n"
"void main()\n"
"{\n"
" gl_FragColor = vec4(0.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// ESSL3 shaders with a duplicate function prototype should be allowed.
// ESSL 3.00.4 section 4.2.3.
TEST_F(FragmentShaderValidationTest, DuplicatePrototypeESSL3)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 my_FragColor;\n"
"void foo();\n"
"void foo();\n"
"void foo() {}\n"
"void main()\n"
"{\n"
" my_FragColor = vec4(0.0);\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Shaders with a local function prototype should be rejected.
// ESSL 3.00.4 section 4.2.4.
TEST_F(FragmentShaderValidationTest, LocalFunctionPrototype)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 my_FragColor;\n"
"void main()\n"
"{\n"
" void foo();\n"
" my_FragColor = vec4(0.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// ESSL 3.00 fragment shaders can not use #pragma STDGL invariant(all).
// ESSL 3.00.4 section 4.6.1. Does not apply to other versions of ESSL.
TEST_F(FragmentShaderValidationTest, ESSL300FragmentInvariantAll)
{
const std::string &shaderString =
"#version 300 es\n"
"#pragma STDGL invariant(all)\n"
"precision mediump float;\n"
"out vec4 my_FragColor;\n"
"void main()\n"
"{\n"
" my_FragColor = vec4(0.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Built-in functions can be overloaded in ESSL 1.00.
TEST_F(FragmentShaderValidationTest, ESSL100BuiltInFunctionOverload)
{
const std::string &shaderString =
"precision mediump float;\n"
"int sin(int x)\n"
"{\n"
" return int(sin(float(x)));\n"
"}\n"
"void main()\n"
"{\n"
" gl_FragColor = vec4(sin(1));"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Built-in functions can not be overloaded in ESSL 3.00.
TEST_F(FragmentShaderValidationTest, ESSL300BuiltInFunctionOverload)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 my_FragColor;\n"
"int sin(int x)\n"
"{\n"
" return int(sin(float(x)));\n"
"}\n"
"void main()\n"
"{\n"
" my_FragColor = vec4(sin(1));"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Multiplying a 4x2 matrix with a 4x2 matrix should not work.
TEST_F(FragmentShaderValidationTest, CompoundMultiplyMatrixIdenticalNonSquareDimensions)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 my_FragColor;\n"
"void main()\n"
"{\n"
" mat4x2 foo;\n"
" foo *= mat4x2(4.0);\n"
" my_FragColor = vec4(0.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Multiplying a matrix with 2 columns and 4 rows with a 2x2 matrix should work.
TEST_F(FragmentShaderValidationTest, CompoundMultiplyMatrixValidNonSquareDimensions)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 my_FragColor;\n"
"void main()\n"
"{\n"
" mat2x4 foo;\n"
" foo *= mat2x2(4.0);\n"
" my_FragColor = vec4(0.0);\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Covers a bug where we would set the incorrect result size on an out-of-bounds vector swizzle.
TEST_F(FragmentShaderValidationTest, OutOfBoundsVectorSwizzle)
{
const std::string &shaderString =
"void main() {\n"
" vec2(0).qq;\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Covers a bug where strange preprocessor defines could trigger asserts.
TEST_F(FragmentShaderValidationTest, DefineWithSemicolon)
{
const std::string &shaderString =
"#define Def; highp\n"
"uniform Def vec2 a;\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Covers a bug in our parsing of malformed shift preprocessor expressions.
TEST_F(FragmentShaderValidationTest, LineDirectiveUndefinedShift)
{
const std::string &shaderString = "#line x << y";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Covers a bug in our parsing of malformed shift preprocessor expressions.
TEST_F(FragmentShaderValidationTest, LineDirectiveNegativeShift)
{
const std::string &shaderString = "#line x << -1";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// gl_MaxImageUnits is only available in ES 3.1 shaders.
TEST_F(FragmentShaderValidationTest, MaxImageUnitsInES3Shader)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 myOutput;"
"void main() {\n"
" float ff = float(gl_MaxImageUnits);\n"
" myOutput = vec4(ff);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// struct += struct is an invalid operation.
TEST_F(FragmentShaderValidationTest, StructCompoundAssignStruct)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 myOutput;\n"
"struct S { float foo; };\n"
"void main() {\n"
" S a, b;\n"
" a += b;\n"
" myOutput = vec4(0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// struct == different struct is an invalid operation.
TEST_F(FragmentShaderValidationTest, StructEqDifferentStruct)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 myOutput;\n"
"struct S { float foo; };\n"
"struct S2 { float foobar; };\n"
"void main() {\n"
" S a;\n"
" S2 b;\n"
" a == b;\n"
" myOutput = vec4(0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Compute shaders are not supported in versions lower than 310.
TEST_F(ComputeShaderValidationTest, Version100)
{
const std::string &shaderString =
"void main()\n"
"layout(local_size_x=1) in;\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Compute shaders are not supported in versions lower than 310.
TEST_F(ComputeShaderValidationTest, Version300)
{
const std::string &shaderString =
"#version 300 es\n"
"void main()\n"
"layout(local_size_x=1) in;\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Compute shaders should have work group size specified. However, it is not a compile time error
// to not have the size specified, but rather a link time one.
// GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
TEST_F(ComputeShaderValidationTest, NoWorkGroupSizeSpecified)
{
const std::string &shaderString =
"#version 310 es\n"
"void main()\n"
"{\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Work group size is less than 1. It should be at least 1.
// GLSL ES 3.10 Revision 4, 7.1.3 Compute Shader Special Variables
// The spec is not clear whether having a local size qualifier equal zero
// is correct.
// TODO (mradev): Ask people from Khronos to clarify the spec.
TEST_F(ComputeShaderValidationTest, WorkGroupSizeTooSmallXdimension)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 0) in;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Work group size is correct for the x and y dimensions, but not for the z dimension.
// GLSL ES 3.10 Revision 4, 7.1.3 Compute Shader Special Variables
TEST_F(ComputeShaderValidationTest, WorkGroupSizeTooSmallZDimension)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 4, local_size_y = 6, local_size_z = 0) in;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Work group size is bigger than the minimum in the x dimension.
// GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
TEST_F(ComputeShaderValidationTest, WorkGroupSizeTooBigXDimension)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 9989899) in;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Work group size is bigger than the minimum in the y dimension.
// GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
TEST_F(ComputeShaderValidationTest, WorkGroupSizeTooBigYDimension)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 5, local_size_y = 9989899) in;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Work group size is definitely bigger than the minimum in the z dimension.
// GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
TEST_F(ComputeShaderValidationTest, WorkGroupSizeTooBigZDimension)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 5, local_size_y = 5, local_size_z = 9989899) in;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Work group size specified through macro expansion.
TEST_F(ComputeShaderValidationTest, WorkGroupSizeMacro)
{
const std::string &shaderString =
"#version 310 es\n"
"#define MYDEF(x) x"
"layout(local_size_x = MYDEF(127)) in;\n"
"void main()\n"
"{\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Work group size specified as an unsigned integer.
TEST_F(ComputeShaderValidationTest, WorkGroupSizeUnsignedInteger)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 123u) in;\n"
"void main()\n"
"{\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Work group size specified in hexadecimal.
TEST_F(ComputeShaderValidationTest, WorkGroupSizeHexadecimal)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 0x3A) in;\n"
"void main()\n"
"{\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// local_size_x is -1 in hexadecimal format.
// -1 is used as unspecified value in the TLayoutQualifier structure.
TEST_F(ComputeShaderValidationTest, WorkGroupSizeMinusOneHexadecimal)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 0xFFFFFFFF) in;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Work group size specified in octal.
TEST_F(ComputeShaderValidationTest, WorkGroupSizeOctal)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 013) in;\n"
"void main()\n"
"{\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Work group size is negative. It is specified in hexadecimal.
TEST_F(ComputeShaderValidationTest, WorkGroupSizeNegativeHexadecimal)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 0xFFFFFFEC) in;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Multiple work group layout qualifiers with differing values.
// GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
TEST_F(ComputeShaderValidationTest, DifferingLayoutQualifiers)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 5, local_size_x = 6) in;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Multiple work group input variables with differing local size values.
// GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
TEST_F(ComputeShaderValidationTest, MultipleInputVariablesDifferingLocalSize)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 5, local_size_y = 6) in;\n"
"layout(local_size_x = 5, local_size_y = 7) in;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Multiple work group input variables with differing local size values.
// GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
TEST_F(ComputeShaderValidationTest, MultipleInputVariablesDifferingLocalSize2)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 5) in;\n"
"layout(local_size_x = 5, local_size_y = 7) in;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Multiple work group input variables with the same local size values. It should compile.
// GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
TEST_F(ComputeShaderValidationTest, MultipleInputVariablesSameLocalSize)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 5, local_size_y = 6) in;\n"
"layout(local_size_x = 5, local_size_y = 6) in;\n"
"void main()\n"
"{\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Multiple work group input variables with the same local size values. It should compile.
// Since the default value is 1, it should compile.
// GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
TEST_F(ComputeShaderValidationTest, MultipleInputVariablesSameLocalSize2)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 5) in;\n"
"layout(local_size_x = 5, local_size_y = 1) in;\n"
"void main()\n"
"{\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Multiple work group input variables with the same local size values. It should compile.
// Since the default value is 1, it should compile.
// GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
TEST_F(ComputeShaderValidationTest, MultipleInputVariablesSameLocalSize3)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 5, local_size_y = 1) in;\n"
"layout(local_size_x = 5) in;\n"
"void main()\n"
"{\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Specifying row_major qualifier in a work group size layout.
// GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
TEST_F(ComputeShaderValidationTest, RowMajorInComputeInputLayout)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 5, row_major) in;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// local size layout can be used only with compute input variables
// GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
TEST_F(ComputeShaderValidationTest, UniformComputeInputLayout)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 5) uniform;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// local size layout can be used only with compute input variables
// GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
TEST_F(ComputeShaderValidationTest, UniformBufferComputeInputLayout)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 5) uniform SomeBuffer { vec4 something; };\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// local size layout can be used only with compute input variables
// GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
TEST_F(ComputeShaderValidationTest, StructComputeInputLayout)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 5) struct SomeBuffer { vec4 something; };\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// local size layout can be used only with compute input variables
// GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
TEST_F(ComputeShaderValidationTest, StructBodyComputeInputLayout)
{
const std::string &shaderString =
"#version 310 es\n"
"struct S {\n"
" layout(local_size_x = 12) vec4 foo;\n"
"};\n"
"void main()"
"{"
"}";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// local size layout can be used only with compute input variables
// GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
TEST_F(ComputeShaderValidationTest, TypeComputeInputLayout)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 5) vec4;\n"
"void main()\n"
"{\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Invalid use of the out storage qualifier in a compute shader.
// GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
TEST_F(ComputeShaderValidationTest, InvalidOutStorageQualifier)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 15) in;\n"
"out vec4 myOutput;\n"
"void main() {\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Invalid use of the out storage qualifier in a compute shader.
// GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
TEST_F(ComputeShaderValidationTest, InvalidOutStorageQualifier2)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 15) in;\n"
"out myOutput;\n"
"void main() {\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Invalid use of the in storage qualifier. Can be only used to describe the local block size.
// GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
TEST_F(ComputeShaderValidationTest, InvalidInStorageQualifier)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 15) in;\n"
"in vec4 myInput;\n"
"void main() {\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Invalid use of the in storage qualifier. Can be only used to describe the local block size.
// The test checks a different part of the GLSL grammar than what InvalidInStorageQualifier checks.
// GLSL ES 3.10 Revision 4, 4.4.1.1 Compute Shader Inputs
TEST_F(ComputeShaderValidationTest, InvalidInStorageQualifier2)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 15) in;\n"
"in myInput;\n"
"void main() {\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// The local_size layout qualifier is only available in compute shaders.
TEST_F(VertexShaderValidationTest, InvalidUseOfLocalSizeX)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"layout(local_size_x = 15) in vec4 myInput;\n"
"out vec4 myOutput;\n"
"void main() {\n"
" myOutput = myInput;\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// The local_size layout qualifier is only available in compute shaders.
TEST_F(FragmentShaderValidationTest, InvalidUseOfLocalSizeX)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"layout(local_size_x = 15) in vec4 myInput;\n"
"out vec4 myOutput;\n"
"void main() {\n"
" myOutput = myInput;\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// It is a compile time error to use the gl_WorkGroupSize constant if
// the local size has not been declared yet.
// GLSL ES 3.10 Revision 4, 7.1.3 Compute Shader Special Variables
TEST_F(ComputeShaderValidationTest, InvalidUsageOfWorkGroupSize)
{
const std::string &shaderString =
"#version 310 es\n"
"void main()\n"
"{\n"
" uvec3 WorkGroupSize = gl_WorkGroupSize;\n"
"}\n"
"layout(local_size_x = 12) in;\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// The test covers the compute shader built-in variables and constants.
TEST_F(ComputeShaderValidationTest, CorrectUsageOfComputeBuiltins)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 12) in;\n"
"void main()\n"
"{\n"
" uvec3 NumWorkGroups = gl_NumWorkGroups;\n"
" uvec3 WorkGroupSize = gl_WorkGroupSize;\n"
" uvec3 WorkGroupID = gl_WorkGroupID;\n"
" uvec3 GlobalInvocationID = gl_GlobalInvocationID;\n"
" uvec3 LocalInvocationID = gl_LocalInvocationID;\n"
" uint LocalInvocationIndex = gl_LocalInvocationIndex;\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// It is illegal to write to a special variable.
TEST_F(ComputeShaderValidationTest, SpecialVariableNumWorkGroups)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 12) in;\n"
"void main()\n"
"{\n"
" gl_NumWorkGroups = uvec3(1); \n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// It is illegal to write to a special variable.
TEST_F(ComputeShaderValidationTest, SpecialVariableWorkGroupID)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 12) in;\n"
"void main()\n"
"{\n"
" gl_WorkGroupID = uvec3(1); \n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// It is illegal to write to a special variable.
TEST_F(ComputeShaderValidationTest, SpecialVariableLocalInvocationID)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 12) in;\n"
"void main()\n"
"{\n"
" gl_LocalInvocationID = uvec3(1); \n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// It is illegal to write to a special variable.
TEST_F(ComputeShaderValidationTest, SpecialVariableGlobalInvocationID)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 12) in;\n"
"void main()\n"
"{\n"
" gl_GlobalInvocationID = uvec3(1); \n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// It is illegal to write to a special variable.
TEST_F(ComputeShaderValidationTest, SpecialVariableLocalInvocationIndex)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 12) in;\n"
"void main()\n"
"{\n"
" gl_LocalInvocationIndex = 1; \n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// It is illegal to write to a special variable.
TEST_F(ComputeShaderValidationTest, SpecialVariableWorkGroupSize)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 12) in;\n"
"void main()\n"
"{\n"
" gl_WorkGroupSize = uvec3(1); \n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// It is illegal to apply an unary operator to a sampler.
TEST_F(FragmentShaderValidationTest, SamplerUnaryOperator)
{
const std::string &shaderString =
"precision mediump float;\n"
"uniform sampler2D s;\n"
"void main()\n"
"{\n"
" -s;\n"
" gl_FragColor = vec4(0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Invariant cannot be used with a work group size declaration.
TEST_F(ComputeShaderValidationTest, InvariantBlockSize)
{
const std::string &shaderString =
"#version 310 es\n"
"invariant layout(local_size_x = 15) in;\n"
"void main() {\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Invariant cannot be used with a non-output variable in ESSL3.
TEST_F(FragmentShaderValidationTest, InvariantNonOuput)
{
const std::string &shaderString =
"#version 300 es\n"
"invariant int value;\n"
"void main() {\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Invariant cannot be used with a non-output variable in ESSL3.
// ESSL 3.00.6 section 4.8: This applies even if the declaration is empty.
TEST_F(FragmentShaderValidationTest, InvariantNonOuputEmptyDeclaration)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"invariant in float;\n"
"void main() {}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Invariant declaration should follow the following format "invariant <out variable name>".
// Test having an incorrect qualifier in the invariant declaration.
TEST_F(FragmentShaderValidationTest, InvariantDeclarationWithStorageQualifier)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 foo;\n"
"invariant centroid foo;\n"
"void main() {\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Invariant declaration should follow the following format "invariant <out variable name>".
// Test having an incorrect precision qualifier in the invariant declaration.
TEST_F(FragmentShaderValidationTest, InvariantDeclarationWithPrecisionQualifier)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 foo;\n"
"invariant highp foo;\n"
"void main() {\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Invariant declaration should follow the following format "invariant <out variable name>".
// Test having an incorrect layout qualifier in the invariant declaration.
TEST_F(FragmentShaderValidationTest, InvariantDeclarationWithLayoutQualifier)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 foo;\n"
"invariant layout(location=0) foo;\n"
"void main() {\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Variable declaration with both invariant and layout qualifiers is not valid in the formal grammar
// provided in the ESSL 3.00 spec. ESSL 3.10 starts allowing this combination, but ESSL 3.00 should
// still disallow it.
TEST_F(FragmentShaderValidationTest, VariableDeclarationWithInvariantAndLayoutQualifierESSL300)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"invariant layout(location = 0) out vec4 my_FragColor;\n"
"void main() {\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Bit shift with a rhs value > 31 has an undefined result in the GLSL spec. Detecting an undefined
// result at compile time should not generate an error either way.
// ESSL 3.00.6 section 5.9.
TEST_F(FragmentShaderValidationTest, ShiftBy32)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"void main() {\n"
" uint u = 1u << 32u;\n"
"}\n";
if (compile(shaderString))
{
if (!hasWarning())
{
FAIL() << "Shader compilation succeeded without warnings, expecting warning:\n"
<< mInfoLog;
}
}
else
{
FAIL() << "Shader compilation failed, expecting success with warning:\n" << mInfoLog;
}
}
// Bit shift with a rhs value < 0 has an undefined result in the GLSL spec. Detecting an undefined
// result at compile time should not generate an error either way.
// ESSL 3.00.6 section 5.9.
TEST_F(FragmentShaderValidationTest, ShiftByNegative)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"void main() {\n"
" uint u = 1u << (-1);\n"
"}\n";
if (compile(shaderString))
{
if (!hasWarning())
{
FAIL() << "Shader compilation succeeded without warnings, expecting warning:\n"
<< mInfoLog;
}
}
else
{
FAIL() << "Shader compilation failed, expecting success with warning:\n" << mInfoLog;
}
}
// Test that deferring global variable init works with an empty main().
TEST_F(FragmentShaderValidationTest, DeferGlobalVariableInitWithEmptyMain)
{
const std::string &shaderString =
"precision mediump float;\n"
"uniform float u;\n"
"float foo = u;\n"
"void main() {}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Test that pruning empty declarations from loop init expression works.
TEST_F(FragmentShaderValidationTest, EmptyDeclarationAsLoopInit)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 my_FragColor;\n"
"void main()\n"
"{\n"
" int i = 0;\n"
" for (int; i < 3; i++)\n"
" {\n"
" my_FragColor = vec4(i);\n"
" }\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// r32f, r32i, r32ui do not require either the writeonly or readonly memory qualifiers.
// GLSL ES 3.10, Revision 4, 4.9 Memory Access Qualifiers
TEST_F(FragmentShaderValidationTest, ImageR32FNoMemoryQualifier)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"precision mediump image2D;\n"
"in vec4 myInput;\n"
"layout(r32f) uniform image2D myImage;\n"
"void main() {\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Images which do not have r32f, r32i or r32ui as internal format, must have readonly or writeonly
// specified.
// GLSL ES 3.10, Revision 4, 4.9 Memory Access Qualifiers
TEST_F(FragmentShaderValidationTest, ImageRGBA32FWithIncorrectMemoryQualifier)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"precision mediump image2D;\n"
"in vec4 myInput;\n"
"layout(rgba32f) uniform image2D myImage;\n"
"void main() {\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// It is a compile-time error to call imageStore when the image is qualified as readonly.
// GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
TEST_F(FragmentShaderValidationTest, StoreInReadOnlyImage)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"precision mediump image2D;\n"
"in vec4 myInput;\n"
"layout(r32f) uniform readonly image2D myImage;\n"
"void main() {\n"
" imageStore(myImage, ivec2(0), vec4(1.0));\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// It is a compile-time error to call imageLoad when the image is qualified as writeonly.
// GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
TEST_F(FragmentShaderValidationTest, LoadFromWriteOnlyImage)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"precision mediump image2D;\n"
"in vec4 myInput;\n"
"layout(r32f) uniform writeonly image2D myImage;\n"
"void main() {\n"
" imageLoad(myImage, ivec2(0));\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// It is a compile-time error to call imageStore when the image is qualified as readonly.
// Test to make sure this is validated correctly for images in arrays.
// GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
TEST_F(FragmentShaderValidationTest, StoreInReadOnlyImageArray)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"precision mediump image2D;\n"
"in vec4 myInput;\n"
"layout(r32f) uniform readonly image2D myImage[2];\n"
"void main() {\n"
" imageStore(myImage[0], ivec2(0), vec4(1.0));\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// It is a compile-time error to call imageStore when the image is qualified as readonly.
// Test to make sure that checking this doesn't crash when validating an image in a struct.
// Image in a struct in itself isn't accepted by the parser, but error recovery still results in
// an image in the struct.
// GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
TEST_F(FragmentShaderValidationTest, StoreInReadOnlyImageInStruct)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"precision mediump image2D;\n"
"in vec4 myInput;\n"
"uniform struct S {\n"
" layout(r32f) readonly image2D myImage;\n"
"} s;\n"
"void main() {\n"
" imageStore(s.myImage, ivec2(0), vec4(1.0));\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// A valid declaration and usage of an image3D.
TEST_F(FragmentShaderValidationTest, ValidImage3D)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"precision mediump image3D;\n"
"in vec4 myInput;\n"
"layout(rgba32f) uniform readonly image3D myImage;\n"
"void main() {\n"
" imageLoad(myImage, ivec3(0));\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// A valid declaration and usage of an imageCube.
TEST_F(FragmentShaderValidationTest, ValidImageCube)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"precision mediump imageCube;\n"
"in vec4 myInput;\n"
"layout(rgba32f) uniform readonly imageCube myImage;\n"
"void main() {\n"
" imageLoad(myImage, ivec3(0));\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// A valid declaration and usage of an image2DArray.
TEST_F(FragmentShaderValidationTest, ValidImage2DArray)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"precision mediump image2DArray;\n"
"in vec4 myInput;\n"
"layout(rgba32f) uniform readonly image2DArray myImage;\n"
"void main() {\n"
" imageLoad(myImage, ivec3(0));\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Images cannot be l-values.
// GLSL ES 3.10 Revision 4, 4.1.7 Opaque Types
TEST_F(FragmentShaderValidationTest, ImageLValueFunctionDefinitionInOut)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"precision mediump image2D;\n"
"void myFunc(inout image2D someImage) {}\n"
"void main() {\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Cannot assign to images.
// GLSL ES 3.10 Revision 4, 4.1.7 Opaque Types
TEST_F(FragmentShaderValidationTest, ImageAssignment)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"precision mediump image2D;\n"
"layout(rgba32f) uniform readonly image2D myImage;\n"
"layout(rgba32f) uniform readonly image2D myImage2;\n"
"void main() {\n"
" myImage = myImage2;\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Passing an image qualifier to a function should not be able to discard the readonly qualifier.
// GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
TEST_F(FragmentShaderValidationTest, ReadOnlyQualifierMissingInFunctionArgument)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"precision mediump image2D;\n"
"layout(rgba32f) uniform readonly image2D myImage;\n"
"void myFunc(in image2D someImage) {}\n"
"void main() {\n"
" myFunc(myImage);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Passing an image qualifier to a function should not be able to discard the readonly qualifier.
// Test with an image from an array.
// GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
TEST_F(FragmentShaderValidationTest, ReadOnlyQualifierMissingInFunctionArgumentArray)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"precision mediump image2D;\n"
"layout(rgba32f) uniform readonly image2D myImage[2];\n"
"void myFunc(in image2D someImage) {}\n"
"void main() {\n"
" myFunc(myImage[0]);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Passing an image qualifier to a function should not be able to discard the readonly qualifier.
// Test that validation doesn't crash on this for an image in a struct.
// Image in a struct in itself isn't accepted by the parser, but error recovery still results in
// an image in the struct.
// GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
TEST_F(FragmentShaderValidationTest, ReadOnlyQualifierMissingInFunctionArgumentStruct)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"precision mediump image2D;\n"
"uniform struct S {\n"
" layout(r32f) readonly image2D myImage;\n"
"} s;\n"
"void myFunc(in image2D someImage) {}\n"
"void main() {\n"
" myFunc(s.myImage);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Passing an image qualifier to a function should not be able to discard the writeonly qualifier.
// GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
TEST_F(FragmentShaderValidationTest, WriteOnlyQualifierMissingInFunctionArgument)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"precision mediump image2D;\n"
"layout(rgba32f) uniform writeonly image2D myImage;\n"
"void myFunc(in image2D someImage) {}\n"
"void main() {\n"
" myFunc(myImage);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Passing an image parameter as an argument to another function should not be able to discard the
// writeonly qualifier.
// GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
TEST_F(FragmentShaderValidationTest, DiscardWriteonlyInFunctionBody)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"precision mediump image2D;\n"
"layout(rgba32f) uniform writeonly image2D myImage;\n"
"void myFunc1(in image2D someImage) {}\n"
"void myFunc2(in writeonly image2D someImage) { myFunc1(someImage); }\n"
"void main() {\n"
" myFunc2(myImage);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// The memory qualifiers for the image declaration and function argument match and the test should
// pass.
TEST_F(FragmentShaderValidationTest, CorrectImageMemoryQualifierSpecified)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"precision mediump image2D;\n"
"layout(r32f) uniform image2D myImage;\n"
"void myFunc(in image2D someImage) {}\n"
"void main() {\n"
" myFunc(myImage);\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// The test adds additional qualifiers to the argument in the function header.
// This is correct since no memory qualifiers are discarded upon the function call.
// GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
TEST_F(FragmentShaderValidationTest, CorrectImageMemoryQualifierSpecified2)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"precision mediump image2D;\n"
"layout(r32f) uniform image2D myImage;\n"
"void myFunc(in readonly writeonly image2D someImage) {}\n"
"void main() {\n"
" myFunc(myImage);\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Images are not allowed in structs.
// GLSL ES 3.10 Revision 4, 4.1.8 Structures
TEST_F(FragmentShaderValidationTest, ImageInStruct)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"precision mediump image2D;\n"
"struct myStruct { layout(r32f) image2D myImage; };\n"
"void main() {\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Images are not allowed in interface blocks.
// GLSL ES 3.10 Revision 4, 4.3.9 Interface Blocks
TEST_F(FragmentShaderValidationTest, ImageInInterfaceBlock)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"precision mediump image2D;\n"
"uniform myBlock { layout(r32f) image2D myImage; };\n"
"void main() {\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Readonly used with an interface block.
TEST_F(FragmentShaderValidationTest, ReadonlyWithInterfaceBlock)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"uniform readonly myBlock { float something; };\n"
"void main() {\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Readonly used with an invariant.
TEST_F(FragmentShaderValidationTest, ReadonlyWithInvariant)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"out vec4 something;\n"
"invariant readonly something;\n"
"void main() {\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Readonly used with a member of a structure.
TEST_F(FragmentShaderValidationTest, ReadonlyWithStructMember)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"out vec4 something;\n"
"struct MyStruct { readonly float myMember; };\n"
"void main() {\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// It should not be possible to use an internal format layout qualifier with an interface block.
TEST_F(FragmentShaderValidationTest, ImageInternalFormatWithInterfaceBlock)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"out vec4 something;\n"
"layout(rgba32f) uniform MyStruct { float myMember; };\n"
"void main() {\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// It should not be possible to use an internal format layout qualifier with a uniform without a
// type.
TEST_F(FragmentShaderValidationTest, ImageInternalFormatInGlobalLayoutQualifier)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"out vec4 something;\n"
"layout(rgba32f) uniform;\n"
"void main() {\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// ESSL 1.00 section 4.1.7.
// Samplers are not allowed as operands for most operations. Test this for ternary operator.
TEST_F(FragmentShaderValidationTest, SamplerAsTernaryOperand)
{
const std::string &shaderString =
"precision mediump float;\n"
"uniform bool u;\n"
"uniform sampler2D s1;\n"
"uniform sampler2D s2;\n"
"void main() {\n"
" gl_FragColor = texture2D(u ? s1 : s2, vec2(0, 0));\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// ESSL 1.00.17 section 4.5.2.
// ESSL 3.00.6 section 4.5.3.
// Precision must be specified for floats. Test this with a declaration with no qualifiers.
TEST_F(FragmentShaderValidationTest, FloatDeclarationNoQualifiersNoPrecision)
{
const std::string &shaderString =
"vec4 foo = vec4(0.0);\n"
"void main()\n"
"{\n"
" gl_FragColor = foo;\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Check compiler doesn't crash on incorrect unsized array declarations.
TEST_F(FragmentShaderValidationTest, IncorrectUnsizedArray)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"float foo[] = 0.0;\n"
"out vec4 my_FragColor;\n"
"void main()\n"
"{\n"
" foo[0] = 1.0;\n"
" my_FragColor = vec4(foo[0]);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Check compiler doesn't crash when a bvec is on the right hand side of a logical operator.
// ESSL 3.00.6 section 5.9.
TEST_F(FragmentShaderValidationTest, LogicalOpRHSIsBVec)
{
const std::string &shaderString =
"#version 300 es\n"
"void main()\n"
"{\n"
" bool b;\n"
" bvec3 b3;\n"
" b && b3;\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Check compiler doesn't crash when there's an unsized array constructor with no parameters.
// ESSL 3.00.6 section 4.1.9: Array size must be greater than zero.
TEST_F(FragmentShaderValidationTest, UnsizedArrayConstructorNoParameters)
{
const std::string &shaderString =
"#version 300 es\n"
"void main()\n"
"{\n"
" int[]();\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Passing an image parameter as an argument to another function should not be able to discard the
// coherent qualifier.
TEST_F(FragmentShaderValidationTest, CoherentQualifierMissingInFunctionArgument)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"precision mediump image2D;\n"
"layout(r32f) uniform coherent image2D myImage;\n"
"void myFunc(in image2D someImage) {}\n"
"void main() {\n"
" myFunc(myImage);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Passing an image parameter as an argument to another function should not be able to discard the
// volatile qualifier.
TEST_F(FragmentShaderValidationTest, VolatileQualifierMissingInFunctionArgument)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"precision mediump image2D;\n"
"layout(r32f) uniform volatile image2D myImage;\n"
"void myFunc(in image2D someImage) {}\n"
"void main() {\n"
" myFunc(myImage);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// The restrict qualifier can be discarded from a function argument.
// GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
TEST_F(FragmentShaderValidationTest, RestrictQualifierDiscardedInFunctionArgument)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"precision mediump image2D;\n"
"layout(r32f) uniform restrict image2D myImage;\n"
"void myFunc(in image2D someImage) {}\n"
"void main() {\n"
" myFunc(myImage);\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Function image arguments can be overqualified.
// GLSL ES 3.10 Revision 4, 4.9 Memory Access Qualifiers
TEST_F(FragmentShaderValidationTest, OverqualifyingImageParameter)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"precision mediump image2D;\n"
"layout(r32f) uniform image2D myImage;\n"
"void myFunc(in coherent volatile image2D someImage) {}\n"
"void main() {\n"
" myFunc(myImage);\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Test that work group size can be used to size arrays.
// GLSL ES 3.10.4 section 7.1.3 Compute Shader Special Variables
TEST_F(ComputeShaderValidationTest, WorkGroupSizeAsArraySize)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 5, local_size_y = 3, local_size_z = 1) in;\n"
"void main()\n"
"{\n"
" int[gl_WorkGroupSize.x] a = int[5](0, 0, 0, 0, 0);\n"
" int[gl_WorkGroupSize.y] b = int[3](0, 0, 0);\n"
" int[gl_WorkGroupSize.z] c = int[1](0);\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Shared memory variables cannot be used inside a vertex shader.
// GLSL ES 3.10 Revision 4, 4.3.8 Shared Variables
TEST_F(VertexShaderValidationTest, VertexShaderSharedMemory)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"in vec4 i;\n"
"shared float myShared[10];\n"
"void main() {\n"
" gl_Position = i;\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Shared memory variables cannot be used inside a fragment shader.
// GLSL ES 3.10 Revision 4, 4.3.8 Shared Variables
TEST_F(FragmentShaderValidationTest, FragmentShaderSharedMemory)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"shared float myShared[10];\n"
"out vec4 color;\n"
"void main() {\n"
" color = vec4(1.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Shared memory cannot be combined with any other storage qualifier.
TEST_F(ComputeShaderValidationTest, UniformSharedMemory)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"layout(local_size_x = 5) in;\n"
"uniform shared float myShared[100];\n"
"void main() {\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Correct usage of shared memory variables.
TEST_F(ComputeShaderValidationTest, CorrectUsageOfSharedMemory)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"layout(local_size_x = 5) in;\n"
"shared float myShared[100];\n"
"void main() {\n"
" myShared[gl_LocalInvocationID.x] = 1.0;\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Shared memory variables cannot be initialized.
// GLSL ES 3.10 Revision 4, 4.3.8 Shared Variables
TEST_F(ComputeShaderValidationTest, SharedVariableInitialization)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"layout(local_size_x = 5) in;\n"
"shared int myShared = 0;\n"
"void main() {\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Local variables cannot be qualified as shared.
// GLSL ES 3.10 Revision 4, 4.3 Storage Qualifiers
TEST_F(ComputeShaderValidationTest, SharedMemoryInFunctionBody)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"layout(local_size_x = 5) in;\n"
"void func() {\n"
" shared int myShared;\n"
"}\n"
"void main() {\n"
" func();\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Struct members cannot be qualified as shared.
TEST_F(ComputeShaderValidationTest, SharedMemoryInStruct)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"layout(local_size_x = 5) in;\n"
"struct MyStruct {\n"
" shared int myShared;\n"
"};\n"
"void main() {\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Interface block members cannot be qualified as shared.
TEST_F(ComputeShaderValidationTest, SharedMemoryInInterfaceBlock)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"layout(local_size_x = 5) in;\n"
"uniform Myblock {\n"
" shared int myShared;\n"
"};\n"
"void main() {\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// The shared qualifier cannot be used with any other qualifier.
TEST_F(ComputeShaderValidationTest, SharedWithInvariant)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"layout(local_size_x = 5) in;\n"
"invariant shared int myShared;\n"
"void main() {\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// The shared qualifier cannot be used with any other qualifier.
TEST_F(ComputeShaderValidationTest, SharedWithMemoryQualifier)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"layout(local_size_x = 5) in;\n"
"readonly shared int myShared;\n"
"void main() {\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// The shared qualifier cannot be used with any other qualifier.
TEST_F(ComputeShaderValidationTest, SharedGlobalLayoutDeclaration)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"layout(local_size_x = 5) in;\n"
"layout(row_major) shared mat4;\n"
"void main() {\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Declaring a function with the same name as a built-in from a higher ESSL version should not cause
// a redeclaration error.
TEST_F(FragmentShaderValidationTest, BuiltinESSL31FunctionDeclaredInESSL30Shader)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"void imageSize() {}\n"
"void main() {\n"
" imageSize();\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success:\n" << mInfoLog;
}
}
// Attempting to declare num_views without enabling OVR_multiview.
TEST_F(VertexShaderValidationTest, InvalidNumViews)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"layout (num_views = 2) in;\n"
"void main() {\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// memoryBarrierShared is only available in a compute shader.
// GLSL ES 3.10 Revision 4, 8.15 Shader Memory Control Functions
TEST_F(FragmentShaderValidationTest, InvalidUseOfMemoryBarrierShared)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"void main() {\n"
" memoryBarrierShared();\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
}
}
// groupMemoryBarrier is only available in a compute shader.
// GLSL ES 3.10 Revision 4, 8.15 Shader Memory Control Functions
TEST_F(FragmentShaderValidationTest, InvalidUseOfGroupMemoryBarrier)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"void main() {\n"
" groupMemoryBarrier();\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
}
}
// barrier can be used in a compute shader.
// GLSL ES 3.10 Revision 4, 8.14 Shader Invocation Control Functions
TEST_F(ComputeShaderValidationTest, ValidUseOfBarrier)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 15) in;\n"
"void main() {\n"
" barrier();\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
}
}
// memoryBarrierImage() can be used in all GLSL ES 3.10 shaders.
// GLSL ES 3.10 Revision 4, 8.15 Shader Memory Control Functions
TEST_F(FragmentShaderValidationTest, ValidUseOfMemoryBarrierImageInFragmentShader)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"precision highp image2D;\n"
"layout(r32f) uniform image2D myImage;\n"
"void main() {\n"
" imageStore(myImage, ivec2(0), vec4(1.0));\n"
" memoryBarrierImage();\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
}
}
// checks that gsampler2DMS is not supported in version lower than 310
TEST_F(FragmentShaderValidationTest, Sampler2DMSInESSL300Shader)
{
const std::string &shaderString =
"#version 300 es\n"
"uniform highp sampler2DMS s;\n"
"void main() {}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
}
}
// Declare main() with incorrect parameters.
// ESSL 3.00.6 section 6.1 Function Definitions.
TEST_F(FragmentShaderValidationTest, InvalidMainPrototypeParameters)
{
const std::string &shaderString =
"#version 300 es\n"
"void main(int a);\n"
"void main() {}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
}
}
// Regression test for a crash in the empty constructor of unsized array
// of a structure with non-basic fields fields. Test with "void".
TEST_F(FragmentShaderValidationTest, VoidFieldStructUnsizedArrayEmptyConstructor)
{
const std::string &shaderString =
"#version 300 es\n"
"struct S {void a;};"
"void main() {S s[] = S[]();}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
}
}
// Regression test for a crash in the empty constructor of unsized array
// of a structure with non-basic fields fields. Test with something other than "void".
TEST_F(FragmentShaderValidationTest, SamplerFieldStructUnsizedArrayEmptyConstructor)
{
const std::string &shaderString =
"#version 300 es\n"
"struct S {sampler2D a;};"
"void main() {S s[] = S[]();}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
}
}
// Checks that odd array initialization syntax is an error, and does not produce
// an ASSERT failure.
TEST_F(VertexShaderValidationTest, InvalidArrayConstruction)
{
const std::string &shaderString =
"struct S { mediump float i; mediump int ggb; };\n"
"void main() {\n"
" S s[2];\n"
" s = S[](s.x, 0.0);\n"
" gl_Position = vec4(1, 0, 0, 1);\n"
"}";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
}
}
// Correct usage of image binding layout qualifier.
TEST_F(ComputeShaderValidationTest, CorrectImageBindingLayoutQualifier)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"precision mediump image2D;\n"
"layout(local_size_x = 5) in;\n"
"layout(binding = 1, rgba32f) writeonly uniform image2D myImage;\n"
"void main()\n"
"{\n"
" imageStore(myImage, ivec2(gl_LocalInvocationID.xy), vec4(1.0));\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
}
}
// Incorrect use of "binding" on a global layout qualifier.
TEST_F(ComputeShaderValidationTest, IncorrectGlobalBindingLayoutQualifier)
{
const std::string &shaderString =
"#version 310 es\n"
"layout(local_size_x = 5, binding = 0) in;\n"
"void main() {}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
}
}
// Incorrect use of "binding" on a struct field layout qualifier.
TEST_F(ComputeShaderValidationTest, IncorrectStructFieldBindingLayoutQualifier)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"layout(local_size_x = 1) in;\n"
"struct S\n"
"{\n"
" layout(binding = 0) float f;\n"
"};\n"
"void main() {}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
}
}
// Variable binding layout qualifier is set to a negative value. 0xffffffff wraps around to -1
// according to the integer parsing rules.
TEST_F(FragmentShaderValidationTest, ImageBindingUnitNegative)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"layout(rgba32f, binding = 0xffffffff) writeonly uniform mediump image2D myImage;\n"
"out vec4 outFrag;\n"
"void main()\n"
"{\n"
" outFrag = vec4(0.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
}
}
// Image binding layout qualifier value is greater than the maximum image binding.
TEST_F(FragmentShaderValidationTest, ImageBindingUnitTooBig)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"layout(rgba32f, binding = 9999) writeonly uniform mediump image2D myImage;\n"
"out vec4 outFrag;\n"
"void main()\n"
"{\n"
" outFrag = vec4(0.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
}
}
// Uniform variable binding is set on a non-opaque type.
TEST_F(FragmentShaderValidationTest, NonOpaqueUniformBinding)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"layout(binding = 0) uniform float myFloat;\n"
"out vec4 outFrag;\n"
"void main()\n"
"{\n"
" outFrag = vec4(myFloat);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
}
}
// Uniform variable binding is set on a sampler type.
// ESSL 3.10 section 4.4.5 Opaque Uniform Layout Qualifiers.
TEST_F(FragmentShaderValidationTest, SamplerUniformBinding)
{
const std::string &shaderString =
"#version 310 es\n"
"precision mediump float;\n"
"layout(binding = 0) uniform mediump sampler2D mySampler;\n"
"out vec4 outFrag;\n"
"void main()\n"
"{\n"
" outFrag = vec4(0.0);\n"
"}\n";
if (!compile(shaderString))
{
FAIL() << "Shader compilation failed, expecting success " << mInfoLog;
}
}
// Uniform variable binding is set on a sampler type in an ESSL 3.00 shader.
// The binding layout qualifier was added in ESSL 3.10, so this is incorrect.
TEST_F(FragmentShaderValidationTest, SamplerUniformBindingESSL300)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"layout(binding = 0) uniform mediump sampler2D mySampler;\n"
"out vec4 outFrag;\n"
"void main()\n"
"{\n"
" outFrag = vec4(0.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
}
}
// Attempting to construct a struct containing a void array should fail without asserting.
TEST_F(FragmentShaderValidationTest, ConstructStructContainingVoidArray)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 outFrag;\n"
"struct S\n"
"{\n"
" void A[1];\n"
"} s = S();\n"
"void main()\n"
"{\n"
" outFrag = vec4(0.0);\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure " << mInfoLog;
}
}
// Uniforms can't have location in ESSL 3.00.
// Test this with an empty declaration (ESSL 3.00.6 section 4.8: The combinations of qualifiers that
// cause compile-time or link-time errors are the same whether or not the declaration is empty).
TEST_F(FragmentShaderValidationTest, UniformLocationEmptyDeclaration)
{
const std::string &shaderString =
"#version 300 es\n"
"precision mediump float;\n"
"layout(location=0) uniform float;\n"
"void main() {}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test function parameters of opaque type can't be l-value too.
TEST_F(FragmentShaderValidationTest, OpaqueParameterCanNotBeLValue)
{
const std::string &shaderString =
"#version 310 es\n"
"uniform sampler2D s;\n"
"void foo(sampler2D as) {\n"
" as = s;\n"
"}\n"
"void main() {}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test samplers must not be operands in expressions, except for array indexing, structure field
// selection and parentheses(ESSL 3.00 Secion 4.1.7).
TEST_F(FragmentShaderValidationTest, InvalidExpressionForSamplerOperands)
{
const std::string &shaderString =
"#version 300 es\n"
"uniform sampler2D s;\n"
"uniform sampler2D s2;\n"
"void main() {\n"
" s + s2;\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test interface blocks as invalid operands to a binary expression.
TEST_F(FragmentShaderValidationTest, InvalidInterfaceBlockBinaryExpression)
{
const std::string &shaderString =
"#version 300 es\n"
"uniform U\n"
"{\n"
" int foo; \n"
"} u;\n"
"void main()\n"
"{\n"
" u + u;\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test interface block as an invalid operand to an unary expression.
TEST_F(FragmentShaderValidationTest, InvalidInterfaceBlockUnaryExpression)
{
const std::string &shaderString =
"#version 300 es\n"
"uniform U\n"
"{\n"
" int foo; \n"
"} u;\n"
"void main()\n"
"{\n"
" +u;\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}
// Test interface block as an invalid operand to a ternary expression.
// Note that the spec is not very explicit on this, but it makes sense to forbid this.
TEST_F(FragmentShaderValidationTest, InvalidInterfaceBlockTernaryExpression)
{
const std::string &shaderString =
"#version 300 es\n"
"uniform U\n"
"{\n"
" int foo; \n"
"} u;\n"
"void main()\n"
"{\n"
" true ? u : u;\n"
"}\n";
if (compile(shaderString))
{
FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
}
}