Validate gl_FragData and gl_FragColor access after parsing
After this simply declaring both variables invariant is not treated as
static use.
This simplifies ParseContext a bit, but the effect on compiler
performance tests seems marginal.
BUG=angleproject:2450
TEST=angle_unittests
Change-Id: Ib90cb1d2bd1331542d1cd37732f24efb7833036a
Reviewed-on: https://chromium-review.googlesource.com/992112
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/compiler/translator/Compiler.cpp b/src/compiler/translator/Compiler.cpp
index 00785c8..946d1e5 100644
--- a/src/compiler/translator/Compiler.cpp
+++ b/src/compiler/translator/Compiler.cpp
@@ -45,6 +45,7 @@
#include "compiler/translator/tree_ops/UnfoldShortCircuitAST.h"
#include "compiler/translator/tree_ops/UseInterfaceBlockFields.h"
#include "compiler/translator/tree_ops/VectorizeVectorScalarArithmetic.h"
+#include "compiler/translator/tree_util/BuiltIn_autogen.h"
#include "compiler/translator/tree_util/IntermNodePatternMatcher.h"
#include "compiler/translator/util.h"
#include "third_party/compiler/ArrayBoundsClamper.h"
@@ -224,6 +225,51 @@
}
}
+bool ValidateFragColorAndFragData(GLenum shaderType,
+ int shaderVersion,
+ const TSymbolTable &symbolTable,
+ TDiagnostics *diagnostics)
+{
+ if (shaderVersion > 100 || shaderType != GL_FRAGMENT_SHADER)
+ {
+ return true;
+ }
+
+ bool usesFragColor = false;
+ bool usesFragData = false;
+ // This validation is a bit stricter than the spec - it's only an error to write to
+ // both FragData and FragColor. But because it's better not to have reads from undefined
+ // variables, we always return an error if they are both referenced, rather than only if they
+ // are written.
+ if (symbolTable.isStaticallyUsed(*BuiltInVariable::gl_FragColor()) ||
+ symbolTable.isStaticallyUsed(*BuiltInVariable::gl_SecondaryFragColorEXT()))
+ {
+ usesFragColor = true;
+ }
+ // Extension variables may not always be initialized (saves some time at symbol table init).
+ bool secondaryFragDataUsed =
+ symbolTable.gl_SecondaryFragDataEXT() != nullptr &&
+ symbolTable.isStaticallyUsed(*symbolTable.gl_SecondaryFragDataEXT());
+ if (symbolTable.isStaticallyUsed(*symbolTable.gl_FragData()) || secondaryFragDataUsed)
+ {
+ usesFragData = true;
+ }
+ if (usesFragColor && usesFragData)
+ {
+ const char *errorMessage = "cannot use both gl_FragData and gl_FragColor";
+ if (symbolTable.isStaticallyUsed(*BuiltInVariable::gl_SecondaryFragColorEXT()) ||
+ secondaryFragDataUsed)
+ {
+ errorMessage =
+ "cannot use both output variable sets (gl_FragData, gl_SecondaryFragDataEXT)"
+ " and (gl_FragColor, gl_SecondaryFragColorEXT)";
+ }
+ diagnostics->globalError(errorMessage);
+ return false;
+ }
+ return true;
+}
+
} // namespace
TShHandleBase::TShHandleBase()
@@ -450,6 +496,11 @@
return false;
}
+ if (!ValidateFragColorAndFragData(shaderType, shaderVersion, symbolTable, &mDiagnostics))
+ {
+ return false;
+ }
+
// Fold expressions that could not be folded before validation that was done as a part of
// parsing.
FoldExpressions(root, &mDiagnostics);