summaryrefslogtreecommitdiffstats
path: root/gfx/angle/src/tests/gl_tests/GLSLTest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/src/tests/gl_tests/GLSLTest.cpp')
-rwxr-xr-xgfx/angle/src/tests/gl_tests/GLSLTest.cpp2443
1 files changed, 2443 insertions, 0 deletions
diff --git a/gfx/angle/src/tests/gl_tests/GLSLTest.cpp b/gfx/angle/src/tests/gl_tests/GLSLTest.cpp
new file mode 100755
index 000000000..00000612d
--- /dev/null
+++ b/gfx/angle/src/tests/gl_tests/GLSLTest.cpp
@@ -0,0 +1,2443 @@
+//
+// Copyright 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.
+//
+
+#include "test_utils/ANGLETest.h"
+
+#include "libANGLE/Context.h"
+#include "libANGLE/Program.h"
+#include "test_utils/gl_raii.h"
+
+using namespace angle;
+
+namespace
+{
+
+class GLSLTest : public ANGLETest
+{
+ protected:
+ GLSLTest()
+ {
+ setWindowWidth(128);
+ setWindowHeight(128);
+ setConfigRedBits(8);
+ setConfigGreenBits(8);
+ setConfigBlueBits(8);
+ setConfigAlphaBits(8);
+ }
+
+ virtual void SetUp()
+ {
+ ANGLETest::SetUp();
+
+ mSimpleVSSource = SHADER_SOURCE
+ (
+ attribute vec4 inputAttribute;
+ void main()
+ {
+ gl_Position = inputAttribute;
+ }
+ );
+ }
+
+ std::string GenerateVaryingType(GLint vectorSize)
+ {
+ char varyingType[10];
+
+ if (vectorSize == 1)
+ {
+ sprintf(varyingType, "float");
+ }
+ else
+ {
+ sprintf(varyingType, "vec%d", vectorSize);
+ }
+
+ return std::string(varyingType);
+ }
+
+ std::string GenerateVectorVaryingDeclaration(GLint vectorSize, GLint arraySize, GLint id)
+ {
+ char buff[100];
+
+ if (arraySize == 1)
+ {
+ sprintf(buff, "varying %s v%d;\n", GenerateVaryingType(vectorSize).c_str(), id);
+ }
+ else
+ {
+ sprintf(buff, "varying %s v%d[%d];\n", GenerateVaryingType(vectorSize).c_str(), id, arraySize);
+ }
+
+ return std::string(buff);
+ }
+
+ std::string GenerateVectorVaryingSettingCode(GLint vectorSize, GLint arraySize, GLint id)
+ {
+ std::string returnString;
+ char buff[100];
+
+ if (arraySize == 1)
+ {
+ sprintf(buff, "\t v%d = %s(1.0);\n", id, GenerateVaryingType(vectorSize).c_str());
+ returnString += buff;
+ }
+ else
+ {
+ for (int i = 0; i < arraySize; i++)
+ {
+ sprintf(buff, "\t v%d[%d] = %s(1.0);\n", id, i, GenerateVaryingType(vectorSize).c_str());
+ returnString += buff;
+ }
+ }
+
+ return returnString;
+ }
+
+ std::string GenerateVectorVaryingUseCode(GLint arraySize, GLint id)
+ {
+ if (arraySize == 1)
+ {
+ char buff[100];
+ sprintf(buff, "v%d + ", id);
+ return std::string(buff);
+ }
+ else
+ {
+ std::string returnString;
+ for (int i = 0; i < arraySize; i++)
+ {
+ char buff[100];
+ sprintf(buff, "v%d[%d] + ", id, i);
+ returnString += buff;
+ }
+ return returnString;
+ }
+ }
+
+ void GenerateGLSLWithVaryings(GLint floatCount, GLint floatArrayCount, GLint vec2Count, GLint vec2ArrayCount, GLint vec3Count, GLint vec3ArrayCount,
+ GLint vec4Count, GLint vec4ArrayCount, bool useFragCoord, bool usePointCoord, bool usePointSize,
+ std::string* fragmentShader, std::string* vertexShader)
+ {
+ // Generate a string declaring the varyings, to share between the fragment shader and the vertex shader.
+ std::string varyingDeclaration;
+
+ unsigned int varyingCount = 0;
+
+ for (GLint i = 0; i < floatCount; i++)
+ {
+ varyingDeclaration += GenerateVectorVaryingDeclaration(1, 1, varyingCount);
+ varyingCount += 1;
+ }
+
+ for (GLint i = 0; i < floatArrayCount; i++)
+ {
+ varyingDeclaration += GenerateVectorVaryingDeclaration(1, 2, varyingCount);
+ varyingCount += 1;
+ }
+
+ for (GLint i = 0; i < vec2Count; i++)
+ {
+ varyingDeclaration += GenerateVectorVaryingDeclaration(2, 1, varyingCount);
+ varyingCount += 1;
+ }
+
+ for (GLint i = 0; i < vec2ArrayCount; i++)
+ {
+ varyingDeclaration += GenerateVectorVaryingDeclaration(2, 2, varyingCount);
+ varyingCount += 1;
+ }
+
+ for (GLint i = 0; i < vec3Count; i++)
+ {
+ varyingDeclaration += GenerateVectorVaryingDeclaration(3, 1, varyingCount);
+ varyingCount += 1;
+ }
+
+ for (GLint i = 0; i < vec3ArrayCount; i++)
+ {
+ varyingDeclaration += GenerateVectorVaryingDeclaration(3, 2, varyingCount);
+ varyingCount += 1;
+ }
+
+ for (GLint i = 0; i < vec4Count; i++)
+ {
+ varyingDeclaration += GenerateVectorVaryingDeclaration(4, 1, varyingCount);
+ varyingCount += 1;
+ }
+
+ for (GLint i = 0; i < vec4ArrayCount; i++)
+ {
+ varyingDeclaration += GenerateVectorVaryingDeclaration(4, 2, varyingCount);
+ varyingCount += 1;
+ }
+
+ // Generate the vertex shader
+ vertexShader->clear();
+ vertexShader->append(varyingDeclaration);
+ vertexShader->append("\nvoid main()\n{\n");
+
+ unsigned int currentVSVarying = 0;
+
+ for (GLint i = 0; i < floatCount; i++)
+ {
+ vertexShader->append(GenerateVectorVaryingSettingCode(1, 1, currentVSVarying));
+ currentVSVarying += 1;
+ }
+
+ for (GLint i = 0; i < floatArrayCount; i++)
+ {
+ vertexShader->append(GenerateVectorVaryingSettingCode(1, 2, currentVSVarying));
+ currentVSVarying += 1;
+ }
+
+ for (GLint i = 0; i < vec2Count; i++)
+ {
+ vertexShader->append(GenerateVectorVaryingSettingCode(2, 1, currentVSVarying));
+ currentVSVarying += 1;
+ }
+
+ for (GLint i = 0; i < vec2ArrayCount; i++)
+ {
+ vertexShader->append(GenerateVectorVaryingSettingCode(2, 2, currentVSVarying));
+ currentVSVarying += 1;
+ }
+
+ for (GLint i = 0; i < vec3Count; i++)
+ {
+ vertexShader->append(GenerateVectorVaryingSettingCode(3, 1, currentVSVarying));
+ currentVSVarying += 1;
+ }
+
+ for (GLint i = 0; i < vec3ArrayCount; i++)
+ {
+ vertexShader->append(GenerateVectorVaryingSettingCode(3, 2, currentVSVarying));
+ currentVSVarying += 1;
+ }
+
+ for (GLint i = 0; i < vec4Count; i++)
+ {
+ vertexShader->append(GenerateVectorVaryingSettingCode(4, 1, currentVSVarying));
+ currentVSVarying += 1;
+ }
+
+ for (GLint i = 0; i < vec4ArrayCount; i++)
+ {
+ vertexShader->append(GenerateVectorVaryingSettingCode(4, 2, currentVSVarying));
+ currentVSVarying += 1;
+ }
+
+ if (usePointSize)
+ {
+ vertexShader->append("gl_PointSize = 1.0;\n");
+ }
+
+ vertexShader->append("}\n");
+
+ // Generate the fragment shader
+ fragmentShader->clear();
+ fragmentShader->append("precision highp float;\n");
+ fragmentShader->append(varyingDeclaration);
+ fragmentShader->append("\nvoid main() \n{ \n\tvec4 retColor = vec4(0,0,0,0);\n");
+
+ unsigned int currentFSVarying = 0;
+
+ // Make use of the float varyings
+ fragmentShader->append("\tretColor += vec4(");
+
+ for (GLint i = 0; i < floatCount; i++)
+ {
+ fragmentShader->append(GenerateVectorVaryingUseCode(1, currentFSVarying));
+ currentFSVarying += 1;
+ }
+
+ for (GLint i = 0; i < floatArrayCount; i++)
+ {
+ fragmentShader->append(GenerateVectorVaryingUseCode(2, currentFSVarying));
+ currentFSVarying += 1;
+ }
+
+ fragmentShader->append("0.0, 0.0, 0.0, 0.0);\n");
+
+ // Make use of the vec2 varyings
+ fragmentShader->append("\tretColor += vec4(");
+
+ for (GLint i = 0; i < vec2Count; i++)
+ {
+ fragmentShader->append(GenerateVectorVaryingUseCode(1, currentFSVarying));
+ currentFSVarying += 1;
+ }
+
+ for (GLint i = 0; i < vec2ArrayCount; i++)
+ {
+ fragmentShader->append(GenerateVectorVaryingUseCode(2, currentFSVarying));
+ currentFSVarying += 1;
+ }
+
+ fragmentShader->append("vec2(0.0, 0.0), 0.0, 0.0);\n");
+
+ // Make use of the vec3 varyings
+ fragmentShader->append("\tretColor += vec4(");
+
+ for (GLint i = 0; i < vec3Count; i++)
+ {
+ fragmentShader->append(GenerateVectorVaryingUseCode(1, currentFSVarying));
+ currentFSVarying += 1;
+ }
+
+ for (GLint i = 0; i < vec3ArrayCount; i++)
+ {
+ fragmentShader->append(GenerateVectorVaryingUseCode(2, currentFSVarying));
+ currentFSVarying += 1;
+ }
+
+ fragmentShader->append("vec3(0.0, 0.0, 0.0), 0.0);\n");
+
+ // Make use of the vec4 varyings
+ fragmentShader->append("\tretColor += ");
+
+ for (GLint i = 0; i < vec4Count; i++)
+ {
+ fragmentShader->append(GenerateVectorVaryingUseCode(1, currentFSVarying));
+ currentFSVarying += 1;
+ }
+
+ for (GLint i = 0; i < vec4ArrayCount; i++)
+ {
+ fragmentShader->append(GenerateVectorVaryingUseCode(2, currentFSVarying));
+ currentFSVarying += 1;
+ }
+
+ fragmentShader->append("vec4(0.0, 0.0, 0.0, 0.0);\n");
+
+ // Set gl_FragColor, and use special variables if requested
+ fragmentShader->append("\tgl_FragColor = retColor");
+
+ if (useFragCoord)
+ {
+ fragmentShader->append(" + gl_FragCoord");
+ }
+
+ if (usePointCoord)
+ {
+ fragmentShader->append(" + vec4(gl_PointCoord, 0.0, 0.0)");
+ }
+
+ fragmentShader->append(";\n}");
+ }
+
+ void VaryingTestBase(GLint floatCount, GLint floatArrayCount, GLint vec2Count, GLint vec2ArrayCount, GLint vec3Count, GLint vec3ArrayCount,
+ GLint vec4Count, GLint vec4ArrayCount, bool useFragCoord, bool usePointCoord, bool usePointSize, bool expectSuccess)
+ {
+ std::string fragmentShaderSource;
+ std::string vertexShaderSource;
+
+ GenerateGLSLWithVaryings(floatCount, floatArrayCount, vec2Count, vec2ArrayCount, vec3Count, vec3ArrayCount,
+ vec4Count, vec4ArrayCount, useFragCoord, usePointCoord, usePointSize,
+ &fragmentShaderSource, &vertexShaderSource);
+
+ GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+
+ if (expectSuccess)
+ {
+ EXPECT_NE(0u, program);
+ }
+ else
+ {
+ EXPECT_EQ(0u, program);
+ }
+ }
+
+ void CompileGLSLWithUniformsAndSamplers(GLint vertexUniformCount,
+ GLint fragmentUniformCount,
+ GLint vertexSamplersCount,
+ GLint fragmentSamplersCount,
+ bool expectSuccess)
+ {
+ std::stringstream vertexShader;
+ std::stringstream fragmentShader;
+
+ // Generate the vertex shader
+ vertexShader << "precision mediump float;\n";
+
+ for (int i = 0; i < vertexUniformCount; i++)
+ {
+ vertexShader << "uniform vec4 v" << i << ";\n";
+ }
+
+ for (int i = 0; i < vertexSamplersCount; i++)
+ {
+ vertexShader << "uniform sampler2D s" << i << ";\n";
+ }
+
+ vertexShader << "void main()\n{\n";
+
+ for (int i = 0; i < vertexUniformCount; i++)
+ {
+ vertexShader << " gl_Position += v" << i << ";\n";
+ }
+
+ for (int i = 0; i < vertexSamplersCount; i++)
+ {
+ vertexShader << " gl_Position += texture2D(s" << i << ", vec2(0.0, 0.0));\n";
+ }
+
+ if (vertexUniformCount == 0 && vertexSamplersCount == 0)
+ {
+ vertexShader << " gl_Position = vec4(0.0);\n";
+ }
+
+ vertexShader << "}\n";
+
+ // Generate the fragment shader
+ fragmentShader << "precision mediump float;\n";
+
+ for (int i = 0; i < fragmentUniformCount; i++)
+ {
+ fragmentShader << "uniform vec4 v" << i << ";\n";
+ }
+
+ for (int i = 0; i < fragmentSamplersCount; i++)
+ {
+ fragmentShader << "uniform sampler2D s" << i << ";\n";
+ }
+
+ fragmentShader << "void main()\n{\n";
+
+ for (int i = 0; i < fragmentUniformCount; i++)
+ {
+ fragmentShader << " gl_FragColor += v" << i << ";\n";
+ }
+
+ for (int i = 0; i < fragmentSamplersCount; i++)
+ {
+ fragmentShader << " gl_FragColor += texture2D(s" << i << ", vec2(0.0, 0.0));\n";
+ }
+
+ if (fragmentUniformCount == 0 && fragmentSamplersCount == 0)
+ {
+ fragmentShader << " gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n";
+ }
+
+ fragmentShader << "}\n";
+
+ GLuint program = CompileProgram(vertexShader.str(), fragmentShader.str());
+
+ if (expectSuccess)
+ {
+ EXPECT_NE(0u, program);
+ }
+ else
+ {
+ EXPECT_EQ(0u, program);
+ }
+ }
+
+ std::string mSimpleVSSource;
+};
+
+class GLSLTest_ES3 : public GLSLTest
+{
+ void SetUp() override
+ {
+ ANGLETest::SetUp();
+
+ mSimpleVSSource =
+ "#version 300 es\n"
+ "in vec4 inputAttribute;"
+ "void main()"
+ "{"
+ " gl_Position = inputAttribute;"
+ "}";
+ }
+};
+
+TEST_P(GLSLTest, NamelessScopedStructs)
+{
+ const std::string fragmentShaderSource = SHADER_SOURCE
+ (
+ precision mediump float;
+
+ void main()
+ {
+ struct
+ {
+ float q;
+ } b;
+
+ gl_FragColor = vec4(1, 0, 0, 1);
+ gl_FragColor.a += b.q;
+ }
+ );
+
+ GLuint program = CompileProgram(mSimpleVSSource, fragmentShaderSource);
+ EXPECT_NE(0u, program);
+}
+
+TEST_P(GLSLTest, ScopedStructsOrderBug)
+{
+ // TODO(geofflang): Find out why this doesn't compile on Apple OpenGL drivers
+ // (http://anglebug.com/1292)
+ // TODO(geofflang): Find out why this doesn't compile on AMD OpenGL drivers
+ // (http://anglebug.com/1291)
+ if (IsDesktopOpenGL() && (IsOSX() || !IsNVIDIA()))
+ {
+ std::cout << "Test disabled on this OpenGL configuration." << std::endl;
+ return;
+ }
+
+ const std::string fragmentShaderSource = SHADER_SOURCE
+ (
+ precision mediump float;
+
+ struct T
+ {
+ float f;
+ };
+
+ void main()
+ {
+ T a;
+
+ struct T
+ {
+ float q;
+ };
+
+ T b;
+
+ gl_FragColor = vec4(1, 0, 0, 1);
+ gl_FragColor.a += a.f;
+ gl_FragColor.a += b.q;
+ }
+ );
+
+ GLuint program = CompileProgram(mSimpleVSSource, fragmentShaderSource);
+ EXPECT_NE(0u, program);
+}
+
+TEST_P(GLSLTest, ScopedStructsBug)
+{
+ const std::string fragmentShaderSource = SHADER_SOURCE
+ (
+ precision mediump float;
+
+ struct T_0
+ {
+ float f;
+ };
+
+ void main()
+ {
+ gl_FragColor = vec4(1, 0, 0, 1);
+
+ struct T
+ {
+ vec2 v;
+ };
+
+ T_0 a;
+ T b;
+
+ gl_FragColor.a += a.f;
+ gl_FragColor.a += b.v.x;
+ }
+ );
+
+ GLuint program = CompileProgram(mSimpleVSSource, fragmentShaderSource);
+ EXPECT_NE(0u, program);
+}
+
+TEST_P(GLSLTest, DxPositionBug)
+{
+ const std::string &vertexShaderSource = SHADER_SOURCE
+ (
+ attribute vec4 inputAttribute;
+ varying float dx_Position;
+ void main()
+ {
+ gl_Position = vec4(inputAttribute);
+ dx_Position = 0.0;
+ }
+ );
+
+ const std::string &fragmentShaderSource = SHADER_SOURCE
+ (
+ precision mediump float;
+
+ varying float dx_Position;
+
+ void main()
+ {
+ gl_FragColor = vec4(dx_Position, 0, 0, 1);
+ }
+ );
+
+ GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+ EXPECT_NE(0u, program);
+}
+
+TEST_P(GLSLTest, ElseIfRewriting)
+{
+ const std::string &vertexShaderSource =
+ "attribute vec4 a_position;\n"
+ "varying float v;\n"
+ "void main() {\n"
+ " gl_Position = a_position;\n"
+ " v = 1.0;\n"
+ " if (a_position.x <= 0.5) {\n"
+ " v = 0.0;\n"
+ " } else if (a_position.x >= 0.5) {\n"
+ " v = 2.0;\n"
+ " }\n"
+ "}\n";
+
+ const std::string &fragmentShaderSource =
+ "precision highp float;\n"
+ "varying float v;\n"
+ "void main() {\n"
+ " vec4 color = vec4(1.0, 0.0, 0.0, 1.0);\n"
+ " if (v >= 1.0) color = vec4(0.0, 1.0, 0.0, 1.0);\n"
+ " if (v >= 2.0) color = vec4(0.0, 0.0, 1.0, 1.0);\n"
+ " gl_FragColor = color;\n"
+ "}\n";
+
+ GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+ ASSERT_NE(0u, program);
+
+ drawQuad(program, "a_position", 0.5f);
+
+ EXPECT_PIXEL_EQ(0, 0, 255, 0, 0, 255);
+ EXPECT_PIXEL_EQ(getWindowWidth()-1, 0, 0, 255, 0, 255);
+}
+
+TEST_P(GLSLTest, TwoElseIfRewriting)
+{
+ const std::string &vertexShaderSource =
+ "attribute vec4 a_position;\n"
+ "varying float v;\n"
+ "void main() {\n"
+ " gl_Position = a_position;\n"
+ " if (a_position.x == 0.0) {\n"
+ " v = 1.0;\n"
+ " } else if (a_position.x > 0.5) {\n"
+ " v = 0.0;\n"
+ " } else if (a_position.x > 0.75) {\n"
+ " v = 0.5;\n"
+ " }\n"
+ "}\n";
+
+ const std::string &fragmentShaderSource =
+ "precision highp float;\n"
+ "varying float v;\n"
+ "void main() {\n"
+ " gl_FragColor = vec4(v, 0.0, 0.0, 1.0);\n"
+ "}\n";
+
+ GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+ EXPECT_NE(0u, program);
+}
+
+TEST_P(GLSLTest, FrontFacingAndVarying)
+{
+ EGLPlatformParameters platform = GetParam().eglParameters;
+
+ const std::string vertexShaderSource = SHADER_SOURCE
+ (
+ attribute vec4 a_position;
+ varying float v_varying;
+ void main()
+ {
+ v_varying = a_position.x;
+ gl_Position = a_position;
+ }
+ );
+
+ const std::string fragmentShaderSource = SHADER_SOURCE
+ (
+ precision mediump float;
+ varying float v_varying;
+ void main()
+ {
+ vec4 c;
+
+ if (gl_FrontFacing)
+ {
+ c = vec4(v_varying, 0, 0, 1.0);
+ }
+ else
+ {
+ c = vec4(0, v_varying, 0, 1.0);
+ }
+ gl_FragColor = c;
+ }
+ );
+
+ GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+
+ // Compilation should fail on D3D11 feature level 9_3, since gl_FrontFacing isn't supported.
+ if (platform.renderer == EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
+ {
+ if (platform.majorVersion == 9 && platform.minorVersion == 3)
+ {
+ EXPECT_EQ(0u, program);
+ return;
+ }
+ }
+
+ // Otherwise, compilation should succeed
+ EXPECT_NE(0u, program);
+}
+
+// Verify that linking shaders declaring different shading language versions fails.
+TEST_P(GLSLTest_ES3, VersionMismatch)
+{
+ const std::string fragmentShaderSource100 =
+ "precision mediump float;\n"
+ "varying float v_varying;\n"
+ "void main() { gl_FragColor = vec4(v_varying, 0, 0, 1.0); }\n";
+
+ const std::string vertexShaderSource100 =
+ "attribute vec4 a_position;\n"
+ "varying float v_varying;\n"
+ "void main() { v_varying = a_position.x; gl_Position = a_position; }\n";
+
+ const std::string fragmentShaderSource300 =
+ "#version 300 es\n"
+ "precision mediump float;\n"
+ "in float v_varying;\n"
+ "out vec4 my_FragColor;\n"
+ "void main() { my_FragColor = vec4(v_varying, 0, 0, 1.0); }\n";
+
+ const std::string vertexShaderSource300 =
+ "#version 300 es\n"
+ "in vec4 a_position;\n"
+ "out float v_varying;\n"
+ "void main() { v_varying = a_position.x; gl_Position = a_position; }\n";
+
+ GLuint program = CompileProgram(vertexShaderSource300, fragmentShaderSource100);
+ EXPECT_EQ(0u, program);
+
+ program = CompileProgram(vertexShaderSource100, fragmentShaderSource300);
+ EXPECT_EQ(0u, program);
+}
+
+// Verify that declaring varying as invariant only in vertex shader fails in ESSL 1.00.
+TEST_P(GLSLTest, InvariantVaryingOut)
+{
+ const std::string fragmentShaderSource =
+ "precision mediump float;\n"
+ "varying float v_varying;\n"
+ "void main() { gl_FragColor = vec4(v_varying, 0, 0, 1.0); }\n";
+
+ const std::string vertexShaderSource =
+ "attribute vec4 a_position;\n"
+ "invariant varying float v_varying;\n"
+ "void main() { v_varying = a_position.x; gl_Position = a_position; }\n";
+
+ GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+ EXPECT_EQ(0u, program);
+}
+
+// Verify that declaring varying as invariant only in vertex shader succeeds in ESSL 3.00.
+TEST_P(GLSLTest_ES3, InvariantVaryingOut)
+{
+ // TODO: ESSL 3.00 -> GLSL 1.20 translation should add "invariant" in fragment shader
+ // for varyings which are invariant in vertex shader (http://anglebug.com/1293)
+ if (IsDesktopOpenGL())
+ {
+ std::cout << "Test disabled on OpenGL." << std::endl;
+ return;
+ }
+
+ const std::string fragmentShaderSource =
+ "#version 300 es\n"
+ "precision mediump float;\n"
+ "in float v_varying;\n"
+ "out vec4 my_FragColor;\n"
+ "void main() { my_FragColor = vec4(v_varying, 0, 0, 1.0); }\n";
+
+ const std::string vertexShaderSource =
+ "#version 300 es\n"
+ "in vec4 a_position;\n"
+ "invariant out float v_varying;\n"
+ "void main() { v_varying = a_position.x; gl_Position = a_position; }\n";
+
+ GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+ EXPECT_NE(0u, program);
+}
+
+// Verify that declaring varying as invariant only in fragment shader fails in ESSL 1.00.
+TEST_P(GLSLTest, InvariantVaryingIn)
+{
+ const std::string fragmentShaderSource =
+ "precision mediump float;\n"
+ "invariant varying float v_varying;\n"
+ "void main() { gl_FragColor = vec4(v_varying, 0, 0, 1.0); }\n";
+
+ const std::string vertexShaderSource =
+ "attribute vec4 a_position;\n"
+ "varying float v_varying;\n"
+ "void main() { v_varying = a_position.x; gl_Position = a_position; }\n";
+
+ GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+ EXPECT_EQ(0u, program);
+}
+
+// Verify that declaring varying as invariant only in fragment shader fails in ESSL 3.00.
+TEST_P(GLSLTest_ES3, InvariantVaryingIn)
+{
+ const std::string fragmentShaderSource =
+ "#version 300 es\n"
+ "precision mediump float;\n"
+ "invariant in float v_varying;\n"
+ "out vec4 my_FragColor;\n"
+ "void main() { my_FragColor = vec4(v_varying, 0, 0, 1.0); }\n";
+
+ const std::string vertexShaderSource =
+ "#version 300 es\n"
+ "in vec4 a_position;\n"
+ "out float v_varying;\n"
+ "void main() { v_varying = a_position.x; gl_Position = a_position; }\n";
+
+ GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+ EXPECT_EQ(0u, program);
+}
+
+// Verify that declaring varying as invariant in both shaders succeeds in ESSL 1.00.
+TEST_P(GLSLTest, InvariantVaryingBoth)
+{
+ const std::string fragmentShaderSource =
+ "precision mediump float;\n"
+ "invariant varying float v_varying;\n"
+ "void main() { gl_FragColor = vec4(v_varying, 0, 0, 1.0); }\n";
+
+ const std::string vertexShaderSource =
+ "attribute vec4 a_position;\n"
+ "invariant varying float v_varying;\n"
+ "void main() { v_varying = a_position.x; gl_Position = a_position; }\n";
+
+ GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+ EXPECT_NE(0u, program);
+}
+
+// Verify that declaring varying as invariant in both shaders fails in ESSL 3.00.
+TEST_P(GLSLTest_ES3, InvariantVaryingBoth)
+{
+ const std::string fragmentShaderSource =
+ "#version 300 es\n"
+ "precision mediump float;\n"
+ "invariant in float v_varying;\n"
+ "out vec4 my_FragColor;\n"
+ "void main() { my_FragColor = vec4(v_varying, 0, 0, 1.0); }\n";
+
+ const std::string vertexShaderSource =
+ "#version 300 es\n"
+ "in vec4 a_position;\n"
+ "invariant out float v_varying;\n"
+ "void main() { v_varying = a_position.x; gl_Position = a_position; }\n";
+
+ GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+ EXPECT_EQ(0u, program);
+}
+
+// Verify that declaring gl_Position as invariant succeeds in ESSL 1.00.
+TEST_P(GLSLTest, InvariantGLPosition)
+{
+ const std::string fragmentShaderSource =
+ "precision mediump float;\n"
+ "varying float v_varying;\n"
+ "void main() { gl_FragColor = vec4(v_varying, 0, 0, 1.0); }\n";
+
+ const std::string vertexShaderSource =
+ "attribute vec4 a_position;\n"
+ "invariant gl_Position;\n"
+ "varying float v_varying;\n"
+ "void main() { v_varying = a_position.x; gl_Position = a_position; }\n";
+
+ GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+ EXPECT_NE(0u, program);
+}
+
+// Verify that declaring gl_Position as invariant succeeds in ESSL 3.00.
+TEST_P(GLSLTest_ES3, InvariantGLPosition)
+{
+ const std::string fragmentShaderSource =
+ "#version 300 es\n"
+ "precision mediump float;\n"
+ "in float v_varying;\n"
+ "out vec4 my_FragColor;\n"
+ "void main() { my_FragColor = vec4(v_varying, 0, 0, 1.0); }\n";
+
+ const std::string vertexShaderSource =
+ "#version 300 es\n"
+ "in vec4 a_position;\n"
+ "invariant gl_Position;\n"
+ "out float v_varying;\n"
+ "void main() { v_varying = a_position.x; gl_Position = a_position; }\n";
+
+ GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+ EXPECT_NE(0u, program);
+}
+
+// Verify that using invariant(all) in both shaders succeeds in ESSL 1.00.
+TEST_P(GLSLTest, InvariantAllBoth)
+{
+ // TODO: ESSL 1.00 -> GLSL 1.20 translation should add "invariant" in fragment shader
+ // for varyings which are invariant in vertex shader individually,
+ // and remove invariant(all) from fragment shader (http://anglebug.com/1293)
+ if (IsDesktopOpenGL())
+ {
+ std::cout << "Test disabled on OpenGL." << std::endl;
+ return;
+ }
+
+ const std::string fragmentShaderSource =
+ "#pragma STDGL invariant(all)\n"
+ "precision mediump float;\n"
+ "varying float v_varying;\n"
+ "void main() { gl_FragColor = vec4(v_varying, 0, 0, 1.0); }\n";
+
+ const std::string vertexShaderSource =
+ "#pragma STDGL invariant(all)\n"
+ "attribute vec4 a_position;\n"
+ "varying float v_varying;\n"
+ "void main() { v_varying = a_position.x; gl_Position = a_position; }\n";
+
+ GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+ EXPECT_NE(0u, program);
+}
+
+// Verify that functions without return statements still compile
+TEST_P(GLSLTest, MissingReturnFloat)
+{
+ const std::string vertexShaderSource =
+ "varying float v_varying;\n"
+ "float f() { if (v_varying > 0.0) return 1.0; }\n"
+ "void main() { gl_Position = vec4(f(), 0, 0, 1); }\n";
+
+ const std::string fragmentShaderSource =
+ "precision mediump float;\n"
+ "void main() { gl_FragColor = vec4(0, 0, 0, 1); }\n";
+
+ GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+ EXPECT_NE(0u, program);
+}
+
+// Verify that functions without return statements still compile
+TEST_P(GLSLTest, MissingReturnVec2)
+{
+ const std::string vertexShaderSource =
+ "varying float v_varying;\n"
+ "vec2 f() { if (v_varying > 0.0) return vec2(1.0, 1.0); }\n"
+ "void main() { gl_Position = vec4(f().x, 0, 0, 1); }\n";
+
+ const std::string fragmentShaderSource =
+ "precision mediump float;\n"
+ "void main() { gl_FragColor = vec4(0, 0, 0, 1); }\n";
+
+ GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+ EXPECT_NE(0u, program);
+}
+
+// Verify that functions without return statements still compile
+TEST_P(GLSLTest, MissingReturnVec3)
+{
+ const std::string vertexShaderSource =
+ "varying float v_varying;\n"
+ "vec3 f() { if (v_varying > 0.0) return vec3(1.0, 1.0, 1.0); }\n"
+ "void main() { gl_Position = vec4(f().x, 0, 0, 1); }\n";
+
+ const std::string fragmentShaderSource =
+ "precision mediump float;\n"
+ "void main() { gl_FragColor = vec4(0, 0, 0, 1); }\n";
+
+ GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+ EXPECT_NE(0u, program);
+}
+
+// Verify that functions without return statements still compile
+TEST_P(GLSLTest, MissingReturnVec4)
+{
+ const std::string vertexShaderSource =
+ "varying float v_varying;\n"
+ "vec4 f() { if (v_varying > 0.0) return vec4(1.0, 1.0, 1.0, 1.0); }\n"
+ "void main() { gl_Position = vec4(f().x, 0, 0, 1); }\n";
+
+ const std::string fragmentShaderSource =
+ "precision mediump float;\n"
+ "void main() { gl_FragColor = vec4(0, 0, 0, 1); }\n";
+
+ GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+ EXPECT_NE(0u, program);
+}
+
+// Verify that functions without return statements still compile
+TEST_P(GLSLTest, MissingReturnIVec4)
+{
+ const std::string vertexShaderSource =
+ "varying float v_varying;\n"
+ "ivec4 f() { if (v_varying > 0.0) return ivec4(1, 1, 1, 1); }\n"
+ "void main() { gl_Position = vec4(f().x, 0, 0, 1); }\n";
+
+ const std::string fragmentShaderSource =
+ "precision mediump float;\n"
+ "void main() { gl_FragColor = vec4(0, 0, 0, 1); }\n";
+
+ GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+ EXPECT_NE(0u, program);
+}
+
+// Verify that functions without return statements still compile
+TEST_P(GLSLTest, MissingReturnMat4)
+{
+ const std::string vertexShaderSource =
+ "varying float v_varying;\n"
+ "mat4 f() { if (v_varying > 0.0) return mat4(1.0); }\n"
+ "void main() { gl_Position = vec4(f()[0][0], 0, 0, 1); }\n";
+
+ const std::string fragmentShaderSource =
+ "precision mediump float;\n"
+ "void main() { gl_FragColor = vec4(0, 0, 0, 1); }\n";
+
+ GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+ EXPECT_NE(0u, program);
+}
+
+// Verify that functions without return statements still compile
+TEST_P(GLSLTest, MissingReturnStruct)
+{
+ const std::string vertexShaderSource =
+ "varying float v_varying;\n"
+ "struct s { float a; int b; vec2 c; };\n"
+ "s f() { if (v_varying > 0.0) return s(1.0, 1, vec2(1.0, 1.0)); }\n"
+ "void main() { gl_Position = vec4(f().a, 0, 0, 1); }\n";
+
+ const std::string fragmentShaderSource =
+ "precision mediump float;\n"
+ "void main() { gl_FragColor = vec4(0, 0, 0, 1); }\n";
+
+ GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+ EXPECT_NE(0u, program);
+}
+
+// Verify that functions without return statements still compile
+TEST_P(GLSLTest_ES3, MissingReturnArray)
+{
+ const std::string vertexShaderSource =
+ "#version 300 es\n"
+ "in float v_varying;\n"
+ "vec2[2] f() { if (v_varying > 0.0) { return vec2[2](vec2(1.0, 1.0), vec2(1.0, 1.0)); } }\n"
+ "void main() { gl_Position = vec4(f()[0].x, 0, 0, 1); }\n";
+
+ const std::string fragmentShaderSource =
+ "#version 300 es\n"
+ "precision mediump float;\n"
+ "out vec4 my_FragColor;\n"
+ "void main() { my_FragColor = vec4(0, 0, 0, 1); }\n";
+
+ GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+ EXPECT_NE(0u, program);
+}
+
+// Verify that functions without return statements still compile
+TEST_P(GLSLTest_ES3, MissingReturnArrayOfStructs)
+{
+ const std::string vertexShaderSource =
+ "#version 300 es\n"
+ "in float v_varying;\n"
+ "struct s { float a; int b; vec2 c; };\n"
+ "s[2] f() { if (v_varying > 0.0) { return s[2](s(1.0, 1, vec2(1.0, 1.0)), s(1.0, 1, "
+ "vec2(1.0, 1.0))); } }\n"
+ "void main() { gl_Position = vec4(f()[0].a, 0, 0, 1); }\n";
+
+ const std::string fragmentShaderSource =
+ "#version 300 es\n"
+ "precision mediump float;\n"
+ "out vec4 my_FragColor;\n"
+ "void main() { my_FragColor = vec4(0, 0, 0, 1); }\n";
+
+ GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+ EXPECT_NE(0u, program);
+}
+
+// Verify that functions without return statements still compile
+TEST_P(GLSLTest_ES3, MissingReturnStructOfArrays)
+{
+ // TODO(cwallez) remove the suppression once NVIDIA removes the restriction for
+ // GLSL >= 300. It was defined only in GLSL 2.0, section 6.1.
+ if (IsNVIDIA() && IsOpenGLES())
+ {
+ std::cout << "Test skipped on NVIDIA OpenGL ES because it disallows returning "
+ "structure of arrays"
+ << std::endl;
+ return;
+ }
+
+ const std::string vertexShaderSource =
+ "#version 300 es\n"
+ "in float v_varying;\n"
+ "struct s { float a[2]; int b[2]; vec2 c[2]; };\n"
+ "s f() { if (v_varying > 0.0) { return s(float[2](1.0, 1.0), int[2](1, 1),"
+ "vec2[2](vec2(1.0, 1.0), vec2(1.0, 1.0))); } }\n"
+ "void main() { gl_Position = vec4(f().a[0], 0, 0, 1); }\n";
+
+ const std::string fragmentShaderSource =
+ "#version 300 es\n"
+ "precision mediump float;\n"
+ "out vec4 my_FragColor;\n"
+ "void main() { my_FragColor = vec4(0, 0, 0, 1); }\n";
+
+ GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+ EXPECT_NE(0u, program);
+}
+
+// Verify that using invariant(all) in both shaders fails in ESSL 3.00.
+TEST_P(GLSLTest_ES3, InvariantAllBoth)
+{
+ const std::string fragmentShaderSource =
+ "#version 300 es\n"
+ "#pragma STDGL invariant(all)\n"
+ "precision mediump float;\n"
+ "in float v_varying;\n"
+ "out vec4 my_FragColor;\n"
+ "void main() { my_FragColor = vec4(v_varying, 0, 0, 1.0); }\n";
+
+ const std::string vertexShaderSource =
+ "#version 300 es\n"
+ "#pragma STDGL invariant(all)\n"
+ "in vec4 a_position;\n"
+ "out float v_varying;\n"
+ "void main() { v_varying = a_position.x; gl_Position = a_position; }\n";
+
+ GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+ EXPECT_EQ(0u, program);
+}
+
+// Verify that using invariant(all) only in fragment shader fails in ESSL 1.00.
+TEST_P(GLSLTest, InvariantAllIn)
+{
+ const std::string fragmentShaderSource =
+ "#pragma STDGL invariant(all)\n"
+ "precision mediump float;\n"
+ "varying float v_varying;\n"
+ "void main() { gl_FragColor = vec4(v_varying, 0, 0, 1.0); }\n";
+
+ const std::string vertexShaderSource =
+ "attribute vec4 a_position;\n"
+ "varying float v_varying;\n"
+ "void main() { v_varying = a_position.x; gl_Position = a_position; }\n";
+
+ GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+ EXPECT_EQ(0u, program);
+}
+
+// Verify that using invariant(all) only in fragment shader fails in ESSL 3.00.
+TEST_P(GLSLTest_ES3, InvariantAllIn)
+{
+ const std::string fragmentShaderSource =
+ "#version 300 es\n"
+ "#pragma STDGL invariant(all)\n"
+ "precision mediump float;\n"
+ "in float v_varying;\n"
+ "out vec4 my_FragColor;\n"
+ "void main() { my_FragColor = vec4(v_varying, 0, 0, 1.0); }\n";
+
+ const std::string vertexShaderSource =
+ "#version 300 es\n"
+ "in vec4 a_position;\n"
+ "out float v_varying;\n"
+ "void main() { v_varying = a_position.x; gl_Position = a_position; }\n";
+
+ GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+ EXPECT_EQ(0u, program);
+}
+
+// Verify that using invariant(all) only in vertex shader fails in ESSL 1.00.
+TEST_P(GLSLTest, InvariantAllOut)
+{
+ const std::string fragmentShaderSource =
+ "precision mediump float;\n"
+ "varying float v_varying;\n"
+ "void main() { gl_FragColor = vec4(v_varying, 0, 0, 1.0); }\n";
+
+ const std::string vertexShaderSource =
+ "#pragma STDGL invariant(all)\n"
+ "attribute vec4 a_position;\n"
+ "varying float v_varying;\n"
+ "void main() { v_varying = a_position.x; gl_Position = a_position; }\n";
+
+ GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+ EXPECT_EQ(0u, program);
+}
+
+// Verify that using invariant(all) only in vertex shader succeeds in ESSL 3.00.
+TEST_P(GLSLTest_ES3, InvariantAllOut)
+{
+ // TODO: ESSL 3.00 -> GLSL 1.20 translation should add "invariant" in fragment shader
+ // for varyings which are invariant in vertex shader,
+ // because of invariant(all) being used in vertex shader (http://anglebug.com/1293)
+ if (IsDesktopOpenGL())
+ {
+ std::cout << "Test disabled on OpenGL." << std::endl;
+ return;
+ }
+
+ const std::string fragmentShaderSource =
+ "#version 300 es\n"
+ "precision mediump float;\n"
+ "in float v_varying;\n"
+ "out vec4 my_FragColor;\n"
+ "void main() { my_FragColor = vec4(v_varying, 0, 0, 1.0); }\n";
+
+ const std::string vertexShaderSource =
+ "#version 300 es\n"
+ "#pragma STDGL invariant(all)\n"
+ "in vec4 a_position;\n"
+ "out float v_varying;\n"
+ "void main() { v_varying = a_position.x; gl_Position = a_position; }\n";
+
+ GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+ EXPECT_NE(0u, program);
+}
+
+TEST_P(GLSLTest, MaxVaryingVec4)
+{
+#if defined(__APPLE__)
+ // TODO(geofflang): Find out why this doesn't compile on Apple AND OpenGL drivers
+ // (http://anglebug.com/1291)
+ if (IsAMD() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
+ {
+ std::cout << "Test disabled on Apple AMD OpenGL." << std::endl;
+ return;
+ }
+#endif
+
+ GLint maxVaryings = 0;
+ glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
+
+ VaryingTestBase(0, 0, 0, 0, 0, 0, maxVaryings, 0, false, false, false, true);
+}
+
+TEST_P(GLSLTest, MaxMinusTwoVaryingVec4PlusTwoSpecialVariables)
+{
+ GLint maxVaryings = 0;
+ glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
+
+ // Generate shader code that uses gl_FragCoord and gl_PointCoord, two special fragment shader variables.
+ VaryingTestBase(0, 0, 0, 0, 0, 0, maxVaryings - 2, 0, true, true, false, true);
+}
+
+TEST_P(GLSLTest, MaxMinusTwoVaryingVec4PlusThreeSpecialVariables)
+{
+ // TODO(geofflang): Figure out why this fails on OpenGL AMD (http://anglebug.com/1291)
+ if (IsAMD() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
+ {
+ std::cout << "Test disabled on OpenGL." << std::endl;
+ return;
+ }
+
+ GLint maxVaryings = 0;
+ glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
+
+ // Generate shader code that uses gl_FragCoord, gl_PointCoord and gl_PointSize.
+ VaryingTestBase(0, 0, 0, 0, 0, 0, maxVaryings - 2, 0, true, true, true, true);
+}
+
+// Disabled because drivers are allowed to successfully compile shaders that have more than the
+// maximum number of varyings. (http://anglebug.com/1296)
+TEST_P(GLSLTest, DISABLED_MaxVaryingVec4PlusFragCoord)
+{
+ GLint maxVaryings = 0;
+ glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
+
+ // Generate shader code that uses gl_FragCoord, a special fragment shader variables.
+ // This test should fail, since we are really using (maxVaryings + 1) varyings.
+ VaryingTestBase(0, 0, 0, 0, 0, 0, maxVaryings, 0, true, false, false, false);
+}
+
+// Disabled because drivers are allowed to successfully compile shaders that have more than the
+// maximum number of varyings. (http://anglebug.com/1296)
+TEST_P(GLSLTest, DISABLED_MaxVaryingVec4PlusPointCoord)
+{
+ GLint maxVaryings = 0;
+ glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
+
+ // Generate shader code that uses gl_FragCoord, a special fragment shader variables.
+ // This test should fail, since we are really using (maxVaryings + 1) varyings.
+ VaryingTestBase(0, 0, 0, 0, 0, 0, maxVaryings, 0, false, true, false, false);
+}
+
+TEST_P(GLSLTest, MaxVaryingVec3)
+{
+ GLint maxVaryings = 0;
+ glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
+
+ VaryingTestBase(0, 0, 0, 0, maxVaryings, 0, 0, 0, false, false, false, true);
+}
+
+TEST_P(GLSLTest, MaxVaryingVec3Array)
+{
+ GLint maxVaryings = 0;
+ glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
+
+ VaryingTestBase(0, 0, 0, 0, 0, maxVaryings / 2, 0, 0, false, false, false, true);
+}
+
+// Disabled because of a failure in D3D9
+TEST_P(GLSLTest, MaxVaryingVec3AndOneFloat)
+{
+ if (IsD3D9())
+ {
+ std::cout << "Test disabled on D3D9." << std::endl;
+ return;
+ }
+
+ GLint maxVaryings = 0;
+ glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
+
+ VaryingTestBase(1, 0, 0, 0, maxVaryings, 0, 0, 0, false, false, false, true);
+}
+
+// Disabled because of a failure in D3D9
+TEST_P(GLSLTest, MaxVaryingVec3ArrayAndOneFloatArray)
+{
+ if (IsD3D9())
+ {
+ std::cout << "Test disabled on D3D9." << std::endl;
+ return;
+ }
+
+ GLint maxVaryings = 0;
+ glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
+
+ VaryingTestBase(0, 1, 0, 0, 0, maxVaryings / 2, 0, 0, false, false, false, true);
+}
+
+// Disabled because of a failure in D3D9
+TEST_P(GLSLTest, TwiceMaxVaryingVec2)
+{
+ if (IsD3D9())
+ {
+ std::cout << "Test disabled on D3D9." << std::endl;
+ return;
+ }
+
+ if (getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE)
+ {
+ // TODO(geofflang): Figure out why this fails on NVIDIA's GLES driver
+ std::cout << "Test disabled on OpenGL ES." << std::endl;
+ return;
+ }
+
+#if defined(__APPLE__)
+ // TODO(geofflang): Find out why this doesn't compile on Apple AND OpenGL drivers
+ // (http://anglebug.com/1291)
+ if (IsAMD() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
+ {
+ std::cout << "Test disabled on Apple AMD OpenGL." << std::endl;
+ return;
+ }
+#endif
+
+ GLint maxVaryings = 0;
+ glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
+
+ VaryingTestBase(0, 0, 2 * maxVaryings, 0, 0, 0, 0, 0, false, false, false, true);
+}
+
+// Disabled because of a failure in D3D9
+TEST_P(GLSLTest, MaxVaryingVec2Arrays)
+{
+ if (IsD3DSM3())
+ {
+ std::cout << "Test disabled on SM3." << std::endl;
+ return;
+ }
+
+ if (getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE)
+ {
+ // TODO(geofflang): Figure out why this fails on NVIDIA's GLES driver
+ std::cout << "Test disabled on OpenGL ES." << std::endl;
+ return;
+ }
+
+#if defined(__APPLE__)
+ // TODO(geofflang): Find out why this doesn't compile on Apple AND OpenGL drivers
+ // (http://anglebug.com/1291)
+ if (IsAMD() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
+ {
+ std::cout << "Test disabled on Apple AMD OpenGL." << std::endl;
+ return;
+ }
+#endif
+
+ GLint maxVaryings = 0;
+ glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
+
+ VaryingTestBase(0, 0, 0, maxVaryings, 0, 0, 0, 0, false, false, false, true);
+}
+
+// Disabled because drivers are allowed to successfully compile shaders that have more than the
+// maximum number of varyings. (http://anglebug.com/1296)
+TEST_P(GLSLTest, DISABLED_MaxPlusOneVaryingVec3)
+{
+ GLint maxVaryings = 0;
+ glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
+
+ VaryingTestBase(0, 0, 0, 0, maxVaryings + 1, 0, 0, 0, false, false, false, false);
+}
+
+// Disabled because drivers are allowed to successfully compile shaders that have more than the
+// maximum number of varyings. (http://anglebug.com/1296)
+TEST_P(GLSLTest, DISABLED_MaxPlusOneVaryingVec3Array)
+{
+ GLint maxVaryings = 0;
+ glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
+
+ VaryingTestBase(0, 0, 0, 0, 0, maxVaryings / 2 + 1, 0, 0, false, false, false, false);
+}
+
+// Disabled because drivers are allowed to successfully compile shaders that have more than the
+// maximum number of varyings. (http://anglebug.com/1296)
+TEST_P(GLSLTest, DISABLED_MaxVaryingVec3AndOneVec2)
+{
+ GLint maxVaryings = 0;
+ glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
+
+ VaryingTestBase(0, 0, 1, 0, maxVaryings, 0, 0, 0, false, false, false, false);
+}
+
+// Disabled because drivers are allowed to successfully compile shaders that have more than the
+// maximum number of varyings. (http://anglebug.com/1296)
+TEST_P(GLSLTest, DISABLED_MaxPlusOneVaryingVec2)
+{
+ GLint maxVaryings = 0;
+ glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
+
+ VaryingTestBase(0, 0, 2 * maxVaryings + 1, 0, 0, 0, 0, 0, false, false, false, false);
+}
+
+// Disabled because drivers are allowed to successfully compile shaders that have more than the
+// maximum number of varyings. (http://anglebug.com/1296)
+TEST_P(GLSLTest, DISABLED_MaxVaryingVec3ArrayAndMaxPlusOneFloatArray)
+{
+ GLint maxVaryings = 0;
+ glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
+
+ VaryingTestBase(0, maxVaryings / 2 + 1, 0, 0, 0, 0, 0, maxVaryings / 2, false, false, false, false);
+}
+
+// Verify shader source with a fixed length that is less than the null-terminated length will compile.
+TEST_P(GLSLTest, FixedShaderLength)
+{
+ GLuint shader = glCreateShader(GL_FRAGMENT_SHADER);
+
+ const std::string appendGarbage = "abcasdfasdfasdfasdfasdf";
+ const std::string source = "void main() { gl_FragColor = vec4(0, 0, 0, 0); }" + appendGarbage;
+ const char *sourceArray[1] = { source.c_str() };
+ GLint lengths[1] = { static_cast<GLint>(source.length() - appendGarbage.length()) };
+ glShaderSource(shader, static_cast<GLsizei>(ArraySize(sourceArray)), sourceArray, lengths);
+ glCompileShader(shader);
+
+ GLint compileResult;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &compileResult);
+ EXPECT_NE(compileResult, 0);
+}
+
+// Verify that a negative shader source length is treated as a null-terminated length.
+TEST_P(GLSLTest, NegativeShaderLength)
+{
+ GLuint shader = glCreateShader(GL_FRAGMENT_SHADER);
+
+ const char *sourceArray[1] = { "void main() { gl_FragColor = vec4(0, 0, 0, 0); }" };
+ GLint lengths[1] = { -10 };
+ glShaderSource(shader, static_cast<GLsizei>(ArraySize(sourceArray)), sourceArray, lengths);
+ glCompileShader(shader);
+
+ GLint compileResult;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &compileResult);
+ EXPECT_NE(compileResult, 0);
+}
+
+// Check that having an invalid char after the "." doesn't cause an assert.
+TEST_P(GLSLTest, InvalidFieldFirstChar)
+{
+ GLuint shader = glCreateShader(GL_VERTEX_SHADER);
+ const char *source = "void main() {vec4 x; x.}";
+ glShaderSource(shader, 1, &source, 0);
+ glCompileShader(shader);
+
+ GLint compileResult;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &compileResult);
+ EXPECT_EQ(0, compileResult);
+}
+
+// Verify that a length array with mixed positive and negative values compiles.
+TEST_P(GLSLTest, MixedShaderLengths)
+{
+ GLuint shader = glCreateShader(GL_FRAGMENT_SHADER);
+
+ const char *sourceArray[] =
+ {
+ "void main()",
+ "{",
+ " gl_FragColor = vec4(0, 0, 0, 0);",
+ "}",
+ };
+ GLint lengths[] =
+ {
+ -10,
+ 1,
+ static_cast<GLint>(strlen(sourceArray[2])),
+ -1,
+ };
+ ASSERT_EQ(ArraySize(sourceArray), ArraySize(lengths));
+
+ glShaderSource(shader, static_cast<GLsizei>(ArraySize(sourceArray)), sourceArray, lengths);
+ glCompileShader(shader);
+
+ GLint compileResult;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &compileResult);
+ EXPECT_NE(compileResult, 0);
+}
+
+// Verify that zero-length shader source does not affect shader compilation.
+TEST_P(GLSLTest, ZeroShaderLength)
+{
+ GLuint shader = glCreateShader(GL_FRAGMENT_SHADER);
+
+ const char *sourceArray[] =
+ {
+ "adfasdf",
+ "34534",
+ "void main() { gl_FragColor = vec4(0, 0, 0, 0); }",
+ "",
+ "asdfasdfsdsdf",
+ };
+ GLint lengths[] =
+ {
+ 0,
+ 0,
+ -1,
+ 0,
+ 0,
+ };
+ ASSERT_EQ(ArraySize(sourceArray), ArraySize(lengths));
+
+ glShaderSource(shader, static_cast<GLsizei>(ArraySize(sourceArray)), sourceArray, lengths);
+ glCompileShader(shader);
+
+ GLint compileResult;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &compileResult);
+ EXPECT_NE(compileResult, 0);
+}
+
+// Tests that bad index expressions don't crash ANGLE's translator.
+// https://code.google.com/p/angleproject/issues/detail?id=857
+TEST_P(GLSLTest, BadIndexBug)
+{
+ const std::string &fragmentShaderSourceVec =
+ "precision mediump float;\n"
+ "uniform vec4 uniformVec;\n"
+ "void main()\n"
+ "{\n"
+ " gl_FragColor = vec4(uniformVec[int()]);\n"
+ "}";
+
+ GLuint shader = CompileShader(GL_FRAGMENT_SHADER, fragmentShaderSourceVec);
+ EXPECT_EQ(0u, shader);
+
+ if (shader != 0)
+ {
+ glDeleteShader(shader);
+ }
+
+ const std::string &fragmentShaderSourceMat =
+ "precision mediump float;\n"
+ "uniform mat4 uniformMat;\n"
+ "void main()\n"
+ "{\n"
+ " gl_FragColor = vec4(uniformMat[int()]);\n"
+ "}";
+
+ shader = CompileShader(GL_FRAGMENT_SHADER, fragmentShaderSourceMat);
+ EXPECT_EQ(0u, shader);
+
+ if (shader != 0)
+ {
+ glDeleteShader(shader);
+ }
+
+ const std::string &fragmentShaderSourceArray =
+ "precision mediump float;\n"
+ "uniform vec4 uniformArray;\n"
+ "void main()\n"
+ "{\n"
+ " gl_FragColor = vec4(uniformArray[int()]);\n"
+ "}";
+
+ shader = CompileShader(GL_FRAGMENT_SHADER, fragmentShaderSourceArray);
+ EXPECT_EQ(0u, shader);
+
+ if (shader != 0)
+ {
+ glDeleteShader(shader);
+ }
+}
+
+// Test that structs defined in uniforms are translated correctly.
+TEST_P(GLSLTest, StructSpecifiersUniforms)
+{
+ const std::string fragmentShaderSource = SHADER_SOURCE
+ (
+ precision mediump float;
+
+ uniform struct S { float field;} s;
+
+ void main()
+ {
+ gl_FragColor = vec4(1, 0, 0, 1);
+ gl_FragColor.a += s.field;
+ }
+ );
+
+ GLuint program = CompileProgram(mSimpleVSSource, fragmentShaderSource);
+ EXPECT_NE(0u, program);
+}
+
+// Test that gl_DepthRange is not stored as a uniform location. Since uniforms
+// beginning with "gl_" are filtered out by our validation logic, we must
+// bypass the validation to test the behaviour of the implementation.
+// (note this test is still Impl-independent)
+TEST_P(GLSLTest, DepthRangeUniforms)
+{
+ const std::string fragmentShaderSource = SHADER_SOURCE
+ (
+ precision mediump float;
+
+ void main()
+ {
+ gl_FragColor = vec4(gl_DepthRange.near, gl_DepthRange.far, gl_DepthRange.diff, 1);
+ }
+ );
+
+ GLuint program = CompileProgram(mSimpleVSSource, fragmentShaderSource);
+ EXPECT_NE(0u, program);
+
+ // dive into the ANGLE internals, so we can bypass validation.
+ gl::Context *context = reinterpret_cast<gl::Context *>(getEGLWindow()->getContext());
+ gl::Program *glProgram = context->getProgram(program);
+ GLint nearIndex = glProgram->getUniformLocation("gl_DepthRange.near");
+ EXPECT_EQ(-1, nearIndex);
+
+ // Test drawing does not throw an exception.
+ drawQuad(program, "inputAttribute", 0.5f);
+
+ EXPECT_GL_NO_ERROR();
+
+ glDeleteProgram(program);
+}
+
+std::string GenerateSmallPowShader(double base, double exponent)
+{
+ std::stringstream stream;
+
+ stream.precision(8);
+
+ double result = pow(base, exponent);
+
+ stream << "precision highp float;\n"
+ << "float fun(float arg)\n"
+ << "{\n"
+ << " return pow(arg, " << std::fixed << exponent << ");\n"
+ << "}\n"
+ << "\n"
+ << "void main()\n"
+ << "{\n"
+ << " const float a = " << std::scientific << base << ";\n"
+ << " float b = fun(a);\n"
+ << " if (abs(" << result << " - b) < " << std::abs(result * 0.001) << ")\n"
+ << " {\n"
+ << " gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
+ << " }\n"
+ << " else\n"
+ << " {\n"
+ << " gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
+ << " }\n"
+ << "}\n";
+
+ return stream.str();
+}
+
+// Covers the WebGL test 'glsl/bugs/pow-of-small-constant-in-user-defined-function'
+// See http://anglebug.com/851
+TEST_P(GLSLTest, PowOfSmallConstant)
+{
+ std::vector<double> bads;
+ for (int eps = -1; eps <= 1; ++eps)
+ {
+ for (int i = -4; i <= 5; ++i)
+ {
+ if (i >= -1 && i <= 1)
+ continue;
+ const double epsilon = 1.0e-8;
+ double bad = static_cast<double>(i) + static_cast<double>(eps) * epsilon;
+ bads.push_back(bad);
+ }
+ }
+
+ for (double bad : bads)
+ {
+ const std::string &fragmentShaderSource = GenerateSmallPowShader(1.0e-6, bad);
+
+ ANGLE_GL_PROGRAM(program, mSimpleVSSource, fragmentShaderSource);
+
+ drawQuad(program.get(), "inputAttribute", 0.5f);
+
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+ EXPECT_GL_NO_ERROR();
+ }
+}
+
+// Test that fragment shaders which contain non-constant loop indexers and compiled for FL9_3 and
+// below
+// fail with a specific error message.
+// Additionally test that the same fragment shader compiles successfully with feature levels greater
+// than FL9_3.
+TEST_P(GLSLTest, LoopIndexingValidation)
+{
+ const std::string fragmentShaderSource = SHADER_SOURCE
+ (
+ precision mediump float;
+
+ uniform float loopMax;
+
+ void main()
+ {
+ gl_FragColor = vec4(1, 0, 0, 1);
+ for (float l = 0.0; l < loopMax; l++)
+ {
+ if (loopMax > 3.0)
+ {
+ gl_FragColor.a += 0.1;
+ }
+ }
+ }
+ );
+
+ GLuint shader = glCreateShader(GL_FRAGMENT_SHADER);
+
+ const char *sourceArray[1] = {fragmentShaderSource.c_str()};
+ glShaderSource(shader, 1, sourceArray, nullptr);
+ glCompileShader(shader);
+
+ GLint compileResult;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &compileResult);
+
+ // If the test is configured to run limited to Feature Level 9_3, then it is
+ // assumed that shader compilation will fail with an expected error message containing
+ // "Loop index cannot be compared with non-constant expression"
+ if ((GetParam() == ES2_D3D11_FL9_3() || GetParam() == ES2_D3D9()))
+ {
+ if (compileResult != 0)
+ {
+ FAIL() << "Shader compilation succeeded, expected failure";
+ }
+ else
+ {
+ GLint infoLogLength;
+ glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
+
+ std::string infoLog;
+ infoLog.resize(infoLogLength);
+ glGetShaderInfoLog(shader, static_cast<GLsizei>(infoLog.size()), NULL, &infoLog[0]);
+
+ if (infoLog.find("Loop index cannot be compared with non-constant expression") ==
+ std::string::npos)
+ {
+ FAIL() << "Shader compilation failed with unexpected error message";
+ }
+ }
+ }
+ else
+ {
+ EXPECT_NE(0, compileResult);
+ }
+
+ if (shader != 0)
+ {
+ glDeleteShader(shader);
+ }
+}
+
+// Tests that the maximum uniforms count returned from querying GL_MAX_VERTEX_UNIFORM_VECTORS
+// can actually be used.
+TEST_P(GLSLTest, VerifyMaxVertexUniformVectors)
+{
+ int maxUniforms = 10000;
+ glGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &maxUniforms);
+ EXPECT_GL_NO_ERROR();
+ std::cout << "Validating GL_MAX_VERTEX_UNIFORM_VECTORS = " << maxUniforms << std::endl;
+
+ CompileGLSLWithUniformsAndSamplers(maxUniforms, 0, 0, 0, true);
+}
+
+// Tests that the maximum uniforms count returned from querying GL_MAX_VERTEX_UNIFORM_VECTORS
+// can actually be used along with the maximum number of texture samplers.
+TEST_P(GLSLTest, VerifyMaxVertexUniformVectorsWithSamplers)
+{
+ if (GetParam().eglParameters.renderer == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE ||
+ GetParam().eglParameters.renderer == EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE)
+ {
+ std::cout << "Test disabled on OpenGL." << std::endl;
+ return;
+ }
+
+ int maxUniforms = 10000;
+ glGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &maxUniforms);
+ EXPECT_GL_NO_ERROR();
+ std::cout << "Validating GL_MAX_VERTEX_UNIFORM_VECTORS = " << maxUniforms << std::endl;
+
+ int maxTextureImageUnits = 0;
+ glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &maxTextureImageUnits);
+
+ CompileGLSLWithUniformsAndSamplers(maxUniforms, 0, maxTextureImageUnits, 0, true);
+}
+
+// Tests that the maximum uniforms count + 1 from querying GL_MAX_VERTEX_UNIFORM_VECTORS
+// fails shader compilation.
+TEST_P(GLSLTest, VerifyMaxVertexUniformVectorsExceeded)
+{
+ int maxUniforms = 10000;
+ glGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &maxUniforms);
+ EXPECT_GL_NO_ERROR();
+ std::cout << "Validating GL_MAX_VERTEX_UNIFORM_VECTORS + 1 = " << maxUniforms + 1 << std::endl;
+
+ CompileGLSLWithUniformsAndSamplers(maxUniforms + 1, 0, 0, 0, false);
+}
+
+// Tests that the maximum uniforms count returned from querying GL_MAX_FRAGMENT_UNIFORM_VECTORS
+// can actually be used.
+TEST_P(GLSLTest, VerifyMaxFragmentUniformVectors)
+{
+ int maxUniforms = 10000;
+ glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &maxUniforms);
+ EXPECT_GL_NO_ERROR();
+ std::cout << "Validating GL_MAX_FRAGMENT_UNIFORM_VECTORS = " << maxUniforms << std::endl;
+
+ CompileGLSLWithUniformsAndSamplers(0, maxUniforms, 0, 0, true);
+}
+
+// Tests that the maximum uniforms count returned from querying GL_MAX_FRAGMENT_UNIFORM_VECTORS
+// can actually be used along with the maximum number of texture samplers.
+TEST_P(GLSLTest, VerifyMaxFragmentUniformVectorsWithSamplers)
+{
+ if (GetParam().eglParameters.renderer == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE ||
+ GetParam().eglParameters.renderer == EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE)
+ {
+ std::cout << "Test disabled on OpenGL." << std::endl;
+ return;
+ }
+
+ int maxUniforms = 10000;
+ glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &maxUniforms);
+ EXPECT_GL_NO_ERROR();
+
+ int maxTextureImageUnits = 0;
+ glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureImageUnits);
+
+ CompileGLSLWithUniformsAndSamplers(0, maxUniforms, 0, maxTextureImageUnits, true);
+}
+
+// Tests that the maximum uniforms count + 1 from querying GL_MAX_FRAGMENT_UNIFORM_VECTORS
+// fails shader compilation.
+TEST_P(GLSLTest, VerifyMaxFragmentUniformVectorsExceeded)
+{
+ int maxUniforms = 10000;
+ glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &maxUniforms);
+ EXPECT_GL_NO_ERROR();
+ std::cout << "Validating GL_MAX_FRAGMENT_UNIFORM_VECTORS + 1 = " << maxUniforms + 1
+ << std::endl;
+
+ CompileGLSLWithUniformsAndSamplers(0, maxUniforms + 1, 0, 0, false);
+}
+
+// Test that two constructors which have vec4 and mat2 parameters get disambiguated (issue in
+// HLSL).
+TEST_P(GLSLTest_ES3, AmbiguousConstructorCall2x2)
+{
+ const std::string fragmentShaderSource =
+ "#version 300 es\n"
+ "precision highp float;\n"
+ "out vec4 my_FragColor;\n"
+ "void main()\n"
+ "{\n"
+ " my_FragColor = vec4(0.0);\n"
+ "}";
+
+ const std::string vertexShaderSource =
+ "#version 300 es\n"
+ "precision highp float;\n"
+ "in vec4 a_vec;\n"
+ "in mat2 a_mat;\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = vec4(a_vec) + vec4(a_mat);\n"
+ "}";
+
+ GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+ EXPECT_NE(0u, program);
+}
+
+// Test that two constructors which have mat2x3 and mat3x2 parameters get disambiguated.
+// This was suspected to be an issue in HLSL, but HLSL seems to be able to natively choose between
+// the function signatures in this case.
+TEST_P(GLSLTest_ES3, AmbiguousConstructorCall2x3)
+{
+ const std::string fragmentShaderSource =
+ "#version 300 es\n"
+ "precision highp float;\n"
+ "out vec4 my_FragColor;\n"
+ "void main()\n"
+ "{\n"
+ " my_FragColor = vec4(0.0);\n"
+ "}";
+
+ const std::string vertexShaderSource =
+ "#version 300 es\n"
+ "precision highp float;\n"
+ "in mat3x2 a_matA;\n"
+ "in mat2x3 a_matB;\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = vec4(a_matA) + vec4(a_matB);\n"
+ "}";
+
+ GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+ EXPECT_NE(0u, program);
+}
+
+// Test that two functions which have vec4 and mat2 parameters get disambiguated (issue in HLSL).
+TEST_P(GLSLTest_ES3, AmbiguousFunctionCall2x2)
+{
+ const std::string fragmentShaderSource =
+ "#version 300 es\n"
+ "precision highp float;\n"
+ "out vec4 my_FragColor;\n"
+ "void main()\n"
+ "{\n"
+ " my_FragColor = vec4(0.0);\n"
+ "}";
+
+ const std::string vertexShaderSource =
+ "#version 300 es\n"
+ "precision highp float;\n"
+ "in vec4 a_vec;\n"
+ "in mat2 a_mat;\n"
+ "vec4 foo(vec4 a)\n"
+ "{\n"
+ " return a;\n"
+ "}\n"
+ "vec4 foo(mat2 a)\n"
+ "{\n"
+ " return vec4(a[0][0]);\n"
+ "}\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = foo(a_vec) + foo(a_mat);\n"
+ "}";
+
+ GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+ EXPECT_NE(0u, program);
+}
+
+// Test that an user-defined function with a large number of float4 parameters doesn't fail due to
+// the function name being too long.
+TEST_P(GLSLTest_ES3, LargeNumberOfFloat4Parameters)
+{
+ const std::string fragmentShaderSource =
+ "#version 300 es\n"
+ "precision highp float;\n"
+ "out vec4 my_FragColor;\n"
+ "void main()\n"
+ "{\n"
+ " my_FragColor = vec4(0.0);\n"
+ "}";
+
+ std::stringstream vertexShaderStream;
+ const unsigned int paramCount = 1024u;
+
+ vertexShaderStream << "#version 300 es\n"
+ "precision highp float;\n"
+ "in vec4 a_vec;\n"
+ "vec4 lotsOfVec4Parameters(";
+ for (unsigned int i = 0; i < paramCount; ++i)
+ {
+ vertexShaderStream << "vec4 a" << i << ", ";
+ }
+ vertexShaderStream << "vec4 aLast)\n"
+ "{\n"
+ " return ";
+ for (unsigned int i = 0; i < paramCount; ++i)
+ {
+ vertexShaderStream << "a" << i << " + ";
+ }
+ vertexShaderStream << "aLast;\n"
+ "}\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = lotsOfVec4Parameters(";
+ for (unsigned int i = 0; i < paramCount; ++i)
+ {
+ vertexShaderStream << "a_vec, ";
+ }
+ vertexShaderStream << "a_vec);\n"
+ "}";
+
+ GLuint program = CompileProgram(vertexShaderStream.str(), fragmentShaderSource);
+ EXPECT_NE(0u, program);
+}
+
+// This test was written specifically to stress DeferGlobalInitializers AST transformation.
+// Test a shader where a global constant array is initialized with an expression containing array
+// indexing. This initializer is tricky to constant fold, so if it's not constant folded it needs to
+// be handled in a way that doesn't generate statements in the global scope in HLSL output.
+// Also includes multiple array initializers in one declaration, where only the second one has
+// array indexing. This makes sure that the qualifier for the declaration is set correctly if
+// transformations are applied to the declaration also in the case of ESSL output.
+TEST_P(GLSLTest_ES3, InitGlobalArrayWithArrayIndexing)
+{
+ // TODO(ynovikov): re-enable once root cause of http://anglebug.com/1428 is fixed
+ if (IsAndroid() && IsAdreno() && IsOpenGLES())
+ {
+ std::cout << "Test skipped on Adreno OpenGLES on Android." << std::endl;
+ return;
+ }
+
+ const std::string vertexShaderSource =
+ "#version 300 es\n"
+ "precision highp float;\n"
+ "in vec4 a_vec;\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = vec4(a_vec);\n"
+ "}";
+
+ const std::string fragmentShaderSource =
+ "#version 300 es\n"
+ "precision highp float;\n"
+ "out vec4 my_FragColor;\n"
+ "const highp float f[2] = float[2](0.1, 0.2);\n"
+ "const highp float[2] g = float[2](0.3, 0.4), h = float[2](0.5, f[1]);\n"
+ "void main()\n"
+ "{\n"
+ " my_FragColor = vec4(h[1]);\n"
+ "}";
+
+ GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+ EXPECT_NE(0u, program);
+}
+
+// Test that index-constant sampler array indexing is supported.
+TEST_P(GLSLTest, IndexConstantSamplerArrayIndexing)
+{
+ if (IsD3D11_FL93()) {
+ std::cout << "Test skipped on D3D11 FL 9.3." << std::endl;
+ return;
+ }
+
+ const std::string vertexShaderSource =
+ "attribute vec4 vPosition;\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = vPosition;\n"
+ "}";
+
+ const std::string fragmentShaderSource =
+ "precision mediump float;\n"
+ "uniform sampler2D uni[2];\n"
+ "\n"
+ "float zero(int x)\n"
+ "{\n"
+ " return float(x) - float(x);\n"
+ "}\n"
+ "\n"
+ "void main()\n"
+ "{\n"
+ " vec4 c = vec4(0,0,0,0);\n"
+ " for (int ii = 1; ii < 3; ++ii) {\n"
+ " if (c.x > 255.0) {\n"
+ " c.x = 255.0 + zero(ii);\n"
+ " break;\n"
+ " }\n"
+ // Index the sampler array with a predictable loop index (index-constant) as opposed to
+ // a true constant. This is valid in OpenGL ES but isn't in many Desktop OpenGL versions,
+ // without an extension.
+ " c += texture2D(uni[ii - 1], vec2(0.5, 0.5));\n"
+ " }\n"
+ " gl_FragColor = c;\n"
+ "}";
+
+ GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+ EXPECT_NE(0u, program);
+}
+
+// Test that the #pragma directive is supported and doesn't trigger a compilation failure on the
+// native driver. The only pragma that gets passed to the OpenGL driver is "invariant" but we don't
+// want to test its behavior, so don't use any varyings.
+TEST_P(GLSLTest, PragmaDirective)
+{
+ const std::string vertexShaderSource =
+ "#pragma STDGL invariant(all)\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = vec4(1.0, 0.0, 0.0, 1.0);\n"
+ "}\n";
+
+ const std::string fragmentShaderSource =
+ "precision mediump float;\n"
+ "void main()\n"
+ "{\n"
+ " gl_FragColor = vec4(1.0);\n"
+ "}\n";
+
+ GLuint program = CompileProgram(vertexShaderSource, fragmentShaderSource);
+ EXPECT_NE(0u, program);
+}
+
+// Sequence operator evaluates operands from left to right (ESSL 3.00 section 5.9).
+// The function call that returns the array needs to be evaluated after ++j for the expression to
+// return the correct value (true).
+TEST_P(GLSLTest_ES3, SequenceOperatorEvaluationOrderArray)
+{
+ const std::string &fragmentShaderSource =
+ "#version 300 es\n"
+ "precision mediump float;\n"
+ "out vec4 my_FragColor; \n"
+ "int[2] func(int param) {\n"
+ " return int[2](param, param);\n"
+ "}\n"
+ "void main() {\n"
+ " int a[2]; \n"
+ " for (int i = 0; i < 2; ++i) {\n"
+ " a[i] = 1;\n"
+ " }\n"
+ " int j = 0; \n"
+ " bool result = ((++j), (a == func(j)));\n"
+ " my_FragColor = vec4(0.0, (result ? 1.0 : 0.0), 0.0, 1.0);\n"
+ "}\n";
+
+ GLuint program = CompileProgram(mSimpleVSSource, fragmentShaderSource);
+ ASSERT_NE(0u, program);
+
+ drawQuad(program, "inputAttribute", 0.5f);
+
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+}
+
+// Sequence operator evaluates operands from left to right (ESSL 3.00 section 5.9).
+// The short-circuiting expression needs to be evaluated after ++j for the expression to return the
+// correct value (true).
+TEST_P(GLSLTest_ES3, SequenceOperatorEvaluationOrderShortCircuit)
+{
+ const std::string &fragmentShaderSource =
+ "#version 300 es\n"
+ "precision mediump float;\n"
+ "out vec4 my_FragColor; \n"
+ "void main() {\n"
+ " int j = 0; \n"
+ " bool result = ((++j), (j == 1 ? true : (++j == 3)));\n"
+ " my_FragColor = vec4(0.0, ((result && j == 1) ? 1.0 : 0.0), 0.0, 1.0);\n"
+ "}\n";
+
+ GLuint program = CompileProgram(mSimpleVSSource, fragmentShaderSource);
+ ASSERT_NE(0u, program);
+
+ drawQuad(program, "inputAttribute", 0.5f);
+
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+}
+
+// Sequence operator evaluates operands from left to right (ESSL 3.00 section 5.9).
+// Indexing the vector needs to be evaluated after func() for the right result.
+TEST_P(GLSLTest_ES3, SequenceOperatorEvaluationOrderDynamicVectorIndexingInLValue)
+{
+ const std::string &fragmentShaderSource =
+ "#version 300 es\n"
+ "precision mediump float;\n"
+ "out vec4 my_FragColor;\n"
+ "uniform int u_zero;\n"
+ "int sideEffectCount = 0;\n"
+ "float func() {\n"
+ " ++sideEffectCount;\n"
+ " return -1.0;\n"
+ "}\n"
+ "void main() {\n"
+ " vec4 v = vec4(0.0, 2.0, 4.0, 6.0); \n"
+ " float f = (func(), (++v[u_zero + sideEffectCount]));\n"
+ " bool green = abs(f - 3.0) < 0.01 && abs(v[1] - 3.0) < 0.01 && sideEffectCount == 1;\n"
+ " my_FragColor = vec4(0.0, (green ? 1.0 : 0.0), 0.0, 1.0);\n"
+ "}\n";
+
+ GLuint program = CompileProgram(mSimpleVSSource, fragmentShaderSource);
+ ASSERT_NE(0u, program);
+
+ drawQuad(program, "inputAttribute", 0.5f);
+
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+}
+
+// Test that using gl_PointCoord with GL_TRIANGLES doesn't produce a link error.
+// From WebGL test conformance/rendering/point-specific-shader-variables.html
+// See http://anglebug.com/1380
+TEST_P(GLSLTest, RenderTrisWithPointCoord)
+{
+ const std::string &vert =
+ "attribute vec2 aPosition;\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = vec4(aPosition, 0, 1);\n"
+ " gl_PointSize = 1.0;\n"
+ "}";
+ const std::string &frag =
+ "void main()\n"
+ "{\n"
+ " gl_FragColor = vec4(gl_PointCoord.xy, 0, 1);\n"
+ " gl_FragColor = vec4(0, 1, 0, 1);\n"
+ "}";
+
+ ANGLE_GL_PROGRAM(prog, vert, frag);
+ drawQuad(prog.get(), "aPosition", 0.5f);
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+}
+
+// Convers a bug with the integer pow statement workaround.
+TEST_P(GLSLTest, NestedPowStatements)
+{
+ const std::string &vert =
+ "attribute vec2 position;\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = vec4(position, 0, 1);\n"
+ "}";
+ const std::string &frag =
+ "precision mediump float;\n"
+ "float func(float v)\n"
+ "{\n"
+ " float f1 = pow(v, 2.0);\n"
+ " return pow(f1 + v, 2.0);\n"
+ "}\n"
+ "void main()\n"
+ "{\n"
+ " float v = func(2.0);\n"
+ " gl_FragColor = abs(v - 36.0) < 0.001 ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1);\n"
+ "}";
+
+ ANGLE_GL_PROGRAM(prog, vert, frag);
+ drawQuad(prog.get(), "position", 0.5f);
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+}
+
+// Convers a bug with the unary minus operator on signed integer workaround.
+TEST_P(GLSLTest_ES3, UnaryMinusOperatorSignedInt)
+{
+ const std::string &vert =
+ "#version 300 es\n"
+ "in highp vec4 position;\n"
+ "out mediump vec4 v_color;\n"
+ "uniform int ui_one;\n"
+ "uniform int ui_two;\n"
+ "uniform int ui_three;\n"
+ "void main() {\n"
+ " int s[3];\n"
+ " s[0] = ui_one;\n"
+ " s[1] = -(-(-ui_two + 1) + 1);\n" // s[1] = -ui_two
+ " s[2] = ui_three;\n"
+ " int result = 0;\n"
+ " for (int i = 0; i < ui_three; i++) {\n"
+ " result += s[i];\n"
+ " }\n"
+ " v_color = (result == 2) ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1);\n"
+ " gl_Position = position;\n"
+ "}\n";
+ const std::string &frag =
+ "#version 300 es\n"
+ "in mediump vec4 v_color;\n"
+ "layout(location=0) out mediump vec4 o_color;\n"
+ "void main() {\n"
+ " o_color = v_color;\n"
+ "}\n";
+
+ ANGLE_GL_PROGRAM(prog, vert, frag);
+
+ gl::Context *context = reinterpret_cast<gl::Context *>(getEGLWindow()->getContext());
+ gl::Program *glProgram = context->getProgram(prog.get());
+ GLint oneIndex = glProgram->getUniformLocation("ui_one");
+ ASSERT_NE(-1, oneIndex);
+ GLint twoIndex = glProgram->getUniformLocation("ui_two");
+ ASSERT_NE(-1, twoIndex);
+ GLint threeIndex = glProgram->getUniformLocation("ui_three");
+ ASSERT_NE(-1, threeIndex);
+ glUseProgram(prog.get());
+ glUniform1i(oneIndex, 1);
+ glUniform1i(twoIndex, 2);
+ glUniform1i(threeIndex, 3);
+
+ drawQuad(prog.get(), "position", 0.5f);
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+}
+
+// Convers a bug with the unary minus operator on unsigned integer workaround.
+TEST_P(GLSLTest_ES3, UnaryMinusOperatorUnsignedInt)
+{
+ const std::string &vert =
+ "#version 300 es\n"
+ "in highp vec4 position;\n"
+ "out mediump vec4 v_color;\n"
+ "uniform uint ui_one;\n"
+ "uniform uint ui_two;\n"
+ "uniform uint ui_three;\n"
+ "void main() {\n"
+ " uint s[3];\n"
+ " s[0] = ui_one;\n"
+ " s[1] = -(-(-ui_two + 1u) + 1u);\n" // s[1] = -ui_two
+ " s[2] = ui_three;\n"
+ " uint result = 0u;\n"
+ " for (uint i = 0u; i < ui_three; i++) {\n"
+ " result += s[i];\n"
+ " }\n"
+ " v_color = (result == 2u) ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1);\n"
+ " gl_Position = position;\n"
+ "}\n";
+ const std::string &frag =
+ "#version 300 es\n"
+ "in mediump vec4 v_color;\n"
+ "layout(location=0) out mediump vec4 o_color;\n"
+ "void main() {\n"
+ " o_color = v_color;\n"
+ "}\n";
+
+ ANGLE_GL_PROGRAM(prog, vert, frag);
+
+ gl::Context *context = reinterpret_cast<gl::Context *>(getEGLWindow()->getContext());
+ gl::Program *glProgram = context->getProgram(prog.get());
+ GLint oneIndex = glProgram->getUniformLocation("ui_one");
+ ASSERT_NE(-1, oneIndex);
+ GLint twoIndex = glProgram->getUniformLocation("ui_two");
+ ASSERT_NE(-1, twoIndex);
+ GLint threeIndex = glProgram->getUniformLocation("ui_three");
+ ASSERT_NE(-1, threeIndex);
+ glUseProgram(prog.get());
+ glUniform1ui(oneIndex, 1u);
+ glUniform1ui(twoIndex, 2u);
+ glUniform1ui(threeIndex, 3u);
+
+ drawQuad(prog.get(), "position", 0.5f);
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+}
+
+// Test a nested sequence operator with a ternary operator inside. The ternary operator is
+// intended to be such that it gets converted to an if statement on the HLSL backend.
+TEST_P(GLSLTest, NestedSequenceOperatorWithTernaryInside)
+{
+ const std::string &vert =
+ "attribute vec2 position;\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = vec4(position, 0, 1);\n"
+ "}";
+
+ // Note that the uniform keep_flop_positive doesn't need to be set - the test expects it to have
+ // its default value false.
+ const std::string &frag =
+ "precision mediump float;\n"
+ "uniform bool keep_flop_positive;\n"
+ "float flop;\n"
+ "void main() {\n"
+ " flop = -1.0,\n"
+ " (flop *= -1.0,\n"
+ " keep_flop_positive ? 0.0 : flop *= -1.0),\n"
+ " gl_FragColor = vec4(0, -flop, 0, 1);\n"
+ "}";
+
+ ANGLE_GL_PROGRAM(prog, vert, frag);
+ drawQuad(prog.get(), "position", 0.5f);
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+}
+
+// Test that using a sampler2D and samplerExternalOES in the same shader works (anglebug.com/1534)
+TEST_P(GLSLTest, ExternalAnd2DSampler)
+{
+ if (!extensionEnabled("GL_OES_EGL_image_external"))
+ {
+ std::cout << "Test skipped because GL_OES_EGL_image_external is not available."
+ << std::endl;
+ return;
+ }
+
+ const std::string fragmentShader =
+ "precision mediump float;\n"
+ "uniform samplerExternalOES tex0;\n"
+ "uniform sampler2D tex1;\n"
+ "void main(void)\n"
+ "{\n"
+ " vec2 uv = vec2(0.0, 0.0);"
+ " gl_FragColor = texture2D(tex0, uv) + texture2D(tex1, uv);\n"
+ "}\n";
+
+ ANGLE_GL_PROGRAM(program, mSimpleVSSource, fragmentShader);
+}
+
+// Test that using an invalid constant right-shift produces an error.
+TEST_P(GLSLTest_ES3, FoldedInvalidRightShift)
+{
+ const std::string &fragmentShader =
+ "#version 300 es\n"
+ "precision mediump float;\n"
+ "out vec4 color;\n"
+ "void main(void)\n"
+ "{\n"
+ " int diff = -100 >> -100;\n"
+ " color = vec4(float(diff));\n"
+ "}\n";
+
+ GLuint program = CompileProgram(mSimpleVSSource, fragmentShader);
+ EXPECT_EQ(0u, program);
+ glDeleteProgram(program);
+}
+
+// Test that using an invalid constant left-shift produces an error.
+TEST_P(GLSLTest_ES3, FoldedInvalidLeftShift)
+{
+ const std::string &fragmentShader =
+ "#version 300 es\n"
+ "precision mediump float;\n"
+ "out vec4 color;\n"
+ "void main(void)\n"
+ "{\n"
+ " int diff = -100 << -100;\n"
+ " color = vec4(float(diff));\n"
+ "}\n";
+
+ GLuint program = CompileProgram(mSimpleVSSource, fragmentShader);
+ EXPECT_EQ(0u, program);
+ glDeleteProgram(program);
+}
+
+} // anonymous namespace
+
+// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
+ANGLE_INSTANTIATE_TEST(GLSLTest,
+ ES2_D3D9(),
+ ES2_D3D11(),
+ ES2_D3D11_FL9_3(),
+ ES2_OPENGL(),
+ ES3_OPENGL(),
+ ES2_OPENGLES(),
+ ES3_OPENGLES());
+
+// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
+ANGLE_INSTANTIATE_TEST(GLSLTest_ES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());