Remove invariant qualifier for input in fragment shader
ESSL and GLSL are not consistent on invariant matching in vertex shader
and fragment shader. See the following rules:
ESSL 1.00 - input and output must match
ESSL 3.00 - only output, inputs cannot be declared as invariant.
GLSL 1.10.59 - does not exist
GLSL 1.20.8 - input and output must match
GLSL 1.30.10 - input and output must match
GLSL 1.40.8 - input and output must match
GLSL 1.50.11 - input and output must match
GLSL 3.30.6 - input and output must match
GLSL 4.00.9 - input and output must match
GLSL 4.10.6 - input and output must match
GLSL 4.20.11 - input can omit invariant
GLSL 4.30.8 - input can omit invariant
GLSL 4.40.9 - input can omit invariant
GLSL 4.50.5 - input can omit invariant
Since GLSL 4.20, invariant qualifier description were changed to:
"
Only variables output from a shader (including those that are then input
to a subsequent shader) can be candidates for invariance. This includes
user-defined output variables and the built-in output variables. As only
outputs need be declared with invariant, an output from one shader stage
will still match an input of a subsequent stage without the input being
declared as invariant.
"
It's not very clear if input in fragment can be declared as invariant.
Mesa driver disallows use of input declared as invariant in fragment
shader, while other drivers may allow it.
In ESSL 3.00, inputs cannot be declared as invariant. ANGLE should
follow this rule for GLSL >= 4.20.
BUG=chromium:639760
Change-Id: I7f7a07401381ac970488b69752f6d50d4f19d31f
Reviewed-on: https://chromium-review.googlesource.com/400005
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Kenneth Russell <kbr@chromium.org>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/compiler/translator/Compiler.cpp b/src/compiler/translator/Compiler.cpp
index 8e1fc19..06b1581 100644
--- a/src/compiler/translator/Compiler.cpp
+++ b/src/compiler/translator/Compiler.cpp
@@ -23,6 +23,7 @@
#include "compiler/translator/ParseContext.h"
#include "compiler/translator/PruneEmptyDeclarations.h"
#include "compiler/translator/RegenerateStructNames.h"
+#include "compiler/translator/RemoveInvariantDeclaration.h"
#include "compiler/translator/RemovePow.h"
#include "compiler/translator/RewriteDoWhile.h"
#include "compiler/translator/ScalarizeVecAndMatConstructorArgs.h"
@@ -91,6 +92,14 @@
output == SH_GLSL_450_CORE_OUTPUT);
}
+bool IsGLSL420OrNewer(ShShaderOutput output)
+{
+ return (output == SH_GLSL_420_CORE_OUTPUT ||
+ output == SH_GLSL_430_CORE_OUTPUT ||
+ output == SH_GLSL_440_CORE_OUTPUT ||
+ output == SH_GLSL_450_CORE_OUTPUT);
+}
+
size_t GetGlobalMaxTokenSize(ShShaderSpec spec)
{
// WebGL defines a max token legnth of 256, while ES2 leaves max token
@@ -382,6 +391,9 @@
(outputType == SH_GLSL_COMPATIBILITY_OUTPUT)))
initializeGLPosition(root);
+ if (success && shaderType == GL_FRAGMENT_SHADER && IsGLSL420OrNewer(outputType))
+ sh::RemoveInvariantDeclaration(root);
+
// This pass might emit short circuits so keep it before the short circuit unfolding
if (success && (compileOptions & SH_REWRITE_DO_WHILE_LOOPS))
RewriteDoWhile(root, getTemporaryIndex());
diff --git a/src/compiler/translator/Compiler.h b/src/compiler/translator/Compiler.h
index 823832b..2081e6d 100644
--- a/src/compiler/translator/Compiler.h
+++ b/src/compiler/translator/Compiler.h
@@ -38,6 +38,7 @@
// Helper function to check if the shader type is GLSL.
//
bool IsGLSL130OrNewer(ShShaderOutput output);
+bool IsGLSL420OrNewer(ShShaderOutput output);
//
// The base class used to back handles returned to the driver.
diff --git a/src/compiler/translator/OutputGLSLBase.cpp b/src/compiler/translator/OutputGLSLBase.cpp
index 2be8e7e..a041cfa 100644
--- a/src/compiler/translator/OutputGLSLBase.cpp
+++ b/src/compiler/translator/OutputGLSLBase.cpp
@@ -146,8 +146,9 @@
void TOutputGLSLBase::writeVariableType(const TType &type)
{
+ TQualifier qualifier = type.getQualifier();
TInfoSinkBase &out = objSink();
- if (type.isInvariant())
+ if (type.isInvariant() && qualifier != EvqFragmentIn && !IsGLSL420OrNewer(mOutput))
{
out << "invariant ";
}
@@ -156,7 +157,6 @@
TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
declareInterfaceBlockLayout(interfaceBlock);
}
- TQualifier qualifier = type.getQualifier();
if (qualifier != EvqTemporary && qualifier != EvqGlobal)
{
if (IsGLSL130OrNewer(mOutput))
diff --git a/src/compiler/translator/RemoveInvariantDeclaration.cpp b/src/compiler/translator/RemoveInvariantDeclaration.cpp
new file mode 100644
index 0000000..8faf8f6
--- /dev/null
+++ b/src/compiler/translator/RemoveInvariantDeclaration.cpp
@@ -0,0 +1,47 @@
+//
+// Copyright (c) 2016 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 "compiler/translator/RemoveInvariantDeclaration.h"
+
+#include "compiler/translator/IntermNode.h"
+
+namespace sh
+{
+
+namespace
+{
+
+// An AST traverser that removes invariant declaration for input in fragment shader
+// when GLSL > 4.20.
+class RemoveInvariantDeclarationTraverser : public TIntermTraverser
+{
+ public:
+ RemoveInvariantDeclarationTraverser() : TIntermTraverser(true, false, false) {}
+
+ private:
+ bool visitAggregate(Visit visit, TIntermAggregate *node) override
+ {
+ if (node->getOp() == EOpInvariantDeclaration)
+ {
+ TIntermSequence emptyReplacement;
+ mMultiReplacements.push_back(
+ NodeReplaceWithMultipleEntry(getParentNode()->getAsBlock(), node, emptyReplacement));
+ return false;
+ }
+ return true;
+ }
+};
+
+} // anonymous namespace
+
+void RemoveInvariantDeclaration(TIntermNode *root)
+{
+ RemoveInvariantDeclarationTraverser traverser;
+ root->traverse(&traverser);
+ traverser.updateTree();
+}
+
+} // namespace sh
diff --git a/src/compiler/translator/RemoveInvariantDeclaration.h b/src/compiler/translator/RemoveInvariantDeclaration.h
new file mode 100644
index 0000000..cf9d4aa
--- /dev/null
+++ b/src/compiler/translator/RemoveInvariantDeclaration.h
@@ -0,0 +1,18 @@
+//
+// Copyright (c) 2016 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.
+//
+
+#ifndef COMPILER_TRANSLATOR_REMOVEINVARIANTDECLARATION_H_
+#define COMPILER_TRANSLATOR_REMOVEINVARIANTDECLARATION_H_
+
+class TIntermNode;
+namespace sh
+{
+
+void RemoveInvariantDeclaration(TIntermNode *root);
+
+} // namespace sh
+
+#endif // COMPILER_TRANSLATOR_REMOVEINVARIANTDECLARATION_H_