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