summaryrefslogtreecommitdiffstats
path: root/gfx/angle/src/tests/compiler_tests/ShaderVariable_test.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/src/tests/compiler_tests/ShaderVariable_test.cpp')
-rwxr-xr-xgfx/angle/src/tests/compiler_tests/ShaderVariable_test.cpp421
1 files changed, 421 insertions, 0 deletions
diff --git a/gfx/angle/src/tests/compiler_tests/ShaderVariable_test.cpp b/gfx/angle/src/tests/compiler_tests/ShaderVariable_test.cpp
new file mode 100755
index 000000000..53dd93fe4
--- /dev/null
+++ b/gfx/angle/src/tests/compiler_tests/ShaderVariable_test.cpp
@@ -0,0 +1,421 @@
+//
+// Copyright (c) 2014 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.
+//
+// CollectVariables_test.cpp:
+// Some tests for shader inspection
+//
+
+#include "angle_gl.h"
+#include "compiler/translator/Compiler.h"
+#include "gtest/gtest.h"
+#include "GLSLANG/ShaderLang.h"
+
+namespace sh
+{
+
+TEST(ShaderVariableTest, FindInfoByMappedName)
+{
+ // struct A {
+ // float x[2];
+ // vec3 y;
+ // };
+ // struct B {
+ // A a[3];
+ // };
+ // B uni[2];
+ ShaderVariable uni;
+ uni.arraySize = 2;
+ uni.name = "uni";
+ uni.mappedName = "m_uni";
+ uni.structName = "B";
+ {
+ ShaderVariable a;
+ a.arraySize = 3;
+ a.name = "a";
+ a.mappedName = "m_a";
+ a.structName = "A";
+ {
+ ShaderVariable x(GL_FLOAT, 2);
+ x.name = "x";
+ x.mappedName = "m_x";
+ a.fields.push_back(x);
+
+ ShaderVariable y(GL_FLOAT_VEC3, 0);
+ y.name = "y";
+ y.mappedName = "m_y";
+ a.fields.push_back(y);
+ }
+ uni.fields.push_back(a);
+ }
+
+ const ShaderVariable *leafVar = nullptr;
+ std::string originalFullName;
+
+ std::string mappedFullName = "wrongName";
+ EXPECT_FALSE(uni.findInfoByMappedName(
+ mappedFullName, &leafVar, &originalFullName));
+
+ mappedFullName = "m_uni";
+ EXPECT_TRUE(uni.findInfoByMappedName(
+ mappedFullName, &leafVar, &originalFullName));
+ EXPECT_EQ(&uni, leafVar);
+ EXPECT_STREQ("uni", originalFullName.c_str());
+
+ mappedFullName = "m_uni[0].m_a[1].wrongName";
+ EXPECT_FALSE(uni.findInfoByMappedName(
+ mappedFullName, &leafVar, &originalFullName));
+
+ mappedFullName = "m_uni[0].m_a[1].m_x";
+ EXPECT_TRUE(uni.findInfoByMappedName(
+ mappedFullName, &leafVar, &originalFullName));
+ EXPECT_EQ(&(uni.fields[0].fields[0]), leafVar);
+ EXPECT_STREQ("uni[0].a[1].x", originalFullName.c_str());
+
+ mappedFullName = "m_uni[0].m_a[1].m_x[0]";
+ EXPECT_TRUE(uni.findInfoByMappedName(
+ mappedFullName, &leafVar, &originalFullName));
+ EXPECT_EQ(&(uni.fields[0].fields[0]), leafVar);
+ EXPECT_STREQ("uni[0].a[1].x[0]", originalFullName.c_str());
+
+ mappedFullName = "m_uni[0].m_a[1].m_y";
+ EXPECT_TRUE(uni.findInfoByMappedName(
+ mappedFullName, &leafVar, &originalFullName));
+ EXPECT_EQ(&(uni.fields[0].fields[1]), leafVar);
+ EXPECT_STREQ("uni[0].a[1].y", originalFullName.c_str());
+}
+
+TEST(ShaderVariableTest, IsSameUniformWithDifferentFieldOrder)
+{
+ // struct A {
+ // float x;
+ // float y;
+ // };
+ // uniform A uni;
+ Uniform vx_a;
+ vx_a.arraySize = 0;
+ vx_a.name = "uni";
+ vx_a.mappedName = "m_uni";
+ vx_a.structName = "A";
+ {
+ ShaderVariable x(GL_FLOAT, 0);
+ x.name = "x";
+ x.mappedName = "m_x";
+ vx_a.fields.push_back(x);
+
+ ShaderVariable y(GL_FLOAT, 0);
+ y.name = "y";
+ y.mappedName = "m_y";
+ vx_a.fields.push_back(y);
+ }
+
+ // struct A {
+ // float y;
+ // float x;
+ // };
+ // uniform A uni;
+ Uniform fx_a;
+ fx_a.arraySize = 0;
+ fx_a.name = "uni";
+ fx_a.mappedName = "m_uni";
+ fx_a.structName = "A";
+ {
+ ShaderVariable y(GL_FLOAT, 0);
+ y.name = "y";
+ y.mappedName = "m_y";
+ fx_a.fields.push_back(y);
+
+ ShaderVariable x(GL_FLOAT, 0);
+ x.name = "x";
+ x.mappedName = "m_x";
+ fx_a.fields.push_back(x);
+ }
+
+ EXPECT_FALSE(vx_a.isSameUniformAtLinkTime(fx_a));
+}
+
+TEST(ShaderVariableTest, IsSameUniformWithDifferentStructNames)
+{
+ // struct A {
+ // float x;
+ // float y;
+ // };
+ // uniform A uni;
+ Uniform vx_a;
+ vx_a.arraySize = 0;
+ vx_a.name = "uni";
+ vx_a.mappedName = "m_uni";
+ vx_a.structName = "A";
+ {
+ ShaderVariable x(GL_FLOAT, 0);
+ x.name = "x";
+ x.mappedName = "m_x";
+ vx_a.fields.push_back(x);
+
+ ShaderVariable y(GL_FLOAT, 0);
+ y.name = "y";
+ y.mappedName = "m_y";
+ vx_a.fields.push_back(y);
+ }
+
+ // struct B {
+ // float x;
+ // float y;
+ // };
+ // uniform B uni;
+ Uniform fx_a;
+ fx_a.arraySize = 0;
+ fx_a.name = "uni";
+ fx_a.mappedName = "m_uni";
+ {
+ ShaderVariable x(GL_FLOAT, 0);
+ x.name = "x";
+ x.mappedName = "m_x";
+ fx_a.fields.push_back(x);
+
+ ShaderVariable y(GL_FLOAT, 0);
+ y.name = "y";
+ y.mappedName = "m_y";
+ fx_a.fields.push_back(y);
+ }
+
+ fx_a.structName = "B";
+ EXPECT_FALSE(vx_a.isSameUniformAtLinkTime(fx_a));
+
+ fx_a.structName = "A";
+ EXPECT_TRUE(vx_a.isSameUniformAtLinkTime(fx_a));
+
+ fx_a.structName = "";
+ EXPECT_FALSE(vx_a.isSameUniformAtLinkTime(fx_a));
+}
+
+TEST(ShaderVariableTest, IsSameVaryingWithDifferentInvariance)
+{
+ // invariant varying float vary;
+ Varying vx;
+ vx.type = GL_FLOAT;
+ vx.arraySize = 0;
+ vx.precision = GL_MEDIUM_FLOAT;
+ vx.name = "vary";
+ vx.mappedName = "m_vary";
+ vx.staticUse = true;
+ vx.isInvariant = true;
+
+ // varying float vary;
+ Varying fx;
+ fx.type = GL_FLOAT;
+ fx.arraySize = 0;
+ fx.precision = GL_MEDIUM_FLOAT;
+ fx.name = "vary";
+ fx.mappedName = "m_vary";
+ fx.staticUse = true;
+ fx.isInvariant = false;
+
+ // Default to ESSL1 behavior: invariance must match
+ EXPECT_FALSE(vx.isSameVaryingAtLinkTime(fx));
+ EXPECT_FALSE(vx.isSameVaryingAtLinkTime(fx, 100));
+ // ESSL3 behavior: invariance doesn't need to match
+ EXPECT_TRUE(vx.isSameVaryingAtLinkTime(fx, 300));
+
+ // invariant varying float vary;
+ fx.isInvariant = true;
+ EXPECT_TRUE(vx.isSameVaryingAtLinkTime(fx));
+ EXPECT_TRUE(vx.isSameVaryingAtLinkTime(fx, 100));
+ EXPECT_TRUE(vx.isSameVaryingAtLinkTime(fx, 300));
+}
+
+// Test that using invariant varyings doesn't trigger a double delete.
+TEST(ShaderVariableTest, InvariantDoubleDeleteBug)
+{
+ ShBuiltInResources resources;
+ sh::InitBuiltInResources(&resources);
+
+ ShHandle compiler = sh::ConstructCompiler(GL_VERTEX_SHADER, SH_GLES2_SPEC,
+ SH_GLSL_COMPATIBILITY_OUTPUT, &resources);
+ EXPECT_NE(static_cast<ShHandle>(0), compiler);
+
+ const char *program[] =
+ {
+ "attribute vec4 position;\n"
+ "varying float v;\n"
+ "invariant v;\n"
+ "void main() {\n"
+ " v = 1.0;\n"
+ " gl_Position = position;\n"
+ "}"
+ };
+
+ EXPECT_TRUE(sh::Compile(compiler, program, 1, SH_OBJECT_CODE));
+ EXPECT_TRUE(sh::Compile(compiler, program, 1, SH_OBJECT_CODE));
+ sh::Destruct(compiler);
+}
+
+TEST(ShaderVariableTest, IllegalInvariantVarying)
+{
+ ShBuiltInResources resources;
+ sh::InitBuiltInResources(&resources);
+
+ ShHandle compiler = sh::ConstructCompiler(GL_VERTEX_SHADER, SH_GLES2_SPEC,
+ SH_GLSL_COMPATIBILITY_OUTPUT, &resources);
+ EXPECT_NE(static_cast<ShHandle>(0), compiler);
+
+ const char *program1[] =
+ {
+ "void foo() {\n"
+ " vec4 v;\n"
+ "}\n"
+ "varying vec4 v_varying;\n"
+ "invariant v_varying;\n"
+ "void main() {\n"
+ " foo();\n"
+ " gl_Position = v_varying;\n"
+ "}"
+ };
+ const char *program2[] =
+ {
+ "varying vec4 v_varying;\n"
+ "void foo() {\n"
+ " invariant v_varying;\n"
+ "}\n"
+ "void main() {\n"
+ " foo();\n"
+ " gl_Position = v_varying;\n"
+ "}"
+ };
+
+ EXPECT_TRUE(sh::Compile(compiler, program1, 1, SH_VARIABLES));
+ EXPECT_FALSE(sh::Compile(compiler, program2, 1, SH_VARIABLES));
+}
+
+TEST(ShaderVariableTest, InvariantLeakAcrossShaders)
+{
+ ShBuiltInResources resources;
+ sh::InitBuiltInResources(&resources);
+
+ ShHandle compiler = sh::ConstructCompiler(GL_VERTEX_SHADER, SH_GLES2_SPEC,
+ SH_GLSL_COMPATIBILITY_OUTPUT, &resources);
+ EXPECT_NE(static_cast<ShHandle>(0), compiler);
+
+ const char *program1[] =
+ {
+ "varying vec4 v_varying;\n"
+ "invariant v_varying;\n"
+ "void main() {\n"
+ " gl_Position = v_varying;\n"
+ "}"
+ };
+ const char *program2[] =
+ {
+ "varying vec4 v_varying;\n"
+ "void main() {\n"
+ " gl_Position = v_varying;\n"
+ "}"
+ };
+
+ EXPECT_TRUE(sh::Compile(compiler, program1, 1, SH_VARIABLES));
+ const std::vector<sh::Varying> *varyings = sh::GetVaryings(compiler);
+ for (const sh::Varying &varying : *varyings)
+ {
+ if (varying.name == "v_varying")
+ EXPECT_TRUE(varying.isInvariant);
+ }
+ EXPECT_TRUE(sh::Compile(compiler, program2, 1, SH_VARIABLES));
+ varyings = sh::GetVaryings(compiler);
+ for (const sh::Varying &varying : *varyings)
+ {
+ if (varying.name == "v_varying")
+ EXPECT_FALSE(varying.isInvariant);
+ }
+}
+
+TEST(ShaderVariableTest, GlobalInvariantLeakAcrossShaders)
+{
+ ShBuiltInResources resources;
+ sh::InitBuiltInResources(&resources);
+
+ ShHandle compiler = sh::ConstructCompiler(GL_VERTEX_SHADER, SH_GLES2_SPEC,
+ SH_GLSL_COMPATIBILITY_OUTPUT, &resources);
+ EXPECT_NE(static_cast<ShHandle>(0), compiler);
+
+ const char *program1[] =
+ {
+ "#pragma STDGL invariant(all)\n"
+ "varying vec4 v_varying;\n"
+ "void main() {\n"
+ " gl_Position = v_varying;\n"
+ "}"
+ };
+ const char *program2[] =
+ {
+ "varying vec4 v_varying;\n"
+ "void main() {\n"
+ " gl_Position = v_varying;\n"
+ "}"
+ };
+
+ EXPECT_TRUE(sh::Compile(compiler, program1, 1, SH_VARIABLES));
+ const std::vector<sh::Varying> *varyings = sh::GetVaryings(compiler);
+ for (const sh::Varying &varying : *varyings)
+ {
+ if (varying.name == "v_varying")
+ EXPECT_TRUE(varying.isInvariant);
+ }
+ EXPECT_TRUE(sh::Compile(compiler, program2, 1, SH_VARIABLES));
+ varyings = sh::GetVaryings(compiler);
+ for (const sh::Varying &varying : *varyings)
+ {
+ if (varying.name == "v_varying")
+ EXPECT_FALSE(varying.isInvariant);
+ }
+}
+
+TEST(ShaderVariableTest, BuiltinInvariantVarying)
+{
+
+ ShBuiltInResources resources;
+ sh::InitBuiltInResources(&resources);
+
+ ShHandle compiler = sh::ConstructCompiler(GL_VERTEX_SHADER, SH_GLES2_SPEC,
+ SH_GLSL_COMPATIBILITY_OUTPUT, &resources);
+ EXPECT_NE(static_cast<ShHandle>(0), compiler);
+
+ const char *program1[] =
+ {
+ "invariant gl_Position;\n"
+ "void main() {\n"
+ " gl_Position = vec4(0, 0, 0, 0);\n"
+ "}"
+ };
+ const char *program2[] =
+ {
+ "void main() {\n"
+ " gl_Position = vec4(0, 0, 0, 0);\n"
+ "}"
+ };
+ const char *program3[] =
+ {
+ "void main() {\n"
+ " invariant gl_Position;\n"
+ " gl_Position = vec4(0, 0, 0, 0);\n"
+ "}"
+ };
+
+ EXPECT_TRUE(sh::Compile(compiler, program1, 1, SH_VARIABLES));
+ const std::vector<sh::Varying> *varyings = sh::GetVaryings(compiler);
+ for (const sh::Varying &varying : *varyings)
+ {
+ if (varying.name == "gl_Position")
+ EXPECT_TRUE(varying.isInvariant);
+ }
+ EXPECT_TRUE(sh::Compile(compiler, program2, 1, SH_VARIABLES));
+ varyings = sh::GetVaryings(compiler);
+ for (const sh::Varying &varying : *varyings)
+ {
+ if (varying.name == "gl_Position")
+ EXPECT_FALSE(varying.isInvariant);
+ }
+ EXPECT_FALSE(sh::Compile(compiler, program3, 1, SH_VARIABLES));
+}
+
+} // namespace sh