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