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