1 //
2 // Copyright (c) 2002-2013 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 
7 #include "angle_gl.h"
8 #include "compiler/translator/SymbolTable.h"
9 #include "compiler/translator/VariableInfo.h"
10 #include "compiler/translator/util.h"
11 #include "common/utilities.h"
12 
13 namespace sh
14 {
15 
16 namespace
17 {
18 
GetBlockLayoutType(TLayoutBlockStorage blockStorage)19 BlockLayoutType GetBlockLayoutType(TLayoutBlockStorage blockStorage)
20 {
21     switch (blockStorage)
22     {
23       case EbsPacked:         return BLOCKLAYOUT_PACKED;
24       case EbsShared:         return BLOCKLAYOUT_SHARED;
25       case EbsStd140:         return BLOCKLAYOUT_STANDARD;
26       default: UNREACHABLE(); return BLOCKLAYOUT_SHARED;
27     }
28 }
29 
ExpandUserDefinedVariable(const ShaderVariable & variable,const std::string & name,const std::string & mappedName,bool markStaticUse,std::vector<ShaderVariable> * expanded)30 void ExpandUserDefinedVariable(const ShaderVariable &variable,
31                                const std::string &name,
32                                const std::string &mappedName,
33                                bool markStaticUse,
34                                std::vector<ShaderVariable> *expanded)
35 {
36     ASSERT(variable.isStruct());
37 
38     const std::vector<ShaderVariable> &fields = variable.fields;
39 
40     for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
41     {
42         const ShaderVariable &field = fields[fieldIndex];
43         ExpandVariable(field,
44                        name + "." + field.name,
45                        mappedName + "." + field.mappedName,
46                        markStaticUse,
47                        expanded);
48     }
49 }
50 
51 template <class VarT>
FindVariable(const TString & name,std::vector<VarT> * infoList)52 VarT *FindVariable(const TString &name,
53                   std::vector<VarT> *infoList)
54 {
55     // TODO(zmo): optimize this function.
56     for (size_t ii = 0; ii < infoList->size(); ++ii)
57     {
58         if ((*infoList)[ii].name.c_str() == name)
59             return &((*infoList)[ii]);
60     }
61 
62     return NULL;
63 }
64 
65 }
66 
CollectVariables(std::vector<sh::Attribute> * attribs,std::vector<sh::OutputVariable> * outputVariables,std::vector<sh::Uniform> * uniforms,std::vector<sh::Varying> * varyings,std::vector<sh::InterfaceBlock> * interfaceBlocks,ShHashFunction64 hashFunction,const TSymbolTable & symbolTable,const TExtensionBehavior & extensionBehavior)67 CollectVariables::CollectVariables(std::vector<sh::Attribute> *attribs,
68                                    std::vector<sh::OutputVariable> *outputVariables,
69                                    std::vector<sh::Uniform> *uniforms,
70                                    std::vector<sh::Varying> *varyings,
71                                    std::vector<sh::InterfaceBlock> *interfaceBlocks,
72                                    ShHashFunction64 hashFunction,
73                                    const TSymbolTable &symbolTable,
74                                    const TExtensionBehavior &extensionBehavior)
75     : TIntermTraverser(true, false, false),
76       mAttribs(attribs),
77       mOutputVariables(outputVariables),
78       mUniforms(uniforms),
79       mVaryings(varyings),
80       mInterfaceBlocks(interfaceBlocks),
81       mDepthRangeAdded(false),
82       mPointCoordAdded(false),
83       mFrontFacingAdded(false),
84       mFragCoordAdded(false),
85       mInstanceIDAdded(false),
86       mVertexIDAdded(false),
87       mPositionAdded(false),
88       mPointSizeAdded(false),
89       mLastFragDataAdded(false),
90       mFragColorAdded(false),
91       mFragDataAdded(false),
92       mFragDepthEXTAdded(false),
93       mFragDepthAdded(false),
94       mSecondaryFragColorEXTAdded(false),
95       mSecondaryFragDataEXTAdded(false),
96       mHashFunction(hashFunction),
97       mSymbolTable(symbolTable),
98       mExtensionBehavior(extensionBehavior)
99 {
100 }
101 
102 // We want to check whether a uniform/varying is statically used
103 // because we only count the used ones in packing computing.
104 // Also, gl_FragCoord, gl_PointCoord, and gl_FrontFacing count
105 // toward varying counting if they are statically used in a fragment
106 // shader.
visitSymbol(TIntermSymbol * symbol)107 void CollectVariables::visitSymbol(TIntermSymbol *symbol)
108 {
109     ASSERT(symbol != NULL);
110     ShaderVariable *var = NULL;
111     const TString &symbolName = symbol->getSymbol();
112 
113     if (IsVarying(symbol->getQualifier()))
114     {
115         var = FindVariable(symbolName, mVaryings);
116     }
117     else if (symbol->getType().getBasicType() == EbtInterfaceBlock)
118     {
119         UNREACHABLE();
120     }
121     else if (symbolName == "gl_DepthRange")
122     {
123         ASSERT(symbol->getQualifier() == EvqUniform);
124 
125         if (!mDepthRangeAdded)
126         {
127             Uniform info;
128             const char kName[] = "gl_DepthRange";
129             info.name = kName;
130             info.mappedName = kName;
131             info.type = GL_STRUCT_ANGLEX;
132             info.arraySize = 0;
133             info.precision = GL_NONE;
134             info.staticUse = true;
135 
136             ShaderVariable nearInfo;
137             const char kNearName[] = "near";
138             nearInfo.name = kNearName;
139             nearInfo.mappedName = kNearName;
140             nearInfo.type = GL_FLOAT;
141             nearInfo.arraySize = 0;
142             nearInfo.precision = GL_HIGH_FLOAT;
143             nearInfo.staticUse = true;
144 
145             ShaderVariable farInfo;
146             const char kFarName[] = "far";
147             farInfo.name = kFarName;
148             farInfo.mappedName = kFarName;
149             farInfo.type = GL_FLOAT;
150             farInfo.arraySize = 0;
151             farInfo.precision = GL_HIGH_FLOAT;
152             farInfo.staticUse = true;
153 
154             ShaderVariable diffInfo;
155             const char kDiffName[] = "diff";
156             diffInfo.name = kDiffName;
157             diffInfo.mappedName = kDiffName;
158             diffInfo.type = GL_FLOAT;
159             diffInfo.arraySize = 0;
160             diffInfo.precision = GL_HIGH_FLOAT;
161             diffInfo.staticUse = true;
162 
163             info.fields.push_back(nearInfo);
164             info.fields.push_back(farInfo);
165             info.fields.push_back(diffInfo);
166 
167             mUniforms->push_back(info);
168             mDepthRangeAdded = true;
169         }
170     }
171     else
172     {
173         switch (symbol->getQualifier())
174         {
175           case EvqAttribute:
176           case EvqVertexIn:
177             var = FindVariable(symbolName, mAttribs);
178             break;
179           case EvqFragmentOut:
180             var = FindVariable(symbolName, mOutputVariables);
181             break;
182           case EvqUniform:
183             {
184                 const TInterfaceBlock *interfaceBlock = symbol->getType().getInterfaceBlock();
185                 if (interfaceBlock)
186                 {
187                     InterfaceBlock *namedBlock = FindVariable(interfaceBlock->name(), mInterfaceBlocks);
188                     ASSERT(namedBlock);
189                     var = FindVariable(symbolName, &namedBlock->fields);
190 
191                     // Set static use on the parent interface block here
192                     namedBlock->staticUse = true;
193                 }
194                 else
195                 {
196                     var = FindVariable(symbolName, mUniforms);
197                 }
198 
199                 // It's an internal error to reference an undefined user uniform
200                 ASSERT(symbolName.compare(0, 3, "gl_") != 0 || var);
201             }
202             break;
203           case EvqFragCoord:
204             if (!mFragCoordAdded)
205             {
206                 Varying info;
207                 const char kName[] = "gl_FragCoord";
208                 info.name = kName;
209                 info.mappedName = kName;
210                 info.type = GL_FLOAT_VEC4;
211                 info.arraySize = 0;
212                 info.precision = GL_MEDIUM_FLOAT;  // Defined by spec.
213                 info.staticUse = true;
214                 info.isInvariant = mSymbolTable.isVaryingInvariant(kName);
215                 mVaryings->push_back(info);
216                 mFragCoordAdded = true;
217             }
218             return;
219           case EvqFrontFacing:
220             if (!mFrontFacingAdded)
221             {
222                 Varying info;
223                 const char kName[] = "gl_FrontFacing";
224                 info.name = kName;
225                 info.mappedName = kName;
226                 info.type = GL_BOOL;
227                 info.arraySize = 0;
228                 info.precision = GL_NONE;
229                 info.staticUse = true;
230                 info.isInvariant = mSymbolTable.isVaryingInvariant(kName);
231                 mVaryings->push_back(info);
232                 mFrontFacingAdded = true;
233             }
234             return;
235           case EvqPointCoord:
236             if (!mPointCoordAdded)
237             {
238                 Varying info;
239                 const char kName[] = "gl_PointCoord";
240                 info.name = kName;
241                 info.mappedName = kName;
242                 info.type = GL_FLOAT_VEC2;
243                 info.arraySize = 0;
244                 info.precision = GL_MEDIUM_FLOAT;  // Defined by spec.
245                 info.staticUse = true;
246                 info.isInvariant = mSymbolTable.isVaryingInvariant(kName);
247                 mVaryings->push_back(info);
248                 mPointCoordAdded = true;
249             }
250             return;
251           case EvqInstanceID:
252             if (!mInstanceIDAdded)
253             {
254                 Attribute info;
255                 const char kName[] = "gl_InstanceID";
256                 info.name = kName;
257                 info.mappedName = kName;
258                 info.type = GL_INT;
259                 info.arraySize = 0;
260                 info.precision = GL_HIGH_INT;  // Defined by spec.
261                 info.staticUse = true;
262                 info.location = -1;
263                 mAttribs->push_back(info);
264                 mInstanceIDAdded = true;
265             }
266             return;
267           case EvqVertexID:
268               if (!mVertexIDAdded)
269               {
270                   Attribute info;
271                   const char kName[] = "gl_VertexID";
272                   info.name          = kName;
273                   info.mappedName    = kName;
274                   info.type          = GL_INT;
275                   info.arraySize     = 0;
276                   info.precision     = GL_HIGH_INT;  // Defined by spec.
277                   info.staticUse     = true;
278                   info.location      = -1;
279                   mAttribs->push_back(info);
280                   mVertexIDAdded = true;
281               }
282               return;
283           case EvqPosition:
284             if (!mPositionAdded)
285             {
286                 Varying info;
287                 const char kName[] = "gl_Position";
288                 info.name = kName;
289                 info.mappedName = kName;
290                 info.type = GL_FLOAT_VEC4;
291                 info.arraySize = 0;
292                 info.precision = GL_HIGH_FLOAT;  // Defined by spec.
293                 info.staticUse = true;
294                 info.isInvariant = mSymbolTable.isVaryingInvariant(kName);
295                 mVaryings->push_back(info);
296                 mPositionAdded = true;
297             }
298             return;
299           case EvqPointSize:
300             if (!mPointSizeAdded)
301             {
302                 Varying info;
303                 const char kName[] = "gl_PointSize";
304                 info.name = kName;
305                 info.mappedName = kName;
306                 info.type = GL_FLOAT;
307                 info.arraySize = 0;
308                 info.precision = GL_MEDIUM_FLOAT;  // Defined by spec.
309                 info.staticUse = true;
310                 info.isInvariant = mSymbolTable.isVaryingInvariant(kName);
311                 mVaryings->push_back(info);
312                 mPointSizeAdded = true;
313             }
314             return;
315           case EvqLastFragData:
316             if (!mLastFragDataAdded)
317             {
318                 Varying info;
319                 const char kName[] = "gl_LastFragData";
320                 info.name = kName;
321                 info.mappedName = kName;
322                 info.type = GL_FLOAT_VEC4;
323                 info.arraySize = static_cast<const TVariable*>(mSymbolTable.findBuiltIn("gl_MaxDrawBuffers", 100))->getConstPointer()->getIConst();
324                 info.precision = GL_MEDIUM_FLOAT;  // Defined by spec.
325                 info.staticUse = true;
326                 info.isInvariant = mSymbolTable.isVaryingInvariant(kName);
327                 mVaryings->push_back(info);
328                 mLastFragDataAdded = true;
329             }
330             return;
331           case EvqFragColor:
332               if (!mFragColorAdded)
333               {
334                   OutputVariable info;
335                   const char kName[] = "gl_FragColor";
336                   info.name          = kName;
337                   info.mappedName    = kName;
338                   info.type          = GL_FLOAT_VEC4;
339                   info.arraySize     = 0;
340                   info.precision     = GL_MEDIUM_FLOAT;  // Defined by spec.
341                   info.staticUse = true;
342                   mOutputVariables->push_back(info);
343                   mFragColorAdded = true;
344               }
345               return;
346           case EvqFragData:
347               if (!mFragDataAdded)
348               {
349                   OutputVariable info;
350                   const char kName[] = "gl_FragData";
351                   info.name          = kName;
352                   info.mappedName    = kName;
353                   info.type          = GL_FLOAT_VEC4;
354                   if (::IsExtensionEnabled(mExtensionBehavior, "GL_EXT_draw_buffers"))
355                   {
356                       info.arraySize = static_cast<const TVariable *>(
357                                            mSymbolTable.findBuiltIn("gl_MaxDrawBuffers", 100))
358                                            ->getConstPointer()
359                                            ->getIConst();
360                   }
361                   else
362                   {
363                       info.arraySize = 1;
364                   }
365                   info.precision = GL_MEDIUM_FLOAT;  // Defined by spec.
366                   info.staticUse = true;
367                   mOutputVariables->push_back(info);
368                   mFragDataAdded = true;
369               }
370               return;
371           case EvqFragDepthEXT:
372               if (!mFragDepthEXTAdded)
373               {
374                   OutputVariable info;
375                   const char kName[] = "gl_FragDepthEXT";
376                   info.name          = kName;
377                   info.mappedName    = kName;
378                   info.type          = GL_FLOAT;
379                   info.arraySize = 0;
380                   info.precision =
381                       GLVariablePrecision(static_cast<const TVariable *>(
382                                               mSymbolTable.findBuiltIn("gl_FragDepthEXT", 100))
383                                               ->getType());
384                   info.staticUse = true;
385                   mOutputVariables->push_back(info);
386                   mFragDepthEXTAdded = true;
387               }
388               return;
389           case EvqFragDepth:
390               if (!mFragDepthAdded)
391               {
392                   OutputVariable info;
393                   const char kName[] = "gl_FragDepth";
394                   info.name          = kName;
395                   info.mappedName    = kName;
396                   info.type          = GL_FLOAT;
397                   info.arraySize     = 0;
398                   info.precision     = GL_HIGH_FLOAT;
399                   info.staticUse = true;
400                   mOutputVariables->push_back(info);
401                   mFragDepthAdded = true;
402               }
403               return;
404           case EvqSecondaryFragColorEXT:
405               if (!mSecondaryFragColorEXTAdded)
406               {
407                   OutputVariable info;
408                   const char kName[] = "gl_SecondaryFragColorEXT";
409                   info.name          = kName;
410                   info.mappedName    = kName;
411                   info.type          = GL_FLOAT_VEC4;
412                   info.arraySize     = 0;
413                   info.precision     = GL_MEDIUM_FLOAT;  // Defined by spec.
414                   info.staticUse = true;
415                   mOutputVariables->push_back(info);
416                   mSecondaryFragColorEXTAdded = true;
417               }
418               return;
419           case EvqSecondaryFragDataEXT:
420               if (!mSecondaryFragDataEXTAdded)
421               {
422                   OutputVariable info;
423                   const char kName[] = "gl_SecondaryFragDataEXT";
424                   info.name          = kName;
425                   info.mappedName    = kName;
426                   info.type          = GL_FLOAT_VEC4;
427 
428                   const TVariable *maxDualSourceDrawBuffersVar = static_cast<const TVariable *>(
429                       mSymbolTable.findBuiltIn("gl_MaxDualSourceDrawBuffersEXT", 100));
430                   info.arraySize = maxDualSourceDrawBuffersVar->getConstPointer()->getIConst();
431                   info.precision = GL_MEDIUM_FLOAT;  // Defined by spec.
432                   info.staticUse = true;
433                   mOutputVariables->push_back(info);
434                   mSecondaryFragDataEXTAdded = true;
435               }
436               return;
437           default:
438             break;
439         }
440     }
441     if (var)
442     {
443         var->staticUse = true;
444     }
445 }
446 
447 class NameHashingTraverser : public GetVariableTraverser
448 {
449   public:
NameHashingTraverser(ShHashFunction64 hashFunction,const TSymbolTable & symbolTable)450     NameHashingTraverser(ShHashFunction64 hashFunction,
451                          const TSymbolTable &symbolTable)
452         : GetVariableTraverser(symbolTable),
453           mHashFunction(hashFunction)
454     {}
455 
456   private:
visitVariable(ShaderVariable * variable)457     void visitVariable(ShaderVariable *variable) override
458     {
459         TString stringName = TString(variable->name.c_str());
460         variable->mappedName = TIntermTraverser::hash(stringName, mHashFunction).c_str();
461     }
462 
463     ShHashFunction64 mHashFunction;
464 };
465 
466 // Attributes, which cannot have struct fields, are a special case
467 template <>
visitVariable(const TIntermSymbol * variable,std::vector<Attribute> * infoList) const468 void CollectVariables::visitVariable(const TIntermSymbol *variable,
469                                      std::vector<Attribute> *infoList) const
470 {
471     ASSERT(variable);
472     const TType &type = variable->getType();
473     ASSERT(!type.getStruct());
474 
475     Attribute attribute;
476 
477     attribute.type = GLVariableType(type);
478     attribute.precision = GLVariablePrecision(type);
479     attribute.name = variable->getSymbol().c_str();
480     attribute.arraySize  = type.getArraySize();
481     attribute.mappedName = TIntermTraverser::hash(variable->getSymbol(), mHashFunction).c_str();
482     attribute.location = variable->getType().getLayoutQualifier().location;
483 
484     infoList->push_back(attribute);
485 }
486 
487 template <>
visitVariable(const TIntermSymbol * variable,std::vector<OutputVariable> * infoList) const488 void CollectVariables::visitVariable(const TIntermSymbol *variable,
489                                      std::vector<OutputVariable> *infoList) const
490 {
491     ASSERT(variable);
492     const TType &type = variable->getType();
493     ASSERT(!type.getStruct());
494 
495     OutputVariable attribute;
496 
497     attribute.type       = GLVariableType(type);
498     attribute.precision  = GLVariablePrecision(type);
499     attribute.name       = variable->getSymbol().c_str();
500     attribute.arraySize  = type.getArraySize();
501     attribute.mappedName = TIntermTraverser::hash(variable->getSymbol(), mHashFunction).c_str();
502     attribute.location   = variable->getType().getLayoutQualifier().location;
503 
504     infoList->push_back(attribute);
505 }
506 
507 template <>
visitVariable(const TIntermSymbol * variable,std::vector<InterfaceBlock> * infoList) const508 void CollectVariables::visitVariable(const TIntermSymbol *variable,
509                                      std::vector<InterfaceBlock> *infoList) const
510 {
511     InterfaceBlock interfaceBlock;
512     const TInterfaceBlock *blockType = variable->getType().getInterfaceBlock();
513     ASSERT(blockType);
514 
515     interfaceBlock.name = blockType->name().c_str();
516     interfaceBlock.mappedName =
517         TIntermTraverser::hash(blockType->name().c_str(), mHashFunction).c_str();
518     interfaceBlock.instanceName = (blockType->hasInstanceName() ? blockType->instanceName().c_str() : "");
519     interfaceBlock.arraySize = variable->getArraySize();
520     interfaceBlock.isRowMajorLayout = (blockType->matrixPacking() == EmpRowMajor);
521     interfaceBlock.layout = GetBlockLayoutType(blockType->blockStorage());
522 
523     // Gather field information
524     for (const TField *field : blockType->fields())
525     {
526         const TType &fieldType = *field->type();
527 
528         NameHashingTraverser traverser(mHashFunction, mSymbolTable);
529         traverser.traverse(fieldType, field->name(), &interfaceBlock.fields);
530 
531         interfaceBlock.fields.back().isRowMajorLayout = (fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor);
532     }
533 
534     infoList->push_back(interfaceBlock);
535 }
536 
537 template <typename VarT>
visitVariable(const TIntermSymbol * variable,std::vector<VarT> * infoList) const538 void CollectVariables::visitVariable(const TIntermSymbol *variable,
539                                      std::vector<VarT> *infoList) const
540 {
541     NameHashingTraverser traverser(mHashFunction, mSymbolTable);
542     traverser.traverse(variable->getType(), variable->getSymbol(), infoList);
543 }
544 
545 template <typename VarT>
visitInfoList(const TIntermSequence & sequence,std::vector<VarT> * infoList) const546 void CollectVariables::visitInfoList(const TIntermSequence &sequence,
547                                      std::vector<VarT> *infoList) const
548 {
549     for (size_t seqIndex = 0; seqIndex < sequence.size(); seqIndex++)
550     {
551         const TIntermSymbol *variable = sequence[seqIndex]->getAsSymbolNode();
552         // The only case in which the sequence will not contain a
553         // TIntermSymbol node is initialization. It will contain a
554         // TInterBinary node in that case. Since attributes, uniforms,
555         // and varyings cannot be initialized in a shader, we must have
556         // only TIntermSymbol nodes in the sequence.
557         ASSERT(variable != NULL);
558         visitVariable(variable, infoList);
559     }
560 }
561 
visitDeclaration(Visit,TIntermDeclaration * node)562 bool CollectVariables::visitDeclaration(Visit, TIntermDeclaration *node)
563 {
564     const TIntermSequence &sequence = *(node->getSequence());
565     ASSERT(!sequence.empty());
566 
567     const TIntermTyped &typedNode = *(sequence.front()->getAsTyped());
568     TQualifier qualifier          = typedNode.getQualifier();
569 
570     if (typedNode.getBasicType() == EbtInterfaceBlock)
571     {
572         visitInfoList(sequence, mInterfaceBlocks);
573         return false;
574     }
575     else if (qualifier == EvqAttribute || qualifier == EvqVertexIn || qualifier == EvqFragmentOut ||
576              qualifier == EvqUniform || IsVarying(qualifier))
577     {
578         switch (qualifier)
579         {
580             case EvqAttribute:
581             case EvqVertexIn:
582                 visitInfoList(sequence, mAttribs);
583                 break;
584             case EvqFragmentOut:
585                 visitInfoList(sequence, mOutputVariables);
586                 break;
587             case EvqUniform:
588                 visitInfoList(sequence, mUniforms);
589                 break;
590             default:
591                 visitInfoList(sequence, mVaryings);
592                 break;
593         }
594 
595         return false;
596     }
597 
598     return true;
599 }
600 
visitBinary(Visit,TIntermBinary * binaryNode)601 bool CollectVariables::visitBinary(Visit, TIntermBinary *binaryNode)
602 {
603     if (binaryNode->getOp() == EOpIndexDirectInterfaceBlock)
604     {
605         // NOTE: we do not determine static use for individual blocks of an array
606         TIntermTyped *blockNode = binaryNode->getLeft()->getAsTyped();
607         ASSERT(blockNode);
608 
609         TIntermConstantUnion *constantUnion = binaryNode->getRight()->getAsConstantUnion();
610         ASSERT(constantUnion);
611 
612         const TInterfaceBlock *interfaceBlock = blockNode->getType().getInterfaceBlock();
613         InterfaceBlock *namedBlock = FindVariable(interfaceBlock->name(), mInterfaceBlocks);
614         ASSERT(namedBlock);
615         namedBlock->staticUse = true;
616 
617         unsigned int fieldIndex = constantUnion->getUConst(0);
618         ASSERT(fieldIndex < namedBlock->fields.size());
619         namedBlock->fields[fieldIndex].staticUse = true;
620         return false;
621     }
622 
623     return true;
624 }
625 
ExpandVariable(const ShaderVariable & variable,const std::string & name,const std::string & mappedName,bool markStaticUse,std::vector<ShaderVariable> * expanded)626 void ExpandVariable(const ShaderVariable &variable,
627                     const std::string &name,
628                     const std::string &mappedName,
629                     bool markStaticUse,
630                     std::vector<ShaderVariable> *expanded)
631 {
632     if (variable.isStruct())
633     {
634         if (variable.isArray())
635         {
636             for (unsigned int elementIndex = 0; elementIndex < variable.elementCount();
637                  elementIndex++)
638             {
639                 std::string lname       = name + ::ArrayString(elementIndex);
640                 std::string lmappedName = mappedName + ::ArrayString(elementIndex);
641                 ExpandUserDefinedVariable(variable, lname, lmappedName, markStaticUse, expanded);
642             }
643         }
644         else
645         {
646             ExpandUserDefinedVariable(variable, name, mappedName, markStaticUse, expanded);
647         }
648     }
649     else
650     {
651         ShaderVariable expandedVar = variable;
652 
653         expandedVar.name       = name;
654         expandedVar.mappedName = mappedName;
655 
656         // Mark all expanded fields as used if the parent is used
657         if (markStaticUse)
658         {
659             expandedVar.staticUse = true;
660         }
661 
662         if (expandedVar.isArray())
663         {
664             expandedVar.name += "[0]";
665             expandedVar.mappedName += "[0]";
666         }
667 
668         expanded->push_back(expandedVar);
669     }
670 }
671 
ExpandUniforms(const std::vector<Uniform> & compact,std::vector<ShaderVariable> * expanded)672 void ExpandUniforms(const std::vector<Uniform> &compact,
673                     std::vector<ShaderVariable> *expanded)
674 {
675     for (size_t variableIndex = 0; variableIndex < compact.size(); variableIndex++)
676     {
677         const ShaderVariable &variable = compact[variableIndex];
678         ExpandVariable(variable, variable.name, variable.mappedName, variable.staticUse, expanded);
679     }
680 }
681 
682 }
683