ShaderStorageBlockOutputHLSL.cpp (24552B)
1 // 2 // Copyright 2018 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 // ShaderStorageBlockOutputHLSL: A traverser to translate a ssbo_access_chain to an offset of 7 // RWByteAddressBuffer. 8 // //EOpIndexDirectInterfaceBlock 9 // ssbo_variable := 10 // | the name of the SSBO 11 // | the name of a variable in an SSBO backed interface block 12 13 // // EOpIndexInDirect 14 // // EOpIndexDirect 15 // ssbo_array_indexing := ssbo_access_chain[expr_no_ssbo] 16 17 // // EOpIndexDirectStruct 18 // ssbo_structure_access := ssbo_access_chain.identifier 19 20 // ssbo_access_chain := 21 // | ssbo_variable 22 // | ssbo_array_indexing 23 // | ssbo_structure_access 24 // 25 26 #include "compiler/translator/ShaderStorageBlockOutputHLSL.h" 27 28 #include "compiler/translator/ResourcesHLSL.h" 29 #include "compiler/translator/blocklayoutHLSL.h" 30 #include "compiler/translator/tree_util/IntermNode_util.h" 31 #include "compiler/translator/util.h" 32 33 namespace sh 34 { 35 36 namespace 37 { 38 39 constexpr const char kShaderStorageDeclarationString[] = 40 "// @@ SHADER STORAGE DECLARATION STRING @@"; 41 42 void GetBlockLayoutInfo(TIntermTyped *node, 43 bool rowMajorAlreadyAssigned, 44 TLayoutBlockStorage *storage, 45 bool *rowMajor) 46 { 47 TIntermSwizzle *swizzleNode = node->getAsSwizzleNode(); 48 if (swizzleNode) 49 { 50 return GetBlockLayoutInfo(swizzleNode->getOperand(), rowMajorAlreadyAssigned, storage, 51 rowMajor); 52 } 53 54 TIntermBinary *binaryNode = node->getAsBinaryNode(); 55 if (binaryNode) 56 { 57 switch (binaryNode->getOp()) 58 { 59 case EOpIndexDirectInterfaceBlock: 60 { 61 // The column_major/row_major qualifier of a field member overrides the interface 62 // block's row_major/column_major. So we can assign rowMajor here and don't need to 63 // assign it again. But we still need to call recursively to get the storage's 64 // value. 65 const TType &type = node->getType(); 66 *rowMajor = type.getLayoutQualifier().matrixPacking == EmpRowMajor; 67 return GetBlockLayoutInfo(binaryNode->getLeft(), true, storage, rowMajor); 68 } 69 case EOpIndexIndirect: 70 case EOpIndexDirect: 71 case EOpIndexDirectStruct: 72 return GetBlockLayoutInfo(binaryNode->getLeft(), rowMajorAlreadyAssigned, storage, 73 rowMajor); 74 default: 75 UNREACHABLE(); 76 return; 77 } 78 } 79 80 const TType &type = node->getType(); 81 ASSERT(type.getQualifier() == EvqBuffer); 82 const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock(); 83 ASSERT(interfaceBlock); 84 *storage = interfaceBlock->blockStorage(); 85 // If the block doesn't have an instance name, rowMajorAlreadyAssigned will be false. In 86 // this situation, we still need to set rowMajor's value. 87 if (!rowMajorAlreadyAssigned) 88 { 89 *rowMajor = type.getLayoutQualifier().matrixPacking == EmpRowMajor; 90 } 91 } 92 93 // It's possible that the current type has lost the original layout information. So we should pass 94 // the right layout information to GetBlockMemberInfoByType. 95 const BlockMemberInfo GetBlockMemberInfoByType(const TType &type, 96 TLayoutBlockStorage storage, 97 bool rowMajor) 98 { 99 sh::Std140BlockEncoder std140Encoder; 100 sh::Std430BlockEncoder std430Encoder; 101 sh::HLSLBlockEncoder hlslEncoder(sh::HLSLBlockEncoder::ENCODE_PACKED, false); 102 sh::BlockLayoutEncoder *encoder = nullptr; 103 104 if (storage == EbsStd140) 105 { 106 encoder = &std140Encoder; 107 } 108 else if (storage == EbsStd430) 109 { 110 encoder = &std430Encoder; 111 } 112 else 113 { 114 encoder = &hlslEncoder; 115 } 116 117 std::vector<unsigned int> arraySizes; 118 const TSpan<const unsigned int> &typeArraySizes = type.getArraySizes(); 119 if (!typeArraySizes.empty()) 120 { 121 arraySizes.assign(typeArraySizes.begin(), typeArraySizes.end()); 122 } 123 return encoder->encodeType(GLVariableType(type), arraySizes, rowMajor); 124 } 125 126 const TField *GetFieldMemberInShaderStorageBlock(const TInterfaceBlock *interfaceBlock, 127 const ImmutableString &variableName) 128 { 129 for (const TField *field : interfaceBlock->fields()) 130 { 131 if (field->name() == variableName) 132 { 133 return field; 134 } 135 } 136 return nullptr; 137 } 138 139 const InterfaceBlock *FindInterfaceBlock(const TInterfaceBlock *needle, 140 const std::vector<InterfaceBlock> &haystack) 141 { 142 for (const InterfaceBlock &block : haystack) 143 { 144 if (strcmp(block.name.c_str(), needle->name().data()) == 0) 145 { 146 ASSERT(block.fields.size() == needle->fields().size()); 147 return █ 148 } 149 } 150 151 UNREACHABLE(); 152 return nullptr; 153 } 154 155 std::string StripArrayIndices(const std::string &nameIn) 156 { 157 std::string name = nameIn; 158 size_t pos = name.find('['); 159 while (pos != std::string::npos) 160 { 161 size_t closePos = name.find(']', pos); 162 ASSERT(closePos != std::string::npos); 163 name.erase(pos, closePos - pos + 1); 164 pos = name.find('[', pos); 165 } 166 ASSERT(name.find(']') == std::string::npos); 167 return name; 168 } 169 170 // Does not include any array indices. 171 void MapVariableToField(const ShaderVariable &variable, 172 const TField *field, 173 std::string currentName, 174 ShaderVarToFieldMap *shaderVarToFieldMap) 175 { 176 ASSERT((field->type()->getStruct() == nullptr) == variable.fields.empty()); 177 (*shaderVarToFieldMap)[currentName] = field; 178 179 if (!variable.fields.empty()) 180 { 181 const TStructure *subStruct = field->type()->getStruct(); 182 ASSERT(variable.fields.size() == subStruct->fields().size()); 183 184 for (size_t index = 0; index < variable.fields.size(); ++index) 185 { 186 const TField *subField = subStruct->fields()[index]; 187 const ShaderVariable &subVariable = variable.fields[index]; 188 std::string subName = currentName + "." + subVariable.name; 189 MapVariableToField(subVariable, subField, subName, shaderVarToFieldMap); 190 } 191 } 192 } 193 194 class BlockInfoVisitor final : public BlockEncoderVisitor 195 { 196 public: 197 BlockInfoVisitor(const std::string &prefix, 198 TLayoutBlockStorage storage, 199 const ShaderVarToFieldMap &shaderVarToFieldMap, 200 BlockMemberInfoMap *blockInfoOut) 201 : BlockEncoderVisitor(prefix, "", getEncoder(storage)), 202 mShaderVarToFieldMap(shaderVarToFieldMap), 203 mBlockInfoOut(blockInfoOut), 204 mHLSLEncoder(HLSLBlockEncoder::ENCODE_PACKED, false), 205 mStorage(storage) 206 {} 207 208 BlockLayoutEncoder *getEncoder(TLayoutBlockStorage storage) 209 { 210 switch (storage) 211 { 212 case EbsStd140: 213 return &mStd140Encoder; 214 case EbsStd430: 215 return &mStd430Encoder; 216 default: 217 return &mHLSLEncoder; 218 } 219 } 220 221 void enterStructAccess(const ShaderVariable &structVar, bool isRowMajor) override 222 { 223 BlockEncoderVisitor::enterStructAccess(structVar, isRowMajor); 224 225 std::string variableName = StripArrayIndices(collapseNameStack()); 226 227 // Remove the trailing "." 228 variableName.pop_back(); 229 230 BlockInfoVisitor childVisitor(variableName, mStorage, mShaderVarToFieldMap, mBlockInfoOut); 231 childVisitor.getEncoder(mStorage)->enterAggregateType(structVar); 232 TraverseShaderVariables(structVar.fields, isRowMajor, &childVisitor); 233 childVisitor.getEncoder(mStorage)->exitAggregateType(structVar); 234 235 int offset = static_cast<int>(getEncoder(mStorage)->getCurrentOffset()); 236 int arrayStride = static_cast<int>(childVisitor.getEncoder(mStorage)->getCurrentOffset()); 237 238 auto iter = mShaderVarToFieldMap.find(variableName); 239 if (iter == mShaderVarToFieldMap.end()) 240 return; 241 242 const TField *structField = iter->second; 243 if (mBlockInfoOut->count(structField) == 0) 244 { 245 mBlockInfoOut->emplace(structField, BlockMemberInfo(offset, arrayStride, -1, false)); 246 } 247 } 248 249 void encodeVariable(const ShaderVariable &variable, 250 const BlockMemberInfo &variableInfo, 251 const std::string &name, 252 const std::string &mappedName) override 253 { 254 auto iter = mShaderVarToFieldMap.find(StripArrayIndices(name)); 255 if (iter == mShaderVarToFieldMap.end()) 256 return; 257 258 const TField *field = iter->second; 259 if (mBlockInfoOut->count(field) == 0) 260 { 261 mBlockInfoOut->emplace(field, variableInfo); 262 } 263 } 264 265 private: 266 const ShaderVarToFieldMap &mShaderVarToFieldMap; 267 BlockMemberInfoMap *mBlockInfoOut; 268 Std140BlockEncoder mStd140Encoder; 269 Std430BlockEncoder mStd430Encoder; 270 HLSLBlockEncoder mHLSLEncoder; 271 TLayoutBlockStorage mStorage; 272 }; 273 274 void GetShaderStorageBlockMembersInfo(const TInterfaceBlock *interfaceBlock, 275 const std::vector<InterfaceBlock> &shaderStorageBlocks, 276 BlockMemberInfoMap *blockInfoOut) 277 { 278 // Find the sh::InterfaceBlock. 279 const InterfaceBlock *block = FindInterfaceBlock(interfaceBlock, shaderStorageBlocks); 280 ASSERT(block); 281 282 // Map ShaderVariable to TField. 283 ShaderVarToFieldMap shaderVarToFieldMap; 284 for (size_t index = 0; index < block->fields.size(); ++index) 285 { 286 const TField *field = interfaceBlock->fields()[index]; 287 const ShaderVariable &variable = block->fields[index]; 288 MapVariableToField(variable, field, variable.name, &shaderVarToFieldMap); 289 } 290 291 BlockInfoVisitor visitor("", interfaceBlock->blockStorage(), shaderVarToFieldMap, blockInfoOut); 292 TraverseShaderVariables(block->fields, false, &visitor); 293 } 294 295 TIntermTyped *Mul(TIntermTyped *left, TIntermTyped *right) 296 { 297 return left && right ? new TIntermBinary(EOpMul, left, right) : nullptr; 298 } 299 300 TIntermTyped *Add(TIntermTyped *left, TIntermTyped *right) 301 { 302 return left ? right ? new TIntermBinary(EOpAdd, left, right) : left : right; 303 } 304 305 } // anonymous namespace 306 307 ShaderStorageBlockOutputHLSL::ShaderStorageBlockOutputHLSL( 308 OutputHLSL *outputHLSL, 309 ResourcesHLSL *resourcesHLSL, 310 const std::vector<InterfaceBlock> &shaderStorageBlocks) 311 : mOutputHLSL(outputHLSL), 312 mResourcesHLSL(resourcesHLSL), 313 mShaderStorageBlocks(shaderStorageBlocks) 314 { 315 mSSBOFunctionHLSL = new ShaderStorageBlockFunctionHLSL; 316 } 317 318 ShaderStorageBlockOutputHLSL::~ShaderStorageBlockOutputHLSL() 319 { 320 SafeDelete(mSSBOFunctionHLSL); 321 } 322 323 void ShaderStorageBlockOutputHLSL::outputStoreFunctionCallPrefix(TIntermTyped *node) 324 { 325 traverseSSBOAccess(node, SSBOMethod::STORE); 326 } 327 328 void ShaderStorageBlockOutputHLSL::outputLoadFunctionCall(TIntermTyped *node) 329 { 330 traverseSSBOAccess(node, SSBOMethod::LOAD); 331 mOutputHLSL->getInfoSink() << ")"; 332 } 333 334 void ShaderStorageBlockOutputHLSL::outputLengthFunctionCall(TIntermTyped *node) 335 { 336 traverseSSBOAccess(node, SSBOMethod::LENGTH); 337 mOutputHLSL->getInfoSink() << ")"; 338 } 339 340 void ShaderStorageBlockOutputHLSL::outputAtomicMemoryFunctionCallPrefix(TIntermTyped *node, 341 TOperator op) 342 { 343 switch (op) 344 { 345 case EOpAtomicAdd: 346 traverseSSBOAccess(node, SSBOMethod::ATOMIC_ADD); 347 break; 348 case EOpAtomicMin: 349 traverseSSBOAccess(node, SSBOMethod::ATOMIC_MIN); 350 break; 351 case EOpAtomicMax: 352 traverseSSBOAccess(node, SSBOMethod::ATOMIC_MAX); 353 break; 354 case EOpAtomicAnd: 355 traverseSSBOAccess(node, SSBOMethod::ATOMIC_AND); 356 break; 357 case EOpAtomicOr: 358 traverseSSBOAccess(node, SSBOMethod::ATOMIC_OR); 359 break; 360 case EOpAtomicXor: 361 traverseSSBOAccess(node, SSBOMethod::ATOMIC_XOR); 362 break; 363 case EOpAtomicExchange: 364 traverseSSBOAccess(node, SSBOMethod::ATOMIC_EXCHANGE); 365 break; 366 case EOpAtomicCompSwap: 367 traverseSSBOAccess(node, SSBOMethod::ATOMIC_COMPSWAP); 368 break; 369 default: 370 UNREACHABLE(); 371 break; 372 } 373 } 374 375 // Note that we must calculate the matrix stride here instead of ShaderStorageBlockFunctionHLSL. 376 // It's because that if the current node's type is a vector which comes from a matrix, we will 377 // lose the matrix type info once we enter ShaderStorageBlockFunctionHLSL. 378 int ShaderStorageBlockOutputHLSL::getMatrixStride(TIntermTyped *node, 379 TLayoutBlockStorage storage, 380 bool rowMajor, 381 bool *isRowMajorMatrix) const 382 { 383 if (node->getType().isMatrix()) 384 { 385 *isRowMajorMatrix = rowMajor; 386 return GetBlockMemberInfoByType(node->getType(), storage, rowMajor).matrixStride; 387 } 388 389 if (node->getType().isVector()) 390 { 391 TIntermBinary *binaryNode = node->getAsBinaryNode(); 392 if (binaryNode) 393 { 394 return getMatrixStride(binaryNode->getLeft(), storage, rowMajor, isRowMajorMatrix); 395 } 396 else 397 { 398 TIntermSwizzle *swizzleNode = node->getAsSwizzleNode(); 399 if (swizzleNode) 400 { 401 return getMatrixStride(swizzleNode->getOperand(), storage, rowMajor, 402 isRowMajorMatrix); 403 } 404 } 405 } 406 return 0; 407 } 408 409 void ShaderStorageBlockOutputHLSL::collectShaderStorageBlocks(TIntermTyped *node) 410 { 411 TIntermSwizzle *swizzleNode = node->getAsSwizzleNode(); 412 if (swizzleNode) 413 { 414 return collectShaderStorageBlocks(swizzleNode->getOperand()); 415 } 416 417 TIntermBinary *binaryNode = node->getAsBinaryNode(); 418 if (binaryNode) 419 { 420 switch (binaryNode->getOp()) 421 { 422 case EOpIndexDirectInterfaceBlock: 423 case EOpIndexIndirect: 424 case EOpIndexDirect: 425 case EOpIndexDirectStruct: 426 return collectShaderStorageBlocks(binaryNode->getLeft()); 427 default: 428 UNREACHABLE(); 429 return; 430 } 431 } 432 433 const TIntermSymbol *symbolNode = node->getAsSymbolNode(); 434 const TType &type = symbolNode->getType(); 435 ASSERT(type.getQualifier() == EvqBuffer); 436 const TVariable &variable = symbolNode->variable(); 437 438 const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock(); 439 ASSERT(interfaceBlock); 440 if (mReferencedShaderStorageBlocks.count(interfaceBlock->uniqueId().get()) == 0) 441 { 442 const TVariable *instanceVariable = nullptr; 443 if (type.isInterfaceBlock()) 444 { 445 instanceVariable = &variable; 446 } 447 mReferencedShaderStorageBlocks[interfaceBlock->uniqueId().get()] = 448 new TReferencedBlock(interfaceBlock, instanceVariable); 449 GetShaderStorageBlockMembersInfo(interfaceBlock, mShaderStorageBlocks, 450 &mBlockMemberInfoMap); 451 } 452 } 453 454 void ShaderStorageBlockOutputHLSL::traverseSSBOAccess(TIntermTyped *node, SSBOMethod method) 455 { 456 // TODO: Merge collectShaderStorageBlocks and GetBlockLayoutInfo to simplify the code. 457 collectShaderStorageBlocks(node); 458 459 // Note that we don't have correct BlockMemberInfo from mBlockMemberInfoMap at the current 460 // point. But we must use those information to generate the right function name. So here we have 461 // to calculate them again. 462 TLayoutBlockStorage storage; 463 bool rowMajor; 464 GetBlockLayoutInfo(node, false, &storage, &rowMajor); 465 int unsizedArrayStride = 0; 466 if (node->getType().isUnsizedArray()) 467 { 468 // The unsized array member must be the last member of a shader storage block. 469 TIntermBinary *binaryNode = node->getAsBinaryNode(); 470 if (binaryNode) 471 { 472 const TInterfaceBlock *interfaceBlock = 473 binaryNode->getLeft()->getType().getInterfaceBlock(); 474 ASSERT(interfaceBlock); 475 const TIntermConstantUnion *index = binaryNode->getRight()->getAsConstantUnion(); 476 const TField *field = interfaceBlock->fields()[index->getIConst(0)]; 477 auto fieldInfoIter = mBlockMemberInfoMap.find(field); 478 ASSERT(fieldInfoIter != mBlockMemberInfoMap.end()); 479 unsizedArrayStride = fieldInfoIter->second.arrayStride; 480 } 481 else 482 { 483 const TIntermSymbol *symbolNode = node->getAsSymbolNode(); 484 const TVariable &variable = symbolNode->variable(); 485 const TInterfaceBlock *interfaceBlock = symbolNode->getType().getInterfaceBlock(); 486 ASSERT(interfaceBlock); 487 const TField *field = 488 GetFieldMemberInShaderStorageBlock(interfaceBlock, variable.name()); 489 auto fieldInfoIter = mBlockMemberInfoMap.find(field); 490 ASSERT(fieldInfoIter != mBlockMemberInfoMap.end()); 491 unsizedArrayStride = fieldInfoIter->second.arrayStride; 492 } 493 } 494 bool isRowMajorMatrix = false; 495 int matrixStride = getMatrixStride(node, storage, rowMajor, &isRowMajorMatrix); 496 497 const TString &functionName = mSSBOFunctionHLSL->registerShaderStorageBlockFunction( 498 node->getType(), method, storage, isRowMajorMatrix, matrixStride, unsizedArrayStride, 499 node->getAsSwizzleNode()); 500 TInfoSinkBase &out = mOutputHLSL->getInfoSink(); 501 out << functionName; 502 out << "("; 503 BlockMemberInfo blockMemberInfo; 504 TIntermNode *loc = traverseNode(out, node, &blockMemberInfo); 505 out << ", "; 506 loc->traverse(mOutputHLSL); 507 } 508 509 void ShaderStorageBlockOutputHLSL::writeShaderStorageBlocksHeader(GLenum shaderType, 510 TInfoSinkBase &out) const 511 { 512 if (mReferencedShaderStorageBlocks.empty()) 513 { 514 return; 515 } 516 517 mResourcesHLSL->allocateShaderStorageBlockRegisters(mReferencedShaderStorageBlocks); 518 out << "// Shader Storage Blocks\n\n"; 519 if (shaderType == GL_COMPUTE_SHADER) 520 { 521 out << mResourcesHLSL->shaderStorageBlocksHeader(mReferencedShaderStorageBlocks); 522 } 523 else 524 { 525 out << kShaderStorageDeclarationString << "\n"; 526 } 527 mSSBOFunctionHLSL->shaderStorageBlockFunctionHeader(out); 528 } 529 530 TIntermTyped *ShaderStorageBlockOutputHLSL::traverseNode(TInfoSinkBase &out, 531 TIntermTyped *node, 532 BlockMemberInfo *blockMemberInfo) 533 { 534 if (TIntermSymbol *symbolNode = node->getAsSymbolNode()) 535 { 536 const TVariable &variable = symbolNode->variable(); 537 const TType &type = variable.getType(); 538 if (type.isInterfaceBlock()) 539 { 540 out << DecorateVariableIfNeeded(variable); 541 } 542 else 543 { 544 const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock(); 545 out << Decorate(interfaceBlock->name()); 546 const TField *field = 547 GetFieldMemberInShaderStorageBlock(interfaceBlock, variable.name()); 548 return createFieldOffset(field, blockMemberInfo); 549 } 550 } 551 else if (TIntermSwizzle *swizzleNode = node->getAsSwizzleNode()) 552 { 553 return traverseNode(out, swizzleNode->getOperand(), blockMemberInfo); 554 } 555 else if (TIntermBinary *binaryNode = node->getAsBinaryNode()) 556 { 557 switch (binaryNode->getOp()) 558 { 559 case EOpIndexDirect: 560 { 561 const TType &leftType = binaryNode->getLeft()->getType(); 562 if (leftType.isInterfaceBlock()) 563 { 564 ASSERT(leftType.getQualifier() == EvqBuffer); 565 TIntermSymbol *instanceArraySymbol = binaryNode->getLeft()->getAsSymbolNode(); 566 567 const int arrayIndex = 568 binaryNode->getRight()->getAsConstantUnion()->getIConst(0); 569 out << mResourcesHLSL->InterfaceBlockInstanceString( 570 instanceArraySymbol->getName(), arrayIndex); 571 } 572 else 573 { 574 return writeEOpIndexDirectOrIndirectOutput(out, binaryNode, blockMemberInfo); 575 } 576 break; 577 } 578 case EOpIndexIndirect: 579 { 580 // We do not currently support indirect references to interface blocks 581 ASSERT(binaryNode->getLeft()->getBasicType() != EbtInterfaceBlock); 582 return writeEOpIndexDirectOrIndirectOutput(out, binaryNode, blockMemberInfo); 583 } 584 case EOpIndexDirectStruct: 585 { 586 // We do not currently support direct references to interface blocks 587 ASSERT(binaryNode->getLeft()->getBasicType() != EbtInterfaceBlock); 588 TIntermTyped *left = traverseNode(out, binaryNode->getLeft(), blockMemberInfo); 589 const TStructure *structure = binaryNode->getLeft()->getType().getStruct(); 590 const TIntermConstantUnion *index = binaryNode->getRight()->getAsConstantUnion(); 591 const TField *field = structure->fields()[index->getIConst(0)]; 592 return Add(createFieldOffset(field, blockMemberInfo), left); 593 } 594 case EOpIndexDirectInterfaceBlock: 595 { 596 ASSERT(IsInShaderStorageBlock(binaryNode->getLeft())); 597 traverseNode(out, binaryNode->getLeft(), blockMemberInfo); 598 const TInterfaceBlock *interfaceBlock = 599 binaryNode->getLeft()->getType().getInterfaceBlock(); 600 const TIntermConstantUnion *index = binaryNode->getRight()->getAsConstantUnion(); 601 const TField *field = interfaceBlock->fields()[index->getIConst(0)]; 602 return createFieldOffset(field, blockMemberInfo); 603 } 604 default: 605 return nullptr; 606 } 607 } 608 return nullptr; 609 } 610 611 TIntermTyped *ShaderStorageBlockOutputHLSL::writeEOpIndexDirectOrIndirectOutput( 612 TInfoSinkBase &out, 613 TIntermBinary *node, 614 BlockMemberInfo *blockMemberInfo) 615 { 616 ASSERT(IsInShaderStorageBlock(node->getLeft())); 617 TIntermTyped *left = traverseNode(out, node->getLeft(), blockMemberInfo); 618 TIntermTyped *right = node->getRight()->deepCopy(); 619 const TType &type = node->getLeft()->getType(); 620 TLayoutBlockStorage storage; 621 bool rowMajor; 622 GetBlockLayoutInfo(node, false, &storage, &rowMajor); 623 624 if (type.isArray()) 625 { 626 const TSpan<const unsigned int> &arraySizes = type.getArraySizes(); 627 for (unsigned int i = 0; i < arraySizes.size() - 1; i++) 628 { 629 right = Mul(CreateUIntNode(arraySizes[i]), right); 630 } 631 right = Mul(CreateUIntNode(blockMemberInfo->arrayStride), right); 632 } 633 else if (type.isMatrix()) 634 { 635 if (rowMajor) 636 { 637 right = Mul(CreateUIntNode(BlockLayoutEncoder::kBytesPerComponent), right); 638 } 639 else 640 { 641 right = Mul(CreateUIntNode(blockMemberInfo->matrixStride), right); 642 } 643 } 644 else if (type.isVector()) 645 { 646 if (blockMemberInfo->isRowMajorMatrix) 647 { 648 right = Mul(CreateUIntNode(blockMemberInfo->matrixStride), right); 649 } 650 else 651 { 652 right = Mul(CreateUIntNode(BlockLayoutEncoder::kBytesPerComponent), right); 653 } 654 } 655 return Add(left, right); 656 } 657 658 TIntermTyped *ShaderStorageBlockOutputHLSL::createFieldOffset(const TField *field, 659 BlockMemberInfo *blockMemberInfo) 660 { 661 auto fieldInfoIter = mBlockMemberInfoMap.find(field); 662 ASSERT(fieldInfoIter != mBlockMemberInfoMap.end()); 663 *blockMemberInfo = fieldInfoIter->second; 664 return CreateUIntNode(blockMemberInfo->offset); 665 } 666 667 } // namespace sh