• 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 
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