Fix non statically used fragment input structs on HLSL
Add static use information to struct fields that mirrors the static
use information on the struct itself. This way dynamically generated
HLSL doesn't need special handling for initializing fragment inputs
if they are structs.
This fixes a problem with the previous code where dynamically
generated HLSL ended up trying to initialize structs that are not
declared in the HLSL output because they were not being referenced.
BUG=angleproject:2104
TEST=angle_end2end_tests
Change-Id: I21283ce4fe26515d62d95e61f8155dc9a9b44cf1
diff --git a/src/compiler/translator/VariableInfo.cpp b/src/compiler/translator/VariableInfo.cpp
index 83eba11..4d1bba5 100644
--- a/src/compiler/translator/VariableInfo.cpp
+++ b/src/compiler/translator/VariableInfo.cpp
@@ -66,6 +66,24 @@
return nullptr;
}
+// Note that this shouldn't be called for interface blocks - static use information is collected for
+// individual fields in case of interface blocks.
+void MarkStaticallyUsed(ShaderVariable *variable)
+{
+ if (!variable->staticUse)
+ {
+ if (variable->isStruct())
+ {
+ // Conservatively assume all fields are statically used as well.
+ for (auto &field : variable->fields)
+ {
+ MarkStaticallyUsed(&field);
+ }
+ }
+ variable->staticUse = true;
+ }
+}
+
// Traverses the intermediate tree to collect all attributes, uniforms, varyings, fragment outputs,
// and interface blocks.
class CollectVariablesTraverser : public TIntermTraverser
@@ -406,7 +424,7 @@
}
if (var)
{
- var->staticUse = true;
+ MarkStaticallyUsed(var);
}
}
diff --git a/src/libANGLE/Program.cpp b/src/libANGLE/Program.cpp
index 52b8720..d6541d2 100644
--- a/src/libANGLE/Program.cpp
+++ b/src/libANGLE/Program.cpp
@@ -2388,7 +2388,8 @@
// Will get the vertex shader interpolation by default.
auto interpolation = ref.second.get()->interpolation;
- // Interpolation qualifiers must match.
+ // Note that we lose the vertex shader static use information here. The data for the
+ // variable is taken from the fragment shader.
if (output->isStruct())
{
ASSERT(!output->isArray());
diff --git a/src/libANGLE/renderer/d3d/DynamicHLSL.cpp b/src/libANGLE/renderer/d3d/DynamicHLSL.cpp
index 31a73ab..27d2994 100644
--- a/src/libANGLE/renderer/d3d/DynamicHLSL.cpp
+++ b/src/libANGLE/renderer/d3d/DynamicHLSL.cpp
@@ -741,10 +741,9 @@
const auto &varying = *packedVarying.varying;
ASSERT(!varying.isBuiltIn() && !varying.isStruct());
- // Don't reference VS-only transform feedback varyings in the PS.
- // TODO: Consider updating the fragment shader's varyings with a parameter signaling that a
- // varying is only used in the vertex shader in MergeVaryings
- if (packedVarying.vertexOnly || (!varying.staticUse && !packedVarying.isStructField()))
+ // Don't reference VS-only transform feedback varyings in the PS. Note that we're relying on
+ // that the staticUse flag is set according to usage in the fragment shader.
+ if (packedVarying.vertexOnly || !varying.staticUse)
continue;
pixelStream << " ";
diff --git a/src/tests/gl_tests/GLSLTest.cpp b/src/tests/gl_tests/GLSLTest.cpp
index 26e3c61..c92c868 100644
--- a/src/tests/gl_tests/GLSLTest.cpp
+++ b/src/tests/gl_tests/GLSLTest.cpp
@@ -3157,6 +3157,100 @@
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
+// Test that a varying struct that's not statically used in the fragment shader works.
+// GLSL ES 3.00.6 section 4.3.10.
+TEST_P(GLSLTest_ES3, VaryingStructNotStaticallyUsedInFragmentShader)
+{
+ const std::string &vertexShader =
+ "#version 300 es\n"
+ "struct S {\n"
+ " vec4 field;\n"
+ "};\n"
+ "out S varStruct;\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = vec4(1.0);\n"
+ " varStruct.field = vec4(0.0, 0.5, 0.0, 0.0);\n"
+ "}\n";
+
+ const std::string &fragmentShader =
+ "#version 300 es\n"
+ "precision mediump float;\n"
+ "struct S {\n"
+ " vec4 field;\n"
+ "};\n"
+ "in S varStruct;\n"
+ "out vec4 col;\n"
+ "void main()\n"
+ "{\n"
+ " col = vec4(1.0);\n"
+ "}\n";
+
+ ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
+}
+
+// Test that a varying struct that's not declared in the fragment shader links successfully.
+// GLSL ES 3.00.6 section 4.3.10.
+TEST_P(GLSLTest_ES3, VaryingStructNotDeclaredInFragmentShader)
+{
+ const std::string &vertexShader =
+ "#version 300 es\n"
+ "struct S {\n"
+ " vec4 field;\n"
+ "};\n"
+ "out S varStruct;\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = vec4(1.0);\n"
+ " varStruct.field = vec4(0.0, 0.5, 0.0, 0.0);\n"
+ "}\n";
+
+ const std::string &fragmentShader =
+ "#version 300 es\n"
+ "precision mediump float;\n"
+ "out vec4 col;\n"
+ "void main()\n"
+ "{\n"
+ " col = vec4(1.0);\n"
+ "}\n";
+
+ ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
+}
+
+// Test that a varying struct that gets used in the fragment shader works.
+TEST_P(GLSLTest_ES3, VaryingStructUsedInFragmentShader)
+{
+ const std::string &vertexShader =
+ "#version 300 es\n"
+ "in vec4 inputAttribute;\n"
+ "struct S {\n"
+ " vec4 field;\n"
+ "};\n"
+ "out S varStruct;\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = inputAttribute;\n"
+ " varStruct.field = vec4(0.0, 1.0, 0.0, 1.0);\n"
+ "}\n";
+
+ const std::string &fragmentShader =
+ "#version 300 es\n"
+ "precision mediump float;\n"
+ "out vec4 col;\n"
+ "struct S {\n"
+ " vec4 field;\n"
+ "};\n"
+ "in S varStruct;\n"
+ "void main()\n"
+ "{\n"
+ " col = varStruct.field;\n"
+ "}\n";
+
+ ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
+ drawQuad(program.get(), "inputAttribute", 0.5f);
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+}
+
// 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(),