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