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