summaryrefslogtreecommitdiffstats
path: root/gfx/angle/checkout/src/compiler/translator/ValidateClipCullDistance.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/checkout/src/compiler/translator/ValidateClipCullDistance.cpp')
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ValidateClipCullDistance.cpp200
1 files changed, 200 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/compiler/translator/ValidateClipCullDistance.cpp b/gfx/angle/checkout/src/compiler/translator/ValidateClipCullDistance.cpp
new file mode 100644
index 0000000000..3ecd8b4295
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ValidateClipCullDistance.cpp
@@ -0,0 +1,200 @@
+//
+// Copyright 2020 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.
+//
+// The ValidateClipCullDistance function checks if the sum of array sizes for gl_ClipDistance and
+// gl_CullDistance exceeds gl_MaxCombinedClipAndCullDistances
+//
+
+#include "ValidateClipCullDistance.h"
+
+#include "compiler/translator/Diagnostics.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+#include "compiler/translator/util.h"
+
+namespace sh
+{
+
+namespace
+{
+
+void error(const TIntermSymbol &symbol, const char *reason, TDiagnostics *diagnostics)
+{
+ diagnostics->error(symbol.getLine(), reason, symbol.getName().data());
+}
+
+class ValidateClipCullDistanceTraverser : public TIntermTraverser
+{
+ public:
+ ValidateClipCullDistanceTraverser();
+ void validate(TDiagnostics *diagnostics, const unsigned int maxCombinedClipAndCullDistances);
+
+ private:
+ bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
+ bool visitBinary(Visit visit, TIntermBinary *node) override;
+
+ unsigned int mClipDistanceSize;
+ unsigned int mCullDistanceSize;
+
+ unsigned int mMaxClipDistanceIndex;
+ unsigned int mMaxCullDistanceIndex;
+
+ const TIntermSymbol *mClipDistance;
+ const TIntermSymbol *mCullDistance;
+};
+
+ValidateClipCullDistanceTraverser::ValidateClipCullDistanceTraverser()
+ : TIntermTraverser(true, false, false),
+ mClipDistanceSize(0),
+ mCullDistanceSize(0),
+ mMaxClipDistanceIndex(0),
+ mMaxCullDistanceIndex(0),
+ mClipDistance(nullptr),
+ mCullDistance(nullptr)
+{}
+
+bool ValidateClipCullDistanceTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node)
+{
+ const TIntermSequence &sequence = *(node->getSequence());
+
+ if (sequence.size() != 1)
+ {
+ return true;
+ }
+
+ const TIntermSymbol *symbol = sequence.front()->getAsSymbolNode();
+ if (symbol == nullptr)
+ {
+ return true;
+ }
+
+ if (symbol->getName() == "gl_ClipDistance")
+ {
+ mClipDistanceSize = symbol->getOutermostArraySize();
+ mClipDistance = symbol;
+ }
+ else if (symbol->getName() == "gl_CullDistance")
+ {
+ mCullDistanceSize = symbol->getOutermostArraySize();
+ mCullDistance = symbol;
+ }
+
+ return true;
+}
+
+bool ValidateClipCullDistanceTraverser::visitBinary(Visit visit, TIntermBinary *node)
+{
+ TOperator op = node->getOp();
+ if (op != EOpIndexDirect && op != EOpIndexIndirect)
+ {
+ return true;
+ }
+
+ TIntermSymbol *left = node->getLeft()->getAsSymbolNode();
+ if (!left)
+ {
+ return true;
+ }
+
+ ImmutableString varName(left->getName());
+ if (varName != "gl_ClipDistance" && varName != "gl_CullDistance")
+ {
+ return true;
+ }
+
+ const TConstantUnion *constIdx = node->getRight()->getConstantValue();
+ if (constIdx)
+ {
+ unsigned int idx = 0;
+ switch (constIdx->getType())
+ {
+ case EbtInt:
+ idx = constIdx->getIConst();
+ break;
+ case EbtUInt:
+ idx = constIdx->getUConst();
+ break;
+ case EbtFloat:
+ idx = static_cast<unsigned int>(constIdx->getFConst());
+ break;
+ case EbtBool:
+ idx = constIdx->getBConst() ? 1 : 0;
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+
+ if (varName == "gl_ClipDistance")
+ {
+ if (idx > mMaxClipDistanceIndex)
+ {
+ mMaxClipDistanceIndex = idx;
+ if (!mClipDistance)
+ {
+ mClipDistance = left;
+ }
+ }
+ }
+ else
+ {
+ ASSERT(varName == "gl_CullDistance");
+ if (idx > mMaxCullDistanceIndex)
+ {
+ mMaxCullDistanceIndex = idx;
+ if (!mCullDistance)
+ {
+ mCullDistance = left;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+void ValidateClipCullDistanceTraverser::validate(TDiagnostics *diagnostics,
+ const unsigned int maxCombinedClipAndCullDistances)
+{
+ ASSERT(diagnostics);
+
+ unsigned int enabledClipDistances =
+ (mClipDistanceSize > 0 ? mClipDistanceSize
+ : (mClipDistance ? mMaxClipDistanceIndex + 1 : 0));
+ unsigned int enabledCullDistances =
+ (mCullDistanceSize > 0 ? mCullDistanceSize
+ : (mCullDistance ? mMaxCullDistanceIndex + 1 : 0));
+ unsigned int combinedClipAndCullDistances =
+ (enabledClipDistances > 0 && enabledCullDistances > 0
+ ? enabledClipDistances + enabledCullDistances
+ : 0);
+
+ if (combinedClipAndCullDistances > maxCombinedClipAndCullDistances)
+ {
+ const TIntermSymbol *greaterSymbol =
+ (enabledClipDistances >= enabledCullDistances ? mClipDistance : mCullDistance);
+
+ std::stringstream strstr = sh::InitializeStream<std::stringstream>();
+ strstr << "The sum of 'gl_ClipDistance' and 'gl_CullDistance' size is greater than "
+ "gl_MaxCombinedClipAndCullDistances ("
+ << combinedClipAndCullDistances << " > " << maxCombinedClipAndCullDistances << ")";
+ error(*greaterSymbol, strstr.str().c_str(), diagnostics);
+ }
+}
+
+} // anonymous namespace
+
+bool ValidateClipCullDistance(TIntermBlock *root,
+ TDiagnostics *diagnostics,
+ const unsigned int maxCombinedClipAndCullDistances)
+{
+ ValidateClipCullDistanceTraverser varyingValidator;
+ root->traverse(&varyingValidator);
+ int numErrorsBefore = diagnostics->numErrors();
+ varyingValidator.validate(diagnostics, maxCombinedClipAndCullDistances);
+ return (diagnostics->numErrors() == numErrorsBefore);
+}
+
+} // namespace sh