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