• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2020 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // The ValidateClipCullDistance function checks if the sum of array sizes for gl_ClipDistance and
7 // gl_CullDistance exceeds gl_MaxCombinedClipAndCullDistances
8 //
9 
10 #include "ValidateClipCullDistance.h"
11 
12 #include "compiler/translator/Diagnostics.h"
13 #include "compiler/translator/SymbolTable.h"
14 #include "compiler/translator/tree_util/IntermTraverse.h"
15 #include "compiler/translator/util.h"
16 
17 namespace sh
18 {
19 
20 namespace
21 {
22 
error(const TIntermSymbol & symbol,const char * reason,TDiagnostics * diagnostics)23 void error(const TIntermSymbol &symbol, const char *reason, TDiagnostics *diagnostics)
24 {
25     diagnostics->error(symbol.getLine(), reason, symbol.getName().data());
26 }
27 
28 class ValidateClipCullDistanceTraverser : public TIntermTraverser
29 {
30   public:
31     ValidateClipCullDistanceTraverser();
32     void validate(TDiagnostics *diagnostics, const unsigned int maxCombinedClipAndCullDistances);
33 
34   private:
35     bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
36     bool visitBinary(Visit visit, TIntermBinary *node) override;
37 
38     unsigned int mClipDistanceSize;
39     unsigned int mCullDistanceSize;
40 
41     unsigned int mMaxClipDistanceIndex;
42     unsigned int mMaxCullDistanceIndex;
43 
44     const TIntermSymbol *mClipDistance;
45     const TIntermSymbol *mCullDistance;
46 };
47 
ValidateClipCullDistanceTraverser()48 ValidateClipCullDistanceTraverser::ValidateClipCullDistanceTraverser()
49     : TIntermTraverser(true, false, false),
50       mClipDistanceSize(0),
51       mCullDistanceSize(0),
52       mMaxClipDistanceIndex(0),
53       mMaxCullDistanceIndex(0),
54       mClipDistance(nullptr),
55       mCullDistance(nullptr)
56 {}
57 
visitDeclaration(Visit visit,TIntermDeclaration * node)58 bool ValidateClipCullDistanceTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node)
59 {
60     const TIntermSequence &sequence = *(node->getSequence());
61 
62     if (sequence.size() != 1)
63     {
64         return true;
65     }
66 
67     const TIntermSymbol *symbol = sequence.front()->getAsSymbolNode();
68     if (symbol == nullptr)
69     {
70         return true;
71     }
72 
73     if (symbol->getName() == "gl_ClipDistance")
74     {
75         mClipDistanceSize = symbol->getOutermostArraySize();
76         mClipDistance     = symbol;
77     }
78     else if (symbol->getName() == "gl_CullDistance")
79     {
80         mCullDistanceSize = symbol->getOutermostArraySize();
81         mCullDistance     = symbol;
82     }
83 
84     return true;
85 }
86 
visitBinary(Visit visit,TIntermBinary * node)87 bool ValidateClipCullDistanceTraverser::visitBinary(Visit visit, TIntermBinary *node)
88 {
89     TOperator op = node->getOp();
90     if (op != EOpIndexDirect && op != EOpIndexIndirect)
91     {
92         return true;
93     }
94 
95     TIntermSymbol *left = node->getLeft()->getAsSymbolNode();
96     if (!left)
97     {
98         return true;
99     }
100 
101     ImmutableString varName(left->getName());
102     if (varName != "gl_ClipDistance" && varName != "gl_CullDistance")
103     {
104         return true;
105     }
106 
107     const TConstantUnion *constIdx = node->getRight()->getConstantValue();
108     if (constIdx)
109     {
110         unsigned int idx = 0;
111         switch (constIdx->getType())
112         {
113             case EbtInt:
114                 idx = constIdx->getIConst();
115                 break;
116             case EbtUInt:
117                 idx = constIdx->getUConst();
118                 break;
119             case EbtFloat:
120                 idx = static_cast<unsigned int>(constIdx->getFConst());
121                 break;
122             case EbtBool:
123                 idx = constIdx->getBConst() ? 1 : 0;
124                 break;
125             default:
126                 UNREACHABLE();
127                 break;
128         }
129 
130         if (varName == "gl_ClipDistance")
131         {
132             if (idx > mMaxClipDistanceIndex)
133             {
134                 mMaxClipDistanceIndex = idx;
135                 if (!mClipDistance)
136                 {
137                     mClipDistance = left;
138                 }
139             }
140         }
141         else
142         {
143             ASSERT(varName == "gl_CullDistance");
144             if (idx > mMaxCullDistanceIndex)
145             {
146                 mMaxCullDistanceIndex = idx;
147                 if (!mCullDistance)
148                 {
149                     mCullDistance = left;
150                 }
151             }
152         }
153     }
154 
155     return true;
156 }
157 
validate(TDiagnostics * diagnostics,const unsigned int maxCombinedClipAndCullDistances)158 void ValidateClipCullDistanceTraverser::validate(TDiagnostics *diagnostics,
159                                                  const unsigned int maxCombinedClipAndCullDistances)
160 {
161     ASSERT(diagnostics);
162 
163     unsigned int enabledClipDistances =
164         (mClipDistanceSize > 0 ? mClipDistanceSize
165                                : (mClipDistance ? mMaxClipDistanceIndex + 1 : 0));
166     unsigned int enabledCullDistances =
167         (mCullDistanceSize > 0 ? mCullDistanceSize
168                                : (mCullDistance ? mMaxCullDistanceIndex + 1 : 0));
169     unsigned int combinedClipAndCullDistances =
170         (enabledClipDistances > 0 && enabledCullDistances > 0
171              ? enabledClipDistances + enabledCullDistances
172              : 0);
173 
174     if (combinedClipAndCullDistances > maxCombinedClipAndCullDistances)
175     {
176         const TIntermSymbol *greaterSymbol =
177             (enabledClipDistances >= enabledCullDistances ? mClipDistance : mCullDistance);
178 
179         std::stringstream strstr = sh::InitializeStream<std::stringstream>();
180         strstr << "The sum of 'gl_ClipDistance' and 'gl_CullDistance' size is greater than "
181                   "gl_MaxCombinedClipAndCullDistances ("
182                << combinedClipAndCullDistances << " > " << maxCombinedClipAndCullDistances << ")";
183         error(*greaterSymbol, strstr.str().c_str(), diagnostics);
184     }
185 }
186 
187 }  // anonymous namespace
188 
ValidateClipCullDistance(TIntermBlock * root,TDiagnostics * diagnostics,const unsigned int maxCombinedClipAndCullDistances)189 bool ValidateClipCullDistance(TIntermBlock *root,
190                               TDiagnostics *diagnostics,
191                               const unsigned int maxCombinedClipAndCullDistances)
192 {
193     ValidateClipCullDistanceTraverser varyingValidator;
194     root->traverse(&varyingValidator);
195     int numErrorsBefore = diagnostics->numErrors();
196     varyingValidator.validate(diagnostics, maxCombinedClipAndCullDistances);
197     return (diagnostics->numErrors() == numErrorsBefore);
198 }
199 
200 }  // namespace sh
201