1 // 2 // Copyright 2021 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 // BuildSPIRV: Helper for OutputSPIRV to build SPIR-V. 7 // 8 9 #ifndef COMPILER_TRANSLATOR_SPIRV_BUILDSPIRV_H_ 10 #define COMPILER_TRANSLATOR_SPIRV_BUILDSPIRV_H_ 11 12 #include "common/FixedVector.h" 13 #include "common/PackedEnums.h" 14 #include "common/bitset_utils.h" 15 #include "common/hash_containers.h" 16 #include "common/hash_utils.h" 17 #include "common/spirv/spirv_instruction_builder_autogen.h" 18 #include "compiler/translator/Compiler.h" 19 20 namespace spirv = angle::spirv; 21 22 namespace sh 23 { 24 // Helper classes to map types to ids 25 26 // The same GLSL type may map to multiple SPIR-V types when said GLSL type is used differently in 27 // the shader source, for example used with |invariant| and without, used in an interface block etc. 28 // This type contains the pieces of information that differentiate SPIR-V types derived from the 29 // same GLSL type. This is referred to as "SPIR-V type specialization" henceforth. 30 struct SpirvType; 31 class SpirvTypeSpec 32 { 33 public: 34 // Some of the properties that specialize SPIR-V types apply to structs or arrays, but not to 35 // their fields or basic types. When extracting fields, array elements, columns or basic types 36 // from a type, the following helpers are used to remove any ineffective (and thus incorrect) 37 // specialization. 38 void inferDefaults(const TType &type, TCompiler *compiler); 39 void onArrayElementSelection(bool isElementTypeBlock, bool isElementTypeArray); 40 void onBlockFieldSelection(const TType &fieldType); 41 void onMatrixColumnSelection(); 42 void onVectorComponentSelection(); 43 44 // If a structure is used in two interface blocks with different layouts, it would have 45 // to generate two SPIR-V types, as its fields' Offset decorations could be different. 46 // For non-block types, when used in an interface block as an array, they could generate 47 // different ArrayStride decorations. As such, the block storage is part of the SPIR-V type 48 // except for non-block non-array types. 49 TLayoutBlockStorage blockStorage = EbsUnspecified; 50 51 // If a structure is used in two I/O blocks or output varyings with and without the invariant 52 // qualifier, it would also have to generate two SPIR-V types, as its fields' Invariant 53 // decorations would be different. 54 bool isInvariantBlock = false; 55 56 // Similarly, a structure containing matrices may be used both with the column_major and 57 // row_major layout qualifier, generating two SPIR-V types with different decorations on its 58 // fields. 59 bool isRowMajorQualifiedBlock = false; 60 61 // Arrays when used in an interface block produce a different type which is decorated with an 62 // ArrayStride. Row-major qualified arrays of matrices can potentially produce a different 63 // stride from column-major ones. 64 bool isRowMajorQualifiedArray = false; 65 66 // Bool is disallowed in interface blocks in SPIR-V. This type is emulated with uint. This 67 // property applies to both blocks with bools in them and the bool type inside the block itself. 68 bool isOrHasBoolInInterfaceBlock = false; 69 70 // When |patch| is specified on an I/O block, the members of the type itself are decorated with 71 // it. This is not recursively applied, and since each I/O block has a unique type, this 72 // doesn't actually result in duplicated types even if it's specializing the type. 73 bool isPatchIOBlock = false; 74 }; 75 76 struct SpirvType 77 { 78 // If struct or interface block, the type is identified by the pointer. Note that both 79 // TStructure and TInterfaceBlock inherit from TFieldListCollection, and their difference is 80 // irrelevant as far as SPIR-V type is concerned. 81 const TFieldListCollection *block = nullptr; 82 83 // Otherwise, it's a basic type + column, row and array dimensions, or it's an image 84 // declaration. 85 // 86 // Notes: 87 // 88 // - `precision` turns into a RelaxedPrecision decoration on the variable and instructions. 89 // - `precise` turns into a NoContraction decoration on the instructions. 90 // - `readonly`, `writeonly`, `coherent`, `volatile` and `restrict` only apply to memory object 91 // declarations 92 // - `invariant` only applies to variable or members of a block 93 // - `matrixPacking` only applies to members of a struct 94 TBasicType type = EbtFloat; 95 96 uint8_t primarySize = 1; 97 uint8_t secondarySize = 1; 98 99 TSpan<const unsigned int> arraySizes; 100 101 // Only useful for image types. 102 TLayoutImageInternalFormat imageInternalFormat = EiifUnspecified; 103 104 // For sampled images (i.e. GLSL samplers), there are two type ids; one is the OpTypeImage that 105 // declares the image itself, and one OpTypeSampledImage. `isSamplerBaseImage` distinguishes 106 // between these two types. Note that for the former, the basic type is still Ebt*Sampler* to 107 // distinguish it from storage images (which have a basic type of Ebt*Image*). 108 bool isSamplerBaseImage = false; 109 110 // Anything that can cause the same GLSL type to produce different SPIR-V types. 111 SpirvTypeSpec typeSpec; 112 }; 113 114 bool operator==(const SpirvType &a, const SpirvType &b); 115 116 struct SpirvIdAndIdList 117 { 118 spirv::IdRef id; 119 spirv::IdRefList idList; 120 121 bool operator==(const SpirvIdAndIdList &other) const 122 { 123 return id == other.id && idList == other.idList; 124 } 125 }; 126 127 struct SpirvIdAndStorageClass 128 { 129 spirv::IdRef id; 130 spv::StorageClass storageClass; 131 132 bool operator==(const SpirvIdAndStorageClass &other) const 133 { 134 return id == other.id && storageClass == other.storageClass; 135 } 136 }; 137 138 struct SpirvTypeHash 139 { operatorSpirvTypeHash140 size_t operator()(const sh::SpirvType &type) const 141 { 142 // Block storage must only affect the type if it's a block type or array type (in a block). 143 ASSERT(type.typeSpec.blockStorage == sh::EbsUnspecified || type.block != nullptr || 144 !type.arraySizes.empty()); 145 146 // Invariant must only affect the type if it's a block type. 147 ASSERT(!type.typeSpec.isInvariantBlock || type.block != nullptr); 148 149 // Row-major block must only affect the type if it's a block type. 150 ASSERT(!type.typeSpec.isRowMajorQualifiedBlock || type.block != nullptr); 151 152 // Patch must only affect the type if it's a block type. 153 ASSERT(!type.typeSpec.isPatchIOBlock || type.block != nullptr); 154 155 // Row-major array must only affect the type if it's an array of non-square matrices in 156 // an std140 or std430 block. 157 ASSERT(!type.typeSpec.isRowMajorQualifiedArray || 158 (type.block == nullptr && !type.arraySizes.empty() && type.secondarySize > 1 && 159 type.primarySize != type.secondarySize && 160 type.typeSpec.blockStorage != sh::EbsUnspecified)); 161 162 size_t result = 0; 163 164 if (!type.arraySizes.empty()) 165 { 166 result = angle::ComputeGenericHash(type.arraySizes.data(), 167 type.arraySizes.size() * sizeof(type.arraySizes[0])); 168 } 169 170 if (type.block != nullptr) 171 { 172 return result ^ angle::ComputeGenericHash(&type.block, sizeof(type.block)) ^ 173 static_cast<size_t>(type.typeSpec.isInvariantBlock) ^ 174 (static_cast<size_t>(type.typeSpec.isRowMajorQualifiedBlock) << 1) ^ 175 (static_cast<size_t>(type.typeSpec.isRowMajorQualifiedArray) << 2) ^ 176 (static_cast<size_t>(type.typeSpec.isPatchIOBlock) << 3) ^ 177 (type.typeSpec.blockStorage << 4); 178 } 179 180 static_assert(sh::EbtLast < 256, "Basic type doesn't fit in uint8_t"); 181 static_assert(sh::EbsLast < 8, "Block storage doesn't fit in 3 bits"); 182 static_assert(sh::EiifLast < 32, "Image format doesn't fit in 5 bits"); 183 ASSERT(type.primarySize > 0 && type.primarySize <= 4); 184 ASSERT(type.secondarySize > 0 && type.secondarySize <= 4); 185 186 const uint8_t properties[4] = { 187 static_cast<uint8_t>(type.type), 188 static_cast<uint8_t>((type.primarySize - 1) | (type.secondarySize - 1) << 2 | 189 type.isSamplerBaseImage << 4), 190 static_cast<uint8_t>(type.typeSpec.blockStorage | type.imageInternalFormat << 3), 191 // Padding because ComputeGenericHash expects a key size divisible by 4 192 }; 193 194 return result ^ angle::ComputeGenericHash(properties, sizeof(properties)); 195 } 196 }; 197 198 struct SpirvIdAndIdListHash 199 { operatorSpirvIdAndIdListHash200 size_t operator()(const SpirvIdAndIdList &key) const 201 { 202 return angle::ComputeGenericHash(key.idList.data(), 203 key.idList.size() * sizeof(key.idList[0])) ^ 204 key.id; 205 } 206 }; 207 208 struct SpirvIdAndStorageClassHash 209 { operatorSpirvIdAndStorageClassHash210 size_t operator()(const SpirvIdAndStorageClass &key) const 211 { 212 ASSERT(key.storageClass < 16); 213 return key.storageClass | key.id << 4; 214 } 215 }; 216 217 // Data tracked per SPIR-V type (keyed by SpirvType). 218 struct SpirvTypeData 219 { 220 // The SPIR-V id corresponding to the type. 221 spirv::IdRef id; 222 }; 223 224 // Decorations to be applied to variable or intermediate ids which are not part of the SPIR-V type 225 // and are not specific enough (like DescriptorSet) to be handled automatically. Currently, these 226 // are: 227 // 228 // RelaxedPrecision: used to implement |lowp| and |mediump| 229 // NoContraction: used to implement |precise|. 230 // Invariant: used to implement |invariant|, which is applied to output variables. 231 // Memory qualifiers: used to implement |coherent, volatile, restrict, readonly, writeonly|, 232 // which apply to shader storage blocks, variables declared within shader 233 // storage blocks, and images. 234 // 235 // Note that Invariant applies to output variables, NoContraction to arithmetic instructions, and 236 // memory qualifiers to shader storage and images, so they are mutually exclusive. A maximum of 6 237 // decorations are possible. FixedVector::push_back will ASSERT if the given size is ever not 238 // enough. 239 using SpirvDecorations = angle::FixedVector<spv::Decoration, 6>; 240 241 // A block of code. SPIR-V produces forward references to blocks, such as OpBranchConditional 242 // specifying the id of the if and else blocks, each of those referencing the id of the block after 243 // the else. Additionally, local variable declarations are accumulated at the top of the first 244 // block in a function. For these reasons, each block of SPIR-V is generated separately and 245 // assembled at the end of the function, allowing prior blocks to be modified when necessary. 246 struct SpirvBlock 247 { 248 // Id of the block 249 spirv::IdRef labelId; 250 251 // Local variable declarations. Only the first block of a function is allowed to contain any 252 // instructions here. 253 spirv::Blob localVariables; 254 255 // Everything *after* OpLabel (which itself is not generated until blocks are assembled) and 256 // local variables. 257 spirv::Blob body; 258 259 // Whether the block is terminated. Useful for functions without return, asserting that code is 260 // not added after return/break/continue etc (i.e. dead code, which should really be removed 261 // earlier by a transformation, but could also be hacked by returning a bogus block to contain 262 // all the "garbage" to throw away), last switch case without a break, etc. 263 bool isTerminated = false; 264 }; 265 266 // Conditional code, constituting ifs, switches and loops. 267 struct SpirvConditional 268 { 269 // The id of blocks that make up the conditional. 270 // 271 // - For if, there are three blocks: the then, else and merge blocks 272 // - For loops, there are four blocks: the condition, body, continue and merge blocks 273 // - For switch, there are a number of blocks based on the cases. 274 // 275 // In all cases, the merge block is the last block in this list. When the conditional is done 276 // with, that's the block that will be made "current" and future instructions written to. The 277 // merge block is also the branch target of "break" instructions. 278 // 279 // For loops, the continue target block is the one before last block in this list. 280 std::vector<spirv::IdRef> blockIds; 281 282 // Up to which block is already generated. Used by nextConditionalBlock() to generate a block 283 // and give it an id pre-determined in blockIds. 284 size_t nextBlockToWrite = 0; 285 286 // Used to determine if continue will affect this (i.e. it's a loop). 287 bool isContinuable = false; 288 // Used to determine if break will affect this (i.e. it's a loop or switch). 289 bool isBreakable = false; 290 }; 291 292 // List of known extensions 293 enum class SPIRVExtensions 294 { 295 // GL_OVR_multiview / SPV_KHR_multiview 296 MultiviewOVR = 0, 297 298 // GL_ARB_fragment_shader_interlock / SPV_EXT_fragment_shader_interlock 299 FragmentShaderInterlockARB = 1, 300 301 InvalidEnum = 2, 302 EnumCount = 2, 303 }; 304 305 // Helper class to construct SPIR-V 306 class SPIRVBuilder : angle::NonCopyable 307 { 308 public: 309 SPIRVBuilder(TCompiler *compiler, 310 const ShCompileOptions &compileOptions, 311 const angle::HashMap<int, uint32_t> &uniqueToSpirvIdMap, 312 uint32_t firstUnusedSpirvId); 313 314 spirv::IdRef getNewId(const SpirvDecorations &decorations); 315 spirv::IdRef getReservedOrNewId(TSymbolUniqueId uniqueId, const SpirvDecorations &decorations); 316 SpirvType getSpirvType(const TType &type, const SpirvTypeSpec &typeSpec) const; 317 const SpirvTypeData &getTypeData(const TType &type, const SpirvTypeSpec &typeSpec); 318 const SpirvTypeData &getTypeDataOverrideTypeSpec(const TType &type, 319 const SpirvTypeSpec &typeSpec); 320 const SpirvTypeData &getSpirvTypeData(const SpirvType &type, const TSymbol *block); 321 spirv::IdRef getBasicTypeId(TBasicType basicType, size_t size); 322 spirv::IdRef getTypePointerId(spirv::IdRef typeId, spv::StorageClass storageClass); 323 spirv::IdRef getFunctionTypeId(spirv::IdRef returnTypeId, const spirv::IdRefList ¶mTypeIds); 324 325 // Decorations that may apply to intermediate instructions (in addition to variables). 326 // |precise| is only applicable to arithmetic nodes. 327 SpirvDecorations getDecorations(const TType &type); 328 SpirvDecorations getArithmeticDecorations(const TType &type, bool isPrecise, TOperator op); 329 330 // Extended instructions 331 spirv::IdRef getExtInstImportIdStd(); 332 getSpirvDebug()333 spirv::Blob *getSpirvDebug() { return &mSpirvDebug; } getSpirvDecorations()334 spirv::Blob *getSpirvDecorations() { return &mSpirvDecorations; } getSpirvTypeAndConstantDecls()335 spirv::Blob *getSpirvTypeAndConstantDecls() { return &mSpirvTypeAndConstantDecls; } getSpirvTypePointerDecls()336 spirv::Blob *getSpirvTypePointerDecls() { return &mSpirvTypePointerDecls; } getSpirvFunctionTypeDecls()337 spirv::Blob *getSpirvFunctionTypeDecls() { return &mSpirvFunctionTypeDecls; } getSpirvVariableDecls()338 spirv::Blob *getSpirvVariableDecls() { return &mSpirvVariableDecls; } getSpirvFunctions()339 spirv::Blob *getSpirvFunctions() { return &mSpirvFunctions; } getSpirvCurrentFunctionBlock()340 spirv::Blob *getSpirvCurrentFunctionBlock() 341 { 342 ASSERT(!mSpirvCurrentFunctionBlocks.empty() && 343 !mSpirvCurrentFunctionBlocks.back().isTerminated); 344 return &mSpirvCurrentFunctionBlocks.back().body; 345 } getSpirvCurrentFunctionBlockId()346 spirv::IdRef getSpirvCurrentFunctionBlockId() 347 { 348 ASSERT(!mSpirvCurrentFunctionBlocks.empty() && 349 !mSpirvCurrentFunctionBlocks.back().isTerminated); 350 return mSpirvCurrentFunctionBlocks.back().labelId; 351 } isCurrentFunctionBlockTerminated()352 bool isCurrentFunctionBlockTerminated() const 353 { 354 ASSERT(!mSpirvCurrentFunctionBlocks.empty()); 355 return mSpirvCurrentFunctionBlocks.back().isTerminated; 356 } terminateCurrentFunctionBlock()357 void terminateCurrentFunctionBlock() 358 { 359 ASSERT(!mSpirvCurrentFunctionBlocks.empty()); 360 mSpirvCurrentFunctionBlocks.back().isTerminated = true; 361 } getCurrentConditional()362 const SpirvConditional *getCurrentConditional() { return &mConditionalStack.back(); } 363 364 bool isInvariantOutput(const TType &type) const; 365 366 void addCapability(spv::Capability capability); 367 void addExecutionMode(spv::ExecutionMode executionMode); 368 void addExtension(SPIRVExtensions extension); 369 void writePerVertexBuiltIns(const TType &type, spirv::IdRef typeId); 370 void writeInterfaceVariableDecorations(const TType &type, spirv::IdRef variableId); 371 void writeBranchConditional(spirv::IdRef conditionValue, 372 spirv::IdRef trueBlock, 373 spirv::IdRef falseBlock, 374 spirv::IdRef mergeBlock); 375 void writeBranchConditionalBlockEnd(); 376 void writeLoopHeader(spirv::IdRef branchToBlock, 377 spirv::IdRef continueBlock, 378 spirv::IdRef mergeBlock); 379 void writeLoopConditionEnd(spirv::IdRef conditionValue, 380 spirv::IdRef branchToBlock, 381 spirv::IdRef mergeBlock); 382 void writeLoopContinueEnd(spirv::IdRef headerBlock); 383 void writeLoopBodyEnd(spirv::IdRef continueBlock); 384 void writeSwitch(spirv::IdRef conditionValue, 385 spirv::IdRef defaultBlock, 386 const spirv::PairLiteralIntegerIdRefList &targetPairList, 387 spirv::IdRef mergeBlock); 388 void writeSwitchCaseBlockEnd(); 389 void writeDebugName(spirv::IdRef id, const char *name); 390 void writeNonSemanticInstruction(vk::spirv::NonSemanticInstruction instruction); 391 392 spirv::IdRef getBoolConstant(bool value); 393 spirv::IdRef getUintConstant(uint32_t value); 394 spirv::IdRef getIntConstant(int32_t value); 395 spirv::IdRef getFloatConstant(float value); 396 spirv::IdRef getUvecConstant(uint32_t value, int size); 397 spirv::IdRef getIvecConstant(int32_t value, int size); 398 spirv::IdRef getVecConstant(float value, int size); 399 spirv::IdRef getCompositeConstant(spirv::IdRef typeId, const spirv::IdRefList &values); 400 spirv::IdRef getNullConstant(spirv::IdRef typeId); 401 402 // Helpers to start and end a function. 403 void startNewFunction(spirv::IdRef functionId, const TFunction *func); 404 void assembleSpirvFunctionBlocks(); 405 406 // Helper to declare a variable. Function-local variables must be placed in the first block of 407 // the current function. If the variable comes from a TSymbol, it's unique id is passed in, 408 // which is used to determine if a reserved SPIR-V id should be used for this variable. 409 spirv::IdRef declareVariable(spirv::IdRef typeId, 410 spv::StorageClass storageClass, 411 const SpirvDecorations &decorations, 412 spirv::IdRef *initializerId, 413 const char *name, 414 const TSymbolUniqueId *uniqueId); 415 // Helper to declare specialization constants. 416 spirv::IdRef declareSpecConst(TBasicType type, int id, const char *name); 417 418 // Helpers for conditionals. 419 void startConditional(size_t blockCount, bool isContinuable, bool isBreakable); 420 void nextConditionalBlock(); 421 void endConditional(); 422 bool isInLoop() const; 423 spirv::IdRef getBreakTargetId() const; 424 spirv::IdRef getContinueTargetId() const; 425 426 ImmutableString getName(const TSymbol *symbol); 427 ImmutableString getFieldName(const TField *field); 428 429 spirv::Blob getSpirv(); 430 431 private: 432 void predefineCommonTypes(); 433 SpirvTypeData declareType(const SpirvType &type, const TSymbol *block); 434 435 uint32_t calculateBaseAlignmentAndSize(const SpirvType &type, uint32_t *sizeInStorageBlockOut); 436 uint32_t calculateSizeAndWriteOffsetDecorations(const SpirvType &type, 437 spirv::IdRef typeId, 438 uint32_t blockBaseAlignment); 439 void writeMemberDecorations(const SpirvType &type, spirv::IdRef typeId); 440 void writeInterpolationDecoration(TQualifier qualifier, spirv::IdRef id, uint32_t fieldIndex); 441 442 void addEntryPointInterfaceVariableId(spirv::IdRef id); 443 444 // Helpers for type declaration. 445 void getImageTypeParameters(TBasicType type, 446 spirv::IdRef *sampledTypeOut, 447 spv::Dim *dimOut, 448 spirv::LiteralInteger *depthOut, 449 spirv::LiteralInteger *arrayedOut, 450 spirv::LiteralInteger *multisampledOut, 451 spirv::LiteralInteger *sampledOut); 452 spv::ImageFormat getImageFormat(TLayoutImageInternalFormat imageInternalFormat); 453 454 spirv::IdRef getBasicConstantHelper(uint32_t value, 455 TBasicType type, 456 angle::HashMap<uint32_t, spirv::IdRef> *constants); 457 spirv::IdRef getNullVectorConstantHelper(TBasicType type, int size); 458 spirv::IdRef getVectorConstantHelper(spirv::IdRef valueId, TBasicType type, int size); 459 460 uint32_t nextUnusedBinding(); 461 uint32_t nextUnusedInputLocation(uint32_t consumedCount); 462 uint32_t nextUnusedOutputLocation(uint32_t consumedCount); 463 464 void writeExecutionModes(spirv::Blob *blob); 465 void writeExtensions(spirv::Blob *blob); 466 void writeSourceExtensions(spirv::Blob *blob); 467 void writeNonSemanticOverview(spirv::Blob *blob, spirv::IdRef id); 468 void writeBlockDebugNames(const TFieldListCollection *block, 469 spirv::IdRef typeId, 470 const char *name); 471 472 ANGLE_MAYBE_UNUSED_PRIVATE_FIELD TCompiler *mCompiler; 473 const ShCompileOptions &mCompileOptions; 474 gl::ShaderType mShaderType; 475 const angle::HashMap<int, uint32_t> &mUniqueToSpirvIdMap; 476 477 // Capabilities the shader is using. Accumulated as the instructions are generated. The Shader 478 // capability is unconditionally generated, so it's not tracked. 479 std::set<spv::Capability> mCapabilities; 480 // Execution modes the shader is using. Most execution modes are automatically derived from 481 // shader metadata, but some are only discovered while traversing the tree. Only the latter 482 // execution modes are stored here. 483 std::set<spv::ExecutionMode> mExecutionModes; 484 // Extensions used by the shader. 485 angle::PackedEnumBitSet<SPIRVExtensions> mExtensions; 486 487 // The list of interface variables populated as the instructions are generated. Used for the 488 // OpEntryPoint instruction. 489 // With SPIR-V 1.4, this list includes all global variables. 490 spirv::IdRefList mEntryPointInterfaceList; 491 492 // Id of imported instructions, if used. 493 spirv::IdRef mExtInstImportIdStd; 494 495 // Current ID bound, used to allocate new ids. 496 spirv::IdRef mNextAvailableId; 497 498 // A map from the AST type to the corresponding SPIR-V ID and associated data. Note that TType 499 // includes a lot of information that pertains to the variable that has the type, not the type 500 // itself. SpirvType instead contains only information that can identify the type itself. 501 angle::HashMap<SpirvType, SpirvTypeData, SpirvTypeHash> mTypeMap; 502 503 // Various sections of SPIR-V. Each section grows as SPIR-V is generated, and the final result 504 // is obtained by stitching the sections together. This puts the instructions in the order 505 // required by the spec. 506 spirv::Blob mSpirvDebug; 507 spirv::Blob mSpirvDecorations; 508 spirv::Blob mSpirvTypeAndConstantDecls; 509 spirv::Blob mSpirvTypePointerDecls; 510 spirv::Blob mSpirvFunctionTypeDecls; 511 spirv::Blob mSpirvVariableDecls; 512 spirv::Blob mSpirvFunctions; 513 // A list of blocks created for the current function. These are assembled by 514 // assembleSpirvFunctionBlocks() when the function is entirely visited. Local variables need to 515 // be inserted at the beginning of the first function block, so the entire SPIR-V of the 516 // function cannot be obtained until it's fully visited. 517 // 518 // The last block in this list is the one currently being written to. 519 std::vector<SpirvBlock> mSpirvCurrentFunctionBlocks; 520 521 // List of constants that are already defined (for reuse). 522 spirv::IdRef mBoolConstants[2]; 523 angle::HashMap<uint32_t, spirv::IdRef> mUintConstants; 524 angle::HashMap<uint32_t, spirv::IdRef> mIntConstants; 525 angle::HashMap<uint32_t, spirv::IdRef> mFloatConstants; 526 angle::HashMap<SpirvIdAndIdList, spirv::IdRef, SpirvIdAndIdListHash> mCompositeConstants; 527 // Keyed by typeId, returns the null constant corresponding to that type. 528 std::vector<spirv::IdRef> mNullConstants; 529 530 // List of type pointers that are already defined. 531 // TODO: if all users call getTypeData(), move to SpirvTypeData. http://anglebug.com/40096715 532 angle::HashMap<SpirvIdAndStorageClass, spirv::IdRef, SpirvIdAndStorageClassHash> 533 mTypePointerIdMap; 534 535 // List of function types that are already defined. 536 angle::HashMap<SpirvIdAndIdList, spirv::IdRef, SpirvIdAndIdListHash> mFunctionTypeIdMap; 537 538 // Stack of conditionals. When an if, loop or switch is visited, a new conditional scope is 539 // added. When the conditional construct is entirely visited, it's popped. As the blocks of 540 // the conditional constructs are visited, ids are consumed from the top of the stack. When 541 // break or continue is visited, the stack is traversed backwards until a loop or switch is 542 // found. 543 std::vector<SpirvConditional> mConditionalStack; 544 545 // Every resource that requires set & binding layout qualifiers is assigned set 0 and an 546 // arbitrary binding. Every input/output that requires a location layout qualifier is assigned 547 // an arbitrary location as well. 548 // 549 // The link-time SPIR-V transformer modifies set, binding and location decorations in SPIR-V 550 // directly. 551 uint32_t mNextUnusedBinding; 552 uint32_t mNextUnusedInputLocation; 553 uint32_t mNextUnusedOutputLocation; 554 555 // Used to provide an overview of what the SPIR-V declares so the SPIR-V translator doesn't have 556 // to discover them. 557 uint32_t mOverviewFlags; 558 }; 559 } // namespace sh 560 561 #endif // COMPILER_TRANSLATOR_SPIRV_BUILDSPIRV_H_ 562