xref: /aosp_15_r20/external/angle/src/compiler/translator/tree_util/ReplaceClipCullDistanceVariable.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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 // ReplaceClipCullDistanceVariable.cpp: Find any references to gl_ClipDistance or gl_CullDistance
7 // and replace it with ANGLEClipDistance or ANGLECullDistance.
8 //
9 
10 #include "compiler/translator/tree_util/ReplaceClipCullDistanceVariable.h"
11 
12 #include "common/bitset_utils.h"
13 #include "common/debug.h"
14 #include "common/utilities.h"
15 #include "compiler/translator/Compiler.h"
16 #include "compiler/translator/SymbolTable.h"
17 #include "compiler/translator/tree_util/BuiltIn.h"
18 #include "compiler/translator/tree_util/FindMain.h"
19 #include "compiler/translator/tree_util/IntermNode_util.h"
20 #include "compiler/translator/tree_util/IntermTraverse.h"
21 #include "compiler/translator/tree_util/ReplaceVariable.h"
22 #include "compiler/translator/tree_util/RunAtTheBeginningOfShader.h"
23 #include "compiler/translator/tree_util/RunAtTheEndOfShader.h"
24 
25 namespace sh
26 {
27 namespace
28 {
29 
30 using ClipCullDistanceIdxSet = angle::BitSet<32>;
31 
32 typedef TIntermNode *AssignFunc(const unsigned int index,
33                                 TIntermSymbol *left,
34                                 TIntermSymbol *right,
35                                 const TIntermTyped *enableFlags);
36 
37 template <typename Variable>
FindVariable(const std::vector<Variable> & mVars,const ImmutableString & name)38 const Variable *FindVariable(const std::vector<Variable> &mVars, const ImmutableString &name)
39 {
40     for (const Variable &var : mVars)
41     {
42         if (name == var.instanceName)
43         {
44             return &var;
45         }
46     }
47 
48     return nullptr;
49 }
50 
51 // Traverse the tree and collect the redeclaration and all constant index references of
52 // gl_ClipDistance/gl_CullDistance
53 class GLClipCullDistanceReferenceTraverser : public TIntermTraverser
54 {
55   public:
GLClipCullDistanceReferenceTraverser(const TIntermSymbol ** redeclaredSymOut,const TVariable ** variableOut,bool * nonConstIdxUsedOut,unsigned int * maxConstIdxOut,ClipCullDistanceIdxSet * constIndicesOut,TQualifier targetQualifier)56     GLClipCullDistanceReferenceTraverser(const TIntermSymbol **redeclaredSymOut,
57                                          const TVariable **variableOut,
58                                          bool *nonConstIdxUsedOut,
59                                          unsigned int *maxConstIdxOut,
60                                          ClipCullDistanceIdxSet *constIndicesOut,
61                                          TQualifier targetQualifier)
62         : TIntermTraverser(true, false, false),
63           mRedeclaredSym(redeclaredSymOut),
64           mVariable(variableOut),
65           mUseNonConstClipCullDistanceIndex(nonConstIdxUsedOut),
66           mMaxConstClipCullDistanceIndex(maxConstIdxOut),
67           mConstClipCullDistanceIndices(constIndicesOut),
68           mTargetQualifier(targetQualifier)
69     {
70         *mRedeclaredSym                    = nullptr;
71         *mVariable                         = nullptr;
72         *mUseNonConstClipCullDistanceIndex = false;
73         *mMaxConstClipCullDistanceIndex    = 0;
74         mConstClipCullDistanceIndices->reset();
75     }
76 
visitDeclaration(Visit visit,TIntermDeclaration * node)77     bool visitDeclaration(Visit visit, TIntermDeclaration *node) override
78     {
79         // If gl_ClipDistance/gl_CullDistance is redeclared, we need to collect its information
80         const TIntermSequence &sequence = *(node->getSequence());
81 
82         if (sequence.size() != 1)
83         {
84             return true;
85         }
86 
87         TIntermSymbol *variable = sequence.front()->getAsSymbolNode();
88         if (variable == nullptr || variable->getType().getQualifier() != mTargetQualifier)
89         {
90             return true;
91         }
92 
93         *mRedeclaredSym = variable->getAsSymbolNode();
94 
95         return true;
96     }
97 
visitBinary(Visit visit,TIntermBinary * node)98     bool visitBinary(Visit visit, TIntermBinary *node) override
99     {
100         TOperator op = node->getOp();
101         if (op != EOpIndexDirect && op != EOpIndexIndirect)
102         {
103             return true;
104         }
105 
106         // gl_ClipDistance / gl_CullDistance
107         TIntermTyped *left = node->getLeft()->getAsTyped();
108         if (!left)
109         {
110             return true;
111         }
112 
113         ASSERT(op == EOpIndexDirect || op == EOpIndexIndirect);
114 
115         TIntermSymbol *clipCullDistance = left->getAsSymbolNode();
116         if (!clipCullDistance)
117         {
118             return true;
119         }
120         if (clipCullDistance->getType().getQualifier() != mTargetQualifier)
121         {
122             return true;
123         }
124 
125         const TConstantUnion *constIdx = node->getRight()->getConstantValue();
126         if (!constIdx)
127         {
128             *mUseNonConstClipCullDistanceIndex = true;
129         }
130         else
131         {
132             unsigned int idx = 0;
133             switch (constIdx->getType())
134             {
135                 case EbtInt:
136                     idx = constIdx->getIConst();
137                     break;
138                 case EbtUInt:
139                     idx = constIdx->getUConst();
140                     break;
141                 case EbtFloat:
142                     idx = static_cast<unsigned int>(constIdx->getFConst());
143                     break;
144                 case EbtBool:
145                     idx = constIdx->getBConst() ? 1 : 0;
146                     break;
147                 default:
148                     UNREACHABLE();
149                     break;
150             }
151             ASSERT(idx < mConstClipCullDistanceIndices->size());
152             mConstClipCullDistanceIndices->set(idx);
153 
154             *mMaxConstClipCullDistanceIndex = std::max(*mMaxConstClipCullDistanceIndex, idx);
155             *mVariable                      = &clipCullDistance->variable();
156         }
157 
158         return true;
159     }
160 
161   private:
162     const TIntermSymbol **mRedeclaredSym;
163     const TVariable **mVariable;
164     // Flag indicating whether there is at least one reference of gl_ClipDistance with non-constant
165     // index
166     bool *mUseNonConstClipCullDistanceIndex;
167     // Max constant index that is used to reference gl_ClipDistance
168     unsigned int *mMaxConstClipCullDistanceIndex;
169     // List of constant index reference of gl_ClipDistance
170     ClipCullDistanceIdxSet *mConstClipCullDistanceIndices;
171     // Qualifier for gl_ClipDistance/gl_CullDistance
172     const TQualifier mTargetQualifier;
173 };
174 
175 // Replace all symbolic occurrences of given variables except one symbol.
176 class ReplaceVariableExceptOneTraverser : public TIntermTraverser
177 {
178   public:
ReplaceVariableExceptOneTraverser(const TVariable * toBeReplaced,const TIntermTyped * replacement,const TIntermSymbol * exception)179     ReplaceVariableExceptOneTraverser(const TVariable *toBeReplaced,
180                                       const TIntermTyped *replacement,
181                                       const TIntermSymbol *exception)
182         : TIntermTraverser(true, false, false),
183           mToBeReplaced(toBeReplaced),
184           mException(exception),
185           mReplacement(replacement)
186     {}
187 
visitSymbol(TIntermSymbol * node)188     void visitSymbol(TIntermSymbol *node) override
189     {
190         if (&node->variable() == mToBeReplaced && node != mException)
191         {
192             queueReplacement(mReplacement->deepCopy(), OriginalNode::IS_DROPPED);
193         }
194     }
195 
196   private:
197     const TVariable *const mToBeReplaced;
198     const TIntermSymbol *const mException;
199     const TIntermTyped *const mReplacement;
200 };
201 
simpleAssignFunc(const unsigned int index,TIntermSymbol * leftSymbol,TIntermSymbol * rightSymbol,const TIntermTyped *)202 TIntermNode *simpleAssignFunc(const unsigned int index,
203                               TIntermSymbol *leftSymbol,
204                               TIntermSymbol *rightSymbol,
205                               const TIntermTyped * /*enableFlags*/)
206 {
207     if (!rightSymbol)
208         return nullptr;
209 
210     // leftSymbol[index] = rightSymbol[index]
211     // E.g., ANGLEClipDistance[index] = gl_ClipDistance[index]
212     TIntermBinary *left =
213         new TIntermBinary(EOpIndexDirect, leftSymbol->deepCopy(), CreateIndexNode(index));
214     TIntermBinary *right =
215         new TIntermBinary(EOpIndexDirect, rightSymbol->deepCopy(), CreateIndexNode(index));
216 
217     return new TIntermBinary(EOpAssign, left, right);
218 }
219 
220 // This is only used for gl_ClipDistance
assignFuncWithEnableFlags(const unsigned int index,TIntermSymbol * leftSymbol,TIntermSymbol * rightSymbol,const TIntermTyped * enableFlags)221 TIntermNode *assignFuncWithEnableFlags(const unsigned int index,
222                                        TIntermSymbol *leftSymbol,
223                                        TIntermSymbol *rightSymbol,
224                                        const TIntermTyped *enableFlags)
225 {
226     //  if (ANGLEUniforms.clipDistancesEnabled & (0x1 << index))
227     //      gl_ClipDistance[index] = ANGLEClipDistance[index];
228     //  else
229     //      gl_ClipDistance[index] = 0;
230     TIntermConstantUnion *bitMask = CreateUIntNode(0x1 << index);
231     TIntermBinary *bitwiseAnd = new TIntermBinary(EOpBitwiseAnd, enableFlags->deepCopy(), bitMask);
232     TIntermBinary *nonZero    = new TIntermBinary(EOpNotEqual, bitwiseAnd, CreateUIntNode(0));
233 
234     TIntermBinary *left =
235         new TIntermBinary(EOpIndexDirect, leftSymbol->deepCopy(), CreateIndexNode(index));
236     TIntermBlock *trueBlock = new TIntermBlock();
237     if (rightSymbol)
238     {
239         TIntermBinary *right =
240             new TIntermBinary(EOpIndexDirect, rightSymbol->deepCopy(), CreateIndexNode(index));
241         TIntermBinary *assignment = new TIntermBinary(EOpAssign, left, right);
242         trueBlock->appendStatement(assignment);
243     }
244 
245     TIntermBinary *zeroAssignment =
246         new TIntermBinary(EOpAssign, left->deepCopy(), CreateFloatNode(0, EbpMedium));
247     TIntermBlock *falseBlock = new TIntermBlock();
248     falseBlock->appendStatement(zeroAssignment);
249 
250     return new TIntermIfElse(nonZero, trueBlock, falseBlock);
251 }
252 
253 class ReplaceClipCullDistanceAssignments : angle::NonCopyable
254 {
255   public:
ReplaceClipCullDistanceAssignments(TCompiler * compiler,TIntermBlock * root,TSymbolTable * symbolTable,const TVariable * glClipCullDistanceVar,const TIntermSymbol * redeclaredGlClipDistance,const ImmutableString & angleVarName)256     ReplaceClipCullDistanceAssignments(TCompiler *compiler,
257                                        TIntermBlock *root,
258                                        TSymbolTable *symbolTable,
259                                        const TVariable *glClipCullDistanceVar,
260                                        const TIntermSymbol *redeclaredGlClipDistance,
261                                        const ImmutableString &angleVarName)
262         : mCompiler(compiler),
263           mRoot(root),
264           mSymbolTable(symbolTable),
265           mGlVar(glClipCullDistanceVar),
266           mRedeclaredGLVar(redeclaredGlClipDistance),
267           mANGLEVarName(angleVarName)
268     {
269         mEnabledDistances = 0;
270     }
271 
272     unsigned int getEnabledClipCullDistance(const bool useNonConstIndex,
273                                             const unsigned int maxConstIndex);
274     const TVariable *declareANGLEVariable(const TVariable *originalVariable);
275     bool assignOriginalValueToANGLEVariable(const GLenum shaderType);
276     bool assignValueToOriginalVariable(const GLenum shaderType,
277                                        const bool isRedeclared,
278                                        const TIntermTyped *enableFlags,
279                                        const ClipCullDistanceIdxSet *constIndices);
280 
281   private:
282     bool assignOriginalValueToANGLEVariableImpl();
283     bool assignValueToOriginalVariableImpl(const bool isRedeclared,
284                                            const TIntermTyped *enableFlags,
285                                            const ClipCullDistanceIdxSet *constIndices,
286                                            AssignFunc assignFunc);
287 
288     // Common variables for replacing gl_Clip/CullDistances with ANGLEClip/CullDistances
289     TCompiler *mCompiler;
290     TIntermBlock *mRoot;
291     TSymbolTable *mSymbolTable;
292 
293     const TVariable *mGlVar;
294     const TIntermSymbol *mRedeclaredGLVar;
295     const ImmutableString mANGLEVarName;
296 
297     unsigned int mEnabledDistances;
298     const TVariable *mANGLEVar = nullptr;
299 };
300 
getEnabledClipCullDistance(const bool useNonConstIndex,const unsigned int maxConstIndex)301 unsigned int ReplaceClipCullDistanceAssignments::getEnabledClipCullDistance(
302     const bool useNonConstIndex,
303     const unsigned int maxConstIndex)
304 {
305     if (mRedeclaredGLVar)
306     {
307         // If array is redeclared by user, use that redeclared size.
308         mEnabledDistances = mRedeclaredGLVar->getType().getOutermostArraySize();
309     }
310     else if (!useNonConstIndex)
311     {
312         ASSERT(maxConstIndex < mGlVar->getType().getOutermostArraySize());
313         // Only use constant index, then use max array index used.
314         mEnabledDistances = maxConstIndex + 1;
315     }
316 
317     return mEnabledDistances;
318 }
319 
declareANGLEVariable(const TVariable * originalVariable)320 const TVariable *ReplaceClipCullDistanceAssignments::declareANGLEVariable(
321     const TVariable *originalVariable)
322 {
323     ASSERT(mEnabledDistances > 0);
324 
325     TType *clipCullDistanceType = new TType(originalVariable->getType());
326     clipCullDistanceType->setQualifier(EvqGlobal);
327     clipCullDistanceType->toArrayBaseType();
328     clipCullDistanceType->makeArray(mEnabledDistances);
329 
330     mANGLEVar =
331         new TVariable(mSymbolTable, mANGLEVarName, clipCullDistanceType, SymbolType::AngleInternal);
332 
333     TIntermSymbol *clipCullDistanceDeclarator = new TIntermSymbol(mANGLEVar);
334     TIntermDeclaration *clipCullDistanceDecl  = new TIntermDeclaration;
335     clipCullDistanceDecl->appendDeclarator(clipCullDistanceDeclarator);
336 
337     // Must declare ANGLEClipdistance/ANGLECullDistance before any function, since
338     // gl_ClipDistance/gl_CullDistance might be accessed within a function declared before main.
339     mRoot->insertStatement(0, clipCullDistanceDecl);
340 
341     return mANGLEVar;
342 }
343 
assignOriginalValueToANGLEVariableImpl()344 bool ReplaceClipCullDistanceAssignments::assignOriginalValueToANGLEVariableImpl()
345 {
346     ASSERT(mEnabledDistances > 0);
347 
348     TIntermBlock *readBlock                 = new TIntermBlock;
349     TIntermSymbol *glClipCullDistanceSymbol = new TIntermSymbol(mGlVar);
350     TIntermSymbol *clipCullDistanceSymbol   = new TIntermSymbol(mANGLEVar);
351 
352     for (unsigned int i = 0; i < mEnabledDistances; i++)
353     {
354         readBlock->appendStatement(
355             simpleAssignFunc(i, clipCullDistanceSymbol, glClipCullDistanceSymbol, nullptr));
356     }
357 
358     return RunAtTheBeginningOfShader(mCompiler, mRoot, readBlock);
359 }
360 
assignValueToOriginalVariableImpl(const bool isRedeclared,const TIntermTyped * enableFlags,const ClipCullDistanceIdxSet * constIndices,AssignFunc assignFunc)361 bool ReplaceClipCullDistanceAssignments::assignValueToOriginalVariableImpl(
362     const bool isRedeclared,
363     const TIntermTyped *enableFlags,
364     const ClipCullDistanceIdxSet *constIndices,
365     AssignFunc assignFunc)
366 {
367     ASSERT(mEnabledDistances > 0);
368 
369     TIntermBlock *assignBlock               = new TIntermBlock;
370     TIntermSymbol *glClipCullDistanceSymbol = new TIntermSymbol(mGlVar);
371     TIntermSymbol *clipCullDistanceSymbol   = mANGLEVar ? new TIntermSymbol(mANGLEVar) : nullptr;
372 
373     // The array size is decided by either redeclaring the variable or accessing the variable with a
374     // integral constant index. And this size is the count of the enabled value. So, if the index
375     // which is greater than the array size, is used to access the variable, this access will be
376     // ignored.
377     if (isRedeclared || !constIndices)
378     {
379         for (unsigned int i = 0; i < mEnabledDistances; ++i)
380         {
381             assignBlock->appendStatement(
382                 assignFunc(i, glClipCullDistanceSymbol, clipCullDistanceSymbol, enableFlags));
383         }
384     }
385     else
386     {
387         // Assign ANGLEClip/CullDistance[i]'s value to gl_Clip/CullDistance[i] if i is in the
388         // constant indices list. Those elements whose index is not in the constant index list will
389         // be zeroise for initialization.
390         for (unsigned int i = 0; i < mEnabledDistances; ++i)
391         {
392             if (constIndices->test(i))
393             {
394                 assignBlock->appendStatement(
395                     assignFunc(i, glClipCullDistanceSymbol, clipCullDistanceSymbol, enableFlags));
396             }
397             else
398             {
399                 // gl_Clip/CullDistance[i] = 0;
400                 TIntermBinary *left = new TIntermBinary(
401                     EOpIndexDirect, glClipCullDistanceSymbol->deepCopy(), CreateIndexNode(i));
402                 TIntermBinary *zeroAssignment =
403                     new TIntermBinary(EOpAssign, left, CreateFloatNode(0, EbpMedium));
404                 assignBlock->appendStatement(zeroAssignment);
405             }
406         }
407     }
408 
409     return RunAtTheEndOfShader(mCompiler, mRoot, assignBlock, mSymbolTable);
410 }
411 
assignOriginalValueToANGLEVariable(const GLenum shaderType)412 [[nodiscard]] bool ReplaceClipCullDistanceAssignments::assignOriginalValueToANGLEVariable(
413     const GLenum shaderType)
414 {
415     switch (shaderType)
416     {
417         case GL_VERTEX_SHADER:
418             // Vertex shader can use gl_Clip/CullDistance as a output only
419             break;
420         case GL_FRAGMENT_SHADER:
421         {
422             // These shader types can use gl_Clip/CullDistance as input
423             if (!assignOriginalValueToANGLEVariableImpl())
424             {
425                 return false;
426             }
427             break;
428         }
429         default:
430         {
431             UNREACHABLE();
432             return false;
433         }
434     }
435 
436     return true;
437 }
438 
assignValueToOriginalVariable(const GLenum shaderType,const bool isRedeclared,const TIntermTyped * enableFlags,const ClipCullDistanceIdxSet * constIndices)439 [[nodiscard]] bool ReplaceClipCullDistanceAssignments::assignValueToOriginalVariable(
440     const GLenum shaderType,
441     const bool isRedeclared,
442     const TIntermTyped *enableFlags,
443     const ClipCullDistanceIdxSet *constIndices)
444 {
445     switch (shaderType)
446     {
447         case GL_VERTEX_SHADER:
448         {
449             // Vertex shader can use gl_Clip/CullDistance as output.
450             // If the enabled gl_Clip/CullDistances are not initialized, results are undefined.
451             // EXT_clip_cull_distance spec :
452             // The shader must also set all values in gl_ClipDistance that have been enabled via the
453             // OpenGL ES API, or results are undefined. Values written into gl_ClipDistance for
454             // planes that are not enabled have no effect.
455             // ...
456             // Shaders writing gl_CullDistance must write all enabled distances, or culling results
457             // are undefined.
458             if (!assignValueToOriginalVariableImpl(
459                     isRedeclared, enableFlags, constIndices,
460                     enableFlags ? assignFuncWithEnableFlags : simpleAssignFunc))
461             {
462                 return false;
463             }
464             break;
465         }
466         case GL_FRAGMENT_SHADER:
467             // Fragment shader can use gl_Clip/CullDistance as input only
468             break;
469         default:
470         {
471             UNREACHABLE();
472             return false;
473         }
474     }
475 
476     return true;
477 }
478 
479 // Common code to transform gl_ClipDistance and gl_CullDistance.  Comments reference
480 // gl_ClipDistance, but are also applicable to gl_CullDistance.
ReplaceClipCullDistanceAssignmentsImpl(TCompiler * compiler,TIntermBlock * root,TSymbolTable * symbolTable,const GLenum shaderType,const TIntermTyped * clipDistanceEnableFlags,const char * builtInName,const char * replacementName,TQualifier builtInQualifier)481 [[nodiscard]] bool ReplaceClipCullDistanceAssignmentsImpl(
482     TCompiler *compiler,
483     TIntermBlock *root,
484     TSymbolTable *symbolTable,
485     const GLenum shaderType,
486     const TIntermTyped *clipDistanceEnableFlags,
487     const char *builtInName,
488     const char *replacementName,
489     TQualifier builtInQualifier)
490 {
491     // Collect all constant index references of gl_ClipDistance
492     ImmutableString name(builtInName);
493     ClipCullDistanceIdxSet constIndices;
494     bool useNonConstIndex                  = false;
495     const TIntermSymbol *redeclaredBuiltIn = nullptr;
496     const TVariable *builtInVariable       = nullptr;
497     unsigned int maxConstIndex             = 0;
498     GLClipCullDistanceReferenceTraverser indexTraverser(&redeclaredBuiltIn, &builtInVariable,
499                                                         &useNonConstIndex, &maxConstIndex,
500                                                         &constIndices, builtInQualifier);
501     root->traverse(&indexTraverser);
502     if (!useNonConstIndex && constIndices.none() && redeclaredBuiltIn == nullptr)
503     {
504         // No references of gl_ClipDistance
505         return true;
506     }
507 
508     // Retrieve gl_ClipDistance variable reference
509     // Search user redeclared gl_ClipDistance first
510     const TVariable *builtInVar = nullptr;
511     if (redeclaredBuiltIn)
512     {
513         builtInVar = &redeclaredBuiltIn->variable();
514     }
515     else
516     {
517         // User defined not found, use implicitly defined. The symbol table cannot be used here as
518         // the variable type could have been adjusted after validation
519         builtInVar = builtInVariable;
520     }
521     if (!builtInVar)
522     {
523         return false;
524     }
525 
526     ReplaceClipCullDistanceAssignments replacementUtils(compiler, root, symbolTable, builtInVar,
527                                                         redeclaredBuiltIn,
528                                                         ImmutableString(replacementName));
529 
530     unsigned int enabledClipDistances =
531         replacementUtils.getEnabledClipCullDistance(useNonConstIndex, maxConstIndex);
532     if (!enabledClipDistances)
533     {
534         // Spec :
535         // The gl_ClipDistance array is predeclared as unsized and must be explicitly sized by the
536         // shader either redeclaring it with a size or implicitly sized by indexing it only with
537         // integral constant expressions.
538         return false;
539     }
540 
541     if (replacementName)
542     {
543 
544         // Declare a global variable substituting gl_ClipDistance
545         const TVariable *replacementVar = replacementUtils.declareANGLEVariable(builtInVar);
546 
547         // Replace gl_ClipDistance reference with ANGLEClipDistance, except the declaration
548         ReplaceVariableExceptOneTraverser replaceTraverser(builtInVar,
549                                                            new TIntermSymbol(replacementVar),
550                                                            /** exception */ redeclaredBuiltIn);
551         root->traverse(&replaceTraverser);
552         if (!replaceTraverser.updateTree(compiler, root))
553         {
554             return false;
555         }
556 
557         // Read gl_ClipDistance to ANGLEClipDistance for getting original data
558         if (!replacementUtils.assignOriginalValueToANGLEVariable(shaderType))
559         {
560             return false;
561         }
562     }
563 
564     // Reassign ANGLEClipDistance to gl_ClipDistance but ignore those that are disabled
565     const bool isRedeclared = redeclaredBuiltIn != nullptr;
566     if (!replacementUtils.assignValueToOriginalVariable(shaderType, isRedeclared,
567                                                         clipDistanceEnableFlags, &constIndices))
568     {
569         return false;
570     }
571 
572     // If not redeclared, replace the built-in with one that is appropriately sized
573     if (!isRedeclared)
574     {
575         TType *resizedType = new TType(builtInVar->getType());
576         resizedType->setArraySize(0, enabledClipDistances);
577 
578         TVariable *resizedVar = new TVariable(symbolTable, name, resizedType, SymbolType::BuiltIn);
579 
580         if (!ReplaceVariable(compiler, root, builtInVar, resizedVar))
581         {
582             return false;
583         }
584 
585         // Built-in was not redeclared in the original shader, add it to the vertex out struct
586         return root->insertChildNodes(FindMainIndex(root), {new TIntermDeclaration{resizedVar}});
587     }
588 
589     return true;
590 }
591 
592 }  // anonymous namespace
593 
ReplaceClipDistanceAssignments(TCompiler * compiler,TIntermBlock * root,TSymbolTable * symbolTable,const GLenum shaderType,const TIntermTyped * clipDistanceEnableFlags)594 [[nodiscard]] bool ReplaceClipDistanceAssignments(TCompiler *compiler,
595                                                   TIntermBlock *root,
596                                                   TSymbolTable *symbolTable,
597                                                   const GLenum shaderType,
598                                                   const TIntermTyped *clipDistanceEnableFlags)
599 {
600     return ReplaceClipCullDistanceAssignmentsImpl(compiler, root, symbolTable, shaderType,
601                                                   clipDistanceEnableFlags, "gl_ClipDistance",
602                                                   "ANGLEClipDistance", EvqClipDistance);
603 }
604 
ReplaceCullDistanceAssignments(TCompiler * compiler,TIntermBlock * root,TSymbolTable * symbolTable,const GLenum shaderType)605 [[nodiscard]] bool ReplaceCullDistanceAssignments(TCompiler *compiler,
606                                                   TIntermBlock *root,
607                                                   TSymbolTable *symbolTable,
608                                                   const GLenum shaderType)
609 {
610     return ReplaceClipCullDistanceAssignmentsImpl(compiler, root, symbolTable, shaderType, nullptr,
611                                                   "gl_CullDistance", "ANGLECullDistance",
612                                                   EvqCullDistance);
613 }
614 
ZeroDisabledClipDistanceAssignments(TCompiler * compiler,TIntermBlock * root,TSymbolTable * symbolTable,const GLenum shaderType,const TIntermTyped * clipDistanceEnableFlags)615 [[nodiscard]] bool ZeroDisabledClipDistanceAssignments(TCompiler *compiler,
616                                                        TIntermBlock *root,
617                                                        TSymbolTable *symbolTable,
618                                                        const GLenum shaderType,
619                                                        const TIntermTyped *clipDistanceEnableFlags)
620 {
621     return ReplaceClipCullDistanceAssignmentsImpl(compiler, root, symbolTable, shaderType,
622                                                   clipDistanceEnableFlags, "gl_ClipDistance",
623                                                   nullptr, EvqClipDistance);
624 }
625 
626 }  // namespace sh
627