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_BUILDSPIRV_H_ 10 #define COMPILER_TRANSLATOR_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 struct SpirvIdAndIdList 114 { 115 spirv::IdRef id; 116 spirv::IdRefList idList; 117 118 bool operator==(const SpirvIdAndIdList &other) const 119 { 120 return id == other.id && idList == other.idList; 121 } 122 }; 123 124 struct SpirvIdAndStorageClass 125 { 126 spirv::IdRef id; 127 spv::StorageClass storageClass; 128 129 bool operator==(const SpirvIdAndStorageClass &other) const 130 { 131 return id == other.id && storageClass == other.storageClass; 132 } 133 }; 134 135 struct SpirvTypeHash 136 { operatorSpirvTypeHash137 size_t operator()(const sh::SpirvType &type) const 138 { 139 // Block storage must only affect the type if it's a block type or array type (in a block). 140 ASSERT(type.typeSpec.blockStorage == sh::EbsUnspecified || type.block != nullptr || 141 !type.arraySizes.empty()); 142 143 // Invariant must only affect the type if it's a block type. 144 ASSERT(!type.typeSpec.isInvariantBlock || type.block != nullptr); 145 146 // Row-major block must only affect the type if it's a block type. 147 ASSERT(!type.typeSpec.isRowMajorQualifiedBlock || type.block != nullptr); 148 149 // Patch must only affect the type if it's a block type. 150 ASSERT(!type.typeSpec.isPatchIOBlock || type.block != nullptr); 151 152 // Row-major array must only affect the type if it's an array of non-square matrices in 153 // an std140 or std430 block. 154 ASSERT(!type.typeSpec.isRowMajorQualifiedArray || 155 (type.block == nullptr && !type.arraySizes.empty() && type.secondarySize > 1 && 156 type.primarySize != type.secondarySize && 157 type.typeSpec.blockStorage != sh::EbsUnspecified)); 158 159 size_t result = 0; 160 161 if (!type.arraySizes.empty()) 162 { 163 result = angle::ComputeGenericHash(type.arraySizes.data(), 164 type.arraySizes.size() * sizeof(type.arraySizes[0])); 165 } 166 167 if (type.block != nullptr) 168 { 169 return result ^ angle::ComputeGenericHash(&type.block, sizeof(type.block)) ^ 170 static_cast<size_t>(type.typeSpec.isInvariantBlock) ^ 171 (static_cast<size_t>(type.typeSpec.isRowMajorQualifiedBlock) << 1) ^ 172 (static_cast<size_t>(type.typeSpec.isRowMajorQualifiedArray) << 2) ^ 173 (static_cast<size_t>(type.typeSpec.isPatchIOBlock) << 3) ^ 174 (type.typeSpec.blockStorage << 4); 175 } 176 177 static_assert(sh::EbtLast < 256, "Basic type doesn't fit in uint8_t"); 178 static_assert(sh::EbsLast < 8, "Block storage doesn't fit in 3 bits"); 179 static_assert(sh::EiifLast < 32, "Image format doesn't fit in 5 bits"); 180 ASSERT(type.primarySize > 0 && type.primarySize <= 4); 181 ASSERT(type.secondarySize > 0 && type.secondarySize <= 4); 182 183 const uint8_t properties[4] = { 184 static_cast<uint8_t>(type.type), 185 static_cast<uint8_t>((type.primarySize - 1) | (type.secondarySize - 1) << 2 | 186 type.isSamplerBaseImage << 4), 187 static_cast<uint8_t>(type.typeSpec.blockStorage | type.imageInternalFormat << 3), 188 // Padding because ComputeGenericHash expects a key size divisible by 4 189 }; 190 191 return result ^ angle::ComputeGenericHash(properties, sizeof(properties)); 192 } 193 }; 194 195 struct SpirvIdAndIdListHash 196 { operatorSpirvIdAndIdListHash197 size_t operator()(const SpirvIdAndIdList &key) const 198 { 199 return angle::ComputeGenericHash(key.idList.data(), 200 key.idList.size() * sizeof(key.idList[0])) ^ 201 key.id; 202 } 203 }; 204 205 struct SpirvIdAndStorageClassHash 206 { operatorSpirvIdAndStorageClassHash207 size_t operator()(const SpirvIdAndStorageClass &key) const 208 { 209 ASSERT(key.storageClass < 16); 210 return key.storageClass | key.id << 4; 211 } 212 }; 213 214 // Data tracked per SPIR-V type (keyed by SpirvType). 215 struct SpirvTypeData 216 { 217 // The SPIR-V id corresponding to the type. 218 spirv::IdRef id; 219 }; 220 221 // Decorations to be applied to variable or intermediate ids which are not part of the SPIR-V type 222 // and are not specific enough (like DescriptorSet) to be handled automatically. Currently, these 223 // are: 224 // 225 // RelaxedPrecision: used to implement |lowp| and |mediump| 226 // NoContraction: used to implement |precise|. TODO: support this. It requires the precise 227 // property to be promoted through the nodes in the AST, which currently isn't. 228 // http://anglebug.com/4889 229 // Invariant: used to implement |invariant|, which is applied to output variables. 230 // 231 // Note that Invariant applies to variables and NoContraction to arithmetic instructions, so they 232 // are mutually exclusive and a maximum of 2 decorations are possible. FixedVector::push_back will 233 // ASSERT if the given size is ever not enough. 234 using SpirvDecorations = angle::FixedVector<spv::Decoration, 2>; 235 236 // A block of code. SPIR-V produces forward references to blocks, such as OpBranchConditional 237 // specifying the id of the if and else blocks, each of those referencing the id of the block after 238 // the else. Additionally, local variable declarations are accumulated at the top of the first 239 // block in a function. For these reasons, each block of SPIR-V is generated separately and 240 // assembled at the end of the function, allowing prior blocks to be modified when necessary. 241 struct SpirvBlock 242 { 243 // Id of the block 244 spirv::IdRef labelId; 245 246 // Local variable declarations. Only the first block of a function is allowed to contain any 247 // instructions here. 248 spirv::Blob localVariables; 249 250 // Everything *after* OpLabel (which itself is not generated until blocks are assembled) and 251 // local variables. 252 spirv::Blob body; 253 254 // Whether the block is terminated. Useful for functions without return, asserting that code is 255 // not added after return/break/continue etc (i.e. dead code, which should really be removed 256 // earlier by a transformation, but could also be hacked by returning a bogus block to contain 257 // all the "garbage" to throw away), last switch case without a break, etc. 258 bool isTerminated = false; 259 }; 260 261 // Conditional code, constituting ifs, switches and loops. 262 struct SpirvConditional 263 { 264 // The id of blocks that make up the conditional. 265 // 266 // - For if, there are three blocks: the then, else and merge blocks 267 // - For loops, there are four blocks: the condition, body, continue and merge blocks 268 // - For switch, there are a number of blocks based on the cases. 269 // 270 // In all cases, the merge block is the last block in this list. When the conditional is done 271 // with, that's the block that will be made "current" and future instructions written to. The 272 // merge block is also the branch target of "break" instructions. 273 // 274 // For loops, the continue target block is the one before last block in this list. 275 std::vector<spirv::IdRef> blockIds; 276 277 // Up to which block is already generated. Used by nextConditionalBlock() to generate a block 278 // and give it an id pre-determined in blockIds. 279 size_t nextBlockToWrite = 0; 280 281 // Used to determine if continue will affect this (i.e. it's a loop). 282 bool isContinuable = false; 283 // Used to determine if break will affect this (i.e. it's a loop or switch). 284 bool isBreakable = false; 285 }; 286 287 // List of known extensions 288 enum class SPIRVExtensions 289 { 290 // GL_OVR_multiview / SPV_KHR_multiview 291 MultiviewOVR = 0, 292 293 InvalidEnum = 1, 294 EnumCount = 1, 295 }; 296 297 // Helper class to construct SPIR-V 298 class SPIRVBuilder : angle::NonCopyable 299 { 300 public: 301 SPIRVBuilder(TCompiler *compiler, 302 ShCompileOptions compileOptions, 303 ShHashFunction64 hashFunction, 304 NameMap &nameMap); 305 306 spirv::IdRef getNewId(const SpirvDecorations &decorations); 307 SpirvType getSpirvType(const TType &type, const SpirvTypeSpec &typeSpec) const; 308 const SpirvTypeData &getTypeData(const TType &type, const SpirvTypeSpec &typeSpec); 309 const SpirvTypeData &getTypeDataOverrideTypeSpec(const TType &type, 310 const SpirvTypeSpec &typeSpec); 311 const SpirvTypeData &getSpirvTypeData(const SpirvType &type, const TSymbol *block); 312 spirv::IdRef getBasicTypeId(TBasicType basicType, size_t size); 313 spirv::IdRef getTypePointerId(spirv::IdRef typeId, spv::StorageClass storageClass); 314 spirv::IdRef getFunctionTypeId(spirv::IdRef returnTypeId, const spirv::IdRefList ¶mTypeIds); 315 316 // Decorations that may apply to intermediate instructions (in addition to variables). 317 // |precise| is only applicable to arithmetic nodes. 318 SpirvDecorations getDecorations(const TType &type); 319 SpirvDecorations getArithmeticDecorations(const TType &type, bool isPrecise, TOperator op); 320 321 // Extended instructions 322 spirv::IdRef getExtInstImportIdStd(); 323 getSpirvDebug()324 spirv::Blob *getSpirvDebug() { return &mSpirvDebug; } getSpirvDecorations()325 spirv::Blob *getSpirvDecorations() { return &mSpirvDecorations; } getSpirvTypeAndConstantDecls()326 spirv::Blob *getSpirvTypeAndConstantDecls() { return &mSpirvTypeAndConstantDecls; } getSpirvTypePointerDecls()327 spirv::Blob *getSpirvTypePointerDecls() { return &mSpirvTypePointerDecls; } getSpirvFunctionTypeDecls()328 spirv::Blob *getSpirvFunctionTypeDecls() { return &mSpirvFunctionTypeDecls; } getSpirvVariableDecls()329 spirv::Blob *getSpirvVariableDecls() { return &mSpirvVariableDecls; } getSpirvFunctions()330 spirv::Blob *getSpirvFunctions() { return &mSpirvFunctions; } getSpirvCurrentFunctionBlock()331 spirv::Blob *getSpirvCurrentFunctionBlock() 332 { 333 ASSERT(!mSpirvCurrentFunctionBlocks.empty() && 334 !mSpirvCurrentFunctionBlocks.back().isTerminated); 335 return &mSpirvCurrentFunctionBlocks.back().body; 336 } getSpirvCurrentFunctionBlockId()337 spirv::IdRef getSpirvCurrentFunctionBlockId() 338 { 339 ASSERT(!mSpirvCurrentFunctionBlocks.empty() && 340 !mSpirvCurrentFunctionBlocks.back().isTerminated); 341 return mSpirvCurrentFunctionBlocks.back().labelId; 342 } isCurrentFunctionBlockTerminated()343 bool isCurrentFunctionBlockTerminated() const 344 { 345 ASSERT(!mSpirvCurrentFunctionBlocks.empty()); 346 return mSpirvCurrentFunctionBlocks.back().isTerminated; 347 } terminateCurrentFunctionBlock()348 void terminateCurrentFunctionBlock() 349 { 350 ASSERT(!mSpirvCurrentFunctionBlocks.empty()); 351 mSpirvCurrentFunctionBlocks.back().isTerminated = true; 352 } getCurrentConditional()353 const SpirvConditional *getCurrentConditional() { return &mConditionalStack.back(); } 354 355 bool isInvariantOutput(const TType &type) const; 356 357 void addCapability(spv::Capability capability); 358 void addExecutionMode(spv::ExecutionMode executionMode); 359 void addExtension(SPIRVExtensions extension); 360 void setEntryPointId(spirv::IdRef id); 361 void addEntryPointInterfaceVariableId(spirv::IdRef id); 362 void writePerVertexBuiltIns(const TType &type, spirv::IdRef typeId); 363 void writeInterfaceVariableDecorations(const TType &type, spirv::IdRef variableId); 364 void writeBranchConditional(spirv::IdRef conditionValue, 365 spirv::IdRef trueBlock, 366 spirv::IdRef falseBlock, 367 spirv::IdRef mergeBlock); 368 void writeBranchConditionalBlockEnd(); 369 void writeLoopHeader(spirv::IdRef branchToBlock, 370 spirv::IdRef continueBlock, 371 spirv::IdRef mergeBlock); 372 void writeLoopConditionEnd(spirv::IdRef conditionValue, 373 spirv::IdRef branchToBlock, 374 spirv::IdRef mergeBlock); 375 void writeLoopContinueEnd(spirv::IdRef headerBlock); 376 void writeLoopBodyEnd(spirv::IdRef continueBlock); 377 void writeSwitch(spirv::IdRef conditionValue, 378 spirv::IdRef defaultBlock, 379 const spirv::PairLiteralIntegerIdRefList &targetPairList, 380 spirv::IdRef mergeBlock); 381 void writeSwitchCaseBlockEnd(); 382 383 spirv::IdRef getBoolConstant(bool value); 384 spirv::IdRef getUintConstant(uint32_t value); 385 spirv::IdRef getIntConstant(int32_t value); 386 spirv::IdRef getFloatConstant(float value); 387 spirv::IdRef getUvecConstant(uint32_t value, int size); 388 spirv::IdRef getIvecConstant(int32_t value, int size); 389 spirv::IdRef getVecConstant(float value, int size); 390 spirv::IdRef getCompositeConstant(spirv::IdRef typeId, const spirv::IdRefList &values); 391 spirv::IdRef getNullConstant(spirv::IdRef typeId); 392 393 // Helpers to start and end a function. 394 void startNewFunction(spirv::IdRef functionId, const TFunction *func); 395 void assembleSpirvFunctionBlocks(); 396 397 // Helper to declare a variable. Function-local variables must be placed in the first block of 398 // the current function. 399 spirv::IdRef declareVariable(spirv::IdRef typeId, 400 spv::StorageClass storageClass, 401 const SpirvDecorations &decorations, 402 spirv::IdRef *initializerId, 403 const char *name); 404 // Helper to declare specialization constants. 405 spirv::IdRef declareSpecConst(TBasicType type, int id, const char *name); 406 407 // Helpers for conditionals. 408 void startConditional(size_t blockCount, bool isContinuable, bool isBreakable); 409 void nextConditionalBlock(); 410 void endConditional(); 411 bool isInLoop() const; 412 spirv::IdRef getBreakTargetId() const; 413 spirv::IdRef getContinueTargetId() const; 414 415 // TODO: remove name hashing once translation through glslang is removed. That is necessary to 416 // avoid name collision between ANGLE's internal symbols and user-defined ones when compiling 417 // the generated GLSL, but is irrelevant when generating SPIR-V directly. Currently, the SPIR-V 418 // transformer relies on the "mapped" names, which should also be changed when this hashing is 419 // removed. 420 ImmutableString hashName(const TSymbol *symbol); 421 ImmutableString hashTypeName(const TType &type); 422 ImmutableString hashFieldName(const TField *field); 423 ImmutableString hashFunctionName(const TFunction *func); 424 425 spirv::Blob getSpirv(); 426 427 private: 428 SpirvTypeData declareType(const SpirvType &type, const TSymbol *block); 429 430 uint32_t calculateBaseAlignmentAndSize(const SpirvType &type, uint32_t *sizeInStorageBlockOut); 431 uint32_t calculateSizeAndWriteOffsetDecorations(const SpirvType &type, 432 spirv::IdRef typeId, 433 uint32_t blockBaseAlignment); 434 void writeMemberDecorations(const SpirvType &type, spirv::IdRef typeId); 435 void writeInterpolationDecoration(TQualifier qualifier, spirv::IdRef id, uint32_t fieldIndex); 436 437 // Helpers for type declaration. 438 void getImageTypeParameters(TBasicType type, 439 spirv::IdRef *sampledTypeOut, 440 spv::Dim *dimOut, 441 spirv::LiteralInteger *depthOut, 442 spirv::LiteralInteger *arrayedOut, 443 spirv::LiteralInteger *multisampledOut, 444 spirv::LiteralInteger *sampledOut); 445 spv::ImageFormat getImageFormat(TLayoutImageInternalFormat imageInternalFormat); 446 447 spirv::IdRef getBasicConstantHelper(uint32_t value, 448 TBasicType type, 449 angle::HashMap<uint32_t, spirv::IdRef> *constants); 450 spirv::IdRef getNullVectorConstantHelper(TBasicType type, int size); 451 spirv::IdRef getVectorConstantHelper(spirv::IdRef valueId, TBasicType type, int size); 452 453 uint32_t nextUnusedBinding(); 454 uint32_t nextUnusedInputLocation(uint32_t consumedCount); 455 uint32_t nextUnusedOutputLocation(uint32_t consumedCount); 456 457 void writeExecutionModes(spirv::Blob *blob); 458 void writeExtensions(spirv::Blob *blob); 459 void writeSourceExtensions(spirv::Blob *blob); 460 461 ANGLE_MAYBE_UNUSED TCompiler *mCompiler; 462 ShCompileOptions mCompileOptions; 463 gl::ShaderType mShaderType; 464 465 // Capabilities the shader is using. Accumulated as the instructions are generated. The Shader 466 // capability is unconditionally generated, so it's not tracked. 467 std::set<spv::Capability> mCapabilities; 468 // Execution modes the shader is using. Most execution modes are automatically derived from 469 // shader metadata, but some are only discovered while traversing the tree. Only the latter 470 // execution modes are stored here. 471 angle::BitSet<32> mExecutionModes; 472 // Extensions used by the shader. 473 angle::PackedEnumBitSet<SPIRVExtensions> mExtensions; 474 475 // The list of interface variables and the id of main() populated as the instructions are 476 // generated. Used for the OpEntryPoint instruction. 477 spirv::IdRefList mEntryPointInterfaceList; 478 spirv::IdRef mEntryPointId; 479 480 // Id of imported instructions, if used. 481 spirv::IdRef mExtInstImportIdStd; 482 483 // Current ID bound, used to allocate new ids. 484 spirv::IdRef mNextAvailableId; 485 486 // A map from the AST type to the corresponding SPIR-V ID and associated data. Note that TType 487 // includes a lot of information that pertains to the variable that has the type, not the type 488 // itself. SpirvType instead contains only information that can identify the type itself. 489 angle::HashMap<SpirvType, SpirvTypeData, SpirvTypeHash> mTypeMap; 490 491 // Various sections of SPIR-V. Each section grows as SPIR-V is generated, and the final result 492 // is obtained by stitching the sections together. This puts the instructions in the order 493 // required by the spec. 494 spirv::Blob mSpirvDebug; 495 spirv::Blob mSpirvDecorations; 496 spirv::Blob mSpirvTypeAndConstantDecls; 497 spirv::Blob mSpirvTypePointerDecls; 498 spirv::Blob mSpirvFunctionTypeDecls; 499 spirv::Blob mSpirvVariableDecls; 500 spirv::Blob mSpirvFunctions; 501 // A list of blocks created for the current function. These are assembled by 502 // assembleSpirvFunctionBlocks() when the function is entirely visited. Local variables need to 503 // be inserted at the beginning of the first function block, so the entire SPIR-V of the 504 // function cannot be obtained until it's fully visited. 505 // 506 // The last block in this list is the one currently being written to. 507 std::vector<SpirvBlock> mSpirvCurrentFunctionBlocks; 508 509 // List of constants that are already defined (for reuse). 510 spirv::IdRef mBoolConstants[2]; 511 angle::HashMap<uint32_t, spirv::IdRef> mUintConstants; 512 angle::HashMap<uint32_t, spirv::IdRef> mIntConstants; 513 angle::HashMap<uint32_t, spirv::IdRef> mFloatConstants; 514 angle::HashMap<SpirvIdAndIdList, spirv::IdRef, SpirvIdAndIdListHash> mCompositeConstants; 515 // Keyed by typeId, returns the null constant corresponding to that type. 516 std::vector<spirv::IdRef> mNullConstants; 517 518 // List of type pointers that are already defined. 519 // TODO: if all users call getTypeData(), move to SpirvTypeData. http://anglebug.com/4889 520 angle::HashMap<SpirvIdAndStorageClass, spirv::IdRef, SpirvIdAndStorageClassHash> 521 mTypePointerIdMap; 522 523 // List of function types that are already defined. 524 angle::HashMap<SpirvIdAndIdList, spirv::IdRef, SpirvIdAndIdListHash> mFunctionTypeIdMap; 525 526 // Stack of conditionals. When an if, loop or switch is visited, a new conditional scope is 527 // added. When the conditional construct is entirely visited, it's popped. As the blocks of 528 // the conditional constructs are visited, ids are consumed from the top of the stack. When 529 // break or continue is visited, the stack is traversed backwards until a loop or switch is 530 // found. 531 std::vector<SpirvConditional> mConditionalStack; 532 533 // name hashing. 534 ShHashFunction64 mHashFunction; 535 NameMap &mNameMap; 536 537 // Every resource that requires set & binding layout qualifiers is assigned set 0 and an 538 // arbitrary binding. Every input/output that requires a location layout qualifier is assigned 539 // an arbitrary location as well. 540 // 541 // The link-time SPIR-V transformer modifies set, binding and location decorations in SPIR-V 542 // directly. 543 uint32_t mNextUnusedBinding; 544 uint32_t mNextUnusedInputLocation; 545 uint32_t mNextUnusedOutputLocation; 546 }; 547 } // namespace sh 548 549 #endif // COMPILER_TRANSLATOR_BUILDSPIRV_H_ 550