ResourcesHLSL.cpp (37826B)
1 // 2 // Copyright 2014 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 // ResourcesHLSL.cpp: 7 // Methods for GLSL to HLSL translation for uniforms and interface blocks. 8 // 9 10 #include "compiler/translator/ResourcesHLSL.h" 11 12 #include "common/utilities.h" 13 #include "compiler/translator/AtomicCounterFunctionHLSL.h" 14 #include "compiler/translator/ImmutableStringBuilder.h" 15 #include "compiler/translator/StructureHLSL.h" 16 #include "compiler/translator/UtilsHLSL.h" 17 #include "compiler/translator/blocklayoutHLSL.h" 18 #include "compiler/translator/util.h" 19 20 namespace sh 21 { 22 23 namespace 24 { 25 26 constexpr const ImmutableString kAngleDecorString("angle_"); 27 28 static const char *UniformRegisterPrefix(const TType &type) 29 { 30 if (IsSampler(type.getBasicType())) 31 { 32 return "s"; 33 } 34 else 35 { 36 return "c"; 37 } 38 } 39 40 static TString InterfaceBlockFieldTypeString(const TField &field, 41 TLayoutBlockStorage blockStorage, 42 bool usedStructuredbuffer) 43 { 44 const TType &fieldType = *field.type(); 45 const TLayoutMatrixPacking matrixPacking = fieldType.getLayoutQualifier().matrixPacking; 46 ASSERT(matrixPacking != EmpUnspecified); 47 const TStructure *structure = fieldType.getStruct(); 48 49 if (fieldType.isMatrix()) 50 { 51 // Use HLSL row-major packing for GLSL column-major matrices 52 const TString &matrixPackString = 53 (matrixPacking == EmpRowMajor ? "column_major" : "row_major"); 54 return matrixPackString + " " + TypeString(fieldType); 55 } 56 else if (structure) 57 { 58 // If uniform block's layout is std140 and translating it to StructuredBuffer, 59 // should pack structure in the end, in order to fit API buffer. 60 bool forcePackingEnd = usedStructuredbuffer && (blockStorage == EbsStd140); 61 // Use HLSL row-major packing for GLSL column-major matrices 62 return QualifiedStructNameString(*structure, matrixPacking == EmpColumnMajor, 63 blockStorage == EbsStd140, forcePackingEnd); 64 } 65 else 66 { 67 return TypeString(fieldType); 68 } 69 } 70 71 static TString InterfaceBlockStructName(const TInterfaceBlock &interfaceBlock) 72 { 73 return DecoratePrivate(interfaceBlock.name()) + "_type"; 74 } 75 76 void OutputUniformIndexArrayInitializer(TInfoSinkBase &out, 77 const TType &type, 78 unsigned int startIndex) 79 { 80 out << "{"; 81 TType elementType(type); 82 elementType.toArrayElementType(); 83 for (unsigned int i = 0u; i < type.getOutermostArraySize(); ++i) 84 { 85 if (i > 0u) 86 { 87 out << ", "; 88 } 89 if (elementType.isArray()) 90 { 91 OutputUniformIndexArrayInitializer(out, elementType, 92 startIndex + i * elementType.getArraySizeProduct()); 93 } 94 else 95 { 96 out << (startIndex + i); 97 } 98 } 99 out << "}"; 100 } 101 102 static TString InterfaceBlockScalarVectorFieldPaddingString(const TType &type) 103 { 104 switch (type.getBasicType()) 105 { 106 case EbtFloat: 107 switch (type.getNominalSize()) 108 { 109 case 1: 110 return "float3 padding;"; 111 case 2: 112 return "float2 padding;"; 113 case 3: 114 return "float padding;"; 115 default: 116 break; 117 } 118 break; 119 case EbtInt: 120 switch (type.getNominalSize()) 121 { 122 case 1: 123 return "int3 padding;"; 124 case 2: 125 return "int2 padding;"; 126 case 3: 127 return "int padding"; 128 default: 129 break; 130 } 131 break; 132 case EbtUInt: 133 switch (type.getNominalSize()) 134 { 135 case 1: 136 return "uint3 padding;"; 137 case 2: 138 return "uint2 padding;"; 139 case 3: 140 return "uint padding;"; 141 default: 142 break; 143 } 144 break; 145 case EbtBool: 146 switch (type.getNominalSize()) 147 { 148 case 1: 149 return "bool3 padding;"; 150 case 2: 151 return "bool2 padding;"; 152 case 3: 153 return "bool padding;"; 154 default: 155 break; 156 } 157 break; 158 default: 159 break; 160 } 161 return ""; 162 } 163 164 static bool IsAnyRasterOrdered(const TVector<const TVariable *> &imageVars) 165 { 166 for (const TVariable *imageVar : imageVars) 167 { 168 if (imageVar->getType().getLayoutQualifier().rasterOrdered) 169 { 170 return true; 171 } 172 } 173 return false; 174 } 175 176 } // anonymous namespace 177 178 ResourcesHLSL::ResourcesHLSL(StructureHLSL *structureHLSL, 179 ShShaderOutput outputType, 180 const std::vector<ShaderVariable> &uniforms, 181 unsigned int firstUniformRegister) 182 : mUniformRegister(firstUniformRegister), 183 mUniformBlockRegister(0), 184 mSRVRegister(0), 185 mUAVRegister(0), 186 mSamplerCount(0), 187 mStructureHLSL(structureHLSL), 188 mOutputType(outputType), 189 mUniforms(uniforms) 190 {} 191 192 void ResourcesHLSL::reserveUniformRegisters(unsigned int registerCount) 193 { 194 mUniformRegister = registerCount; 195 } 196 197 void ResourcesHLSL::reserveUniformBlockRegisters(unsigned int registerCount) 198 { 199 mUniformBlockRegister = registerCount; 200 } 201 202 const ShaderVariable *ResourcesHLSL::findUniformByName(const ImmutableString &name) const 203 { 204 for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); ++uniformIndex) 205 { 206 if (name == mUniforms[uniformIndex].name) 207 { 208 return &mUniforms[uniformIndex]; 209 } 210 } 211 212 return nullptr; 213 } 214 215 unsigned int ResourcesHLSL::assignUniformRegister(const TType &type, 216 const ImmutableString &name, 217 unsigned int *outRegisterCount) 218 { 219 unsigned int registerIndex; 220 const ShaderVariable *uniform = findUniformByName(name); 221 ASSERT(uniform); 222 223 if (IsSampler(type.getBasicType()) || 224 (IsImage(type.getBasicType()) && type.getMemoryQualifier().readonly)) 225 { 226 registerIndex = mSRVRegister; 227 } 228 else if (IsImage(type.getBasicType())) 229 { 230 registerIndex = mUAVRegister; 231 } 232 else 233 { 234 registerIndex = mUniformRegister; 235 } 236 237 if (uniform->name == "angle_DrawID" && uniform->mappedName == "angle_DrawID") 238 { 239 mUniformRegisterMap["gl_DrawID"] = registerIndex; 240 } 241 else 242 { 243 mUniformRegisterMap[uniform->name] = registerIndex; 244 } 245 246 if (uniform->name == "angle_BaseVertex" && uniform->mappedName == "angle_BaseVertex") 247 { 248 mUniformRegisterMap["gl_BaseVertex"] = registerIndex; 249 } 250 else 251 { 252 mUniformRegisterMap[uniform->name] = registerIndex; 253 } 254 255 if (uniform->name == "angle_BaseInstance" && uniform->mappedName == "angle_BaseInstance") 256 { 257 mUniformRegisterMap["gl_BaseInstance"] = registerIndex; 258 } 259 else 260 { 261 mUniformRegisterMap[uniform->name] = registerIndex; 262 } 263 264 unsigned int registerCount = HLSLVariableRegisterCount(*uniform, mOutputType); 265 266 if (IsSampler(type.getBasicType()) || 267 (IsImage(type.getBasicType()) && type.getMemoryQualifier().readonly)) 268 { 269 mSRVRegister += registerCount; 270 } 271 else if (IsImage(type.getBasicType())) 272 { 273 mUAVRegister += registerCount; 274 } 275 else 276 { 277 mUniformRegister += registerCount; 278 } 279 if (outRegisterCount) 280 { 281 *outRegisterCount = registerCount; 282 } 283 return registerIndex; 284 } 285 286 unsigned int ResourcesHLSL::assignSamplerInStructUniformRegister(const TType &type, 287 const TString &name, 288 unsigned int *outRegisterCount) 289 { 290 // Sampler that is a field of a uniform structure. 291 ASSERT(IsSampler(type.getBasicType())); 292 unsigned int registerIndex = mSRVRegister; 293 mUniformRegisterMap[std::string(name.c_str())] = registerIndex; 294 unsigned int registerCount = type.isArray() ? type.getArraySizeProduct() : 1u; 295 mSRVRegister += registerCount; 296 if (outRegisterCount) 297 { 298 *outRegisterCount = registerCount; 299 } 300 return registerIndex; 301 } 302 303 void ResourcesHLSL::outputHLSLSamplerUniformGroup( 304 TInfoSinkBase &out, 305 const HLSLTextureGroup textureGroup, 306 const TVector<const TVariable *> &group, 307 const TMap<const TVariable *, TString> &samplerInStructSymbolsToAPINames, 308 unsigned int *groupTextureRegisterIndex) 309 { 310 if (group.empty()) 311 { 312 return; 313 } 314 unsigned int groupRegisterCount = 0; 315 for (const TVariable *uniform : group) 316 { 317 const TType &type = uniform->getType(); 318 const ImmutableString &name = uniform->name(); 319 unsigned int registerCount; 320 321 // The uniform might be just a regular sampler or one extracted from a struct. 322 unsigned int samplerArrayIndex = 0u; 323 const ShaderVariable *uniformByName = findUniformByName(name); 324 if (uniformByName) 325 { 326 samplerArrayIndex = assignUniformRegister(type, name, ®isterCount); 327 } 328 else 329 { 330 ASSERT(samplerInStructSymbolsToAPINames.find(uniform) != 331 samplerInStructSymbolsToAPINames.end()); 332 samplerArrayIndex = assignSamplerInStructUniformRegister( 333 type, samplerInStructSymbolsToAPINames.at(uniform), ®isterCount); 334 } 335 groupRegisterCount += registerCount; 336 337 if (type.isArray()) 338 { 339 out << "static const uint " << DecorateVariableIfNeeded(*uniform) << ArrayString(type) 340 << " = "; 341 OutputUniformIndexArrayInitializer(out, type, samplerArrayIndex); 342 out << ";\n"; 343 } 344 else 345 { 346 out << "static const uint " << DecorateVariableIfNeeded(*uniform) << " = " 347 << samplerArrayIndex << ";\n"; 348 } 349 } 350 TString suffix = TextureGroupSuffix(textureGroup); 351 // Since HLSL_TEXTURE_2D is the first group, it has a fixed offset of zero. 352 if (textureGroup != HLSL_TEXTURE_2D) 353 { 354 out << "static const uint textureIndexOffset" << suffix << " = " 355 << (*groupTextureRegisterIndex) << ";\n"; 356 out << "static const uint samplerIndexOffset" << suffix << " = " 357 << (*groupTextureRegisterIndex) << ";\n"; 358 } 359 out << "uniform " << TextureString(textureGroup) << " textures" << suffix << "[" 360 << groupRegisterCount << "]" 361 << " : register(t" << (*groupTextureRegisterIndex) << ");\n"; 362 out << "uniform " << SamplerString(textureGroup) << " samplers" << suffix << "[" 363 << groupRegisterCount << "]" 364 << " : register(s" << (*groupTextureRegisterIndex) << ");\n"; 365 *groupTextureRegisterIndex += groupRegisterCount; 366 } 367 368 void ResourcesHLSL::outputHLSLImageUniformIndices(TInfoSinkBase &out, 369 const TVector<const TVariable *> &group, 370 unsigned int imageArrayIndex, 371 unsigned int *groupRegisterCount) 372 { 373 for (const TVariable *uniform : group) 374 { 375 const TType &type = uniform->getType(); 376 const ImmutableString &name = uniform->name(); 377 unsigned int registerCount = 0; 378 379 assignUniformRegister(type, name, ®isterCount); 380 *groupRegisterCount += registerCount; 381 382 if (type.isArray()) 383 { 384 out << "static const uint " << DecorateVariableIfNeeded(*uniform) << ArrayString(type) 385 << " = "; 386 OutputUniformIndexArrayInitializer(out, type, imageArrayIndex); 387 out << ";\n"; 388 } 389 else 390 { 391 out << "static const uint " << DecorateVariableIfNeeded(*uniform) << " = " 392 << imageArrayIndex << ";\n"; 393 } 394 395 imageArrayIndex += registerCount; 396 } 397 } 398 399 void ResourcesHLSL::outputHLSLReadonlyImageUniformGroup(TInfoSinkBase &out, 400 const HLSLTextureGroup textureGroup, 401 const TVector<const TVariable *> &group, 402 unsigned int *groupTextureRegisterIndex) 403 { 404 if (group.empty()) 405 { 406 return; 407 } 408 409 unsigned int groupRegisterCount = 0; 410 outputHLSLImageUniformIndices(out, group, *groupTextureRegisterIndex, &groupRegisterCount); 411 412 TString suffix = TextureGroupSuffix(textureGroup); 413 out << "static const uint readonlyImageIndexOffset" << suffix << " = " 414 << (*groupTextureRegisterIndex) << ";\n"; 415 out << "uniform " << TextureString(textureGroup) << " readonlyImages" << suffix << "[" 416 << groupRegisterCount << "]" 417 << " : register(t" << (*groupTextureRegisterIndex) << ");\n"; 418 *groupTextureRegisterIndex += groupRegisterCount; 419 } 420 421 void ResourcesHLSL::outputHLSLImageUniformGroup(TInfoSinkBase &out, 422 const HLSLRWTextureGroup textureGroup, 423 const TVector<const TVariable *> &group, 424 unsigned int *groupTextureRegisterIndex) 425 { 426 if (group.empty()) 427 { 428 return; 429 } 430 431 // ROVs should all be written out in DynamicImage2DHLSL.cpp. 432 ASSERT(!IsAnyRasterOrdered(group)); 433 434 unsigned int groupRegisterCount = 0; 435 outputHLSLImageUniformIndices(out, group, *groupTextureRegisterIndex, &groupRegisterCount); 436 437 TString suffix = RWTextureGroupSuffix(textureGroup); 438 out << "static const uint imageIndexOffset" << suffix << " = " << (*groupTextureRegisterIndex) 439 << ";\n"; 440 out << "uniform " << RWTextureString(textureGroup) << " images" << suffix << "[" 441 << groupRegisterCount << "]" 442 << " : register(u" << (*groupTextureRegisterIndex) << ");\n"; 443 *groupTextureRegisterIndex += groupRegisterCount; 444 } 445 446 void ResourcesHLSL::outputHLSL4_0_FL9_3Sampler(TInfoSinkBase &out, 447 const TType &type, 448 const TVariable &variable, 449 const unsigned int registerIndex) 450 { 451 out << "uniform " << SamplerString(type.getBasicType()) << " sampler_" 452 << DecorateVariableIfNeeded(variable) << ArrayString(type) << " : register(s" 453 << str(registerIndex) << ");\n"; 454 out << "uniform " << TextureString(type.getBasicType()) << " texture_" 455 << DecorateVariableIfNeeded(variable) << ArrayString(type) << " : register(t" 456 << str(registerIndex) << ");\n"; 457 } 458 459 void ResourcesHLSL::outputUniform(TInfoSinkBase &out, 460 const TType &type, 461 const TVariable &variable, 462 const unsigned int registerIndex) 463 { 464 const TStructure *structure = type.getStruct(); 465 // If this is a nameless struct, we need to use its full definition, rather than its (empty) 466 // name. 467 // TypeString() will invoke defineNameless in this case; qualifier prefixes are unnecessary for 468 // nameless structs in ES, as nameless structs cannot be used anywhere that layout qualifiers 469 // are permitted. 470 const TString &typeName = ((structure && structure->symbolType() != SymbolType::Empty) 471 ? QualifiedStructNameString(*structure, false, false, false) 472 : TypeString(type)); 473 474 const TString ®isterString = 475 TString("register(") + UniformRegisterPrefix(type) + str(registerIndex) + ")"; 476 477 out << "uniform " << typeName << " "; 478 479 out << DecorateVariableIfNeeded(variable); 480 481 out << ArrayString(type) << " : " << registerString << ";\n"; 482 } 483 484 void ResourcesHLSL::outputAtomicCounterBuffer(TInfoSinkBase &out, 485 const int binding, 486 const unsigned int registerIndex) 487 { 488 // Atomic counter memory access is not incoherent 489 out << "uniform globallycoherent RWByteAddressBuffer " 490 << getAtomicCounterNameForBinding(binding) << " : register(u" << registerIndex << ");\n"; 491 } 492 493 void ResourcesHLSL::uniformsHeader(TInfoSinkBase &out, 494 ShShaderOutput outputType, 495 const ReferencedVariables &referencedUniforms, 496 TSymbolTable *symbolTable) 497 { 498 if (!referencedUniforms.empty()) 499 { 500 out << "// Uniforms\n\n"; 501 } 502 // In the case of HLSL 4, sampler uniforms need to be grouped by type before the code is 503 // written. They are grouped based on the combination of the HLSL texture type and 504 // HLSL sampler type, enumerated in HLSLTextureSamplerGroup. 505 TVector<TVector<const TVariable *>> groupedSamplerUniforms(HLSL_TEXTURE_MAX + 1); 506 TMap<const TVariable *, TString> samplerInStructSymbolsToAPINames; 507 TVector<TVector<const TVariable *>> groupedReadonlyImageUniforms(HLSL_TEXTURE_MAX + 1); 508 TVector<TVector<const TVariable *>> groupedImageUniforms(HLSL_RWTEXTURE_MAX + 1); 509 510 TUnorderedMap<int, unsigned int> assignedAtomicCounterBindings; 511 unsigned int reservedReadonlyImageRegisterCount = 0, reservedImageRegisterCount = 0; 512 for (auto &uniformIt : referencedUniforms) 513 { 514 // Output regular uniforms. Group sampler uniforms by type. 515 const TVariable &variable = *uniformIt.second; 516 const TType &type = variable.getType(); 517 518 if (outputType == SH_HLSL_4_1_OUTPUT && IsSampler(type.getBasicType())) 519 { 520 HLSLTextureGroup group = TextureGroup(type.getBasicType()); 521 groupedSamplerUniforms[group].push_back(&variable); 522 } 523 else if (outputType == SH_HLSL_4_0_FL9_3_OUTPUT && IsSampler(type.getBasicType())) 524 { 525 unsigned int registerIndex = assignUniformRegister(type, variable.name(), nullptr); 526 outputHLSL4_0_FL9_3Sampler(out, type, variable, registerIndex); 527 } 528 else if (outputType == SH_HLSL_4_1_OUTPUT && IsImage(type.getBasicType())) 529 { 530 if (IsImage2D(type.getBasicType())) 531 { 532 const ShaderVariable *uniform = findUniformByName(variable.name()); 533 if (type.getMemoryQualifier().readonly) 534 { 535 reservedReadonlyImageRegisterCount += 536 HLSLVariableRegisterCount(*uniform, mOutputType); 537 } 538 else 539 { 540 reservedImageRegisterCount += HLSLVariableRegisterCount(*uniform, mOutputType); 541 } 542 continue; 543 } 544 if (type.getMemoryQualifier().readonly) 545 { 546 HLSLTextureGroup group = TextureGroup( 547 type.getBasicType(), type.getLayoutQualifier().imageInternalFormat); 548 groupedReadonlyImageUniforms[group].push_back(&variable); 549 } 550 else 551 { 552 HLSLRWTextureGroup group = RWTextureGroup( 553 type.getBasicType(), type.getLayoutQualifier().imageInternalFormat); 554 groupedImageUniforms[group].push_back(&variable); 555 } 556 } 557 else if (outputType == SH_HLSL_4_1_OUTPUT && IsAtomicCounter(type.getBasicType())) 558 { 559 TLayoutQualifier layout = type.getLayoutQualifier(); 560 int binding = layout.binding; 561 unsigned int registerIndex; 562 if (assignedAtomicCounterBindings.find(binding) == assignedAtomicCounterBindings.end()) 563 { 564 registerIndex = mUAVRegister++; 565 assignedAtomicCounterBindings[binding] = registerIndex; 566 outputAtomicCounterBuffer(out, binding, registerIndex); 567 } 568 else 569 { 570 registerIndex = assignedAtomicCounterBindings[binding]; 571 } 572 const ShaderVariable *uniform = findUniformByName(variable.name()); 573 mUniformRegisterMap[uniform->name] = registerIndex; 574 } 575 else 576 { 577 if (type.isStructureContainingSamplers()) 578 { 579 TVector<const TVariable *> samplerSymbols; 580 TMap<const TVariable *, TString> symbolsToAPINames; 581 ImmutableStringBuilder namePrefix(kAngleDecorString.length() + 582 variable.name().length()); 583 namePrefix << kAngleDecorString; 584 namePrefix << variable.name(); 585 type.createSamplerSymbols(namePrefix, TString(variable.name().data()), 586 &samplerSymbols, &symbolsToAPINames, symbolTable); 587 for (const TVariable *sampler : samplerSymbols) 588 { 589 const TType &samplerType = sampler->getType(); 590 591 if (outputType == SH_HLSL_4_1_OUTPUT) 592 { 593 HLSLTextureGroup group = TextureGroup(samplerType.getBasicType()); 594 groupedSamplerUniforms[group].push_back(sampler); 595 samplerInStructSymbolsToAPINames[sampler] = symbolsToAPINames[sampler]; 596 } 597 else if (outputType == SH_HLSL_4_0_FL9_3_OUTPUT) 598 { 599 unsigned int registerIndex = assignSamplerInStructUniformRegister( 600 samplerType, symbolsToAPINames[sampler], nullptr); 601 outputHLSL4_0_FL9_3Sampler(out, samplerType, *sampler, registerIndex); 602 } 603 else 604 { 605 ASSERT(outputType == SH_HLSL_3_0_OUTPUT); 606 unsigned int registerIndex = assignSamplerInStructUniformRegister( 607 samplerType, symbolsToAPINames[sampler], nullptr); 608 outputUniform(out, samplerType, *sampler, registerIndex); 609 } 610 } 611 } 612 unsigned int registerIndex = assignUniformRegister(type, variable.name(), nullptr); 613 outputUniform(out, type, variable, registerIndex); 614 } 615 } 616 617 if (outputType == SH_HLSL_4_1_OUTPUT) 618 { 619 unsigned int groupTextureRegisterIndex = 0; 620 // Atomic counters and RW texture share the same resources. Therefore, RW texture need to 621 // start counting after the last atomic counter. 622 unsigned int groupRWTextureRegisterIndex = mUAVRegister; 623 // TEXTURE_2D is special, index offset is assumed to be 0 and omitted in that case. 624 ASSERT(HLSL_TEXTURE_MIN == HLSL_TEXTURE_2D); 625 for (int groupId = HLSL_TEXTURE_MIN; groupId < HLSL_TEXTURE_MAX; ++groupId) 626 { 627 outputHLSLSamplerUniformGroup( 628 out, HLSLTextureGroup(groupId), groupedSamplerUniforms[groupId], 629 samplerInStructSymbolsToAPINames, &groupTextureRegisterIndex); 630 } 631 mSamplerCount = groupTextureRegisterIndex; 632 633 // Reserve t type register for readonly image2D variables. 634 mReadonlyImage2DRegisterIndex = mSRVRegister; 635 groupTextureRegisterIndex += reservedReadonlyImageRegisterCount; 636 mSRVRegister += reservedReadonlyImageRegisterCount; 637 638 for (int groupId = HLSL_TEXTURE_MIN; groupId < HLSL_TEXTURE_MAX; ++groupId) 639 { 640 outputHLSLReadonlyImageUniformGroup(out, HLSLTextureGroup(groupId), 641 groupedReadonlyImageUniforms[groupId], 642 &groupTextureRegisterIndex); 643 } 644 mReadonlyImageCount = groupTextureRegisterIndex - mReadonlyImage2DRegisterIndex; 645 if (mReadonlyImageCount) 646 { 647 out << "static const uint readonlyImageIndexStart = " << mReadonlyImage2DRegisterIndex 648 << ";\n"; 649 } 650 651 // Reserve u type register for writable image2D variables. 652 mImage2DRegisterIndex = mUAVRegister; 653 groupRWTextureRegisterIndex += reservedImageRegisterCount; 654 mUAVRegister += reservedImageRegisterCount; 655 656 for (int groupId = HLSL_RWTEXTURE_MIN; groupId < HLSL_RWTEXTURE_MAX; ++groupId) 657 { 658 outputHLSLImageUniformGroup(out, HLSLRWTextureGroup(groupId), 659 groupedImageUniforms[groupId], 660 &groupRWTextureRegisterIndex); 661 } 662 mImageCount = groupRWTextureRegisterIndex - mImage2DRegisterIndex; 663 if (mImageCount) 664 { 665 out << "static const uint imageIndexStart = " << mImage2DRegisterIndex << ";\n"; 666 } 667 } 668 } 669 670 void ResourcesHLSL::samplerMetadataUniforms(TInfoSinkBase &out, unsigned int regIndex) 671 { 672 // If mSamplerCount is 0 the shader doesn't use any textures for samplers. 673 if (mSamplerCount > 0) 674 { 675 out << " struct SamplerMetadata\n" 676 " {\n" 677 " int baseLevel;\n" 678 " int internalFormatBits;\n" 679 " int wrapModes;\n" 680 " int padding;\n" 681 " int4 intBorderColor;\n" 682 " };\n" 683 " SamplerMetadata samplerMetadata[" 684 << mSamplerCount << "] : packoffset(c" << regIndex << ");\n"; 685 } 686 } 687 688 void ResourcesHLSL::imageMetadataUniforms(TInfoSinkBase &out, unsigned int regIndex) 689 { 690 if (mReadonlyImageCount > 0 || mImageCount > 0) 691 { 692 out << " struct ImageMetadata\n" 693 " {\n" 694 " int layer;\n" 695 " uint level;\n" 696 " int2 padding;\n" 697 " };\n"; 698 699 if (mReadonlyImageCount > 0) 700 { 701 out << " ImageMetadata readonlyImageMetadata[" << mReadonlyImageCount 702 << "] : packoffset(c" << regIndex << ");\n"; 703 } 704 705 if (mImageCount > 0) 706 { 707 out << " ImageMetadata imageMetadata[" << mImageCount << "] : packoffset(c" 708 << regIndex + mReadonlyImageCount << ");\n"; 709 } 710 } 711 } 712 713 TString ResourcesHLSL::uniformBlocksHeader( 714 const ReferencedInterfaceBlocks &referencedInterfaceBlocks, 715 const std::map<int, const TInterfaceBlock *> &uniformBlockOptimizedMap) 716 { 717 TString interfaceBlocks; 718 719 for (const auto &blockReference : referencedInterfaceBlocks) 720 { 721 const TInterfaceBlock &interfaceBlock = *blockReference.second->block; 722 const TVariable *instanceVariable = blockReference.second->instanceVariable; 723 if (instanceVariable != nullptr) 724 { 725 interfaceBlocks += uniformBlockStructString(interfaceBlock); 726 } 727 728 // In order to avoid compile performance issue, translate uniform block to structured 729 // buffer. anglebug.com/3682. 730 if (uniformBlockOptimizedMap.count(interfaceBlock.uniqueId().get()) != 0) 731 { 732 unsigned int structuredBufferRegister = mSRVRegister; 733 if (instanceVariable != nullptr && instanceVariable->getType().isArray()) 734 { 735 unsigned int instanceArraySize = 736 instanceVariable->getType().getOutermostArraySize(); 737 for (unsigned int arrayIndex = 0; arrayIndex < instanceArraySize; arrayIndex++) 738 { 739 interfaceBlocks += uniformBlockWithOneLargeArrayMemberString( 740 interfaceBlock, instanceVariable, structuredBufferRegister + arrayIndex, 741 arrayIndex); 742 } 743 mSRVRegister += instanceArraySize; 744 } 745 else 746 { 747 interfaceBlocks += uniformBlockWithOneLargeArrayMemberString( 748 interfaceBlock, instanceVariable, structuredBufferRegister, GL_INVALID_INDEX); 749 mSRVRegister += 1u; 750 } 751 mUniformBlockRegisterMap[interfaceBlock.name().data()] = structuredBufferRegister; 752 mUniformBlockUseStructuredBufferMap[interfaceBlock.name().data()] = true; 753 continue; 754 } 755 756 unsigned int activeRegister = mUniformBlockRegister; 757 mUniformBlockRegisterMap[interfaceBlock.name().data()] = activeRegister; 758 759 if (instanceVariable != nullptr && instanceVariable->getType().isArray()) 760 { 761 unsigned int instanceArraySize = instanceVariable->getType().getOutermostArraySize(); 762 for (unsigned int arrayIndex = 0; arrayIndex < instanceArraySize; arrayIndex++) 763 { 764 interfaceBlocks += uniformBlockString(interfaceBlock, instanceVariable, 765 activeRegister + arrayIndex, arrayIndex); 766 } 767 mUniformBlockRegister += instanceArraySize; 768 } 769 else 770 { 771 interfaceBlocks += uniformBlockString(interfaceBlock, instanceVariable, activeRegister, 772 GL_INVALID_INDEX); 773 mUniformBlockRegister += 1u; 774 } 775 } 776 777 return (interfaceBlocks.empty() ? "" : ("// Uniform Blocks\n\n" + interfaceBlocks)); 778 } 779 780 void ResourcesHLSL::allocateShaderStorageBlockRegisters( 781 const ReferencedInterfaceBlocks &referencedInterfaceBlocks) 782 { 783 for (const auto &interfaceBlockReference : referencedInterfaceBlocks) 784 { 785 const TInterfaceBlock &interfaceBlock = *interfaceBlockReference.second->block; 786 const TVariable *instanceVariable = interfaceBlockReference.second->instanceVariable; 787 788 mShaderStorageBlockRegisterMap[interfaceBlock.name().data()] = mUAVRegister; 789 790 if (instanceVariable != nullptr && instanceVariable->getType().isArray()) 791 { 792 mUAVRegister += instanceVariable->getType().getOutermostArraySize(); 793 } 794 else 795 { 796 mUAVRegister += 1u; 797 } 798 } 799 } 800 801 TString ResourcesHLSL::shaderStorageBlocksHeader( 802 const ReferencedInterfaceBlocks &referencedInterfaceBlocks) 803 { 804 TString interfaceBlocks; 805 806 for (const auto &interfaceBlockReference : referencedInterfaceBlocks) 807 { 808 const TInterfaceBlock &interfaceBlock = *interfaceBlockReference.second->block; 809 const TVariable *instanceVariable = interfaceBlockReference.second->instanceVariable; 810 811 unsigned int activeRegister = mShaderStorageBlockRegisterMap[interfaceBlock.name().data()]; 812 813 if (instanceVariable != nullptr && instanceVariable->getType().isArray()) 814 { 815 unsigned int instanceArraySize = instanceVariable->getType().getOutermostArraySize(); 816 for (unsigned int arrayIndex = 0; arrayIndex < instanceArraySize; arrayIndex++) 817 { 818 interfaceBlocks += shaderStorageBlockString( 819 interfaceBlock, instanceVariable, activeRegister + arrayIndex, arrayIndex); 820 } 821 } 822 else 823 { 824 interfaceBlocks += shaderStorageBlockString(interfaceBlock, instanceVariable, 825 activeRegister, GL_INVALID_INDEX); 826 } 827 } 828 829 return interfaceBlocks; 830 } 831 832 TString ResourcesHLSL::uniformBlockString(const TInterfaceBlock &interfaceBlock, 833 const TVariable *instanceVariable, 834 unsigned int registerIndex, 835 unsigned int arrayIndex) 836 { 837 const TString &arrayIndexString = (arrayIndex != GL_INVALID_INDEX ? str(arrayIndex) : ""); 838 const TString &blockName = TString(interfaceBlock.name().data()) + arrayIndexString; 839 TString hlsl; 840 841 hlsl += "cbuffer " + blockName + " : register(b" + str(registerIndex) + 842 ")\n" 843 "{\n"; 844 845 if (instanceVariable != nullptr) 846 { 847 hlsl += " " + InterfaceBlockStructName(interfaceBlock) + " " + 848 InterfaceBlockInstanceString(instanceVariable->name(), arrayIndex) + ";\n"; 849 } 850 else 851 { 852 const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage(); 853 hlsl += uniformBlockMembersString(interfaceBlock, blockStorage); 854 } 855 856 hlsl += "};\n\n"; 857 858 return hlsl; 859 } 860 861 TString ResourcesHLSL::uniformBlockWithOneLargeArrayMemberString( 862 const TInterfaceBlock &interfaceBlock, 863 const TVariable *instanceVariable, 864 unsigned int registerIndex, 865 unsigned int arrayIndex) 866 { 867 TString hlsl, typeString; 868 869 const TField &field = *interfaceBlock.fields()[0]; 870 const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage(); 871 typeString = InterfaceBlockFieldTypeString(field, blockStorage, true); 872 const TType &fieldType = *field.type(); 873 if (fieldType.isMatrix()) 874 { 875 if (arrayIndex == GL_INVALID_INDEX || arrayIndex == 0) 876 { 877 hlsl += "struct pack" + Decorate(interfaceBlock.name()) + " { " + typeString + " " + 878 Decorate(field.name()) + "; };\n"; 879 } 880 typeString = "pack" + Decorate(interfaceBlock.name()); 881 } 882 else if (fieldType.isVectorArray() || fieldType.isScalarArray()) 883 { 884 // If the member is an array of scalars or vectors, std140 rules require the base array 885 // stride are rounded up to the base alignment of a vec4. 886 if (arrayIndex == GL_INVALID_INDEX || arrayIndex == 0) 887 { 888 hlsl += "struct pack" + Decorate(interfaceBlock.name()) + " { " + typeString + " " + 889 Decorate(field.name()) + ";\n"; 890 hlsl += InterfaceBlockScalarVectorFieldPaddingString(fieldType) + " };\n"; 891 } 892 typeString = "pack" + Decorate(interfaceBlock.name()); 893 } 894 895 if (instanceVariable != nullptr) 896 { 897 898 hlsl += "StructuredBuffer <" + typeString + "> " + 899 InterfaceBlockInstanceString(instanceVariable->name(), arrayIndex) + "_" + 900 Decorate(field.name()) + +" : register(t" + str(registerIndex) + ");\n"; 901 } 902 else 903 { 904 hlsl += "StructuredBuffer <" + typeString + "> " + Decorate(field.name()) + 905 " : register(t" + str(registerIndex) + ");\n"; 906 } 907 908 return hlsl; 909 } 910 911 TString ResourcesHLSL::shaderStorageBlockString(const TInterfaceBlock &interfaceBlock, 912 const TVariable *instanceVariable, 913 unsigned int registerIndex, 914 unsigned int arrayIndex) 915 { 916 TString hlsl; 917 if (instanceVariable != nullptr) 918 { 919 hlsl += "RWByteAddressBuffer " + 920 InterfaceBlockInstanceString(instanceVariable->name(), arrayIndex) + 921 ": register(u" + str(registerIndex) + ");\n"; 922 } 923 else 924 { 925 hlsl += "RWByteAddressBuffer " + Decorate(interfaceBlock.name()) + ": register(u" + 926 str(registerIndex) + ");\n"; 927 } 928 return hlsl; 929 } 930 931 TString ResourcesHLSL::InterfaceBlockInstanceString(const ImmutableString &instanceName, 932 unsigned int arrayIndex) 933 { 934 if (arrayIndex != GL_INVALID_INDEX) 935 { 936 return DecoratePrivate(instanceName) + "_" + str(arrayIndex); 937 } 938 else 939 { 940 return Decorate(instanceName); 941 } 942 } 943 944 TString ResourcesHLSL::uniformBlockMembersString(const TInterfaceBlock &interfaceBlock, 945 TLayoutBlockStorage blockStorage) 946 { 947 TString hlsl; 948 949 Std140PaddingHelper padHelper = mStructureHLSL->getPaddingHelper(); 950 951 const unsigned int fieldCount = static_cast<unsigned int>(interfaceBlock.fields().size()); 952 for (unsigned int typeIndex = 0; typeIndex < fieldCount; typeIndex++) 953 { 954 const TField &field = *interfaceBlock.fields()[typeIndex]; 955 const TType &fieldType = *field.type(); 956 957 if (blockStorage == EbsStd140) 958 { 959 // 2 and 3 component vector types in some cases need pre-padding 960 hlsl += padHelper.prePaddingString(fieldType, false); 961 } 962 963 hlsl += " " + InterfaceBlockFieldTypeString(field, blockStorage, false) + " " + 964 Decorate(field.name()) + ArrayString(fieldType).data() + ";\n"; 965 966 // must pad out after matrices and arrays, where HLSL usually allows itself room to pack 967 // stuff 968 if (blockStorage == EbsStd140) 969 { 970 const bool useHLSLRowMajorPacking = 971 (fieldType.getLayoutQualifier().matrixPacking == EmpColumnMajor); 972 hlsl += padHelper.postPaddingString(fieldType, useHLSLRowMajorPacking, 973 typeIndex == fieldCount - 1, false); 974 } 975 } 976 977 return hlsl; 978 } 979 980 TString ResourcesHLSL::uniformBlockStructString(const TInterfaceBlock &interfaceBlock) 981 { 982 const TLayoutBlockStorage blockStorage = interfaceBlock.blockStorage(); 983 984 return "struct " + InterfaceBlockStructName(interfaceBlock) + 985 "\n" 986 "{\n" + 987 uniformBlockMembersString(interfaceBlock, blockStorage) + "};\n\n"; 988 } 989 } // namespace sh