xref: /aosp_15_r20/external/angle/src/compiler/translator/ValidateClipCullDistance.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1*8975f5c5SAndroid Build Coastguard Worker //
2*8975f5c5SAndroid Build Coastguard Worker // Copyright 2020 The ANGLE Project Authors. All rights reserved.
3*8975f5c5SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
4*8975f5c5SAndroid Build Coastguard Worker // found in the LICENSE file.
5*8975f5c5SAndroid Build Coastguard Worker //
6*8975f5c5SAndroid Build Coastguard Worker // The ValidateClipCullDistance function:
7*8975f5c5SAndroid Build Coastguard Worker // * gathers clip/cull distance usages
8*8975f5c5SAndroid Build Coastguard Worker // * checks if the sum of array sizes for gl_ClipDistance and
9*8975f5c5SAndroid Build Coastguard Worker //   gl_CullDistance exceeds gl_MaxCombinedClipAndCullDistances
10*8975f5c5SAndroid Build Coastguard Worker // * checks if length() operator is used correctly
11*8975f5c5SAndroid Build Coastguard Worker // * adds an explicit clip/cull distance declaration
12*8975f5c5SAndroid Build Coastguard Worker //
13*8975f5c5SAndroid Build Coastguard Worker 
14*8975f5c5SAndroid Build Coastguard Worker #include "ValidateClipCullDistance.h"
15*8975f5c5SAndroid Build Coastguard Worker 
16*8975f5c5SAndroid Build Coastguard Worker #include "compiler/translator/Diagnostics.h"
17*8975f5c5SAndroid Build Coastguard Worker #include "compiler/translator/SymbolTable.h"
18*8975f5c5SAndroid Build Coastguard Worker #include "compiler/translator/tree_util/IntermTraverse.h"
19*8975f5c5SAndroid Build Coastguard Worker #include "compiler/translator/tree_util/ReplaceVariable.h"
20*8975f5c5SAndroid Build Coastguard Worker #include "compiler/translator/util.h"
21*8975f5c5SAndroid Build Coastguard Worker 
22*8975f5c5SAndroid Build Coastguard Worker namespace sh
23*8975f5c5SAndroid Build Coastguard Worker {
24*8975f5c5SAndroid Build Coastguard Worker 
25*8975f5c5SAndroid Build Coastguard Worker namespace
26*8975f5c5SAndroid Build Coastguard Worker {
27*8975f5c5SAndroid Build Coastguard Worker 
error(const TIntermSymbol & symbol,const char * reason,TDiagnostics * diagnostics)28*8975f5c5SAndroid Build Coastguard Worker void error(const TIntermSymbol &symbol, const char *reason, TDiagnostics *diagnostics)
29*8975f5c5SAndroid Build Coastguard Worker {
30*8975f5c5SAndroid Build Coastguard Worker     diagnostics->error(symbol.getLine(), reason, symbol.getName().data());
31*8975f5c5SAndroid Build Coastguard Worker }
32*8975f5c5SAndroid Build Coastguard Worker 
33*8975f5c5SAndroid Build Coastguard Worker class ValidateClipCullDistanceTraverser : public TIntermTraverser
34*8975f5c5SAndroid Build Coastguard Worker {
35*8975f5c5SAndroid Build Coastguard Worker   public:
36*8975f5c5SAndroid Build Coastguard Worker     ValidateClipCullDistanceTraverser();
37*8975f5c5SAndroid Build Coastguard Worker     void validate(TDiagnostics *diagnostics,
38*8975f5c5SAndroid Build Coastguard Worker                   const unsigned int maxCombinedClipAndCullDistances,
39*8975f5c5SAndroid Build Coastguard Worker                   uint8_t *clipDistanceSizeOut,
40*8975f5c5SAndroid Build Coastguard Worker                   uint8_t *cullDistanceSizeOut,
41*8975f5c5SAndroid Build Coastguard Worker                   bool *clipDistanceRedeclaredOut,
42*8975f5c5SAndroid Build Coastguard Worker                   bool *cullDistanceRedeclaredOut,
43*8975f5c5SAndroid Build Coastguard Worker                   bool *clipDistanceUsedOut);
44*8975f5c5SAndroid Build Coastguard Worker 
45*8975f5c5SAndroid Build Coastguard Worker   private:
46*8975f5c5SAndroid Build Coastguard Worker     bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
47*8975f5c5SAndroid Build Coastguard Worker     bool visitBinary(Visit visit, TIntermBinary *node) override;
48*8975f5c5SAndroid Build Coastguard Worker 
49*8975f5c5SAndroid Build Coastguard Worker     uint8_t mClipDistanceSize;
50*8975f5c5SAndroid Build Coastguard Worker     uint8_t mCullDistanceSize;
51*8975f5c5SAndroid Build Coastguard Worker 
52*8975f5c5SAndroid Build Coastguard Worker     int8_t mMaxClipDistanceIndex;
53*8975f5c5SAndroid Build Coastguard Worker     int8_t mMaxCullDistanceIndex;
54*8975f5c5SAndroid Build Coastguard Worker 
55*8975f5c5SAndroid Build Coastguard Worker     bool mHasNonConstClipDistanceIndex;
56*8975f5c5SAndroid Build Coastguard Worker     bool mHasNonConstCullDistanceIndex;
57*8975f5c5SAndroid Build Coastguard Worker 
58*8975f5c5SAndroid Build Coastguard Worker     const TIntermSymbol *mClipDistance;
59*8975f5c5SAndroid Build Coastguard Worker     const TIntermSymbol *mCullDistance;
60*8975f5c5SAndroid Build Coastguard Worker };
61*8975f5c5SAndroid Build Coastguard Worker 
ValidateClipCullDistanceTraverser()62*8975f5c5SAndroid Build Coastguard Worker ValidateClipCullDistanceTraverser::ValidateClipCullDistanceTraverser()
63*8975f5c5SAndroid Build Coastguard Worker     : TIntermTraverser(true, false, false),
64*8975f5c5SAndroid Build Coastguard Worker       mClipDistanceSize(0),
65*8975f5c5SAndroid Build Coastguard Worker       mCullDistanceSize(0),
66*8975f5c5SAndroid Build Coastguard Worker       mMaxClipDistanceIndex(-1),
67*8975f5c5SAndroid Build Coastguard Worker       mMaxCullDistanceIndex(-1),
68*8975f5c5SAndroid Build Coastguard Worker       mHasNonConstClipDistanceIndex(false),
69*8975f5c5SAndroid Build Coastguard Worker       mHasNonConstCullDistanceIndex(false),
70*8975f5c5SAndroid Build Coastguard Worker       mClipDistance(nullptr),
71*8975f5c5SAndroid Build Coastguard Worker       mCullDistance(nullptr)
72*8975f5c5SAndroid Build Coastguard Worker {}
73*8975f5c5SAndroid Build Coastguard Worker 
visitDeclaration(Visit visit,TIntermDeclaration * node)74*8975f5c5SAndroid Build Coastguard Worker bool ValidateClipCullDistanceTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node)
75*8975f5c5SAndroid Build Coastguard Worker {
76*8975f5c5SAndroid Build Coastguard Worker     const TIntermSequence &sequence = *(node->getSequence());
77*8975f5c5SAndroid Build Coastguard Worker 
78*8975f5c5SAndroid Build Coastguard Worker     if (sequence.size() != 1)
79*8975f5c5SAndroid Build Coastguard Worker     {
80*8975f5c5SAndroid Build Coastguard Worker         return true;
81*8975f5c5SAndroid Build Coastguard Worker     }
82*8975f5c5SAndroid Build Coastguard Worker 
83*8975f5c5SAndroid Build Coastguard Worker     const TIntermSymbol *symbol = sequence.front()->getAsSymbolNode();
84*8975f5c5SAndroid Build Coastguard Worker     if (symbol == nullptr)
85*8975f5c5SAndroid Build Coastguard Worker     {
86*8975f5c5SAndroid Build Coastguard Worker         return true;
87*8975f5c5SAndroid Build Coastguard Worker     }
88*8975f5c5SAndroid Build Coastguard Worker 
89*8975f5c5SAndroid Build Coastguard Worker     if (symbol->getName() == "gl_ClipDistance")
90*8975f5c5SAndroid Build Coastguard Worker     {
91*8975f5c5SAndroid Build Coastguard Worker         mClipDistanceSize = static_cast<uint8_t>(symbol->getOutermostArraySize());
92*8975f5c5SAndroid Build Coastguard Worker         mClipDistance     = symbol;
93*8975f5c5SAndroid Build Coastguard Worker     }
94*8975f5c5SAndroid Build Coastguard Worker     else if (symbol->getName() == "gl_CullDistance")
95*8975f5c5SAndroid Build Coastguard Worker     {
96*8975f5c5SAndroid Build Coastguard Worker         mCullDistanceSize = static_cast<uint8_t>(symbol->getOutermostArraySize());
97*8975f5c5SAndroid Build Coastguard Worker         mCullDistance     = symbol;
98*8975f5c5SAndroid Build Coastguard Worker     }
99*8975f5c5SAndroid Build Coastguard Worker 
100*8975f5c5SAndroid Build Coastguard Worker     return true;
101*8975f5c5SAndroid Build Coastguard Worker }
102*8975f5c5SAndroid Build Coastguard Worker 
visitBinary(Visit visit,TIntermBinary * node)103*8975f5c5SAndroid Build Coastguard Worker bool ValidateClipCullDistanceTraverser::visitBinary(Visit visit, TIntermBinary *node)
104*8975f5c5SAndroid Build Coastguard Worker {
105*8975f5c5SAndroid Build Coastguard Worker     TOperator op = node->getOp();
106*8975f5c5SAndroid Build Coastguard Worker     if (op != EOpIndexDirect && op != EOpIndexIndirect)
107*8975f5c5SAndroid Build Coastguard Worker     {
108*8975f5c5SAndroid Build Coastguard Worker         return true;
109*8975f5c5SAndroid Build Coastguard Worker     }
110*8975f5c5SAndroid Build Coastguard Worker 
111*8975f5c5SAndroid Build Coastguard Worker     TIntermSymbol *left = node->getLeft()->getAsSymbolNode();
112*8975f5c5SAndroid Build Coastguard Worker     if (!left)
113*8975f5c5SAndroid Build Coastguard Worker     {
114*8975f5c5SAndroid Build Coastguard Worker         return true;
115*8975f5c5SAndroid Build Coastguard Worker     }
116*8975f5c5SAndroid Build Coastguard Worker 
117*8975f5c5SAndroid Build Coastguard Worker     ImmutableString varName(left->getName());
118*8975f5c5SAndroid Build Coastguard Worker     if (varName != "gl_ClipDistance" && varName != "gl_CullDistance")
119*8975f5c5SAndroid Build Coastguard Worker     {
120*8975f5c5SAndroid Build Coastguard Worker         return true;
121*8975f5c5SAndroid Build Coastguard Worker     }
122*8975f5c5SAndroid Build Coastguard Worker 
123*8975f5c5SAndroid Build Coastguard Worker     const TConstantUnion *constIdx = node->getRight()->getConstantValue();
124*8975f5c5SAndroid Build Coastguard Worker     if (constIdx)
125*8975f5c5SAndroid Build Coastguard Worker     {
126*8975f5c5SAndroid Build Coastguard Worker         int idx = 0;
127*8975f5c5SAndroid Build Coastguard Worker         switch (constIdx->getType())
128*8975f5c5SAndroid Build Coastguard Worker         {
129*8975f5c5SAndroid Build Coastguard Worker             case EbtInt:
130*8975f5c5SAndroid Build Coastguard Worker                 idx = constIdx->getIConst();
131*8975f5c5SAndroid Build Coastguard Worker                 break;
132*8975f5c5SAndroid Build Coastguard Worker             case EbtUInt:
133*8975f5c5SAndroid Build Coastguard Worker                 idx = constIdx->getUConst();
134*8975f5c5SAndroid Build Coastguard Worker                 break;
135*8975f5c5SAndroid Build Coastguard Worker             default:
136*8975f5c5SAndroid Build Coastguard Worker                 UNREACHABLE();
137*8975f5c5SAndroid Build Coastguard Worker                 break;
138*8975f5c5SAndroid Build Coastguard Worker         }
139*8975f5c5SAndroid Build Coastguard Worker 
140*8975f5c5SAndroid Build Coastguard Worker         if (varName == "gl_ClipDistance")
141*8975f5c5SAndroid Build Coastguard Worker         {
142*8975f5c5SAndroid Build Coastguard Worker             if (idx > mMaxClipDistanceIndex)
143*8975f5c5SAndroid Build Coastguard Worker             {
144*8975f5c5SAndroid Build Coastguard Worker                 mMaxClipDistanceIndex = static_cast<int8_t>(idx);
145*8975f5c5SAndroid Build Coastguard Worker                 if (!mClipDistance)
146*8975f5c5SAndroid Build Coastguard Worker                 {
147*8975f5c5SAndroid Build Coastguard Worker                     mClipDistance = left;
148*8975f5c5SAndroid Build Coastguard Worker                 }
149*8975f5c5SAndroid Build Coastguard Worker             }
150*8975f5c5SAndroid Build Coastguard Worker         }
151*8975f5c5SAndroid Build Coastguard Worker         else
152*8975f5c5SAndroid Build Coastguard Worker         {
153*8975f5c5SAndroid Build Coastguard Worker             ASSERT(varName == "gl_CullDistance");
154*8975f5c5SAndroid Build Coastguard Worker             if (idx > mMaxCullDistanceIndex)
155*8975f5c5SAndroid Build Coastguard Worker             {
156*8975f5c5SAndroid Build Coastguard Worker                 mMaxCullDistanceIndex = static_cast<int8_t>(idx);
157*8975f5c5SAndroid Build Coastguard Worker                 if (!mCullDistance)
158*8975f5c5SAndroid Build Coastguard Worker                 {
159*8975f5c5SAndroid Build Coastguard Worker                     mCullDistance = left;
160*8975f5c5SAndroid Build Coastguard Worker                 }
161*8975f5c5SAndroid Build Coastguard Worker             }
162*8975f5c5SAndroid Build Coastguard Worker         }
163*8975f5c5SAndroid Build Coastguard Worker     }
164*8975f5c5SAndroid Build Coastguard Worker     else
165*8975f5c5SAndroid Build Coastguard Worker     {
166*8975f5c5SAndroid Build Coastguard Worker         if (varName == "gl_ClipDistance")
167*8975f5c5SAndroid Build Coastguard Worker         {
168*8975f5c5SAndroid Build Coastguard Worker             mHasNonConstClipDistanceIndex = true;
169*8975f5c5SAndroid Build Coastguard Worker             if (!mClipDistance)
170*8975f5c5SAndroid Build Coastguard Worker             {
171*8975f5c5SAndroid Build Coastguard Worker                 mClipDistance = left;
172*8975f5c5SAndroid Build Coastguard Worker             }
173*8975f5c5SAndroid Build Coastguard Worker         }
174*8975f5c5SAndroid Build Coastguard Worker         else
175*8975f5c5SAndroid Build Coastguard Worker         {
176*8975f5c5SAndroid Build Coastguard Worker             ASSERT(varName == "gl_CullDistance");
177*8975f5c5SAndroid Build Coastguard Worker             mHasNonConstCullDistanceIndex = true;
178*8975f5c5SAndroid Build Coastguard Worker             if (!mCullDistance)
179*8975f5c5SAndroid Build Coastguard Worker             {
180*8975f5c5SAndroid Build Coastguard Worker                 mCullDistance = left;
181*8975f5c5SAndroid Build Coastguard Worker             }
182*8975f5c5SAndroid Build Coastguard Worker         }
183*8975f5c5SAndroid Build Coastguard Worker     }
184*8975f5c5SAndroid Build Coastguard Worker 
185*8975f5c5SAndroid Build Coastguard Worker     return true;
186*8975f5c5SAndroid Build Coastguard Worker }
187*8975f5c5SAndroid Build Coastguard Worker 
validate(TDiagnostics * diagnostics,const unsigned int maxCombinedClipAndCullDistances,uint8_t * clipDistanceSizeOut,uint8_t * cullDistanceSizeOut,bool * clipDistanceRedeclaredOut,bool * cullDistanceRedeclaredOut,bool * clipDistanceUsedOut)188*8975f5c5SAndroid Build Coastguard Worker void ValidateClipCullDistanceTraverser::validate(TDiagnostics *diagnostics,
189*8975f5c5SAndroid Build Coastguard Worker                                                  const unsigned int maxCombinedClipAndCullDistances,
190*8975f5c5SAndroid Build Coastguard Worker                                                  uint8_t *clipDistanceSizeOut,
191*8975f5c5SAndroid Build Coastguard Worker                                                  uint8_t *cullDistanceSizeOut,
192*8975f5c5SAndroid Build Coastguard Worker                                                  bool *clipDistanceRedeclaredOut,
193*8975f5c5SAndroid Build Coastguard Worker                                                  bool *cullDistanceRedeclaredOut,
194*8975f5c5SAndroid Build Coastguard Worker                                                  bool *clipDistanceUsedOut)
195*8975f5c5SAndroid Build Coastguard Worker {
196*8975f5c5SAndroid Build Coastguard Worker     ASSERT(diagnostics);
197*8975f5c5SAndroid Build Coastguard Worker 
198*8975f5c5SAndroid Build Coastguard Worker     if (mClipDistanceSize == 0 && mHasNonConstClipDistanceIndex)
199*8975f5c5SAndroid Build Coastguard Worker     {
200*8975f5c5SAndroid Build Coastguard Worker         error(*mClipDistance,
201*8975f5c5SAndroid Build Coastguard Worker               "The array must be sized by the shader either redeclaring it with a size or "
202*8975f5c5SAndroid Build Coastguard Worker               "indexing it only with constant integral expressions",
203*8975f5c5SAndroid Build Coastguard Worker               diagnostics);
204*8975f5c5SAndroid Build Coastguard Worker     }
205*8975f5c5SAndroid Build Coastguard Worker 
206*8975f5c5SAndroid Build Coastguard Worker     if (mCullDistanceSize == 0 && mHasNonConstCullDistanceIndex)
207*8975f5c5SAndroid Build Coastguard Worker     {
208*8975f5c5SAndroid Build Coastguard Worker         error(*mCullDistance,
209*8975f5c5SAndroid Build Coastguard Worker               "The array must be sized by the shader either redeclaring it with a size or "
210*8975f5c5SAndroid Build Coastguard Worker               "indexing it only with constant integral expressions",
211*8975f5c5SAndroid Build Coastguard Worker               diagnostics);
212*8975f5c5SAndroid Build Coastguard Worker     }
213*8975f5c5SAndroid Build Coastguard Worker 
214*8975f5c5SAndroid Build Coastguard Worker     unsigned int enabledClipDistances =
215*8975f5c5SAndroid Build Coastguard Worker         (mClipDistanceSize > 0 ? mClipDistanceSize
216*8975f5c5SAndroid Build Coastguard Worker                                : (mClipDistance ? mMaxClipDistanceIndex + 1 : 0));
217*8975f5c5SAndroid Build Coastguard Worker     unsigned int enabledCullDistances =
218*8975f5c5SAndroid Build Coastguard Worker         (mCullDistanceSize > 0 ? mCullDistanceSize
219*8975f5c5SAndroid Build Coastguard Worker                                : (mCullDistance ? mMaxCullDistanceIndex + 1 : 0));
220*8975f5c5SAndroid Build Coastguard Worker     unsigned int combinedClipAndCullDistances =
221*8975f5c5SAndroid Build Coastguard Worker         (enabledClipDistances > 0 && enabledCullDistances > 0
222*8975f5c5SAndroid Build Coastguard Worker              ? enabledClipDistances + enabledCullDistances
223*8975f5c5SAndroid Build Coastguard Worker              : 0);
224*8975f5c5SAndroid Build Coastguard Worker 
225*8975f5c5SAndroid Build Coastguard Worker     // When cull distances are not supported, i.e., when GL_ANGLE_clip_cull_distance is
226*8975f5c5SAndroid Build Coastguard Worker     // exposed but GL_EXT_clip_cull_distance is not exposed, the combined limit is 0.
227*8975f5c5SAndroid Build Coastguard Worker     if (enabledCullDistances > 0 && maxCombinedClipAndCullDistances == 0)
228*8975f5c5SAndroid Build Coastguard Worker     {
229*8975f5c5SAndroid Build Coastguard Worker         error(*mCullDistance, "Cull distance functionality is not available", diagnostics);
230*8975f5c5SAndroid Build Coastguard Worker     }
231*8975f5c5SAndroid Build Coastguard Worker 
232*8975f5c5SAndroid Build Coastguard Worker     if (combinedClipAndCullDistances > maxCombinedClipAndCullDistances)
233*8975f5c5SAndroid Build Coastguard Worker     {
234*8975f5c5SAndroid Build Coastguard Worker         const TIntermSymbol *greaterSymbol =
235*8975f5c5SAndroid Build Coastguard Worker             (enabledClipDistances >= enabledCullDistances ? mClipDistance : mCullDistance);
236*8975f5c5SAndroid Build Coastguard Worker 
237*8975f5c5SAndroid Build Coastguard Worker         std::stringstream strstr = sh::InitializeStream<std::stringstream>();
238*8975f5c5SAndroid Build Coastguard Worker         strstr << "The sum of 'gl_ClipDistance' and 'gl_CullDistance' size is greater than "
239*8975f5c5SAndroid Build Coastguard Worker                   "gl_MaxCombinedClipAndCullDistances ("
240*8975f5c5SAndroid Build Coastguard Worker                << combinedClipAndCullDistances << " > " << maxCombinedClipAndCullDistances << ")";
241*8975f5c5SAndroid Build Coastguard Worker         error(*greaterSymbol, strstr.str().c_str(), diagnostics);
242*8975f5c5SAndroid Build Coastguard Worker     }
243*8975f5c5SAndroid Build Coastguard Worker 
244*8975f5c5SAndroid Build Coastguard Worker     // Update the compiler state
245*8975f5c5SAndroid Build Coastguard Worker     *clipDistanceSizeOut = mClipDistanceSize ? mClipDistanceSize : (mMaxClipDistanceIndex + 1);
246*8975f5c5SAndroid Build Coastguard Worker     *cullDistanceSizeOut = mCullDistanceSize ? mCullDistanceSize : (mMaxCullDistanceIndex + 1);
247*8975f5c5SAndroid Build Coastguard Worker     *clipDistanceRedeclaredOut = mClipDistanceSize != 0;
248*8975f5c5SAndroid Build Coastguard Worker     *cullDistanceRedeclaredOut = mCullDistanceSize != 0;
249*8975f5c5SAndroid Build Coastguard Worker     *clipDistanceUsedOut       = (mMaxClipDistanceIndex != -1) || mHasNonConstClipDistanceIndex;
250*8975f5c5SAndroid Build Coastguard Worker }
251*8975f5c5SAndroid Build Coastguard Worker 
252*8975f5c5SAndroid Build Coastguard Worker class ValidateClipCullDistanceLengthTraverser : public TIntermTraverser
253*8975f5c5SAndroid Build Coastguard Worker {
254*8975f5c5SAndroid Build Coastguard Worker   public:
255*8975f5c5SAndroid Build Coastguard Worker     ValidateClipCullDistanceLengthTraverser(TDiagnostics *diagnostics,
256*8975f5c5SAndroid Build Coastguard Worker                                             uint8_t clipDistanceSized,
257*8975f5c5SAndroid Build Coastguard Worker                                             uint8_t cullDistanceSized);
258*8975f5c5SAndroid Build Coastguard Worker 
259*8975f5c5SAndroid Build Coastguard Worker   private:
260*8975f5c5SAndroid Build Coastguard Worker     bool visitUnary(Visit visit, TIntermUnary *node) override;
261*8975f5c5SAndroid Build Coastguard Worker 
262*8975f5c5SAndroid Build Coastguard Worker     TDiagnostics *mDiagnostics;
263*8975f5c5SAndroid Build Coastguard Worker     const bool mClipDistanceSized;
264*8975f5c5SAndroid Build Coastguard Worker     const bool mCullDistanceSized;
265*8975f5c5SAndroid Build Coastguard Worker };
266*8975f5c5SAndroid Build Coastguard Worker 
ValidateClipCullDistanceLengthTraverser(TDiagnostics * diagnostics,uint8_t clipDistanceSize,uint8_t cullDistanceSize)267*8975f5c5SAndroid Build Coastguard Worker ValidateClipCullDistanceLengthTraverser::ValidateClipCullDistanceLengthTraverser(
268*8975f5c5SAndroid Build Coastguard Worker     TDiagnostics *diagnostics,
269*8975f5c5SAndroid Build Coastguard Worker     uint8_t clipDistanceSize,
270*8975f5c5SAndroid Build Coastguard Worker     uint8_t cullDistanceSize)
271*8975f5c5SAndroid Build Coastguard Worker     : TIntermTraverser(true, false, false),
272*8975f5c5SAndroid Build Coastguard Worker       mDiagnostics(diagnostics),
273*8975f5c5SAndroid Build Coastguard Worker       mClipDistanceSized(clipDistanceSize > 0),
274*8975f5c5SAndroid Build Coastguard Worker       mCullDistanceSized(cullDistanceSize > 0)
275*8975f5c5SAndroid Build Coastguard Worker {}
276*8975f5c5SAndroid Build Coastguard Worker 
visitUnary(Visit visit,TIntermUnary * node)277*8975f5c5SAndroid Build Coastguard Worker bool ValidateClipCullDistanceLengthTraverser::visitUnary(Visit visit, TIntermUnary *node)
278*8975f5c5SAndroid Build Coastguard Worker {
279*8975f5c5SAndroid Build Coastguard Worker     if (node->getOp() == EOpArrayLength)
280*8975f5c5SAndroid Build Coastguard Worker     {
281*8975f5c5SAndroid Build Coastguard Worker         TIntermTyped *operand = node->getOperand();
282*8975f5c5SAndroid Build Coastguard Worker         if ((operand->getQualifier() == EvqClipDistance && !mClipDistanceSized) ||
283*8975f5c5SAndroid Build Coastguard Worker             (operand->getQualifier() == EvqCullDistance && !mCullDistanceSized))
284*8975f5c5SAndroid Build Coastguard Worker         {
285*8975f5c5SAndroid Build Coastguard Worker             error(*operand->getAsSymbolNode(),
286*8975f5c5SAndroid Build Coastguard Worker                   "The length() method cannot be called on an array that is not "
287*8975f5c5SAndroid Build Coastguard Worker                   "runtime sized and also has not yet been explicitly sized",
288*8975f5c5SAndroid Build Coastguard Worker                   mDiagnostics);
289*8975f5c5SAndroid Build Coastguard Worker         }
290*8975f5c5SAndroid Build Coastguard Worker     }
291*8975f5c5SAndroid Build Coastguard Worker     return true;
292*8975f5c5SAndroid Build Coastguard Worker }
293*8975f5c5SAndroid Build Coastguard Worker 
ReplaceAndDeclareVariable(TCompiler * compiler,TIntermBlock * root,const ImmutableString & name,unsigned int size)294*8975f5c5SAndroid Build Coastguard Worker bool ReplaceAndDeclareVariable(TCompiler *compiler,
295*8975f5c5SAndroid Build Coastguard Worker                                TIntermBlock *root,
296*8975f5c5SAndroid Build Coastguard Worker                                const ImmutableString &name,
297*8975f5c5SAndroid Build Coastguard Worker                                unsigned int size)
298*8975f5c5SAndroid Build Coastguard Worker {
299*8975f5c5SAndroid Build Coastguard Worker     const TVariable *var = static_cast<const TVariable *>(
300*8975f5c5SAndroid Build Coastguard Worker         compiler->getSymbolTable().findBuiltIn(name, compiler->getShaderVersion()));
301*8975f5c5SAndroid Build Coastguard Worker     ASSERT(var != nullptr);
302*8975f5c5SAndroid Build Coastguard Worker 
303*8975f5c5SAndroid Build Coastguard Worker     if (size != var->getType().getOutermostArraySize())
304*8975f5c5SAndroid Build Coastguard Worker     {
305*8975f5c5SAndroid Build Coastguard Worker         TType *resizedType = new TType(var->getType());
306*8975f5c5SAndroid Build Coastguard Worker         resizedType->setArraySize(0, size);
307*8975f5c5SAndroid Build Coastguard Worker         TVariable *resizedVar =
308*8975f5c5SAndroid Build Coastguard Worker             new TVariable(&compiler->getSymbolTable(), name, resizedType, SymbolType::BuiltIn);
309*8975f5c5SAndroid Build Coastguard Worker         if (!ReplaceVariable(compiler, root, var, resizedVar))
310*8975f5c5SAndroid Build Coastguard Worker         {
311*8975f5c5SAndroid Build Coastguard Worker             return false;
312*8975f5c5SAndroid Build Coastguard Worker         }
313*8975f5c5SAndroid Build Coastguard Worker         var = resizedVar;
314*8975f5c5SAndroid Build Coastguard Worker     }
315*8975f5c5SAndroid Build Coastguard Worker 
316*8975f5c5SAndroid Build Coastguard Worker     TIntermDeclaration *globalDecl = new TIntermDeclaration();
317*8975f5c5SAndroid Build Coastguard Worker     globalDecl->appendDeclarator(new TIntermSymbol(var));
318*8975f5c5SAndroid Build Coastguard Worker     root->insertStatement(0, globalDecl);
319*8975f5c5SAndroid Build Coastguard Worker 
320*8975f5c5SAndroid Build Coastguard Worker     return true;
321*8975f5c5SAndroid Build Coastguard Worker }
322*8975f5c5SAndroid Build Coastguard Worker 
323*8975f5c5SAndroid Build Coastguard Worker }  // anonymous namespace
324*8975f5c5SAndroid Build Coastguard Worker 
ValidateClipCullDistance(TCompiler * compiler,TIntermBlock * root,TDiagnostics * diagnostics,const unsigned int maxCombinedClipAndCullDistances,uint8_t * clipDistanceSizeOut,uint8_t * cullDistanceSizeOut,bool * clipDistanceUsedOut)325*8975f5c5SAndroid Build Coastguard Worker bool ValidateClipCullDistance(TCompiler *compiler,
326*8975f5c5SAndroid Build Coastguard Worker                               TIntermBlock *root,
327*8975f5c5SAndroid Build Coastguard Worker                               TDiagnostics *diagnostics,
328*8975f5c5SAndroid Build Coastguard Worker                               const unsigned int maxCombinedClipAndCullDistances,
329*8975f5c5SAndroid Build Coastguard Worker                               uint8_t *clipDistanceSizeOut,
330*8975f5c5SAndroid Build Coastguard Worker                               uint8_t *cullDistanceSizeOut,
331*8975f5c5SAndroid Build Coastguard Worker                               bool *clipDistanceUsedOut)
332*8975f5c5SAndroid Build Coastguard Worker {
333*8975f5c5SAndroid Build Coastguard Worker     ValidateClipCullDistanceTraverser varyingValidator;
334*8975f5c5SAndroid Build Coastguard Worker     root->traverse(&varyingValidator);
335*8975f5c5SAndroid Build Coastguard Worker     int numErrorsBefore = diagnostics->numErrors();
336*8975f5c5SAndroid Build Coastguard Worker     bool clipDistanceRedeclared;
337*8975f5c5SAndroid Build Coastguard Worker     bool cullDistanceRedeclared;
338*8975f5c5SAndroid Build Coastguard Worker     varyingValidator.validate(diagnostics, maxCombinedClipAndCullDistances, clipDistanceSizeOut,
339*8975f5c5SAndroid Build Coastguard Worker                               cullDistanceSizeOut, &clipDistanceRedeclared, &cullDistanceRedeclared,
340*8975f5c5SAndroid Build Coastguard Worker                               clipDistanceUsedOut);
341*8975f5c5SAndroid Build Coastguard Worker 
342*8975f5c5SAndroid Build Coastguard Worker     ValidateClipCullDistanceLengthTraverser lengthValidator(diagnostics, *clipDistanceSizeOut,
343*8975f5c5SAndroid Build Coastguard Worker                                                             *cullDistanceSizeOut);
344*8975f5c5SAndroid Build Coastguard Worker     root->traverse(&lengthValidator);
345*8975f5c5SAndroid Build Coastguard Worker     if (diagnostics->numErrors() != numErrorsBefore)
346*8975f5c5SAndroid Build Coastguard Worker     {
347*8975f5c5SAndroid Build Coastguard Worker         return false;
348*8975f5c5SAndroid Build Coastguard Worker     }
349*8975f5c5SAndroid Build Coastguard Worker 
350*8975f5c5SAndroid Build Coastguard Worker     // If the clip/cull distance variables are not explicitly redeclared in the incoming shader,
351*8975f5c5SAndroid Build Coastguard Worker     // redeclare them to ensure that various pruning passes will not cause inconsistent AST state.
352*8975f5c5SAndroid Build Coastguard Worker     if (*clipDistanceSizeOut > 0 && !clipDistanceRedeclared &&
353*8975f5c5SAndroid Build Coastguard Worker         !ReplaceAndDeclareVariable(compiler, root, ImmutableString("gl_ClipDistance"),
354*8975f5c5SAndroid Build Coastguard Worker                                    *clipDistanceSizeOut))
355*8975f5c5SAndroid Build Coastguard Worker     {
356*8975f5c5SAndroid Build Coastguard Worker 
357*8975f5c5SAndroid Build Coastguard Worker         return false;
358*8975f5c5SAndroid Build Coastguard Worker     }
359*8975f5c5SAndroid Build Coastguard Worker     if (*cullDistanceSizeOut > 0 && !cullDistanceRedeclared &&
360*8975f5c5SAndroid Build Coastguard Worker         !ReplaceAndDeclareVariable(compiler, root, ImmutableString("gl_CullDistance"),
361*8975f5c5SAndroid Build Coastguard Worker                                    *cullDistanceSizeOut))
362*8975f5c5SAndroid Build Coastguard Worker     {
363*8975f5c5SAndroid Build Coastguard Worker         return false;
364*8975f5c5SAndroid Build Coastguard Worker     }
365*8975f5c5SAndroid Build Coastguard Worker 
366*8975f5c5SAndroid Build Coastguard Worker     return true;
367*8975f5c5SAndroid Build Coastguard Worker }
368*8975f5c5SAndroid Build Coastguard Worker 
369*8975f5c5SAndroid Build Coastguard Worker }  // namespace sh
370