• 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,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     angle::base::CheckedNumeric<size_t> checkedOffset(arrayStride);
216     checkedOffset *= outermostArraySize;
217     checkedOffset /= kBytesPerComponent;
218     checkedOffset += mCurrentOffset;
219     mCurrentOffset = checkedOffset.ValueOrDefault(std::numeric_limits<size_t>::max());
220 
221     return memberInfo;
222 }
223 
getCurrentOffset() const224 size_t BlockLayoutEncoder::getCurrentOffset() const
225 {
226     angle::base::CheckedNumeric<size_t> checkedOffset(mCurrentOffset);
227     checkedOffset *= kBytesPerComponent;
228     return checkedOffset.ValueOrDefault(std::numeric_limits<size_t>::max());
229 }
230 
getShaderVariableSize(const ShaderVariable & structVar,bool isRowMajor)231 size_t BlockLayoutEncoder::getShaderVariableSize(const ShaderVariable &structVar, bool isRowMajor)
232 {
233     size_t currentOffset = mCurrentOffset;
234     mCurrentOffset       = 0;
235     BlockEncoderVisitor visitor("", "", this);
236     enterAggregateType(structVar);
237     TraverseShaderVariables(structVar.fields, isRowMajor, &visitor);
238     exitAggregateType(structVar);
239     size_t structVarSize = getCurrentOffset();
240     mCurrentOffset       = currentOffset;
241     return structVarSize;
242 }
243 
244 // static
GetBlockRegister(const BlockMemberInfo & info)245 size_t BlockLayoutEncoder::GetBlockRegister(const BlockMemberInfo &info)
246 {
247     return (info.offset / kBytesPerComponent) / kComponentsPerRegister;
248 }
249 
250 // static
GetBlockRegisterElement(const BlockMemberInfo & info)251 size_t BlockLayoutEncoder::GetBlockRegisterElement(const BlockMemberInfo &info)
252 {
253     return (info.offset / kBytesPerComponent) % kComponentsPerRegister;
254 }
255 
align(size_t baseAlignment)256 void BlockLayoutEncoder::align(size_t baseAlignment)
257 {
258     angle::base::CheckedNumeric<size_t> checkedOffset(mCurrentOffset);
259     checkedOffset += baseAlignment;
260     checkedOffset -= 1;
261     angle::base::CheckedNumeric<size_t> checkedAlignmentOffset = checkedOffset;
262     checkedAlignmentOffset %= baseAlignment;
263     checkedOffset -= checkedAlignmentOffset.ValueOrDefault(std::numeric_limits<size_t>::max());
264     mCurrentOffset = checkedOffset.ValueOrDefault(std::numeric_limits<size_t>::max());
265 }
266 
267 // StubBlockEncoder implementation.
getBlockLayoutInfo(GLenum type,const std::vector<unsigned int> & arraySizes,bool isRowMajorMatrix,int * arrayStrideOut,int * matrixStrideOut)268 void StubBlockEncoder::getBlockLayoutInfo(GLenum type,
269                                           const std::vector<unsigned int> &arraySizes,
270                                           bool isRowMajorMatrix,
271                                           int *arrayStrideOut,
272                                           int *matrixStrideOut)
273 {
274     *arrayStrideOut  = 0;
275     *matrixStrideOut = 0;
276 }
277 
278 // Std140BlockEncoder implementation.
Std140BlockEncoder()279 Std140BlockEncoder::Std140BlockEncoder() {}
280 
enterAggregateType(const ShaderVariable & structVar)281 void Std140BlockEncoder::enterAggregateType(const ShaderVariable &structVar)
282 {
283     align(getBaseAlignment(structVar));
284 }
285 
exitAggregateType(const ShaderVariable & structVar)286 void Std140BlockEncoder::exitAggregateType(const ShaderVariable &structVar)
287 {
288     align(getBaseAlignment(structVar));
289 }
290 
getBlockLayoutInfo(GLenum type,const std::vector<unsigned int> & arraySizes,bool isRowMajorMatrix,int * arrayStrideOut,int * matrixStrideOut)291 void Std140BlockEncoder::getBlockLayoutInfo(GLenum type,
292                                             const std::vector<unsigned int> &arraySizes,
293                                             bool isRowMajorMatrix,
294                                             int *arrayStrideOut,
295                                             int *matrixStrideOut)
296 {
297     // We assume we are only dealing with 4 byte components (no doubles or half-words currently)
298     ASSERT(gl::VariableComponentSize(gl::VariableComponentType(type)) == kBytesPerComponent);
299 
300     size_t baseAlignment = 0;
301     int matrixStride     = 0;
302     int arrayStride      = 0;
303 
304     if (gl::IsMatrixType(type))
305     {
306         baseAlignment = getTypeBaseAlignment(type, isRowMajorMatrix);
307         matrixStride  = static_cast<int>(getTypeBaseAlignment(type, isRowMajorMatrix));
308 
309         if (!arraySizes.empty())
310         {
311             const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix);
312             arrayStride =
313                 static_cast<int>(getTypeBaseAlignment(type, isRowMajorMatrix) * numRegisters);
314         }
315     }
316     else if (!arraySizes.empty())
317     {
318         baseAlignment = static_cast<int>(getTypeBaseAlignment(type, false));
319         arrayStride   = static_cast<int>(getTypeBaseAlignment(type, false));
320     }
321     else
322     {
323         const size_t numComponents = static_cast<size_t>(gl::VariableComponentCount(type));
324         baseAlignment              = ComponentAlignment(numComponents);
325     }
326 
327     align(baseAlignment);
328 
329     *matrixStrideOut = matrixStride;
330     *arrayStrideOut  = arrayStride;
331 }
332 
advanceOffset(GLenum type,const std::vector<unsigned int> & arraySizes,bool isRowMajorMatrix,int arrayStride,int matrixStride)333 void Std140BlockEncoder::advanceOffset(GLenum type,
334                                        const std::vector<unsigned int> &arraySizes,
335                                        bool isRowMajorMatrix,
336                                        int arrayStride,
337                                        int matrixStride)
338 {
339     if (!arraySizes.empty())
340     {
341         angle::base::CheckedNumeric<size_t> checkedOffset(arrayStride);
342         checkedOffset *= gl::ArraySizeProduct(arraySizes);
343         checkedOffset += mCurrentOffset;
344         mCurrentOffset = checkedOffset.ValueOrDefault(std::numeric_limits<size_t>::max());
345     }
346     else if (gl::IsMatrixType(type))
347     {
348         angle::base::CheckedNumeric<size_t> checkedOffset(matrixStride);
349         checkedOffset *= gl::MatrixRegisterCount(type, isRowMajorMatrix);
350         checkedOffset += mCurrentOffset;
351         mCurrentOffset = checkedOffset.ValueOrDefault(std::numeric_limits<size_t>::max());
352     }
353     else
354     {
355         angle::base::CheckedNumeric<size_t> checkedOffset(mCurrentOffset);
356         checkedOffset += gl::VariableComponentCount(type);
357         mCurrentOffset = checkedOffset.ValueOrDefault(std::numeric_limits<size_t>::max());
358     }
359 }
360 
getBaseAlignment(const ShaderVariable & variable) const361 size_t Std140BlockEncoder::getBaseAlignment(const ShaderVariable &variable) const
362 {
363     return kComponentsPerRegister;
364 }
365 
getTypeBaseAlignment(GLenum type,bool isRowMajorMatrix) const366 size_t Std140BlockEncoder::getTypeBaseAlignment(GLenum type, bool isRowMajorMatrix) const
367 {
368     return kComponentsPerRegister;
369 }
370 
371 // Std430BlockEncoder implementation.
Std430BlockEncoder()372 Std430BlockEncoder::Std430BlockEncoder() {}
373 
getBaseAlignment(const ShaderVariable & shaderVar) const374 size_t Std430BlockEncoder::getBaseAlignment(const ShaderVariable &shaderVar) const
375 {
376     if (shaderVar.isStruct())
377     {
378         BaseAlignmentVisitor visitor;
379         TraverseShaderVariables(shaderVar.fields, false, &visitor);
380         return visitor.getBaseAlignment();
381     }
382 
383     return GetStd430BaseAlignment(shaderVar.type, shaderVar.isRowMajorLayout);
384 }
385 
getTypeBaseAlignment(GLenum type,bool isRowMajorMatrix) const386 size_t Std430BlockEncoder::getTypeBaseAlignment(GLenum type, bool isRowMajorMatrix) const
387 {
388     return GetStd430BaseAlignment(type, isRowMajorMatrix);
389 }
390 
GetInterfaceBlockInfo(const std::vector<ShaderVariable> & fields,const std::string & prefix,BlockLayoutEncoder * encoder,BlockLayoutMap * blockInfoOut)391 void GetInterfaceBlockInfo(const std::vector<ShaderVariable> &fields,
392                            const std::string &prefix,
393                            BlockLayoutEncoder *encoder,
394                            BlockLayoutMap *blockInfoOut)
395 {
396     // Matrix packing is always recorded in individual fields, so they'll set the row major layout
397     // flag to true if needed.
398     // Iterates over all variables.
399     GetInterfaceBlockInfo(fields, prefix, encoder, false, false, blockInfoOut);
400 }
401 
GetActiveUniformBlockInfo(const std::vector<ShaderVariable> & uniforms,const std::string & prefix,BlockLayoutEncoder * encoder,BlockLayoutMap * blockInfoOut)402 void GetActiveUniformBlockInfo(const std::vector<ShaderVariable> &uniforms,
403                                const std::string &prefix,
404                                BlockLayoutEncoder *encoder,
405                                BlockLayoutMap *blockInfoOut)
406 {
407     // Matrix packing is always recorded in individual fields, so they'll set the row major layout
408     // flag to true if needed.
409     // Iterates only over the active variables.
410     GetInterfaceBlockInfo(uniforms, prefix, encoder, false, true, blockInfoOut);
411 }
412 
413 // VariableNameVisitor implementation.
VariableNameVisitor(const std::string & namePrefix,const std::string & mappedNamePrefix)414 VariableNameVisitor::VariableNameVisitor(const std::string &namePrefix,
415                                          const std::string &mappedNamePrefix)
416 {
417     if (!namePrefix.empty())
418     {
419         mNameStack.push_back(namePrefix + ".");
420     }
421 
422     if (!mappedNamePrefix.empty())
423     {
424         mMappedNameStack.push_back(mappedNamePrefix + ".");
425     }
426 }
427 
428 VariableNameVisitor::~VariableNameVisitor() = default;
429 
enterStruct(const ShaderVariable & structVar)430 void VariableNameVisitor::enterStruct(const ShaderVariable &structVar)
431 {
432     mNameStack.push_back(structVar.name);
433     mMappedNameStack.push_back(structVar.mappedName);
434 }
435 
exitStruct(const ShaderVariable & structVar)436 void VariableNameVisitor::exitStruct(const ShaderVariable &structVar)
437 {
438     mNameStack.pop_back();
439     mMappedNameStack.pop_back();
440 }
441 
enterStructAccess(const ShaderVariable & structVar,bool isRowMajor)442 void VariableNameVisitor::enterStructAccess(const ShaderVariable &structVar, bool isRowMajor)
443 {
444     mNameStack.push_back(".");
445     mMappedNameStack.push_back(".");
446 }
447 
exitStructAccess(const ShaderVariable & structVar,bool isRowMajor)448 void VariableNameVisitor::exitStructAccess(const ShaderVariable &structVar, bool isRowMajor)
449 {
450     mNameStack.pop_back();
451     mMappedNameStack.pop_back();
452 }
453 
enterArray(const ShaderVariable & arrayVar)454 void VariableNameVisitor::enterArray(const ShaderVariable &arrayVar)
455 {
456     if (!arrayVar.hasParentArrayIndex() && !arrayVar.isStruct())
457     {
458         mNameStack.push_back(arrayVar.name);
459         mMappedNameStack.push_back(arrayVar.mappedName);
460     }
461     mArraySizeStack.push_back(arrayVar.getOutermostArraySize());
462 }
463 
exitArray(const ShaderVariable & arrayVar)464 void VariableNameVisitor::exitArray(const ShaderVariable &arrayVar)
465 {
466     if (!arrayVar.hasParentArrayIndex() && !arrayVar.isStruct())
467     {
468         mNameStack.pop_back();
469         mMappedNameStack.pop_back();
470     }
471     mArraySizeStack.pop_back();
472 }
473 
enterArrayElement(const ShaderVariable & arrayVar,unsigned int arrayElement)474 void VariableNameVisitor::enterArrayElement(const ShaderVariable &arrayVar,
475                                             unsigned int arrayElement)
476 {
477     std::stringstream strstr = sh::InitializeStream<std::stringstream>();
478     strstr << "[" << arrayElement << "]";
479     std::string elementString = strstr.str();
480     mNameStack.push_back(elementString);
481     mMappedNameStack.push_back(elementString);
482 }
483 
exitArrayElement(const ShaderVariable & arrayVar,unsigned int arrayElement)484 void VariableNameVisitor::exitArrayElement(const ShaderVariable &arrayVar,
485                                            unsigned int arrayElement)
486 {
487     mNameStack.pop_back();
488     mMappedNameStack.pop_back();
489 }
490 
collapseNameStack() const491 std::string VariableNameVisitor::collapseNameStack() const
492 {
493     return CollapseNameStack(mNameStack);
494 }
495 
collapseMappedNameStack() const496 std::string VariableNameVisitor::collapseMappedNameStack() const
497 {
498     return CollapseNameStack(mMappedNameStack);
499 }
500 
visitOpaqueObject(const sh::ShaderVariable & variable)501 void VariableNameVisitor::visitOpaqueObject(const sh::ShaderVariable &variable)
502 {
503     if (!variable.hasParentArrayIndex())
504     {
505         mNameStack.push_back(variable.name);
506         mMappedNameStack.push_back(variable.mappedName);
507     }
508 
509     std::string name       = collapseNameStack();
510     std::string mappedName = collapseMappedNameStack();
511 
512     if (!variable.hasParentArrayIndex())
513     {
514         mNameStack.pop_back();
515         mMappedNameStack.pop_back();
516     }
517 
518     visitNamedOpaqueObject(variable, name, mappedName, mArraySizeStack);
519 }
520 
visitVariable(const ShaderVariable & variable,bool isRowMajor)521 void VariableNameVisitor::visitVariable(const ShaderVariable &variable, bool isRowMajor)
522 {
523     if (!variable.hasParentArrayIndex())
524     {
525         mNameStack.push_back(variable.name);
526         mMappedNameStack.push_back(variable.mappedName);
527     }
528 
529     std::string name       = collapseNameStack();
530     std::string mappedName = collapseMappedNameStack();
531 
532     if (!variable.hasParentArrayIndex())
533     {
534         mNameStack.pop_back();
535         mMappedNameStack.pop_back();
536     }
537 
538     visitNamedVariable(variable, isRowMajor, name, mappedName, mArraySizeStack);
539 }
540 
541 // BlockEncoderVisitor implementation.
BlockEncoderVisitor(const std::string & namePrefix,const std::string & mappedNamePrefix,BlockLayoutEncoder * encoder)542 BlockEncoderVisitor::BlockEncoderVisitor(const std::string &namePrefix,
543                                          const std::string &mappedNamePrefix,
544                                          BlockLayoutEncoder *encoder)
545     : VariableNameVisitor(namePrefix, mappedNamePrefix), mEncoder(encoder)
546 {}
547 
548 BlockEncoderVisitor::~BlockEncoderVisitor() = default;
549 
enterStructAccess(const ShaderVariable & structVar,bool isRowMajor)550 void BlockEncoderVisitor::enterStructAccess(const ShaderVariable &structVar, bool isRowMajor)
551 {
552     mStructStackSize++;
553     if (!mIsTopLevelArrayStrideReady)
554     {
555         size_t structSize = mEncoder->getShaderVariableSize(structVar, isRowMajor);
556         mTopLevelArrayStride *= structSize;
557         mIsTopLevelArrayStrideReady = true;
558     }
559 
560     VariableNameVisitor::enterStructAccess(structVar, isRowMajor);
561     mEncoder->enterAggregateType(structVar);
562 }
563 
exitStructAccess(const ShaderVariable & structVar,bool isRowMajor)564 void BlockEncoderVisitor::exitStructAccess(const ShaderVariable &structVar, bool isRowMajor)
565 {
566     mStructStackSize--;
567     mEncoder->exitAggregateType(structVar);
568     VariableNameVisitor::exitStructAccess(structVar, isRowMajor);
569 }
570 
enterArrayElement(const sh::ShaderVariable & arrayVar,unsigned int arrayElement)571 void BlockEncoderVisitor::enterArrayElement(const sh::ShaderVariable &arrayVar,
572                                             unsigned int arrayElement)
573 {
574     if (mStructStackSize == 0 && !arrayVar.hasParentArrayIndex())
575     {
576         // From the ES 3.1 spec "7.3.1.1 Naming Active Resources":
577         // For an active shader storage block member declared as an array of an aggregate type,
578         // an entry will be generated only for the first array element, regardless of its type.
579         // Such block members are referred to as top-level arrays. If the block member is an
580         // aggregate type, the enumeration rules are then applied recursively.
581         if (arrayElement == 0)
582         {
583             mTopLevelArraySize          = arrayVar.getOutermostArraySize();
584             mTopLevelArrayStride        = arrayVar.getInnerArraySizeProduct();
585             mIsTopLevelArrayStrideReady = false;
586         }
587         else
588         {
589             mSkipEnabled = true;
590         }
591     }
592     VariableNameVisitor::enterArrayElement(arrayVar, arrayElement);
593 }
594 
exitArrayElement(const sh::ShaderVariable & arrayVar,unsigned int arrayElement)595 void BlockEncoderVisitor::exitArrayElement(const sh::ShaderVariable &arrayVar,
596                                            unsigned int arrayElement)
597 {
598     if (mStructStackSize == 0 && !arrayVar.hasParentArrayIndex())
599     {
600         mTopLevelArraySize          = 1;
601         mTopLevelArrayStride        = 0;
602         mIsTopLevelArrayStrideReady = true;
603         mSkipEnabled                = false;
604     }
605     VariableNameVisitor::exitArrayElement(arrayVar, arrayElement);
606 }
607 
visitNamedVariable(const ShaderVariable & variable,bool isRowMajor,const std::string & name,const std::string & mappedName,const std::vector<unsigned int> & arraySizes)608 void BlockEncoderVisitor::visitNamedVariable(const ShaderVariable &variable,
609                                              bool isRowMajor,
610                                              const std::string &name,
611                                              const std::string &mappedName,
612                                              const std::vector<unsigned int> &arraySizes)
613 {
614     std::vector<unsigned int> innermostArraySize;
615 
616     if (variable.isArray())
617     {
618         innermostArraySize.push_back(variable.getNestedArraySize(0));
619     }
620     BlockMemberInfo variableInfo =
621         mEncoder->encodeType(variable.type, innermostArraySize, isRowMajor);
622     if (!mIsTopLevelArrayStrideReady)
623     {
624         ASSERT(mTopLevelArrayStride);
625         mTopLevelArrayStride *= variableInfo.arrayStride;
626         mIsTopLevelArrayStrideReady = true;
627     }
628     variableInfo.topLevelArrayStride = mTopLevelArrayStride;
629     encodeVariable(variable, variableInfo, name, mappedName);
630 }
631 
TraverseShaderVariable(const ShaderVariable & variable,bool isRowMajorLayout,ShaderVariableVisitor * visitor)632 void TraverseShaderVariable(const ShaderVariable &variable,
633                             bool isRowMajorLayout,
634                             ShaderVariableVisitor *visitor)
635 {
636     bool rowMajorLayout = (isRowMajorLayout || variable.isRowMajorLayout);
637     bool isRowMajor     = rowMajorLayout && gl::IsMatrixType(variable.type);
638 
639     if (variable.isStruct())
640     {
641         visitor->enterStruct(variable);
642         if (variable.isArray())
643         {
644             TraverseStructArrayVariable(variable, rowMajorLayout, visitor);
645         }
646         else
647         {
648             TraverseStructVariable(variable, rowMajorLayout, visitor);
649         }
650         visitor->exitStruct(variable);
651     }
652     else if (variable.isArrayOfArrays())
653     {
654         TraverseArrayOfArraysVariable(variable, 0u, isRowMajor, visitor);
655     }
656     else if (gl::IsSamplerType(variable.type) || gl::IsImageType(variable.type) ||
657              variable.isFragmentInOut)
658     {
659         visitor->visitOpaqueObject(variable);
660     }
661     else
662     {
663         visitor->visitVariable(variable, isRowMajor);
664     }
665 }
666 }  // namespace sh
667