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