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 writePerVertexBuiltIns(const TType &type, spirv::IdRef typeId); 369 void writeInterfaceVariableDecorations(const TType &type, spirv::IdRef variableId); 370 void writeBranchConditional(spirv::IdRef conditionValue, 371 spirv::IdRef trueBlock, 372 spirv::IdRef falseBlock, 373 spirv::IdRef mergeBlock); 374 void writeBranchConditionalBlockEnd(); 375 void writeLoopHeader(spirv::IdRef branchToBlock, 376 spirv::IdRef continueBlock, 377 spirv::IdRef mergeBlock); 378 void writeLoopConditionEnd(spirv::IdRef conditionValue, 379 spirv::IdRef branchToBlock, 380 spirv::IdRef mergeBlock); 381 void writeLoopContinueEnd(spirv::IdRef headerBlock); 382 void writeLoopBodyEnd(spirv::IdRef continueBlock); 383 void writeSwitch(spirv::IdRef conditionValue, 384 spirv::IdRef defaultBlock, 385 const spirv::PairLiteralIntegerIdRefList &targetPairList, 386 spirv::IdRef mergeBlock); 387 void writeSwitchCaseBlockEnd(); 388 void writeDebugName(spirv::IdRef id, const char *name); 389 void writeNonSemanticInstruction(vk::spirv::NonSemanticInstruction instruction); 390 391 spirv::IdRef getBoolConstant(bool value); 392 spirv::IdRef getUintConstant(uint32_t value); 393 spirv::IdRef getIntConstant(int32_t value); 394 spirv::IdRef getFloatConstant(float value); 395 spirv::IdRef getUvecConstant(uint32_t value, int size); 396 spirv::IdRef getIvecConstant(int32_t value, int size); 397 spirv::IdRef getVecConstant(float value, int size); 398 spirv::IdRef getCompositeConstant(spirv::IdRef typeId, const spirv::IdRefList &values); 399 spirv::IdRef getNullConstant(spirv::IdRef typeId); 400 401 // Helpers to start and end a function. 402 void startNewFunction(spirv::IdRef functionId, const TFunction *func); 403 void assembleSpirvFunctionBlocks(); 404 405 // Helper to declare a variable. Function-local variables must be placed in the first block of 406 // the current function. If the variable comes from a TSymbol, it's unique id is passed in, 407 // which is used to determine if a reserved SPIR-V id should be used for this variable. 408 spirv::IdRef declareVariable(spirv::IdRef typeId, 409 spv::StorageClass storageClass, 410 const SpirvDecorations &decorations, 411 spirv::IdRef *initializerId, 412 const char *name, 413 const TSymbolUniqueId *uniqueId); 414 // Helper to declare specialization constants. 415 spirv::IdRef declareSpecConst(TBasicType type, int id, const char *name); 416 417 // Helpers for conditionals. 418 void startConditional(size_t blockCount, bool isContinuable, bool isBreakable); 419 void nextConditionalBlock(); 420 void endConditional(); 421 bool isInLoop() const; 422 spirv::IdRef getBreakTargetId() const; 423 spirv::IdRef getContinueTargetId() const; 424 425 ImmutableString getName(const TSymbol *symbol); 426 ImmutableString getFieldName(const TField *field); 427 428 spirv::Blob getSpirv(); 429 430 private: 431 void predefineCommonTypes(); 432 SpirvTypeData declareType(const SpirvType &type, const TSymbol *block); 433 434 uint32_t calculateBaseAlignmentAndSize(const SpirvType &type, uint32_t *sizeInStorageBlockOut); 435 uint32_t calculateSizeAndWriteOffsetDecorations(const SpirvType &type, 436 spirv::IdRef typeId, 437 uint32_t blockBaseAlignment); 438 void writeMemberDecorations(const SpirvType &type, spirv::IdRef typeId); 439 void writeInterpolationDecoration(TQualifier qualifier, spirv::IdRef id, uint32_t fieldIndex); 440 441 void addEntryPointInterfaceVariableId(spirv::IdRef id); 442 443 // Helpers for type declaration. 444 void getImageTypeParameters(TBasicType type, 445 spirv::IdRef *sampledTypeOut, 446 spv::Dim *dimOut, 447 spirv::LiteralInteger *depthOut, 448 spirv::LiteralInteger *arrayedOut, 449 spirv::LiteralInteger *multisampledOut, 450 spirv::LiteralInteger *sampledOut); 451 spv::ImageFormat getImageFormat(TLayoutImageInternalFormat imageInternalFormat); 452 453 spirv::IdRef getBasicConstantHelper(uint32_t value, 454 TBasicType type, 455 angle::HashMap<uint32_t, spirv::IdRef> *constants); 456 spirv::IdRef getNullVectorConstantHelper(TBasicType type, int size); 457 spirv::IdRef getVectorConstantHelper(spirv::IdRef valueId, TBasicType type, int size); 458 459 uint32_t nextUnusedBinding(); 460 uint32_t nextUnusedInputLocation(uint32_t consumedCount); 461 uint32_t nextUnusedOutputLocation(uint32_t consumedCount); 462 463 void writeExecutionModes(spirv::Blob *blob); 464 void writeExtensions(spirv::Blob *blob); 465 void writeSourceExtensions(spirv::Blob *blob); 466 void writeNonSemanticOverview(spirv::Blob *blob, spirv::IdRef id); 467 void writeBlockDebugNames(const TFieldListCollection *block, 468 spirv::IdRef typeId, 469 const char *name); 470 471 ANGLE_MAYBE_UNUSED_PRIVATE_FIELD TCompiler *mCompiler; 472 const ShCompileOptions &mCompileOptions; 473 gl::ShaderType mShaderType; 474 const angle::HashMap<int, uint32_t> &mUniqueToSpirvIdMap; 475 476 // Capabilities the shader is using. Accumulated as the instructions are generated. The Shader 477 // capability is unconditionally generated, so it's not tracked. 478 std::set<spv::Capability> mCapabilities; 479 // Execution modes the shader is using. Most execution modes are automatically derived from 480 // shader metadata, but some are only discovered while traversing the tree. Only the latter 481 // execution modes are stored here. 482 std::set<spv::ExecutionMode> mExecutionModes; 483 // Extensions used by the shader. 484 angle::PackedEnumBitSet<SPIRVExtensions> mExtensions; 485 486 // The list of interface variables populated as the instructions are generated. Used for the 487 // OpEntryPoint instruction. 488 // With SPIR-V 1.4, this list includes all global variables. 489 spirv::IdRefList mEntryPointInterfaceList; 490 491 // Id of imported instructions, if used. 492 spirv::IdRef mExtInstImportIdStd; 493 494 // Current ID bound, used to allocate new ids. 495 spirv::IdRef mNextAvailableId; 496 497 // A map from the AST type to the corresponding SPIR-V ID and associated data. Note that TType 498 // includes a lot of information that pertains to the variable that has the type, not the type 499 // itself. SpirvType instead contains only information that can identify the type itself. 500 angle::HashMap<SpirvType, SpirvTypeData, SpirvTypeHash> mTypeMap; 501 502 // Various sections of SPIR-V. Each section grows as SPIR-V is generated, and the final result 503 // is obtained by stitching the sections together. This puts the instructions in the order 504 // required by the spec. 505 spirv::Blob mSpirvDebug; 506 spirv::Blob mSpirvDecorations; 507 spirv::Blob mSpirvTypeAndConstantDecls; 508 spirv::Blob mSpirvTypePointerDecls; 509 spirv::Blob mSpirvFunctionTypeDecls; 510 spirv::Blob mSpirvVariableDecls; 511 spirv::Blob mSpirvFunctions; 512 // A list of blocks created for the current function. These are assembled by 513 // assembleSpirvFunctionBlocks() when the function is entirely visited. Local variables need to 514 // be inserted at the beginning of the first function block, so the entire SPIR-V of the 515 // function cannot be obtained until it's fully visited. 516 // 517 // The last block in this list is the one currently being written to. 518 std::vector<SpirvBlock> mSpirvCurrentFunctionBlocks; 519 520 // List of constants that are already defined (for reuse). 521 spirv::IdRef mBoolConstants[2]; 522 angle::HashMap<uint32_t, spirv::IdRef> mUintConstants; 523 angle::HashMap<uint32_t, spirv::IdRef> mIntConstants; 524 angle::HashMap<uint32_t, spirv::IdRef> mFloatConstants; 525 angle::HashMap<SpirvIdAndIdList, spirv::IdRef, SpirvIdAndIdListHash> mCompositeConstants; 526 // Keyed by typeId, returns the null constant corresponding to that type. 527 std::vector<spirv::IdRef> mNullConstants; 528 529 // List of type pointers that are already defined. 530 // TODO: if all users call getTypeData(), move to SpirvTypeData. http://anglebug.com/4889 531 angle::HashMap<SpirvIdAndStorageClass, spirv::IdRef, SpirvIdAndStorageClassHash> 532 mTypePointerIdMap; 533 534 // List of function types that are already defined. 535 angle::HashMap<SpirvIdAndIdList, spirv::IdRef, SpirvIdAndIdListHash> mFunctionTypeIdMap; 536 537 // Stack of conditionals. When an if, loop or switch is visited, a new conditional scope is 538 // added. When the conditional construct is entirely visited, it's popped. As the blocks of 539 // the conditional constructs are visited, ids are consumed from the top of the stack. When 540 // break or continue is visited, the stack is traversed backwards until a loop or switch is 541 // found. 542 std::vector<SpirvConditional> mConditionalStack; 543 544 // Every resource that requires set & binding layout qualifiers is assigned set 0 and an 545 // arbitrary binding. Every input/output that requires a location layout qualifier is assigned 546 // an arbitrary location as well. 547 // 548 // The link-time SPIR-V transformer modifies set, binding and location decorations in SPIR-V 549 // directly. 550 uint32_t mNextUnusedBinding; 551 uint32_t mNextUnusedInputLocation; 552 uint32_t mNextUnusedOutputLocation; 553 554 // Used to provide an overview of what the SPIR-V declares so the SPIR-V translator doesn't have 555 // to discover them. 556 uint32_t mOverviewFlags; 557 }; 558 } // namespace sh 559 560 #endif // COMPILER_TRANSLATOR_SPIRV_BUILDSPIRV_H_ 561