1 //
2 // Copyright 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 // blocklayout.cpp:
7 //   Implementation for block layout classes and methods.
8 //
9 
10 #include "compiler/translator/blocklayout.h"
11 
12 #include "common/mathutil.h"
13 #include "common/utilities.h"
14 #include "compiler/translator/Common.h"
15 
16 namespace sh
17 {
18 
19 namespace
20 {
21 class BlockLayoutMapVisitor : public BlockEncoderVisitor
22 {
23   public:
BlockLayoutMapVisitor(BlockLayoutMap * blockInfoOut,const std::string & instanceName,BlockLayoutEncoder * encoder)24     BlockLayoutMapVisitor(BlockLayoutMap *blockInfoOut,
25                           const std::string &instanceName,
26                           BlockLayoutEncoder *encoder)
27         : BlockEncoderVisitor(instanceName, instanceName, encoder), mInfoOut(blockInfoOut)
28     {}
29 
encodeVariable(const ShaderVariable & variable,const BlockMemberInfo & variableInfo,const std::string & name,const std::string & mappedName)30     void encodeVariable(const ShaderVariable &variable,
31                         const BlockMemberInfo &variableInfo,
32                         const std::string &name,
33                         const std::string &mappedName) override
34     {
35         ASSERT(!gl::IsSamplerType(variable.type));
36         if (!gl::IsOpaqueType(variable.type))
37         {
38             (*mInfoOut)[name] = variableInfo;
39         }
40     }
41 
42   private:
43     BlockLayoutMap *mInfoOut;
44 };
45 
46 template <typename VarT>
GetInterfaceBlockInfo(const std::vector<VarT> & fields,const std::string & prefix,BlockLayoutEncoder * encoder,bool inRowMajorLayout,bool onlyActiveVariables,BlockLayoutMap * blockInfoOut)47 void GetInterfaceBlockInfo(const std::vector<VarT> &fields,
48                            const std::string &prefix,
49                            BlockLayoutEncoder *encoder,
50                            bool inRowMajorLayout,
51                            bool onlyActiveVariables,
52                            BlockLayoutMap *blockInfoOut)
53 {
54     BlockLayoutMapVisitor visitor(blockInfoOut, prefix, encoder);
55     if (onlyActiveVariables)
56     {
57         TraverseActiveShaderVariables(fields, inRowMajorLayout, &visitor);
58     }
59     else
60     {
61         TraverseShaderVariables(fields, inRowMajorLayout, &visitor);
62     }
63 }
64 
TraverseStructVariable(const ShaderVariable & variable,bool isRowMajorLayout,ShaderVariableVisitor * visitor)65 void TraverseStructVariable(const ShaderVariable &variable,
66                             bool isRowMajorLayout,
67                             ShaderVariableVisitor *visitor)
68 {
69     const std::vector<ShaderVariable> &fields = variable.fields;
70 
71     visitor->enterStructAccess(variable, isRowMajorLayout);
72     TraverseShaderVariables(fields, isRowMajorLayout, visitor);
73     visitor->exitStructAccess(variable, isRowMajorLayout);
74 }
75 
TraverseStructArrayVariable(const ShaderVariable & variable,bool inRowMajorLayout,ShaderVariableVisitor * visitor)76 void TraverseStructArrayVariable(const ShaderVariable &variable,
77                                  bool inRowMajorLayout,
78                                  ShaderVariableVisitor *visitor)
79 {
80     visitor->enterArray(variable);
81 
82     // Nested arrays are processed starting from outermost (arrayNestingIndex 0u) and ending at the
83     // innermost. We make a special case for unsized arrays.
84     const unsigned int currentArraySize = variable.getNestedArraySize(0);
85     for (unsigned int arrayElement = 0u; arrayElement < currentArraySize; ++arrayElement)
86     {
87         visitor->enterArrayElement(variable, arrayElement);
88         ShaderVariable elementVar = variable;
89         elementVar.indexIntoArray(arrayElement);
90 
91         if (variable.arraySizes.size() > 1u)
92         {
93             TraverseStructArrayVariable(elementVar, inRowMajorLayout, visitor);
94         }
95         else
96         {
97             TraverseStructVariable(elementVar, inRowMajorLayout, visitor);
98         }
99 
100         visitor->exitArrayElement(variable, arrayElement);
101     }
102 
103     visitor->exitArray(variable);
104 }
105 
TraverseArrayOfArraysVariable(const ShaderVariable & variable,unsigned int arrayNestingIndex,bool isRowMajorMatrix,ShaderVariableVisitor * visitor)106 void TraverseArrayOfArraysVariable(const ShaderVariable &variable,
107                                    unsigned int arrayNestingIndex,
108                                    bool isRowMajorMatrix,
109                                    ShaderVariableVisitor *visitor)
110 {
111     visitor->enterArray(variable);
112 
113     const unsigned int currentArraySize = variable.getNestedArraySize(arrayNestingIndex);
114     unsigned int count                  = std::max(currentArraySize, 1u);
115     for (unsigned int arrayElement = 0u; arrayElement < count; ++arrayElement)
116     {
117         visitor->enterArrayElement(variable, arrayElement);
118 
119         ShaderVariable elementVar = variable;
120         elementVar.indexIntoArray(arrayElement);
121 
122         if (arrayNestingIndex + 2u < variable.arraySizes.size())
123         {
124             TraverseArrayOfArraysVariable(elementVar, arrayNestingIndex, isRowMajorMatrix, visitor);
125         }
126         else
127         {
128             if (gl::IsSamplerType(variable.type) || gl::IsImageType(variable.type) ||
129                 variable.isFragmentInOut)
130             {
131                 visitor->visitOpaqueObject(elementVar);
132             }
133             else
134             {
135                 visitor->visitVariable(elementVar, isRowMajorMatrix);
136             }
137         }
138 
139         visitor->exitArrayElement(variable, arrayElement);
140     }
141 
142     visitor->exitArray(variable);
143 }
144 
CollapseNameStack(const std::vector<std::string> & nameStack)145 std::string CollapseNameStack(const std::vector<std::string> &nameStack)
146 {
147     std::stringstream strstr = sh::InitializeStream<std::stringstream>();
148     for (const std::string &part : nameStack)
149     {
150         strstr << part;
151     }
152     return strstr.str();
153 }
154 
GetStd430BaseAlignment(GLenum variableType,bool isRowMajor)155 size_t GetStd430BaseAlignment(GLenum variableType, bool isRowMajor)
156 {
157     GLenum flippedType   = isRowMajor ? variableType : gl::TransposeMatrixType(variableType);
158     size_t numComponents = static_cast<size_t>(gl::VariableColumnCount(flippedType));
159     return ComponentAlignment(numComponents);
160 }
161 
162 class BaseAlignmentVisitor : public ShaderVariableVisitor
163 {
164   public:
165     BaseAlignmentVisitor() = default;
visitVariable(const ShaderVariable & variable,bool isRowMajor)166     void visitVariable(const ShaderVariable &variable, bool isRowMajor) override
167     {
168         size_t baseAlignment = GetStd430BaseAlignment(variable.type, isRowMajor);
169         mCurrentAlignment    = std::max(mCurrentAlignment, baseAlignment);
170     }
171 
172     // This is in components rather than bytes.
getBaseAlignment() const173     size_t getBaseAlignment() const { return mCurrentAlignment; }
174 
175   private:
176     size_t mCurrentAlignment = 0;
177 };
178 }  // anonymous namespace
179 
180 // BlockLayoutEncoder implementation.
BlockLayoutEncoder()181 BlockLayoutEncoder::BlockLayoutEncoder() : mCurrentOffset(0) {}
182 
encodeType(GLenum type,const std::vector<unsigned int> & arraySizes,bool isRowMajorMatrix)183 BlockMemberInfo BlockLayoutEncoder::encodeType(GLenum type,
184                                                const std::vector<unsigned int> &arraySizes,
185                                                bool isRowMajorMatrix)
186 {
187     int arrayStride;
188     int matrixStride;
189 
190     getBlockLayoutInfo(type, arraySizes, isRowMajorMatrix, &arrayStride, &matrixStride);
191 
192     const BlockMemberInfo memberInfo(static_cast<int>(mCurrentOffset * kBytesPerComponent),
193                                      static_cast<int>(arrayStride * kBytesPerComponent),
194                                      static_cast<int>(matrixStride * kBytesPerComponent),
195                                      isRowMajorMatrix);
196 
197     advanceOffset(type, arraySizes, isRowMajorMatrix, arrayStride, matrixStride);
198 
199     return memberInfo;
200 }
201 
encodeArrayOfPreEncodedStructs(size_t size,const std::vector<unsigned int> & arraySizes)202 BlockMemberInfo BlockLayoutEncoder::encodeArrayOfPreEncodedStructs(
203     size_t size,
204     const std::vector<unsigned int> &arraySizes)
205 {
206     const unsigned int innerArraySizeProduct = gl::InnerArraySizeProduct(arraySizes);
207     const unsigned int outermostArraySize    = gl::OutermostArraySize(arraySizes);
208 
209     // The size of struct is expected to be already aligned appropriately.
210     const size_t arrayStride = size * innerArraySizeProduct;
211 
212     const BlockMemberInfo memberInfo(static_cast<int>(mCurrentOffset * kBytesPerComponent),
213                                      static_cast<int>(arrayStride), -1, false);
214 
215     mCurrentOffset += arrayStride * outermostArraySize / kBytesPerComponent;
216 
217     return memberInfo;
218 }
219 
getShaderVariableSize(const ShaderVariable & structVar,bool isRowMajor)220 size_t BlockLayoutEncoder::getShaderVariableSize(const ShaderVariable &structVar, bool isRowMajor)
221 {
222     size_t currentOffset = mCurrentOffset;
223     mCurrentOffset       = 0;
224     BlockEncoderVisitor visitor("", "", this);
225     enterAggregateType(structVar);
226     TraverseShaderVariables(structVar.fields, isRowMajor, &visitor);
227     exitAggregateType(structVar);
228     size_t structVarSize = getCurrentOffset();
229     mCurrentOffset       = currentOffset;
230     return structVarSize;
231 }
232 
233 // static
GetBlockRegister(const BlockMemberInfo & info)234 size_t BlockLayoutEncoder::GetBlockRegister(const BlockMemberInfo &info)
235 {
236     return (info.offset / kBytesPerComponent) / kComponentsPerRegister;
237 }
238 
239 // static
GetBlockRegisterElement(const BlockMemberInfo & info)240 size_t BlockLayoutEncoder::GetBlockRegisterElement(const BlockMemberInfo &info)
241 {
242     return (info.offset / kBytesPerComponent) % kComponentsPerRegister;
243 }
244 
align(size_t baseAlignment)245 void BlockLayoutEncoder::align(size_t baseAlignment)
246 {
247     mCurrentOffset = rx::roundUp<size_t>(mCurrentOffset, baseAlignment);
248 }
249 
250 // StubBlockEncoder implementation.
getBlockLayoutInfo(GLenum type,const std::vector<unsigned int> & arraySizes,bool isRowMajorMatrix,int * arrayStrideOut,int * matrixStrideOut)251 void StubBlockEncoder::getBlockLayoutInfo(GLenum type,
252                                           const std::vector<unsigned int> &arraySizes,
253                                           bool isRowMajorMatrix,
254                                           int *arrayStrideOut,
255                                           int *matrixStrideOut)
256 {
257     *arrayStrideOut  = 0;
258     *matrixStrideOut = 0;
259 }
260 
261 // Std140BlockEncoder implementation.
Std140BlockEncoder()262 Std140BlockEncoder::Std140BlockEncoder() {}
263 
enterAggregateType(const ShaderVariable & structVar)264 void Std140BlockEncoder::enterAggregateType(const ShaderVariable &structVar)
265 {
266     align(getBaseAlignment(structVar));
267 }
268 
exitAggregateType(const ShaderVariable & structVar)269 void Std140BlockEncoder::exitAggregateType(const ShaderVariable &structVar)
270 {
271     align(getBaseAlignment(structVar));
272 }
273 
getBlockLayoutInfo(GLenum type,const std::vector<unsigned int> & arraySizes,bool isRowMajorMatrix,int * arrayStrideOut,int * matrixStrideOut)274 void Std140BlockEncoder::getBlockLayoutInfo(GLenum type,
275                                             const std::vector<unsigned int> &arraySizes,
276                                             bool isRowMajorMatrix,
277                                             int *arrayStrideOut,
278                                             int *matrixStrideOut)
279 {
280     // We assume we are only dealing with 4 byte components (no doubles or half-words currently)
281     ASSERT(gl::VariableComponentSize(gl::VariableComponentType(type)) == kBytesPerComponent);
282 
283     size_t baseAlignment = 0;
284     int matrixStride     = 0;
285     int arrayStride      = 0;
286 
287     if (gl::IsMatrixType(type))
288     {
289         baseAlignment = getTypeBaseAlignment(type, isRowMajorMatrix);
290         matrixStride  = static_cast<int>(getTypeBaseAlignment(type, isRowMajorMatrix));
291 
292         if (!arraySizes.empty())
293         {
294             const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
295             arrayStride =
296                 static_cast<int>(getTypeBaseAlignment(type, isRowMajorMatrix) * numRegisters);
297         }
298     }
299     else if (!arraySizes.empty())
300     {
301         baseAlignment = static_cast<int>(getTypeBaseAlignment(type, false));
302         arrayStride   = static_cast<int>(getTypeBaseAlignment(type, false));
303     }
304     else
305     {
306         const size_t numComponents = static_cast<size_t>(gl::VariableComponentCount(type));
307         baseAlignment              = ComponentAlignment(numComponents);
308     }
309 
310     mCurrentOffset = rx::roundUp(mCurrentOffset, baseAlignment);
311 
312     *matrixStrideOut = matrixStride;
313     *arrayStrideOut  = arrayStride;
314 }
315 
advanceOffset(GLenum type,const std::vector<unsigned int> & arraySizes,bool isRowMajorMatrix,int arrayStride,int matrixStride)316 void Std140BlockEncoder::advanceOffset(GLenum type,
317                                        const std::vector<unsigned int> &arraySizes,
318                                        bool isRowMajorMatrix,
319                                        int arrayStride,
320                                        int matrixStride)
321 {
322     if (!arraySizes.empty())
323     {
324         mCurrentOffset += arrayStride * gl::ArraySizeProduct(arraySizes);
325     }
326     else if (gl::IsMatrixType(type))
327     {
328         const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
329         mCurrentOffset += matrixStride * numRegisters;
330     }
331     else
332     {
333         mCurrentOffset += gl::VariableComponentCount(type);
334     }
335 }
336 
getBaseAlignment(const ShaderVariable & variable) const337 size_t Std140BlockEncoder::getBaseAlignment(const ShaderVariable &variable) const
338 {
339     return kComponentsPerRegister;
340 }
341 
getTypeBaseAlignment(GLenum type,bool isRowMajorMatrix) const342 size_t Std140BlockEncoder::getTypeBaseAlignment(GLenum type, bool isRowMajorMatrix) const
343 {
344     return kComponentsPerRegister;
345 }
346 
347 // Std430BlockEncoder implementation.
Std430BlockEncoder()348 Std430BlockEncoder::Std430BlockEncoder() {}
349 
getBaseAlignment(const ShaderVariable & shaderVar) const350 size_t Std430BlockEncoder::getBaseAlignment(const ShaderVariable &shaderVar) const
351 {
352     if (shaderVar.isStruct())
353     {
354         BaseAlignmentVisitor visitor;
355         TraverseShaderVariables(shaderVar.fields, false, &visitor);
356         return visitor.getBaseAlignment();
357     }
358 
359     return GetStd430BaseAlignment(shaderVar.type, shaderVar.isRowMajorLayout);
360 }
361 
getTypeBaseAlignment(GLenum type,bool isRowMajorMatrix) const362 size_t Std430BlockEncoder::getTypeBaseAlignment(GLenum type, bool isRowMajorMatrix) const
363 {
364     return GetStd430BaseAlignment(type, isRowMajorMatrix);
365 }
366 
GetInterfaceBlockInfo(const std::vector<ShaderVariable> & fields,const std::string & prefix,BlockLayoutEncoder * encoder,BlockLayoutMap * blockInfoOut)367 void GetInterfaceBlockInfo(const std::vector<ShaderVariable> &fields,
368                            const std::string &prefix,
369                            BlockLayoutEncoder *encoder,
370                            BlockLayoutMap *blockInfoOut)
371 {
372     // Matrix packing is always recorded in individual fields, so they'll set the row major layout
373     // flag to true if needed.
374     // Iterates over all variables.
375     GetInterfaceBlockInfo(fields, prefix, encoder, false, false, blockInfoOut);
376 }
377 
GetActiveUniformBlockInfo(const std::vector<ShaderVariable> & uniforms,const std::string & prefix,BlockLayoutEncoder * encoder,BlockLayoutMap * blockInfoOut)378 void GetActiveUniformBlockInfo(const std::vector<ShaderVariable> &uniforms,
379                                const std::string &prefix,
380                                BlockLayoutEncoder *encoder,
381                                BlockLayoutMap *blockInfoOut)
382 {
383     // Matrix packing is always recorded in individual fields, so they'll set the row major layout
384     // flag to true if needed.
385     // Iterates only over the active variables.
386     GetInterfaceBlockInfo(uniforms, prefix, encoder, false, true, blockInfoOut);
387 }
388 
389 // VariableNameVisitor implementation.
VariableNameVisitor(const std::string & namePrefix,const std::string & mappedNamePrefix)390 VariableNameVisitor::VariableNameVisitor(const std::string &namePrefix,
391                                          const std::string &mappedNamePrefix)
392 {
393     if (!namePrefix.empty())
394     {
395         mNameStack.push_back(namePrefix + ".");
396     }
397 
398     if (!mappedNamePrefix.empty())
399     {
400         mMappedNameStack.push_back(mappedNamePrefix + ".");
401     }
402 }
403 
404 VariableNameVisitor::~VariableNameVisitor() = default;
405 
enterStruct(const ShaderVariable & structVar)406 void VariableNameVisitor::enterStruct(const ShaderVariable &structVar)
407 {
408     mNameStack.push_back(structVar.name);
409     mMappedNameStack.push_back(structVar.mappedName);
410 }
411 
exitStruct(const ShaderVariable & structVar)412 void VariableNameVisitor::exitStruct(const ShaderVariable &structVar)
413 {
414     mNameStack.pop_back();
415     mMappedNameStack.pop_back();
416 }
417 
enterStructAccess(const ShaderVariable & structVar,bool isRowMajor)418 void VariableNameVisitor::enterStructAccess(const ShaderVariable &structVar, bool isRowMajor)
419 {
420     mNameStack.push_back(".");
421     mMappedNameStack.push_back(".");
422 }
423 
exitStructAccess(const ShaderVariable & structVar,bool isRowMajor)424 void VariableNameVisitor::exitStructAccess(const ShaderVariable &structVar, bool isRowMajor)
425 {
426     mNameStack.pop_back();
427     mMappedNameStack.pop_back();
428 }
429 
enterArray(const ShaderVariable & arrayVar)430 void VariableNameVisitor::enterArray(const ShaderVariable &arrayVar)
431 {
432     if (!arrayVar.hasParentArrayIndex() && !arrayVar.isStruct())
433     {
434         mNameStack.push_back(arrayVar.name);
435         mMappedNameStack.push_back(arrayVar.mappedName);
436     }
437     mArraySizeStack.push_back(arrayVar.getOutermostArraySize());
438 }
439 
exitArray(const ShaderVariable & arrayVar)440 void VariableNameVisitor::exitArray(const ShaderVariable &arrayVar)
441 {
442     if (!arrayVar.hasParentArrayIndex() && !arrayVar.isStruct())
443     {
444         mNameStack.pop_back();
445         mMappedNameStack.pop_back();
446     }
447     mArraySizeStack.pop_back();
448 }
449 
enterArrayElement(const ShaderVariable & arrayVar,unsigned int arrayElement)450 void VariableNameVisitor::enterArrayElement(const ShaderVariable &arrayVar,
451                                             unsigned int arrayElement)
452 {
453     std::stringstream strstr = sh::InitializeStream<std::stringstream>();
454     strstr << "[" << arrayElement << "]";
455     std::string elementString = strstr.str();
456     mNameStack.push_back(elementString);
457     mMappedNameStack.push_back(elementString);
458 }
459 
exitArrayElement(const ShaderVariable & arrayVar,unsigned int arrayElement)460 void VariableNameVisitor::exitArrayElement(const ShaderVariable &arrayVar,
461                                            unsigned int arrayElement)
462 {
463     mNameStack.pop_back();
464     mMappedNameStack.pop_back();
465 }
466 
collapseNameStack() const467 std::string VariableNameVisitor::collapseNameStack() const
468 {
469     return CollapseNameStack(mNameStack);
470 }
471 
collapseMappedNameStack() const472 std::string VariableNameVisitor::collapseMappedNameStack() const
473 {
474     return CollapseNameStack(mMappedNameStack);
475 }
476 
visitOpaqueObject(const sh::ShaderVariable & variable)477 void VariableNameVisitor::visitOpaqueObject(const sh::ShaderVariable &variable)
478 {
479     if (!variable.hasParentArrayIndex())
480     {
481         mNameStack.push_back(variable.name);
482         mMappedNameStack.push_back(variable.mappedName);
483     }
484 
485     std::string name       = collapseNameStack();
486     std::string mappedName = collapseMappedNameStack();
487 
488     if (!variable.hasParentArrayIndex())
489     {
490         mNameStack.pop_back();
491         mMappedNameStack.pop_back();
492     }
493 
494     visitNamedOpaqueObject(variable, name, mappedName, mArraySizeStack);
495 }
496 
visitVariable(const ShaderVariable & variable,bool isRowMajor)497 void VariableNameVisitor::visitVariable(const ShaderVariable &variable, bool isRowMajor)
498 {
499     if (!variable.hasParentArrayIndex())
500     {
501         mNameStack.push_back(variable.name);
502         mMappedNameStack.push_back(variable.mappedName);
503     }
504 
505     std::string name       = collapseNameStack();
506     std::string mappedName = collapseMappedNameStack();
507 
508     if (!variable.hasParentArrayIndex())
509     {
510         mNameStack.pop_back();
511         mMappedNameStack.pop_back();
512     }
513 
514     visitNamedVariable(variable, isRowMajor, name, mappedName, mArraySizeStack);
515 }
516 
517 // BlockEncoderVisitor implementation.
BlockEncoderVisitor(const std::string & namePrefix,const std::string & mappedNamePrefix,BlockLayoutEncoder * encoder)518 BlockEncoderVisitor::BlockEncoderVisitor(const std::string &namePrefix,
519                                          const std::string &mappedNamePrefix,
520                                          BlockLayoutEncoder *encoder)
521     : VariableNameVisitor(namePrefix, mappedNamePrefix), mEncoder(encoder)
522 {}
523 
524 BlockEncoderVisitor::~BlockEncoderVisitor() = default;
525 
enterStructAccess(const ShaderVariable & structVar,bool isRowMajor)526 void BlockEncoderVisitor::enterStructAccess(const ShaderVariable &structVar, bool isRowMajor)
527 {
528     mStructStackSize++;
529     if (!mIsTopLevelArrayStrideReady)
530     {
531         size_t structSize = mEncoder->getShaderVariableSize(structVar, isRowMajor);
532         mTopLevelArrayStride *= structSize;
533         mIsTopLevelArrayStrideReady = true;
534     }
535 
536     VariableNameVisitor::enterStructAccess(structVar, isRowMajor);
537     mEncoder->enterAggregateType(structVar);
538 }
539 
exitStructAccess(const ShaderVariable & structVar,bool isRowMajor)540 void BlockEncoderVisitor::exitStructAccess(const ShaderVariable &structVar, bool isRowMajor)
541 {
542     mStructStackSize--;
543     mEncoder->exitAggregateType(structVar);
544     VariableNameVisitor::exitStructAccess(structVar, isRowMajor);
545 }
546 
enterArrayElement(const sh::ShaderVariable & arrayVar,unsigned int arrayElement)547 void BlockEncoderVisitor::enterArrayElement(const sh::ShaderVariable &arrayVar,
548                                             unsigned int arrayElement)
549 {
550     if (mStructStackSize == 0 && !arrayVar.hasParentArrayIndex())
551     {
552         // From the ES 3.1 spec "7.3.1.1 Naming Active Resources":
553         // For an active shader storage block member declared as an array of an aggregate type,
554         // an entry will be generated only for the first array element, regardless of its type.
555         // Such block members are referred to as top-level arrays. If the block member is an
556         // aggregate type, the enumeration rules are then applied recursively.
557         if (arrayElement == 0)
558         {
559             mTopLevelArraySize          = arrayVar.getOutermostArraySize();
560             mTopLevelArrayStride        = arrayVar.getInnerArraySizeProduct();
561             mIsTopLevelArrayStrideReady = false;
562         }
563         else
564         {
565             mSkipEnabled = true;
566         }
567     }
568     VariableNameVisitor::enterArrayElement(arrayVar, arrayElement);
569 }
570 
exitArrayElement(const sh::ShaderVariable & arrayVar,unsigned int arrayElement)571 void BlockEncoderVisitor::exitArrayElement(const sh::ShaderVariable &arrayVar,
572                                            unsigned int arrayElement)
573 {
574     if (mStructStackSize == 0 && !arrayVar.hasParentArrayIndex())
575     {
576         mTopLevelArraySize          = 1;
577         mTopLevelArrayStride        = 0;
578         mIsTopLevelArrayStrideReady = true;
579         mSkipEnabled                = false;
580     }
581     VariableNameVisitor::exitArrayElement(arrayVar, arrayElement);
582 }
583 
visitNamedVariable(const ShaderVariable & variable,bool isRowMajor,const std::string & name,const std::string & mappedName,const std::vector<unsigned int> & arraySizes)584 void BlockEncoderVisitor::visitNamedVariable(const ShaderVariable &variable,
585                                              bool isRowMajor,
586                                              const std::string &name,
587                                              const std::string &mappedName,
588                                              const std::vector<unsigned int> &arraySizes)
589 {
590     std::vector<unsigned int> innermostArraySize;
591 
592     if (variable.isArray())
593     {
594         innermostArraySize.push_back(variable.getNestedArraySize(0));
595     }
596     BlockMemberInfo variableInfo =
597         mEncoder->encodeType(variable.type, innermostArraySize, isRowMajor);
598     if (!mIsTopLevelArrayStrideReady)
599     {
600         ASSERT(mTopLevelArrayStride);
601         mTopLevelArrayStride *= variableInfo.arrayStride;
602         mIsTopLevelArrayStrideReady = true;
603     }
604     variableInfo.topLevelArrayStride = mTopLevelArrayStride;
605     encodeVariable(variable, variableInfo, name, mappedName);
606 }
607 
TraverseShaderVariable(const ShaderVariable & variable,bool isRowMajorLayout,ShaderVariableVisitor * visitor)608 void TraverseShaderVariable(const ShaderVariable &variable,
609                             bool isRowMajorLayout,
610                             ShaderVariableVisitor *visitor)
611 {
612     bool rowMajorLayout = (isRowMajorLayout || variable.isRowMajorLayout);
613     bool isRowMajor     = rowMajorLayout && gl::IsMatrixType(variable.type);
614 
615     if (variable.isStruct())
616     {
617         visitor->enterStruct(variable);
618         if (variable.isArray())
619         {
620             TraverseStructArrayVariable(variable, rowMajorLayout, visitor);
621         }
622         else
623         {
624             TraverseStructVariable(variable, rowMajorLayout, visitor);
625         }
626         visitor->exitStruct(variable);
627     }
628     else if (variable.isArrayOfArrays())
629     {
630         TraverseArrayOfArraysVariable(variable, 0u, isRowMajor, visitor);
631     }
632     else if (gl::IsSamplerType(variable.type) || gl::IsImageType(variable.type) ||
633              variable.isFragmentInOut)
634     {
635         visitor->visitOpaqueObject(variable);
636     }
637     else
638     {
639         visitor->visitVariable(variable, isRowMajor);
640     }
641 }
642 }  // namespace sh
643