• 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,
33                   const unsigned int maxCullDistances,
34                   const unsigned int maxCombinedClipAndCullDistances,
35                   uint8_t *clipDistanceSizeOut,
36                   uint8_t *cullDistanceSizeOut,
37                   bool *clipDistanceRedeclaredOut,
38                   bool *cullDistanceRedeclaredOut,
39                   bool *clipDistanceUsedOut);
40 
41   private:
42     bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
43     bool visitBinary(Visit visit, TIntermBinary *node) override;
44 
45     uint8_t mClipDistanceSize;
46     uint8_t mCullDistanceSize;
47 
48     int8_t mMaxClipDistanceIndex;
49     int8_t mMaxCullDistanceIndex;
50 
51     bool mHasNonConstClipDistanceIndex;
52     bool mHasNonConstCullDistanceIndex;
53 
54     const TIntermSymbol *mClipDistance;
55     const TIntermSymbol *mCullDistance;
56 };
57 
ValidateClipCullDistanceTraverser()58 ValidateClipCullDistanceTraverser::ValidateClipCullDistanceTraverser()
59     : TIntermTraverser(true, false, false),
60       mClipDistanceSize(0),
61       mCullDistanceSize(0),
62       mMaxClipDistanceIndex(-1),
63       mMaxCullDistanceIndex(-1),
64       mHasNonConstClipDistanceIndex(false),
65       mHasNonConstCullDistanceIndex(false),
66       mClipDistance(nullptr),
67       mCullDistance(nullptr)
68 {}
69 
visitDeclaration(Visit visit,TIntermDeclaration * node)70 bool ValidateClipCullDistanceTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node)
71 {
72     const TIntermSequence &sequence = *(node->getSequence());
73 
74     if (sequence.size() != 1)
75     {
76         return true;
77     }
78 
79     const TIntermSymbol *symbol = sequence.front()->getAsSymbolNode();
80     if (symbol == nullptr)
81     {
82         return true;
83     }
84 
85     if (symbol->getName() == "gl_ClipDistance")
86     {
87         mClipDistanceSize = static_cast<uint8_t>(symbol->getOutermostArraySize());
88         mClipDistance     = symbol;
89     }
90     else if (symbol->getName() == "gl_CullDistance")
91     {
92         mCullDistanceSize = static_cast<uint8_t>(symbol->getOutermostArraySize());
93         mCullDistance     = symbol;
94     }
95 
96     return true;
97 }
98 
visitBinary(Visit visit,TIntermBinary * node)99 bool ValidateClipCullDistanceTraverser::visitBinary(Visit visit, TIntermBinary *node)
100 {
101     TOperator op = node->getOp();
102     if (op != EOpIndexDirect && op != EOpIndexIndirect)
103     {
104         return true;
105     }
106 
107     TIntermSymbol *left = node->getLeft()->getAsSymbolNode();
108     if (!left)
109     {
110         return true;
111     }
112 
113     ImmutableString varName(left->getName());
114     if (varName != "gl_ClipDistance" && varName != "gl_CullDistance")
115     {
116         return true;
117     }
118 
119     const TConstantUnion *constIdx = node->getRight()->getConstantValue();
120     if (constIdx)
121     {
122         int idx = 0;
123         switch (constIdx->getType())
124         {
125             case EbtInt:
126                 idx = constIdx->getIConst();
127                 break;
128             case EbtUInt:
129                 idx = constIdx->getUConst();
130                 break;
131             case EbtFloat:
132                 idx = static_cast<int>(constIdx->getFConst());
133                 break;
134             case EbtBool:
135                 idx = constIdx->getBConst() ? 1 : 0;
136                 break;
137             default:
138                 UNREACHABLE();
139                 break;
140         }
141 
142         if (varName == "gl_ClipDistance")
143         {
144             if (idx > mMaxClipDistanceIndex)
145             {
146                 mMaxClipDistanceIndex = static_cast<int8_t>(idx);
147                 if (!mClipDistance)
148                 {
149                     mClipDistance = left;
150                 }
151             }
152         }
153         else
154         {
155             ASSERT(varName == "gl_CullDistance");
156             if (idx > mMaxCullDistanceIndex)
157             {
158                 mMaxCullDistanceIndex = static_cast<int8_t>(idx);
159                 if (!mCullDistance)
160                 {
161                     mCullDistance = left;
162                 }
163             }
164         }
165     }
166     else
167     {
168         if (varName == "gl_ClipDistance")
169         {
170             mHasNonConstClipDistanceIndex = true;
171             if (!mClipDistance)
172             {
173                 mClipDistance = left;
174             }
175         }
176         else
177         {
178             ASSERT(varName == "gl_CullDistance");
179             mHasNonConstCullDistanceIndex = true;
180             if (!mCullDistance)
181             {
182                 mCullDistance = left;
183             }
184         }
185     }
186 
187     return true;
188 }
189 
validate(TDiagnostics * diagnostics,const unsigned int maxCullDistances,const unsigned int maxCombinedClipAndCullDistances,uint8_t * clipDistanceSizeOut,uint8_t * cullDistanceSizeOut,bool * clipDistanceRedeclaredOut,bool * cullDistanceRedeclaredOut,bool * clipDistanceUsedOut)190 void ValidateClipCullDistanceTraverser::validate(TDiagnostics *diagnostics,
191                                                  const unsigned int maxCullDistances,
192                                                  const unsigned int maxCombinedClipAndCullDistances,
193                                                  uint8_t *clipDistanceSizeOut,
194                                                  uint8_t *cullDistanceSizeOut,
195                                                  bool *clipDistanceRedeclaredOut,
196                                                  bool *cullDistanceRedeclaredOut,
197                                                  bool *clipDistanceUsedOut)
198 {
199     ASSERT(diagnostics);
200 
201     if (mClipDistanceSize == 0 && mHasNonConstClipDistanceIndex)
202     {
203         error(*mClipDistance,
204               "The array must be sized by the shader either redeclaring it with a size or "
205               "indexing it only with constant integral expressions",
206               diagnostics);
207     }
208 
209     if (mCullDistanceSize == 0 && mHasNonConstCullDistanceIndex)
210     {
211         error(*mCullDistance,
212               "The array must be sized by the shader either redeclaring it with a size or "
213               "indexing it only with constant integral expressions",
214               diagnostics);
215     }
216 
217     unsigned int enabledClipDistances =
218         (mClipDistanceSize > 0 ? mClipDistanceSize
219                                : (mClipDistance ? mMaxClipDistanceIndex + 1 : 0));
220     unsigned int enabledCullDistances =
221         (mCullDistanceSize > 0 ? mCullDistanceSize
222                                : (mCullDistance ? mMaxCullDistanceIndex + 1 : 0));
223     unsigned int combinedClipAndCullDistances =
224         (enabledClipDistances > 0 && enabledCullDistances > 0
225              ? enabledClipDistances + enabledCullDistances
226              : 0);
227 
228     if (enabledCullDistances > 0 && maxCullDistances == 0)
229     {
230         error(*mCullDistance, "Cull distance functionality is not available", diagnostics);
231     }
232 
233     if (combinedClipAndCullDistances > maxCombinedClipAndCullDistances)
234     {
235         const TIntermSymbol *greaterSymbol =
236             (enabledClipDistances >= enabledCullDistances ? mClipDistance : mCullDistance);
237 
238         std::stringstream strstr = sh::InitializeStream<std::stringstream>();
239         strstr << "The sum of 'gl_ClipDistance' and 'gl_CullDistance' size is greater than "
240                   "gl_MaxCombinedClipAndCullDistances ("
241                << combinedClipAndCullDistances << " > " << maxCombinedClipAndCullDistances << ")";
242         error(*greaterSymbol, strstr.str().c_str(), diagnostics);
243     }
244 
245     // Update the compiler state
246     *clipDistanceSizeOut = mClipDistanceSize ? mClipDistanceSize : (mMaxClipDistanceIndex + 1);
247     *cullDistanceSizeOut = mCullDistanceSize ? mCullDistanceSize : (mMaxCullDistanceIndex + 1);
248     *clipDistanceRedeclaredOut = mClipDistanceSize != 0;
249     *cullDistanceRedeclaredOut = mCullDistanceSize != 0;
250     *clipDistanceUsedOut       = (mMaxClipDistanceIndex != -1) || mHasNonConstClipDistanceIndex;
251 }
252 
253 }  // anonymous namespace
254 
ValidateClipCullDistance(TIntermBlock * root,TDiagnostics * diagnostics,const unsigned int maxCullDistances,const unsigned int maxCombinedClipAndCullDistances,uint8_t * clipDistanceSizeOut,uint8_t * cullDistanceSizeOut,bool * clipDistanceRedeclaredOut,bool * cullDistanceRedeclaredOut,bool * clipDistanceUsedOut)255 bool ValidateClipCullDistance(TIntermBlock *root,
256                               TDiagnostics *diagnostics,
257                               const unsigned int maxCullDistances,
258                               const unsigned int maxCombinedClipAndCullDistances,
259                               uint8_t *clipDistanceSizeOut,
260                               uint8_t *cullDistanceSizeOut,
261                               bool *clipDistanceRedeclaredOut,
262                               bool *cullDistanceRedeclaredOut,
263                               bool *clipDistanceUsedOut)
264 {
265     ValidateClipCullDistanceTraverser varyingValidator;
266     root->traverse(&varyingValidator);
267     int numErrorsBefore = diagnostics->numErrors();
268     varyingValidator.validate(diagnostics, maxCullDistances, maxCombinedClipAndCullDistances,
269                               clipDistanceSizeOut, cullDistanceSizeOut, clipDistanceRedeclaredOut,
270                               cullDistanceRedeclaredOut, clipDistanceUsedOut);
271     return (diagnostics->numErrors() == numErrorsBefore);
272 }
273 
274 }  // namespace sh
275