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