xref: /aosp_15_r20/external/angle/src/compiler/translator/spirv/BuildSPIRV.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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 #include "compiler/translator/spirv/BuildSPIRV.h"
10 
11 #include "common/spirv/spirv_instruction_builder_autogen.h"
12 #include "compiler/translator/ValidateVaryingLocations.h"
13 #include "compiler/translator/blocklayout.h"
14 #include "compiler/translator/util.h"
15 
16 namespace sh
17 {
operator ==(const SpirvType & a,const SpirvType & b)18 bool operator==(const SpirvType &a, const SpirvType &b)
19 {
20     if (a.block != b.block)
21     {
22         return false;
23     }
24 
25     if (a.arraySizes != b.arraySizes)
26     {
27         return false;
28     }
29 
30     // If structure or interface block, they should match by pointer (i.e. be the same block).  The
31     // AST transformations are expected to keep the AST consistent by using the same structure and
32     // interface block pointer between declarations and usages.  This is validated by
33     // ValidateASTOptions::validateVariableReferences.
34     if (a.block != nullptr)
35     {
36         return a.typeSpec.blockStorage == b.typeSpec.blockStorage &&
37                a.typeSpec.isInvariantBlock == b.typeSpec.isInvariantBlock &&
38                a.typeSpec.isRowMajorQualifiedBlock == b.typeSpec.isRowMajorQualifiedBlock &&
39                a.typeSpec.isPatchIOBlock == b.typeSpec.isPatchIOBlock &&
40                a.typeSpec.isOrHasBoolInInterfaceBlock == b.typeSpec.isOrHasBoolInInterfaceBlock;
41     }
42 
43     // Otherwise, match by the type contents.  The AST transformations sometimes recreate types that
44     // are already defined, so we can't rely on pointers being unique.
45     return a.type == b.type && a.primarySize == b.primarySize &&
46            a.secondarySize == b.secondarySize && a.imageInternalFormat == b.imageInternalFormat &&
47            a.isSamplerBaseImage == b.isSamplerBaseImage &&
48            a.typeSpec.blockStorage == b.typeSpec.blockStorage &&
49            a.typeSpec.isRowMajorQualifiedArray == b.typeSpec.isRowMajorQualifiedArray &&
50            a.typeSpec.isOrHasBoolInInterfaceBlock == b.typeSpec.isOrHasBoolInInterfaceBlock;
51 }
52 
53 namespace
54 {
IsBlockFieldRowMajorQualified(const TType & fieldType,bool isParentBlockRowMajorQualified)55 bool IsBlockFieldRowMajorQualified(const TType &fieldType, bool isParentBlockRowMajorQualified)
56 {
57     // If the field is specifically qualified as row-major, it will be row-major.  Otherwise unless
58     // specifically qualified as column-major, its matrix packing is inherited from the parent
59     // block.
60     const TLayoutMatrixPacking fieldMatrixPacking = fieldType.getLayoutQualifier().matrixPacking;
61     return fieldMatrixPacking == EmpRowMajor ||
62            (fieldMatrixPacking == EmpUnspecified && isParentBlockRowMajorQualified);
63 }
64 
IsNonSquareRowMajorArrayInBlock(const TType & type,const SpirvTypeSpec & parentTypeSpec)65 bool IsNonSquareRowMajorArrayInBlock(const TType &type, const SpirvTypeSpec &parentTypeSpec)
66 {
67     return parentTypeSpec.blockStorage != EbsUnspecified && type.isArray() && type.isMatrix() &&
68            type.getCols() != type.getRows() &&
69            IsBlockFieldRowMajorQualified(type, parentTypeSpec.isRowMajorQualifiedBlock);
70 }
71 
IsInvariant(const TType & type,TCompiler * compiler)72 bool IsInvariant(const TType &type, TCompiler *compiler)
73 {
74     const bool invariantAll = compiler->getPragma().stdgl.invariantAll;
75 
76     // The Invariant decoration is applied to output variables if specified or if globally enabled.
77     return type.isInvariant() || (IsShaderOut(type.getQualifier()) && invariantAll);
78 }
79 
GetBlockStorage(const TType & type)80 TLayoutBlockStorage GetBlockStorage(const TType &type)
81 {
82     // For interface blocks, the block storage is specified on the symbol itself.
83     if (type.getInterfaceBlock() != nullptr)
84     {
85         return type.getInterfaceBlock()->blockStorage();
86     }
87 
88     // I/O blocks must have been handled above.
89     ASSERT(!IsShaderIoBlock(type.getQualifier()));
90 
91     // Additionally, interface blocks are already handled, so it's not expected for the type to have
92     // a block storage specified.
93     ASSERT(type.getLayoutQualifier().blockStorage == EbsUnspecified);
94 
95     // Default to std140 for uniform and std430 for buffer blocks.
96     return type.getQualifier() == EvqBuffer ? EbsStd430 : EbsStd140;
97 }
98 
ToShaderVariable(const TFieldListCollection * block,GLenum type,const TSpan<const unsigned int> arraySizes,bool isRowMajor)99 ShaderVariable ToShaderVariable(const TFieldListCollection *block,
100                                 GLenum type,
101                                 const TSpan<const unsigned int> arraySizes,
102                                 bool isRowMajor)
103 {
104     ShaderVariable var;
105 
106     var.type             = type;
107     var.arraySizes       = {arraySizes.begin(), arraySizes.end()};
108     var.isRowMajorLayout = isRowMajor;
109 
110     if (block != nullptr)
111     {
112         for (const TField *field : block->fields())
113         {
114             const TType &fieldType = *field->type();
115 
116             const TLayoutMatrixPacking fieldMatrixPacking =
117                 fieldType.getLayoutQualifier().matrixPacking;
118             const bool isFieldRowMajor = fieldMatrixPacking == EmpRowMajor ||
119                                          (fieldMatrixPacking == EmpUnspecified && isRowMajor);
120             const GLenum glType =
121                 fieldType.getStruct() != nullptr ? GL_NONE : GLVariableType(fieldType);
122 
123             var.fields.push_back(ToShaderVariable(fieldType.getStruct(), glType,
124                                                   fieldType.getArraySizes(), isFieldRowMajor));
125         }
126     }
127 
128     return var;
129 }
130 
SpirvTypeToShaderVariable(const SpirvType & type)131 ShaderVariable SpirvTypeToShaderVariable(const SpirvType &type)
132 {
133     const bool isRowMajor =
134         type.typeSpec.isRowMajorQualifiedBlock || type.typeSpec.isRowMajorQualifiedArray;
135     const GLenum glType =
136         type.block != nullptr
137             ? EbtStruct
138             : GLVariableType(TType(type.type, type.primarySize, type.secondarySize));
139 
140     return ToShaderVariable(type.block, glType, type.arraySizes, isRowMajor);
141 }
142 
143 // The following function encodes a variable in a std140 or std430 block.  The variable could be:
144 //
145 // - An interface block: In this case, |decorationsBlob| is provided and SPIR-V decorations are
146 //   output to this blob.
147 // - A struct: In this case, the return value is of interest as the size of the struct in the
148 //   encoding.
149 //
150 // This function ignores arrayness in calculating the struct size.
151 //
Encode(const ShaderVariable & var,bool isStd140,spirv::IdRef blockTypeId,spirv::Blob * decorationsBlob)152 uint32_t Encode(const ShaderVariable &var,
153                 bool isStd140,
154                 spirv::IdRef blockTypeId,
155                 spirv::Blob *decorationsBlob)
156 {
157     Std140BlockEncoder std140;
158     Std430BlockEncoder std430;
159     BlockLayoutEncoder *encoder = isStd140 ? &std140 : &std430;
160 
161     ASSERT(var.isStruct());
162     encoder->enterAggregateType(var);
163 
164     uint32_t fieldIndex = 0;
165 
166     for (const ShaderVariable &fieldVar : var.fields)
167     {
168         BlockMemberInfo fieldInfo;
169 
170         // Encode the variable.
171         if (fieldVar.isStruct())
172         {
173             // For structs, recursively encode it.
174             const uint32_t structSize = Encode(fieldVar, isStd140, {}, nullptr);
175 
176             encoder->enterAggregateType(fieldVar);
177             fieldInfo = encoder->encodeArrayOfPreEncodedStructs(structSize, fieldVar.arraySizes);
178             encoder->exitAggregateType(fieldVar);
179         }
180         else
181         {
182             fieldInfo =
183                 encoder->encodeType(fieldVar.type, fieldVar.arraySizes, fieldVar.isRowMajorLayout);
184         }
185 
186         if (decorationsBlob)
187         {
188             ASSERT(blockTypeId.valid());
189 
190             // Write the Offset decoration.
191             spirv::WriteMemberDecorate(decorationsBlob, blockTypeId,
192                                        spirv::LiteralInteger(fieldIndex), spv::DecorationOffset,
193                                        {spirv::LiteralInteger(fieldInfo.offset)});
194 
195             // For matrix types, write the MatrixStride decoration as well.
196             if (IsMatrixGLType(fieldVar.type))
197             {
198                 ASSERT(fieldInfo.matrixStride > 0);
199 
200                 // MatrixStride
201                 spirv::WriteMemberDecorate(
202                     decorationsBlob, blockTypeId, spirv::LiteralInteger(fieldIndex),
203                     spv::DecorationMatrixStride, {spirv::LiteralInteger(fieldInfo.matrixStride)});
204             }
205         }
206 
207         ++fieldIndex;
208     }
209 
210     encoder->exitAggregateType(var);
211     return static_cast<uint32_t>(encoder->getCurrentOffset());
212 }
213 
GetArrayStrideInBlock(const ShaderVariable & var,bool isStd140)214 uint32_t GetArrayStrideInBlock(const ShaderVariable &var, bool isStd140)
215 {
216     Std140BlockEncoder std140;
217     Std430BlockEncoder std430;
218     BlockLayoutEncoder *encoder = isStd140 ? &std140 : &std430;
219 
220     ASSERT(var.isArray());
221 
222     // For structs, encode the struct to get the size, and calculate the stride based on that.
223     if (var.isStruct())
224     {
225         // Remove arrayness.
226         ShaderVariable element = var;
227         element.arraySizes.clear();
228 
229         const uint32_t structSize = Encode(element, isStd140, {}, nullptr);
230 
231         // Stride is struct size by inner array size
232         return structSize * var.getInnerArraySizeProduct();
233     }
234 
235     // Otherwise encode the basic type.
236     BlockMemberInfo memberInfo =
237         encoder->encodeType(var.type, var.arraySizes, var.isRowMajorLayout);
238 
239     // The encoder returns the array stride for the base element type (which is not an array!), so
240     // need to multiply by the inner array sizes to get the outermost array's stride.
241     return memberInfo.arrayStride * var.getInnerArraySizeProduct();
242 }
243 
GetGeometryInputExecutionMode(TLayoutPrimitiveType primitiveType)244 spv::ExecutionMode GetGeometryInputExecutionMode(TLayoutPrimitiveType primitiveType)
245 {
246     // Default input primitive type for geometry shaders is points
247     if (primitiveType == EptUndefined)
248     {
249         primitiveType = EptPoints;
250     }
251 
252     switch (primitiveType)
253     {
254         case EptPoints:
255             return spv::ExecutionModeInputPoints;
256         case EptLines:
257             return spv::ExecutionModeInputLines;
258         case EptLinesAdjacency:
259             return spv::ExecutionModeInputLinesAdjacency;
260         case EptTriangles:
261             return spv::ExecutionModeTriangles;
262         case EptTrianglesAdjacency:
263             return spv::ExecutionModeInputTrianglesAdjacency;
264         case EptLineStrip:
265         case EptTriangleStrip:
266         default:
267             UNREACHABLE();
268             return {};
269     }
270 }
271 
GetGeometryOutputExecutionMode(TLayoutPrimitiveType primitiveType)272 spv::ExecutionMode GetGeometryOutputExecutionMode(TLayoutPrimitiveType primitiveType)
273 {
274     // Default output primitive type for geometry shaders is points
275     if (primitiveType == EptUndefined)
276     {
277         primitiveType = EptPoints;
278     }
279 
280     switch (primitiveType)
281     {
282         case EptPoints:
283             return spv::ExecutionModeOutputPoints;
284         case EptLineStrip:
285             return spv::ExecutionModeOutputLineStrip;
286         case EptTriangleStrip:
287             return spv::ExecutionModeOutputTriangleStrip;
288         case EptLines:
289         case EptLinesAdjacency:
290         case EptTriangles:
291         case EptTrianglesAdjacency:
292         default:
293             UNREACHABLE();
294             return {};
295     }
296 }
297 
GetTessEvalInputExecutionMode(TLayoutTessEvaluationType inputType)298 spv::ExecutionMode GetTessEvalInputExecutionMode(TLayoutTessEvaluationType inputType)
299 {
300     // It's invalid for input type to not be specified, but that's a link-time error.  Default to
301     // anything.
302     if (inputType == EtetUndefined)
303     {
304         inputType = EtetTriangles;
305     }
306 
307     switch (inputType)
308     {
309         case EtetTriangles:
310             return spv::ExecutionModeTriangles;
311         case EtetQuads:
312             return spv::ExecutionModeQuads;
313         case EtetIsolines:
314             return spv::ExecutionModeIsolines;
315         default:
316             UNREACHABLE();
317             return {};
318     }
319 }
320 
GetTessEvalSpacingExecutionMode(TLayoutTessEvaluationType spacing)321 spv::ExecutionMode GetTessEvalSpacingExecutionMode(TLayoutTessEvaluationType spacing)
322 {
323     switch (spacing)
324     {
325         case EtetEqualSpacing:
326         case EtetUndefined:
327             return spv::ExecutionModeSpacingEqual;
328         case EtetFractionalEvenSpacing:
329             return spv::ExecutionModeSpacingFractionalEven;
330         case EtetFractionalOddSpacing:
331             return spv::ExecutionModeSpacingFractionalOdd;
332         default:
333             UNREACHABLE();
334             return {};
335     }
336 }
337 
GetTessEvalOrderingExecutionMode(TLayoutTessEvaluationType ordering)338 spv::ExecutionMode GetTessEvalOrderingExecutionMode(TLayoutTessEvaluationType ordering)
339 {
340     switch (ordering)
341     {
342         case EtetCw:
343             return spv::ExecutionModeVertexOrderCw;
344         case EtetCcw:
345         case EtetUndefined:
346             return spv::ExecutionModeVertexOrderCcw;
347         default:
348             UNREACHABLE();
349             return {};
350     }
351 }
352 
WriteInterpolationDecoration(spv::Decoration decoration,spirv::IdRef id,uint32_t fieldIndex,spirv::Blob * decorationsBlob)353 void WriteInterpolationDecoration(spv::Decoration decoration,
354                                   spirv::IdRef id,
355                                   uint32_t fieldIndex,
356                                   spirv::Blob *decorationsBlob)
357 {
358     if (fieldIndex != std::numeric_limits<uint32_t>::max())
359     {
360         spirv::WriteMemberDecorate(decorationsBlob, id, spirv::LiteralInteger(fieldIndex),
361                                    decoration, {});
362     }
363     else
364     {
365         spirv::WriteDecorate(decorationsBlob, id, decoration, {});
366     }
367 }
368 
ApplyDecorations(spirv::IdRef id,const SpirvDecorations & decorations,spirv::Blob * decorationsBlob)369 void ApplyDecorations(spirv::IdRef id,
370                       const SpirvDecorations &decorations,
371                       spirv::Blob *decorationsBlob)
372 {
373     for (const spv::Decoration decoration : decorations)
374     {
375         spirv::WriteDecorate(decorationsBlob, id, decoration, {});
376     }
377 }
378 }  // anonymous namespace
379 
inferDefaults(const TType & type,TCompiler * compiler)380 void SpirvTypeSpec::inferDefaults(const TType &type, TCompiler *compiler)
381 {
382     // Infer some defaults based on type.  If necessary, this overrides some fields (if not already
383     // specified).  Otherwise, it leaves the pre-initialized values as-is.
384 
385     // Handle interface blocks and fields of nameless interface blocks.
386     if (type.getInterfaceBlock() != nullptr)
387     {
388         // Calculate the block storage from the interface block automatically.  The fields inherit
389         // from this.  Only blocks and arrays in blocks produce different SPIR-V types based on
390         // block storage.
391         const bool isBlock = type.isInterfaceBlock() || type.getStruct();
392         if (blockStorage == EbsUnspecified && (isBlock || type.isArray()))
393         {
394             blockStorage = GetBlockStorage(type);
395         }
396 
397         // row_major can only be specified on an interface block or one of its fields.  The fields
398         // will inherit this from the interface block itself.
399         if (!isRowMajorQualifiedBlock && isBlock)
400         {
401             isRowMajorQualifiedBlock = type.getLayoutQualifier().matrixPacking == EmpRowMajor;
402         }
403 
404         // Arrays of matrices in a uniform/buffer block may generate a different stride based on
405         // whether they are row- or column-major.  Square matrices are trivially known not to
406         // generate a different type.
407         if (!isRowMajorQualifiedArray)
408         {
409             isRowMajorQualifiedArray = IsNonSquareRowMajorArrayInBlock(type, *this);
410         }
411 
412         // Structs with bools, bool arrays, bool vectors and bools themselves are replaced with uint
413         // when used in an interface block.
414         if (!isOrHasBoolInInterfaceBlock)
415         {
416             isOrHasBoolInInterfaceBlock = type.isInterfaceBlockContainingType(EbtBool) ||
417                                           type.isStructureContainingType(EbtBool) ||
418                                           type.getBasicType() == EbtBool;
419         }
420 
421         if (!isPatchIOBlock && type.isInterfaceBlock())
422         {
423             isPatchIOBlock =
424                 type.getQualifier() == EvqPatchIn || type.getQualifier() == EvqPatchOut;
425         }
426     }
427 
428     // |invariant| is significant for structs as the fields of the type are decorated with Invariant
429     // in SPIR-V.  This is possible for outputs of struct type, or struct-typed fields of an
430     // interface block.
431     if (type.getStruct() != nullptr)
432     {
433         isInvariantBlock = isInvariantBlock || IsInvariant(type, compiler);
434     }
435 }
436 
onArrayElementSelection(bool isElementTypeBlock,bool isElementTypeArray)437 void SpirvTypeSpec::onArrayElementSelection(bool isElementTypeBlock, bool isElementTypeArray)
438 {
439     // No difference in type for non-block non-array types in std140 and std430 block storage.
440     if (!isElementTypeBlock && !isElementTypeArray)
441     {
442         blockStorage = EbsUnspecified;
443     }
444 
445     // No difference in type for non-array types in std140 and std430 block storage.
446     if (!isElementTypeArray)
447     {
448         isRowMajorQualifiedArray = false;
449     }
450 }
451 
onBlockFieldSelection(const TType & fieldType)452 void SpirvTypeSpec::onBlockFieldSelection(const TType &fieldType)
453 {
454     // Patch is never recursively applied.
455     isPatchIOBlock = false;
456 
457     if (fieldType.getStruct() == nullptr)
458     {
459         // If the field is not a block, no difference if the parent block was invariant or
460         // row-major.
461         isRowMajorQualifiedArray = IsNonSquareRowMajorArrayInBlock(fieldType, *this);
462         isInvariantBlock         = false;
463         isRowMajorQualifiedBlock = false;
464 
465         // If the field is not an array, no difference in storage block.
466         if (!fieldType.isArray())
467         {
468             blockStorage = EbsUnspecified;
469         }
470 
471         if (fieldType.getBasicType() != EbtBool)
472         {
473             isOrHasBoolInInterfaceBlock = false;
474         }
475     }
476     else
477     {
478         // Apply row-major only to structs that contain matrices.
479         isRowMajorQualifiedBlock =
480             IsBlockFieldRowMajorQualified(fieldType, isRowMajorQualifiedBlock) &&
481             fieldType.isStructureContainingMatrices();
482 
483         // Structs without bools aren't affected by |isOrHasBoolInInterfaceBlock|.
484         if (isOrHasBoolInInterfaceBlock)
485         {
486             isOrHasBoolInInterfaceBlock = fieldType.isStructureContainingType(EbtBool);
487         }
488     }
489 }
490 
onMatrixColumnSelection()491 void SpirvTypeSpec::onMatrixColumnSelection()
492 {
493     // The matrix types are never differentiated, so neither would be their columns.
494     ASSERT(!isInvariantBlock && !isRowMajorQualifiedBlock && !isRowMajorQualifiedArray &&
495            !isOrHasBoolInInterfaceBlock && blockStorage == EbsUnspecified);
496 }
497 
onVectorComponentSelection()498 void SpirvTypeSpec::onVectorComponentSelection()
499 {
500     // The vector types are never differentiated, so neither would be their components.  The only
501     // exception is bools in interface blocks, in which case the component and the vector are
502     // similarly differentiated.
503     ASSERT(!isInvariantBlock && !isRowMajorQualifiedBlock && !isRowMajorQualifiedArray &&
504            blockStorage == EbsUnspecified);
505 }
506 
SPIRVBuilder(TCompiler * compiler,const ShCompileOptions & compileOptions,const angle::HashMap<int,uint32_t> & uniqueToSpirvIdMap,uint32_t firstUnusedSpirvId)507 SPIRVBuilder::SPIRVBuilder(TCompiler *compiler,
508                            const ShCompileOptions &compileOptions,
509                            const angle::HashMap<int, uint32_t> &uniqueToSpirvIdMap,
510                            uint32_t firstUnusedSpirvId)
511     : mCompiler(compiler),
512       mCompileOptions(compileOptions),
513       mShaderType(gl::FromGLenum<gl::ShaderType>(compiler->getShaderType())),
514       mUniqueToSpirvIdMap(uniqueToSpirvIdMap),
515       mNextAvailableId(firstUnusedSpirvId),
516       mNextUnusedBinding(0),
517       mNextUnusedInputLocation(0),
518       mNextUnusedOutputLocation(0),
519       mOverviewFlags(0)
520 {
521     // The Shader capability is always defined.
522     addCapability(spv::CapabilityShader);
523 
524     // Add Geometry or Tessellation capabilities based on shader type.
525     if (mCompiler->getShaderType() == GL_GEOMETRY_SHADER)
526     {
527         addCapability(spv::CapabilityGeometry);
528     }
529     else if (mCompiler->getShaderType() == GL_TESS_CONTROL_SHADER_EXT ||
530              mCompiler->getShaderType() == GL_TESS_EVALUATION_SHADER_EXT)
531     {
532         addCapability(spv::CapabilityTessellation);
533     }
534 
535     mExtInstImportIdStd = getNewId({});
536 
537     predefineCommonTypes();
538 }
539 
getNewId(const SpirvDecorations & decorations)540 spirv::IdRef SPIRVBuilder::getNewId(const SpirvDecorations &decorations)
541 {
542     spirv::IdRef newId = mNextAvailableId;
543     mNextAvailableId   = spirv::IdRef(mNextAvailableId + 1);
544 
545     ApplyDecorations(newId, decorations, &mSpirvDecorations);
546 
547     return newId;
548 }
549 
getReservedOrNewId(TSymbolUniqueId uniqueId,const SpirvDecorations & decorations)550 spirv::IdRef SPIRVBuilder::getReservedOrNewId(TSymbolUniqueId uniqueId,
551                                               const SpirvDecorations &decorations)
552 {
553     auto iter = mUniqueToSpirvIdMap.find(uniqueId.get());
554     if (iter == mUniqueToSpirvIdMap.end())
555     {
556         return getNewId(decorations);
557     }
558 
559     const spirv::IdRef reservedId = spirv::IdRef(iter->second);
560     ApplyDecorations(reservedId, decorations, &mSpirvDecorations);
561     return reservedId;
562 }
563 
getSpirvType(const TType & type,const SpirvTypeSpec & typeSpec) const564 SpirvType SPIRVBuilder::getSpirvType(const TType &type, const SpirvTypeSpec &typeSpec) const
565 {
566     SpirvType spirvType;
567     spirvType.type                = type.getBasicType();
568     spirvType.primarySize         = type.getNominalSize();
569     spirvType.secondarySize       = type.getSecondarySize();
570     spirvType.arraySizes          = type.getArraySizes();
571     spirvType.imageInternalFormat = type.getLayoutQualifier().imageInternalFormat;
572 
573     switch (spirvType.type)
574     {
575         // External textures are treated as 2D textures in the vulkan back-end.
576         case EbtSamplerExternalOES:
577         case EbtSamplerExternal2DY2YEXT:
578         // WEBGL video textures too.
579         case EbtSamplerVideoWEBGL:
580             spirvType.type = EbtSampler2D;
581             break;
582         // yuvCscStandardEXT is just a uint under the hood.
583         case EbtYuvCscStandardEXT:
584             spirvType.type = EbtUInt;
585             break;
586         default:
587             break;
588     }
589 
590     if (type.getStruct() != nullptr)
591     {
592         spirvType.block = type.getStruct();
593     }
594     else if (type.isInterfaceBlock())
595     {
596         spirvType.block = type.getInterfaceBlock();
597     }
598 
599     // Automatically inherit or infer the type-specializing properties.
600     spirvType.typeSpec = typeSpec;
601     spirvType.typeSpec.inferDefaults(type, mCompiler);
602 
603     return spirvType;
604 }
605 
getTypeData(const TType & type,const SpirvTypeSpec & typeSpec)606 const SpirvTypeData &SPIRVBuilder::getTypeData(const TType &type, const SpirvTypeSpec &typeSpec)
607 {
608     SpirvType spirvType = getSpirvType(type, typeSpec);
609 
610     const TSymbol *block = nullptr;
611     if (type.getStruct() != nullptr)
612     {
613         block = type.getStruct();
614     }
615     else if (type.isInterfaceBlock())
616     {
617         block = type.getInterfaceBlock();
618     }
619 
620     return getSpirvTypeData(spirvType, block);
621 }
622 
getTypeDataOverrideTypeSpec(const TType & type,const SpirvTypeSpec & typeSpec)623 const SpirvTypeData &SPIRVBuilder::getTypeDataOverrideTypeSpec(const TType &type,
624                                                                const SpirvTypeSpec &typeSpec)
625 {
626     // This is a variant of getTypeData() where type spec is not automatically derived.  It's useful
627     // in cast operations that specifically need to override the spec.
628     SpirvType spirvType = getSpirvType(type, typeSpec);
629     spirvType.typeSpec  = typeSpec;
630 
631     return getSpirvTypeData(spirvType, nullptr);
632 }
633 
getSpirvTypeData(const SpirvType & type,const TSymbol * block)634 const SpirvTypeData &SPIRVBuilder::getSpirvTypeData(const SpirvType &type, const TSymbol *block)
635 {
636     // Structs with bools generate a different type when used in an interface block (where the bool
637     // is replaced with a uint).  The bool, bool vector and bool arrays too generate a different
638     // type when nested in an interface block, but that type is the same as the equivalent uint
639     // type.  To avoid defining duplicate uint types, we switch the basic type here to uint.  From
640     // the outside, therefore bool in an interface block and uint look like different types, but
641     // under the hood will be the same uint.
642     if (type.block == nullptr && type.typeSpec.isOrHasBoolInInterfaceBlock)
643     {
644         ASSERT(type.type == EbtBool);
645 
646         SpirvType uintType                            = type;
647         uintType.type                                 = EbtUInt;
648         uintType.typeSpec.isOrHasBoolInInterfaceBlock = false;
649         return getSpirvTypeData(uintType, block);
650     }
651 
652     auto iter = mTypeMap.find(type);
653     if (iter == mTypeMap.end())
654     {
655         SpirvTypeData newTypeData = declareType(type, block);
656 
657         iter = mTypeMap.insert({type, newTypeData}).first;
658     }
659 
660     return iter->second;
661 }
662 
getBasicTypeId(TBasicType basicType,size_t size)663 spirv::IdRef SPIRVBuilder::getBasicTypeId(TBasicType basicType, size_t size)
664 {
665     SpirvType type;
666     type.type        = basicType;
667     type.primarySize = static_cast<uint8_t>(size);
668     return getSpirvTypeData(type, nullptr).id;
669 }
670 
getTypePointerId(spirv::IdRef typeId,spv::StorageClass storageClass)671 spirv::IdRef SPIRVBuilder::getTypePointerId(spirv::IdRef typeId, spv::StorageClass storageClass)
672 {
673     SpirvIdAndStorageClass key{typeId, storageClass};
674 
675     auto iter = mTypePointerIdMap.find(key);
676     if (iter == mTypePointerIdMap.end())
677     {
678         // Note that some type pointers have predefined ids.
679         const spirv::IdRef typePointerId =
680             typeId == vk::spirv::kIdOutputPerVertexBlock
681                 ? spirv::IdRef(vk::spirv::kIdOutputPerVertexTypePointer)
682                 : getNewId({});
683 
684         spirv::WriteTypePointer(&mSpirvTypePointerDecls, typePointerId, storageClass, typeId);
685 
686         iter = mTypePointerIdMap.insert({key, typePointerId}).first;
687     }
688 
689     return iter->second;
690 }
691 
getFunctionTypeId(spirv::IdRef returnTypeId,const spirv::IdRefList & paramTypeIds)692 spirv::IdRef SPIRVBuilder::getFunctionTypeId(spirv::IdRef returnTypeId,
693                                              const spirv::IdRefList &paramTypeIds)
694 {
695     SpirvIdAndIdList key{returnTypeId, paramTypeIds};
696 
697     auto iter = mFunctionTypeIdMap.find(key);
698     if (iter == mFunctionTypeIdMap.end())
699     {
700         const spirv::IdRef functionTypeId = getNewId({});
701 
702         spirv::WriteTypeFunction(&mSpirvFunctionTypeDecls, functionTypeId, returnTypeId,
703                                  paramTypeIds);
704 
705         iter = mFunctionTypeIdMap.insert({key, functionTypeId}).first;
706     }
707 
708     return iter->second;
709 }
710 
getDecorations(const TType & type)711 SpirvDecorations SPIRVBuilder::getDecorations(const TType &type)
712 {
713     const bool enablePrecision = !mCompileOptions.ignorePrecisionQualifiers;
714     const TPrecision precision = type.getPrecision();
715 
716     SpirvDecorations decorations;
717 
718     // Handle precision.
719     if (enablePrecision && (precision == EbpMedium || precision == EbpLow))
720     {
721         decorations.push_back(spv::DecorationRelaxedPrecision);
722     }
723 
724     return decorations;
725 }
726 
getArithmeticDecorations(const TType & type,bool isPrecise,TOperator op)727 SpirvDecorations SPIRVBuilder::getArithmeticDecorations(const TType &type,
728                                                         bool isPrecise,
729                                                         TOperator op)
730 {
731     SpirvDecorations decorations = getDecorations(type);
732 
733     // In GLSL, findMsb operates on a highp operand, while returning a lowp result.  In SPIR-V,
734     // RelaxedPrecision cannot be applied on the Find*Msb instructions as that affects the operand
735     // as well:
736     //
737     // > The RelaxedPrecision Decoration can be applied to:
738     // > ...
739     // > The Result <id> of an instruction that operates on numerical types, meaning the instruction
740     // > is to operate at relaxed precision. The instruction's operands may also be truncated to the
741     // > relaxed precision.
742     // > ...
743     //
744     // findLSB() and bitCount() are in a similar situation.  Here, we remove RelaxedPrecision from
745     // such problematic instructions.
746     switch (op)
747     {
748         case EOpFindMSB:
749         case EOpFindLSB:
750         case EOpBitCount:
751             // Currently getDecorations() only adds RelaxedPrecision, so removing the
752             // RelaxedPrecision decoration is simply done by clearing the vector.
753             ASSERT(decorations.empty() ||
754                    (decorations.size() == 1 && decorations[0] == spv::DecorationRelaxedPrecision));
755             decorations.clear();
756             break;
757         default:
758             break;
759     }
760 
761     // Handle |precise|.
762     if (isPrecise)
763     {
764         decorations.push_back(spv::DecorationNoContraction);
765     }
766 
767     return decorations;
768 }
769 
getExtInstImportIdStd()770 spirv::IdRef SPIRVBuilder::getExtInstImportIdStd()
771 {
772     ASSERT(mExtInstImportIdStd.valid());
773     return mExtInstImportIdStd;
774 }
775 
predefineCommonTypes()776 void SPIRVBuilder::predefineCommonTypes()
777 {
778     SpirvType type;
779     spirv::IdRef id;
780 
781     using namespace vk::spirv;
782 
783     // Predefine types that are either practically ubiquitous, or end up generally being useful to
784     // the SPIR-V transformer.
785 
786     // void: used by OpExtInst non-semantic instructions. This type is always present due to void
787     // main().
788     type.type = EbtVoid;
789     id        = spirv::IdRef(kIdVoid);
790     mTypeMap.insert({type, {id}});
791     spirv::WriteTypeVoid(&mSpirvTypeAndConstantDecls, id);
792 
793     // float, vec and mat types
794     type.type = EbtFloat;
795     id        = spirv::IdRef(kIdFloat);
796     mTypeMap.insert({type, {id}});
797     spirv::WriteTypeFloat(&mSpirvTypeAndConstantDecls, id, spirv::LiteralInteger(32), nullptr);
798 
799     // vecN ids equal vec2 id + (vec size - 2)
800     static_assert(kIdVec3 == kIdVec2 + 1);
801     static_assert(kIdVec4 == kIdVec2 + 2);
802     // mat type ids equal mat2 id + (primary - 2)
803     // Note that only square matrices are needed.
804     static_assert(kIdMat3 == kIdMat2 + 1);
805     static_assert(kIdMat4 == kIdMat2 + 2);
806     for (uint8_t vecSize = 2; vecSize <= 4; ++vecSize)
807     {
808         // The base vec type
809         type.primarySize         = vecSize;
810         type.secondarySize       = 1;
811         const spirv::IdRef vecId = spirv::IdRef(kIdVec2 + (vecSize - 2));
812         mTypeMap.insert({type, {vecId}});
813         spirv::WriteTypeVector(&mSpirvTypeAndConstantDecls, vecId, spirv::IdRef(kIdFloat),
814                                spirv::LiteralInteger(vecSize));
815 
816         // The matrix types using this vec type
817         type.secondarySize       = vecSize;
818         const spirv::IdRef matId = spirv::IdRef(kIdMat2 + (vecSize - 2));
819         mTypeMap.insert({type, {matId}});
820         spirv::WriteTypeMatrix(&mSpirvTypeAndConstantDecls, matId, vecId,
821                                spirv::LiteralInteger(vecSize));
822     }
823 
824     type.primarySize   = 1;
825     type.secondarySize = 1;
826 
827     // Integer types
828     type.type = EbtUInt;
829     id        = spirv::IdRef(kIdUint);
830     mTypeMap.insert({type, {id}});
831     spirv::WriteTypeInt(&mSpirvTypeAndConstantDecls, id, spirv::LiteralInteger(32),
832                         spirv::LiteralInteger(0));
833 
834     type.type = EbtInt;
835     id        = spirv::IdRef(kIdInt);
836     mTypeMap.insert({type, {id}});
837     spirv::WriteTypeInt(&mSpirvTypeAndConstantDecls, id, spirv::LiteralInteger(32),
838                         spirv::LiteralInteger(1));
839 
840     type.primarySize = 4;
841     id               = spirv::IdRef(kIdIVec4);
842     mTypeMap.insert({type, {id}});
843     spirv::WriteTypeVector(&mSpirvTypeAndConstantDecls, id, spirv::IdRef(kIdInt),
844                            spirv::LiteralInteger(type.primarySize));
845 
846     // Common constants
847     static_assert(kIdIntOne == kIdIntZero + 1);
848     static_assert(kIdIntTwo == kIdIntZero + 2);
849     static_assert(kIdIntThree == kIdIntZero + 3);
850     for (uint32_t value = 0; value < 4; ++value)
851     {
852         id = spirv::IdRef(kIdIntZero + value);
853         spirv::WriteConstant(&mSpirvTypeAndConstantDecls, spirv::IdRef(kIdInt), id,
854                              spirv::LiteralContextDependentNumber(value));
855         mIntConstants.insert({value, id});
856     }
857 
858     // A few type pointers that are helpful for the SPIR-V transformer
859     if (mShaderType != gl::ShaderType::Compute)
860     {
861         struct
862         {
863             ReservedIds typeId;
864             ReservedIds typePointerId;
865             spv::StorageClass storageClass;
866         } infos[] = {
867             {
868                 kIdInt,
869                 kIdIntInputTypePointer,
870                 spv::StorageClassInput,
871             },
872             {
873                 kIdVec4,
874                 kIdVec4OutputTypePointer,
875                 spv::StorageClassOutput,
876             },
877             {
878                 kIdIVec4,
879                 kIdIVec4FunctionTypePointer,
880                 spv::StorageClassFunction,
881             },
882         };
883 
884         for (size_t index = 0; index < ArraySize(infos); ++index)
885         {
886             const auto &info = infos[index];
887 
888             const spirv::IdRef typeId        = spirv::IdRef(info.typeId);
889             const spirv::IdRef typePointerId = spirv::IdRef(info.typePointerId);
890             SpirvIdAndStorageClass key{typeId, info.storageClass};
891 
892             spirv::WriteTypePointer(&mSpirvTypePointerDecls, typePointerId, info.storageClass,
893                                     typeId);
894             mTypePointerIdMap.insert({key, typePointerId});
895         }
896     }
897 }
898 
writeDebugName(spirv::IdRef id,const char * name)899 void SPIRVBuilder::writeDebugName(spirv::IdRef id, const char *name)
900 {
901     if (mCompileOptions.outputDebugInfo && name[0] != '\0')
902     {
903         spirv::WriteName(&mSpirvDebug, id, name);
904     }
905 }
906 
writeBlockDebugNames(const TFieldListCollection * block,spirv::IdRef typeId,const char * name)907 void SPIRVBuilder::writeBlockDebugNames(const TFieldListCollection *block,
908                                         spirv::IdRef typeId,
909                                         const char *name)
910 {
911     if (!mCompileOptions.outputDebugInfo)
912     {
913         return;
914     }
915 
916     if (name[0] != '\0')
917     {
918         spirv::WriteName(&mSpirvDebug, typeId, name);
919     }
920 
921     uint32_t fieldIndex = 0;
922     for (const TField *field : block->fields())
923     {
924         spirv::WriteMemberName(&mSpirvDebug, typeId, spirv::LiteralInteger(fieldIndex++),
925                                getFieldName(field).data());
926     }
927 }
928 
declareType(const SpirvType & type,const TSymbol * block)929 SpirvTypeData SPIRVBuilder::declareType(const SpirvType &type, const TSymbol *block)
930 {
931     // Recursively declare the type.  Type id is allocated afterwards purely for better id order in
932     // output.
933     spirv::IdRef typeId;
934 
935     if (!type.arraySizes.empty())
936     {
937         // Declaring an array.  First, declare the type without the outermost array size, then
938         // declare a new array type based on that.
939 
940         SpirvType subType  = type;
941         subType.arraySizes = type.arraySizes.first(type.arraySizes.size() - 1);
942         subType.typeSpec.onArrayElementSelection(subType.block != nullptr,
943                                                  !subType.arraySizes.empty());
944 
945         const spirv::IdRef subTypeId = getSpirvTypeData(subType, block).id;
946 
947         const unsigned int length = type.arraySizes.back();
948 
949         if (length == 0)
950         {
951             // Storage buffers may include a dynamically-sized array, which is identified by it
952             // having a length of 0.
953             typeId = getNewId({});
954             spirv::WriteTypeRuntimeArray(&mSpirvTypeAndConstantDecls, typeId, subTypeId);
955         }
956         else
957         {
958             const spirv::IdRef lengthId = getUintConstant(length);
959             // Note that some type arrays use reserved ids.
960             switch (subTypeId)
961             {
962                 case vk::spirv::kIdInputPerVertexBlock:
963                     typeId = spirv::IdRef(vk::spirv::kIdInputPerVertexBlockArray);
964                     break;
965                 case vk::spirv::kIdOutputPerVertexBlock:
966                     typeId = spirv::IdRef(vk::spirv::kIdOutputPerVertexBlockArray);
967                     break;
968                 default:
969                     typeId = getNewId({});
970                     break;
971             }
972             spirv::WriteTypeArray(&mSpirvTypeAndConstantDecls, typeId, subTypeId, lengthId);
973         }
974     }
975     else if (type.block != nullptr)
976     {
977         // Declaring a block.  First, declare all the fields, then declare a struct based on the
978         // list of field types.
979 
980         spirv::IdRefList fieldTypeIds;
981         for (const TField *field : type.block->fields())
982         {
983             const TType &fieldType = *field->type();
984 
985             SpirvTypeSpec fieldTypeSpec = type.typeSpec;
986             fieldTypeSpec.onBlockFieldSelection(fieldType);
987 
988             const SpirvType fieldSpirvType = getSpirvType(fieldType, fieldTypeSpec);
989             const spirv::IdRef fieldTypeId =
990                 getSpirvTypeData(fieldSpirvType, fieldType.getStruct()).id;
991             fieldTypeIds.push_back(fieldTypeId);
992         }
993 
994         // Note that some blocks have predefined ids.
995         typeId = block != nullptr ? getReservedOrNewId(block->uniqueId(), {}) : getNewId({});
996         spirv::WriteTypeStruct(&mSpirvTypeAndConstantDecls, typeId, fieldTypeIds);
997     }
998     else if (IsSampler(type.type) && !type.isSamplerBaseImage)
999     {
1000         // Declaring a sampler.  First, declare the non-sampled image and then a combined
1001         // image-sampler.
1002 
1003         SpirvType imageType          = type;
1004         imageType.isSamplerBaseImage = true;
1005 
1006         const spirv::IdRef nonSampledId = getSpirvTypeData(imageType, nullptr).id;
1007 
1008         typeId = getNewId({});
1009         spirv::WriteTypeSampledImage(&mSpirvTypeAndConstantDecls, typeId, nonSampledId);
1010     }
1011     else if (IsImage(type.type) || IsSubpassInputType(type.type) || type.isSamplerBaseImage)
1012     {
1013         // Declaring an image.
1014 
1015         spirv::IdRef sampledType;
1016         spv::Dim dim;
1017         spirv::LiteralInteger depth;
1018         spirv::LiteralInteger arrayed;
1019         spirv::LiteralInteger multisampled;
1020         spirv::LiteralInteger sampled;
1021 
1022         getImageTypeParameters(type.type, &sampledType, &dim, &depth, &arrayed, &multisampled,
1023                                &sampled);
1024         const spv::ImageFormat imageFormat = getImageFormat(type.imageInternalFormat);
1025 
1026         typeId = getNewId({});
1027         spirv::WriteTypeImage(&mSpirvTypeAndConstantDecls, typeId, sampledType, dim, depth, arrayed,
1028                               multisampled, sampled, imageFormat, nullptr);
1029     }
1030     else if (type.secondarySize > 1)
1031     {
1032         // Declaring a matrix.  Declare the column type first, then create a matrix out of it.
1033 
1034         SpirvType columnType     = type;
1035         columnType.primarySize   = columnType.secondarySize;
1036         columnType.secondarySize = 1;
1037         columnType.typeSpec.onMatrixColumnSelection();
1038 
1039         const spirv::IdRef columnTypeId = getSpirvTypeData(columnType, nullptr).id;
1040 
1041         typeId = getNewId({});
1042         spirv::WriteTypeMatrix(&mSpirvTypeAndConstantDecls, typeId, columnTypeId,
1043                                spirv::LiteralInteger(type.primarySize));
1044     }
1045     else if (type.primarySize > 1)
1046     {
1047         // Declaring a vector.  Declare the component type first, then create a vector out of it.
1048 
1049         SpirvType componentType   = type;
1050         componentType.primarySize = 1;
1051         componentType.typeSpec.onVectorComponentSelection();
1052 
1053         const spirv::IdRef componentTypeId = getSpirvTypeData(componentType, nullptr).id;
1054 
1055         typeId = getNewId({});
1056         spirv::WriteTypeVector(&mSpirvTypeAndConstantDecls, typeId, componentTypeId,
1057                                spirv::LiteralInteger(type.primarySize));
1058     }
1059     else
1060     {
1061         typeId = getNewId({});
1062 
1063         // Declaring a basic type.  There's a different instruction for each.
1064         switch (type.type)
1065         {
1066             case EbtBool:
1067                 spirv::WriteTypeBool(&mSpirvTypeAndConstantDecls, typeId);
1068                 break;
1069             default:
1070                 UNREACHABLE();
1071         }
1072     }
1073 
1074     // If this was a block declaration, add debug information for its type and field names.
1075     if (mCompileOptions.outputDebugInfo && block != nullptr && type.arraySizes.empty())
1076     {
1077         writeBlockDebugNames(type.block, typeId, getName(block).data());
1078     }
1079 
1080     // Write decorations for interface block fields.
1081     if (type.typeSpec.blockStorage != EbsUnspecified)
1082     {
1083         // Cannot have opaque uniforms inside interface blocks.
1084         ASSERT(!IsOpaqueType(type.type));
1085 
1086         const bool isInterfaceBlock = block != nullptr && block->isInterfaceBlock();
1087         const bool isStd140         = type.typeSpec.blockStorage != EbsStd430;
1088 
1089         if (!type.arraySizes.empty() && !isInterfaceBlock)
1090         {
1091             // Write the ArrayStride decoration for arrays inside interface blocks.  An array of
1092             // interface blocks doesn't need a stride.
1093             const ShaderVariable var = SpirvTypeToShaderVariable(type);
1094             const uint32_t stride    = GetArrayStrideInBlock(var, isStd140);
1095 
1096             spirv::WriteDecorate(&mSpirvDecorations, typeId, spv::DecorationArrayStride,
1097                                  {spirv::LiteralInteger(stride)});
1098         }
1099         else if (type.arraySizes.empty() && type.block != nullptr)
1100         {
1101             // Write the Offset decoration for interface blocks and structs in them.
1102             const ShaderVariable var = SpirvTypeToShaderVariable(type);
1103             Encode(var, isStd140, typeId, &mSpirvDecorations);
1104         }
1105     }
1106 
1107     // Write other member decorations.
1108     if (block != nullptr && type.arraySizes.empty())
1109     {
1110         writeMemberDecorations(type, typeId);
1111     }
1112 
1113     return {typeId};
1114 }
1115 
getImageTypeParameters(TBasicType type,spirv::IdRef * sampledTypeOut,spv::Dim * dimOut,spirv::LiteralInteger * depthOut,spirv::LiteralInteger * arrayedOut,spirv::LiteralInteger * multisampledOut,spirv::LiteralInteger * sampledOut)1116 void SPIRVBuilder::getImageTypeParameters(TBasicType type,
1117                                           spirv::IdRef *sampledTypeOut,
1118                                           spv::Dim *dimOut,
1119                                           spirv::LiteralInteger *depthOut,
1120                                           spirv::LiteralInteger *arrayedOut,
1121                                           spirv::LiteralInteger *multisampledOut,
1122                                           spirv::LiteralInteger *sampledOut)
1123 {
1124     TBasicType sampledType = EbtFloat;
1125     *dimOut                = IsSubpassInputType(type) ? spv::DimSubpassData : spv::Dim2D;
1126     bool isDepth           = false;
1127     bool isArrayed         = false;
1128     bool isMultisampled    = false;
1129 
1130     // Decompose the basic type into image properties
1131     switch (type)
1132     {
1133         // Float 2D Images
1134         case EbtSampler2D:
1135         case EbtImage2D:
1136         case EbtSubpassInput:
1137             break;
1138         case EbtSamplerExternalOES:
1139         case EbtSamplerExternal2DY2YEXT:
1140         case EbtSamplerVideoWEBGL:
1141             // These must have already been converted to EbtSampler2D.
1142             UNREACHABLE();
1143             break;
1144         case EbtSampler2DArray:
1145         case EbtImage2DArray:
1146             isArrayed = true;
1147             break;
1148         case EbtSampler2DMS:
1149         case EbtImage2DMS:
1150             isMultisampled = true;
1151             break;
1152         case EbtSampler2DMSArray:
1153         case EbtImage2DMSArray:
1154             isArrayed      = true;
1155             isMultisampled = true;
1156             break;
1157         case EbtSampler2DShadow:
1158             isDepth = true;
1159             break;
1160         case EbtSampler2DArrayShadow:
1161             isDepth   = true;
1162             isArrayed = true;
1163             break;
1164 
1165         // Integer 2D images
1166         case EbtISampler2D:
1167         case EbtIImage2D:
1168         case EbtISubpassInput:
1169             sampledType = EbtInt;
1170             break;
1171         case EbtISampler2DArray:
1172         case EbtIImage2DArray:
1173             sampledType = EbtInt;
1174             isArrayed   = true;
1175             break;
1176         case EbtISampler2DMS:
1177         case EbtIImage2DMS:
1178             sampledType    = EbtInt;
1179             isMultisampled = true;
1180             break;
1181         case EbtISampler2DMSArray:
1182         case EbtIImage2DMSArray:
1183             sampledType    = EbtInt;
1184             isArrayed      = true;
1185             isMultisampled = true;
1186             break;
1187 
1188         // Unsinged integer 2D images
1189         case EbtUSampler2D:
1190         case EbtUImage2D:
1191         case EbtUSubpassInput:
1192             sampledType = EbtUInt;
1193             break;
1194         case EbtUSampler2DArray:
1195         case EbtUImage2DArray:
1196             sampledType = EbtUInt;
1197             isArrayed   = true;
1198             break;
1199         case EbtUSampler2DMS:
1200         case EbtUImage2DMS:
1201             sampledType    = EbtUInt;
1202             isMultisampled = true;
1203             break;
1204         case EbtUSampler2DMSArray:
1205         case EbtUImage2DMSArray:
1206             sampledType    = EbtUInt;
1207             isArrayed      = true;
1208             isMultisampled = true;
1209             break;
1210 
1211         // 3D images
1212         case EbtSampler3D:
1213         case EbtImage3D:
1214             *dimOut = spv::Dim3D;
1215             break;
1216         case EbtISampler3D:
1217         case EbtIImage3D:
1218             sampledType = EbtInt;
1219             *dimOut     = spv::Dim3D;
1220             break;
1221         case EbtUSampler3D:
1222         case EbtUImage3D:
1223             sampledType = EbtUInt;
1224             *dimOut     = spv::Dim3D;
1225             break;
1226 
1227         // Float cube images
1228         case EbtSamplerCube:
1229         case EbtImageCube:
1230             *dimOut = spv::DimCube;
1231             break;
1232         case EbtSamplerCubeArray:
1233         case EbtImageCubeArray:
1234             *dimOut   = spv::DimCube;
1235             isArrayed = true;
1236             break;
1237         case EbtSamplerCubeArrayShadow:
1238             *dimOut   = spv::DimCube;
1239             isDepth   = true;
1240             isArrayed = true;
1241             break;
1242         case EbtSamplerCubeShadow:
1243             *dimOut = spv::DimCube;
1244             isDepth = true;
1245             break;
1246 
1247         // Integer cube images
1248         case EbtISamplerCube:
1249         case EbtIImageCube:
1250             sampledType = EbtInt;
1251             *dimOut     = spv::DimCube;
1252             break;
1253         case EbtISamplerCubeArray:
1254         case EbtIImageCubeArray:
1255             sampledType = EbtInt;
1256             *dimOut     = spv::DimCube;
1257             isArrayed   = true;
1258             break;
1259 
1260         // Unsigned integer cube images
1261         case EbtUSamplerCube:
1262         case EbtUImageCube:
1263             sampledType = EbtUInt;
1264             *dimOut     = spv::DimCube;
1265             break;
1266         case EbtUSamplerCubeArray:
1267         case EbtUImageCubeArray:
1268             sampledType = EbtUInt;
1269             *dimOut     = spv::DimCube;
1270             isArrayed   = true;
1271             break;
1272 
1273         // Rect images
1274         case EbtSampler2DRect:
1275         case EbtImageRect:
1276             *dimOut = spv::DimRect;
1277             break;
1278         case EbtSampler2DRectShadow:
1279             *dimOut = spv::DimRect;
1280             isDepth = true;
1281             break;
1282         case EbtISampler2DRect:
1283         case EbtIImageRect:
1284             sampledType = EbtInt;
1285             *dimOut     = spv::DimRect;
1286             break;
1287         case EbtUSampler2DRect:
1288         case EbtUImageRect:
1289             sampledType = EbtUInt;
1290             *dimOut     = spv::DimRect;
1291             break;
1292 
1293         // Image buffers
1294         case EbtSamplerBuffer:
1295         case EbtImageBuffer:
1296             *dimOut = spv::DimBuffer;
1297             break;
1298         case EbtISamplerBuffer:
1299         case EbtIImageBuffer:
1300             sampledType = EbtInt;
1301             *dimOut     = spv::DimBuffer;
1302             break;
1303         case EbtUSamplerBuffer:
1304         case EbtUImageBuffer:
1305             sampledType = EbtUInt;
1306             *dimOut     = spv::DimBuffer;
1307             break;
1308         default:
1309             UNREACHABLE();
1310     }
1311 
1312     // Get id of the component type of the image
1313     SpirvType sampledSpirvType;
1314     sampledSpirvType.type = sampledType;
1315 
1316     *sampledTypeOut = getSpirvTypeData(sampledSpirvType, nullptr).id;
1317 
1318     const bool isSampledImage = IsSampler(type);
1319 
1320     // Set flags based on SPIR-V required values.  See OpTypeImage:
1321     //
1322     // - For depth:        0 = non-depth,      1 = depth
1323     // - For arrayed:      0 = non-arrayed,    1 = arrayed
1324     // - For multisampled: 0 = single-sampled, 1 = multisampled
1325     // - For sampled:      1 = sampled,        2 = storage
1326     //
1327     *depthOut        = spirv::LiteralInteger(isDepth ? 1 : 0);
1328     *arrayedOut      = spirv::LiteralInteger(isArrayed ? 1 : 0);
1329     *multisampledOut = spirv::LiteralInteger(isMultisampled ? 1 : 0);
1330     *sampledOut      = spirv::LiteralInteger(isSampledImage ? 1 : 2);
1331 
1332     // Add the necessary capability based on parameters.  The SPIR-V spec section 3.8 Dim specfies
1333     // the required capabilities:
1334     //
1335     //     Dim          Sampled         Storage            Storage Array
1336     //     --------------------------------------------------------------
1337     //     2D           Shader                             ImageMSArray
1338     //     3D
1339     //     Cube         Shader                             ImageCubeArray
1340     //     Rect         SampledRect     ImageRect
1341     //     Buffer       SampledBuffer   ImageBuffer
1342     //
1343     // Additionally, the SubpassData Dim requires the InputAttachment capability.
1344     //
1345     // Note that the Shader capability is always unconditionally added.
1346     //
1347     switch (*dimOut)
1348     {
1349         case spv::Dim2D:
1350             if (!isSampledImage && isArrayed && isMultisampled)
1351             {
1352                 addCapability(spv::CapabilityImageMSArray);
1353             }
1354             break;
1355         case spv::Dim3D:
1356             break;
1357         case spv::DimCube:
1358             if (!isSampledImage && isArrayed)
1359             {
1360                 addCapability(spv::CapabilityImageCubeArray);
1361             }
1362             break;
1363         case spv::DimRect:
1364             addCapability(isSampledImage ? spv::CapabilitySampledRect : spv::CapabilityImageRect);
1365             break;
1366         case spv::DimBuffer:
1367             addCapability(isSampledImage ? spv::CapabilitySampledBuffer
1368                                          : spv::CapabilityImageBuffer);
1369             break;
1370         case spv::DimSubpassData:
1371             addCapability(spv::CapabilityInputAttachment);
1372             break;
1373         default:
1374             UNREACHABLE();
1375     }
1376 }
1377 
getImageFormat(TLayoutImageInternalFormat imageInternalFormat)1378 spv::ImageFormat SPIRVBuilder::getImageFormat(TLayoutImageInternalFormat imageInternalFormat)
1379 {
1380     switch (imageInternalFormat)
1381     {
1382         case EiifUnspecified:
1383             return spv::ImageFormatUnknown;
1384         case EiifRGBA32F:
1385             return spv::ImageFormatRgba32f;
1386         case EiifRGBA16F:
1387             return spv::ImageFormatRgba16f;
1388         case EiifR32F:
1389             return spv::ImageFormatR32f;
1390         case EiifRGBA32UI:
1391             return spv::ImageFormatRgba32ui;
1392         case EiifRGBA16UI:
1393             return spv::ImageFormatRgba16ui;
1394         case EiifRGBA8UI:
1395             return spv::ImageFormatRgba8ui;
1396         case EiifR32UI:
1397             return spv::ImageFormatR32ui;
1398         case EiifRGBA32I:
1399             return spv::ImageFormatRgba32i;
1400         case EiifRGBA16I:
1401             return spv::ImageFormatRgba16i;
1402         case EiifRGBA8I:
1403             return spv::ImageFormatRgba8i;
1404         case EiifR32I:
1405             return spv::ImageFormatR32i;
1406         case EiifRGBA8:
1407             return spv::ImageFormatRgba8;
1408         case EiifRGBA8_SNORM:
1409             return spv::ImageFormatRgba8Snorm;
1410         default:
1411             UNREACHABLE();
1412             return spv::ImageFormatUnknown;
1413     }
1414 }
1415 
getBoolConstant(bool value)1416 spirv::IdRef SPIRVBuilder::getBoolConstant(bool value)
1417 {
1418     uint32_t asInt = static_cast<uint32_t>(value);
1419 
1420     spirv::IdRef constantId = mBoolConstants[asInt];
1421 
1422     if (!constantId.valid())
1423     {
1424         SpirvType boolType;
1425         boolType.type = EbtBool;
1426 
1427         const spirv::IdRef boolTypeId = getSpirvTypeData(boolType, nullptr).id;
1428 
1429         mBoolConstants[asInt] = constantId = getNewId({});
1430         if (value)
1431         {
1432             spirv::WriteConstantTrue(&mSpirvTypeAndConstantDecls, boolTypeId, constantId);
1433         }
1434         else
1435         {
1436             spirv::WriteConstantFalse(&mSpirvTypeAndConstantDecls, boolTypeId, constantId);
1437         }
1438     }
1439 
1440     return constantId;
1441 }
1442 
getBasicConstantHelper(uint32_t value,TBasicType type,angle::HashMap<uint32_t,spirv::IdRef> * constants)1443 spirv::IdRef SPIRVBuilder::getBasicConstantHelper(uint32_t value,
1444                                                   TBasicType type,
1445                                                   angle::HashMap<uint32_t, spirv::IdRef> *constants)
1446 {
1447     auto iter = constants->find(value);
1448     if (iter != constants->end())
1449     {
1450         return iter->second;
1451     }
1452 
1453     SpirvType spirvType;
1454     spirvType.type = type;
1455 
1456     const spirv::IdRef typeId     = getSpirvTypeData(spirvType, nullptr).id;
1457     const spirv::IdRef constantId = getNewId({});
1458 
1459     spirv::WriteConstant(&mSpirvTypeAndConstantDecls, typeId, constantId,
1460                          spirv::LiteralContextDependentNumber(value));
1461 
1462     return constants->insert({value, constantId}).first->second;
1463 }
1464 
getUintConstant(uint32_t value)1465 spirv::IdRef SPIRVBuilder::getUintConstant(uint32_t value)
1466 {
1467     return getBasicConstantHelper(value, EbtUInt, &mUintConstants);
1468 }
1469 
getIntConstant(int32_t value)1470 spirv::IdRef SPIRVBuilder::getIntConstant(int32_t value)
1471 {
1472     uint32_t asUint = static_cast<uint32_t>(value);
1473     return getBasicConstantHelper(asUint, EbtInt, &mIntConstants);
1474 }
1475 
getFloatConstant(float value)1476 spirv::IdRef SPIRVBuilder::getFloatConstant(float value)
1477 {
1478     union
1479     {
1480         float f;
1481         uint32_t u;
1482     } asUint;
1483     asUint.f = value;
1484     return getBasicConstantHelper(asUint.u, EbtFloat, &mFloatConstants);
1485 }
1486 
getNullConstant(spirv::IdRef typeId)1487 spirv::IdRef SPIRVBuilder::getNullConstant(spirv::IdRef typeId)
1488 {
1489     if (typeId >= mNullConstants.size())
1490     {
1491         mNullConstants.resize(typeId + 1);
1492     }
1493 
1494     if (!mNullConstants[typeId].valid())
1495     {
1496         const spirv::IdRef constantId = getNewId({});
1497         mNullConstants[typeId]        = constantId;
1498 
1499         spirv::WriteConstantNull(&mSpirvTypeAndConstantDecls, typeId, constantId);
1500     }
1501 
1502     return mNullConstants[typeId];
1503 }
1504 
getNullVectorConstantHelper(TBasicType type,int size)1505 spirv::IdRef SPIRVBuilder::getNullVectorConstantHelper(TBasicType type, int size)
1506 {
1507     SpirvType vecType;
1508     vecType.type        = type;
1509     vecType.primarySize = static_cast<uint8_t>(size);
1510 
1511     return getNullConstant(getSpirvTypeData(vecType, nullptr).id);
1512 }
1513 
getVectorConstantHelper(spirv::IdRef valueId,TBasicType type,int size)1514 spirv::IdRef SPIRVBuilder::getVectorConstantHelper(spirv::IdRef valueId, TBasicType type, int size)
1515 {
1516     if (size == 1)
1517     {
1518         return valueId;
1519     }
1520 
1521     SpirvType vecType;
1522     vecType.type        = type;
1523     vecType.primarySize = static_cast<uint8_t>(size);
1524 
1525     const spirv::IdRef typeId = getSpirvTypeData(vecType, nullptr).id;
1526     const spirv::IdRefList valueIds(size, valueId);
1527 
1528     return getCompositeConstant(typeId, valueIds);
1529 }
1530 
getUvecConstant(uint32_t value,int size)1531 spirv::IdRef SPIRVBuilder::getUvecConstant(uint32_t value, int size)
1532 {
1533     if (value == 0)
1534     {
1535         return getNullVectorConstantHelper(EbtUInt, size);
1536     }
1537 
1538     const spirv::IdRef valueId = getUintConstant(value);
1539     return getVectorConstantHelper(valueId, EbtUInt, size);
1540 }
1541 
getIvecConstant(int32_t value,int size)1542 spirv::IdRef SPIRVBuilder::getIvecConstant(int32_t value, int size)
1543 {
1544     if (value == 0)
1545     {
1546         return getNullVectorConstantHelper(EbtInt, size);
1547     }
1548 
1549     const spirv::IdRef valueId = getIntConstant(value);
1550     return getVectorConstantHelper(valueId, EbtInt, size);
1551 }
1552 
getVecConstant(float value,int size)1553 spirv::IdRef SPIRVBuilder::getVecConstant(float value, int size)
1554 {
1555     if (value == 0)
1556     {
1557         return getNullVectorConstantHelper(EbtFloat, size);
1558     }
1559 
1560     const spirv::IdRef valueId = getFloatConstant(value);
1561     return getVectorConstantHelper(valueId, EbtFloat, size);
1562 }
1563 
getCompositeConstant(spirv::IdRef typeId,const spirv::IdRefList & values)1564 spirv::IdRef SPIRVBuilder::getCompositeConstant(spirv::IdRef typeId, const spirv::IdRefList &values)
1565 {
1566     SpirvIdAndIdList key{typeId, values};
1567 
1568     auto iter = mCompositeConstants.find(key);
1569     if (iter == mCompositeConstants.end())
1570     {
1571         const spirv::IdRef constantId = getNewId({});
1572 
1573         spirv::WriteConstantComposite(&mSpirvTypeAndConstantDecls, typeId, constantId, values);
1574 
1575         iter = mCompositeConstants.insert({key, constantId}).first;
1576     }
1577 
1578     return iter->second;
1579 }
1580 
startNewFunction(spirv::IdRef functionId,const TFunction * func)1581 void SPIRVBuilder::startNewFunction(spirv::IdRef functionId, const TFunction *func)
1582 {
1583     ASSERT(mSpirvCurrentFunctionBlocks.empty());
1584 
1585     // Add the first block of the function.
1586     mSpirvCurrentFunctionBlocks.emplace_back();
1587     mSpirvCurrentFunctionBlocks.back().labelId = getNewId({});
1588 
1589     // Output debug information.
1590     writeDebugName(functionId, getName(func).data());
1591 }
1592 
assembleSpirvFunctionBlocks()1593 void SPIRVBuilder::assembleSpirvFunctionBlocks()
1594 {
1595     // Take all the blocks and place them in the functions section of SPIR-V in sequence.
1596     for (const SpirvBlock &block : mSpirvCurrentFunctionBlocks)
1597     {
1598         // Every block must be properly terminated.
1599         ASSERT(block.isTerminated);
1600 
1601         // Generate the OpLabel instruction for the block.
1602         spirv::WriteLabel(&mSpirvFunctions, block.labelId);
1603 
1604         // Add the variable declarations if any.
1605         mSpirvFunctions.insert(mSpirvFunctions.end(), block.localVariables.begin(),
1606                                block.localVariables.end());
1607 
1608         // Add the body of the block.
1609         mSpirvFunctions.insert(mSpirvFunctions.end(), block.body.begin(), block.body.end());
1610     }
1611 
1612     // Clean up.
1613     mSpirvCurrentFunctionBlocks.clear();
1614 }
1615 
declareVariable(spirv::IdRef typeId,spv::StorageClass storageClass,const SpirvDecorations & decorations,spirv::IdRef * initializerId,const char * name,const TSymbolUniqueId * uniqueId)1616 spirv::IdRef SPIRVBuilder::declareVariable(spirv::IdRef typeId,
1617                                            spv::StorageClass storageClass,
1618                                            const SpirvDecorations &decorations,
1619                                            spirv::IdRef *initializerId,
1620                                            const char *name,
1621                                            const TSymbolUniqueId *uniqueId)
1622 {
1623     const bool isFunctionLocal = storageClass == spv::StorageClassFunction;
1624 
1625     // Make sure storage class is consistent with where the variable is declared.
1626     ASSERT(!isFunctionLocal || !mSpirvCurrentFunctionBlocks.empty());
1627 
1628     // Function-local variables go in the first block of the function, while the rest are in the
1629     // global variables section.
1630     spirv::Blob *spirvSection = isFunctionLocal
1631                                     ? &mSpirvCurrentFunctionBlocks.front().localVariables
1632                                     : &mSpirvVariableDecls;
1633 
1634     const spirv::IdRef typePointerId = getTypePointerId(typeId, storageClass);
1635     spirv::IdRef variableId;
1636     if (uniqueId)
1637     {
1638         variableId = getReservedOrNewId(*uniqueId, decorations);
1639 
1640         if (variableId == vk::spirv::kIdOutputPerVertexVar)
1641         {
1642             mOverviewFlags |= vk::spirv::kOverviewHasOutputPerVertexMask;
1643         }
1644         else if (variableId == vk::spirv::kIdSampleID)
1645         {
1646             mOverviewFlags |= vk::spirv::kOverviewHasSampleIDMask;
1647         }
1648     }
1649     else
1650     {
1651         variableId = getNewId(decorations);
1652     }
1653 
1654     spirv::WriteVariable(spirvSection, typePointerId, variableId, storageClass, initializerId);
1655 
1656     // Output debug information.
1657     if (name)
1658     {
1659         writeDebugName(variableId, name);
1660     }
1661 
1662     if (!isFunctionLocal)
1663     {
1664         // With SPIR-V 1.4, every global variable must be specified in OpEntryPoint
1665         // With SPIR-V 1.3, only the Input and Output variables must be specified.
1666         if (mCompileOptions.emitSPIRV14 || storageClass == spv::StorageClassInput ||
1667             storageClass == spv::StorageClassOutput)
1668         {
1669             addEntryPointInterfaceVariableId(variableId);
1670         }
1671     }
1672 
1673     return variableId;
1674 }
1675 
declareSpecConst(TBasicType type,int id,const char * name)1676 spirv::IdRef SPIRVBuilder::declareSpecConst(TBasicType type, int id, const char *name)
1677 {
1678     SpirvType spirvType;
1679     spirvType.type = type;
1680 
1681     const spirv::IdRef typeId      = getSpirvTypeData(spirvType, nullptr).id;
1682     const spirv::IdRef specConstId = getNewId({});
1683 
1684     // Note: all spec constants are 0 initialized by the translator.
1685     if (type == EbtBool)
1686     {
1687         spirv::WriteSpecConstantFalse(&mSpirvTypeAndConstantDecls, typeId, specConstId);
1688     }
1689     else
1690     {
1691         spirv::WriteSpecConstant(&mSpirvTypeAndConstantDecls, typeId, specConstId,
1692                                  spirv::LiteralContextDependentNumber(0));
1693     }
1694 
1695     // Add the SpecId decoration
1696     spirv::WriteDecorate(&mSpirvDecorations, specConstId, spv::DecorationSpecId,
1697                          {spirv::LiteralInteger(id)});
1698 
1699     // Output debug information.
1700     if (name)
1701     {
1702         writeDebugName(specConstId, name);
1703     }
1704 
1705     return specConstId;
1706 }
1707 
startConditional(size_t blockCount,bool isContinuable,bool isBreakable)1708 void SPIRVBuilder::startConditional(size_t blockCount, bool isContinuable, bool isBreakable)
1709 {
1710     mConditionalStack.emplace_back();
1711     SpirvConditional &conditional = mConditionalStack.back();
1712 
1713     // Create the requested number of block ids.
1714     conditional.blockIds.resize(blockCount);
1715     for (spirv::IdRef &blockId : conditional.blockIds)
1716     {
1717         blockId = getNewId({});
1718     }
1719 
1720     conditional.isContinuable = isContinuable;
1721     conditional.isBreakable   = isBreakable;
1722 
1723     // Don't automatically start the next block.  The caller needs to generate instructions based on
1724     // the ids that were just generated above.
1725 }
1726 
nextConditionalBlock()1727 void SPIRVBuilder::nextConditionalBlock()
1728 {
1729     ASSERT(!mConditionalStack.empty());
1730     SpirvConditional &conditional = mConditionalStack.back();
1731 
1732     ASSERT(conditional.nextBlockToWrite < conditional.blockIds.size());
1733     const spirv::IdRef blockId = conditional.blockIds[conditional.nextBlockToWrite++];
1734 
1735     // The previous block must have properly terminated.
1736     ASSERT(isCurrentFunctionBlockTerminated());
1737 
1738     // Generate a new block.
1739     mSpirvCurrentFunctionBlocks.emplace_back();
1740     mSpirvCurrentFunctionBlocks.back().labelId = blockId;
1741 }
1742 
endConditional()1743 void SPIRVBuilder::endConditional()
1744 {
1745     ASSERT(!mConditionalStack.empty());
1746 
1747     // No blocks should be left.
1748     ASSERT(mConditionalStack.back().nextBlockToWrite == mConditionalStack.back().blockIds.size());
1749 
1750     mConditionalStack.pop_back();
1751 }
1752 
isInLoop() const1753 bool SPIRVBuilder::isInLoop() const
1754 {
1755     for (const SpirvConditional &conditional : mConditionalStack)
1756     {
1757         if (conditional.isContinuable)
1758         {
1759             return true;
1760         }
1761     }
1762 
1763     return false;
1764 }
1765 
getBreakTargetId() const1766 spirv::IdRef SPIRVBuilder::getBreakTargetId() const
1767 {
1768     for (size_t index = mConditionalStack.size(); index > 0; --index)
1769     {
1770         const SpirvConditional &conditional = mConditionalStack[index - 1];
1771 
1772         if (conditional.isBreakable)
1773         {
1774             // The target of break; is always the merge block, and the merge block is always the
1775             // last block.
1776             return conditional.blockIds.back();
1777         }
1778     }
1779 
1780     UNREACHABLE();
1781     return spirv::IdRef{};
1782 }
1783 
getContinueTargetId() const1784 spirv::IdRef SPIRVBuilder::getContinueTargetId() const
1785 {
1786     for (size_t index = mConditionalStack.size(); index > 0; --index)
1787     {
1788         const SpirvConditional &conditional = mConditionalStack[index - 1];
1789 
1790         if (conditional.isContinuable)
1791         {
1792             // The target of continue; is always the block before merge, so it's the one before
1793             // last.
1794             ASSERT(conditional.blockIds.size() > 2);
1795             return conditional.blockIds[conditional.blockIds.size() - 2];
1796         }
1797     }
1798 
1799     UNREACHABLE();
1800     return spirv::IdRef{};
1801 }
1802 
nextUnusedBinding()1803 uint32_t SPIRVBuilder::nextUnusedBinding()
1804 {
1805     return mNextUnusedBinding++;
1806 }
1807 
nextUnusedInputLocation(uint32_t consumedCount)1808 uint32_t SPIRVBuilder::nextUnusedInputLocation(uint32_t consumedCount)
1809 {
1810     uint32_t nextUnused = mNextUnusedInputLocation;
1811     mNextUnusedInputLocation += consumedCount;
1812     return nextUnused;
1813 }
1814 
nextUnusedOutputLocation(uint32_t consumedCount)1815 uint32_t SPIRVBuilder::nextUnusedOutputLocation(uint32_t consumedCount)
1816 {
1817     uint32_t nextUnused = mNextUnusedOutputLocation;
1818     mNextUnusedOutputLocation += consumedCount;
1819     return nextUnused;
1820 }
1821 
isInvariantOutput(const TType & type) const1822 bool SPIRVBuilder::isInvariantOutput(const TType &type) const
1823 {
1824     return IsInvariant(type, mCompiler);
1825 }
1826 
addCapability(spv::Capability capability)1827 void SPIRVBuilder::addCapability(spv::Capability capability)
1828 {
1829     mCapabilities.insert(capability);
1830 
1831     if (capability == spv::CapabilitySampleRateShading)
1832     {
1833         mOverviewFlags |= vk::spirv::kOverviewHasSampleRateShadingMask;
1834     }
1835 }
1836 
addExecutionMode(spv::ExecutionMode executionMode)1837 void SPIRVBuilder::addExecutionMode(spv::ExecutionMode executionMode)
1838 {
1839     mExecutionModes.insert(executionMode);
1840 }
1841 
addExtension(SPIRVExtensions extension)1842 void SPIRVBuilder::addExtension(SPIRVExtensions extension)
1843 {
1844     mExtensions.set(extension);
1845 }
1846 
addEntryPointInterfaceVariableId(spirv::IdRef id)1847 void SPIRVBuilder::addEntryPointInterfaceVariableId(spirv::IdRef id)
1848 {
1849     mEntryPointInterfaceList.push_back(id);
1850 }
1851 
writePerVertexBuiltIns(const TType & type,spirv::IdRef typeId)1852 void SPIRVBuilder::writePerVertexBuiltIns(const TType &type, spirv::IdRef typeId)
1853 {
1854     ASSERT(type.isInterfaceBlock());
1855     const TInterfaceBlock *block = type.getInterfaceBlock();
1856 
1857     uint32_t fieldIndex = 0;
1858     for (const TField *field : block->fields())
1859     {
1860         spv::BuiltIn decorationValue = spv::BuiltInPosition;
1861         switch (field->type()->getQualifier())
1862         {
1863             case EvqPosition:
1864                 decorationValue = spv::BuiltInPosition;
1865                 break;
1866             case EvqPointSize:
1867                 decorationValue = spv::BuiltInPointSize;
1868                 break;
1869             case EvqClipDistance:
1870                 decorationValue = spv::BuiltInClipDistance;
1871                 break;
1872             case EvqCullDistance:
1873                 decorationValue = spv::BuiltInCullDistance;
1874                 break;
1875             default:
1876                 UNREACHABLE();
1877         }
1878 
1879         spirv::WriteMemberDecorate(&mSpirvDecorations, typeId, spirv::LiteralInteger(fieldIndex++),
1880                                    spv::DecorationBuiltIn,
1881                                    {spirv::LiteralInteger(decorationValue)});
1882     }
1883 }
1884 
writeInterfaceVariableDecorations(const TType & type,spirv::IdRef variableId)1885 void SPIRVBuilder::writeInterfaceVariableDecorations(const TType &type, spirv::IdRef variableId)
1886 {
1887     const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
1888     const bool isVarying                    = IsVarying(type.getQualifier());
1889     const bool needsSetBinding =
1890         !layoutQualifier.pushConstant &&
1891         (IsSampler(type.getBasicType()) ||
1892          (type.isInterfaceBlock() &&
1893           (type.getQualifier() == EvqUniform || type.getQualifier() == EvqBuffer)) ||
1894          IsImage(type.getBasicType()) || IsSubpassInputType(type.getBasicType()));
1895     const bool needsLocation = type.getQualifier() == EvqAttribute ||
1896                                type.getQualifier() == EvqVertexIn ||
1897                                type.getQualifier() == EvqFragmentOut || isVarying;
1898     const bool needsInputAttachmentIndex = IsSubpassInputType(type.getBasicType());
1899 
1900     const bool needsYuvDecorate = mCompileOptions.addVulkanYUVLayoutQualifier &&
1901                                   type.getQualifier() == EvqFragmentOut && layoutQualifier.yuv;
1902 
1903     // If the resource declaration requires set & binding, add the DescriptorSet and Binding
1904     // decorations.
1905     if (needsSetBinding)
1906     {
1907         spirv::WriteDecorate(&mSpirvDecorations, variableId, spv::DecorationDescriptorSet,
1908                              {spirv::LiteralInteger(0)});
1909         spirv::WriteDecorate(&mSpirvDecorations, variableId, spv::DecorationBinding,
1910                              {spirv::LiteralInteger(nextUnusedBinding())});
1911     }
1912 
1913     if (needsLocation)
1914     {
1915         const unsigned int locationCount =
1916             CalculateVaryingLocationCount(type, gl::ToGLenum(mShaderType));
1917         const uint32_t location = IsShaderIn(type.getQualifier())
1918                                       ? nextUnusedInputLocation(locationCount)
1919                                       : nextUnusedOutputLocation(locationCount);
1920 
1921         spirv::WriteDecorate(&mSpirvDecorations, variableId, spv::DecorationLocation,
1922                              {spirv::LiteralInteger(location)});
1923     }
1924 
1925     // If the resource declaration is an input attachment, add the InputAttachmentIndex decoration.
1926     // Depth and stencil input attachments are exempt.
1927     if (needsInputAttachmentIndex && layoutQualifier.inputAttachmentIndex >= 0)
1928     {
1929         spirv::WriteDecorate(&mSpirvDecorations, variableId, spv::DecorationInputAttachmentIndex,
1930                              {spirv::LiteralInteger(layoutQualifier.inputAttachmentIndex)});
1931     }
1932 
1933     if (needsYuvDecorate)
1934     {
1935         // WIP in spec
1936         const spv::Decoration yuvDecorate = static_cast<spv::Decoration>(6088);
1937         spirv::WriteDecorate(&mSpirvDecorations, variableId, yuvDecorate,
1938                              {spirv::LiteralInteger(layoutQualifier.index)});
1939     }
1940 
1941     // Handle interpolation and auxiliary decorations on varyings
1942     if (isVarying)
1943     {
1944         writeInterpolationDecoration(type.getQualifier(), variableId,
1945                                      std::numeric_limits<uint32_t>::max());
1946     }
1947 }
1948 
writeBranchConditional(spirv::IdRef conditionValue,spirv::IdRef trueBlock,spirv::IdRef falseBlock,spirv::IdRef mergeBlock)1949 void SPIRVBuilder::writeBranchConditional(spirv::IdRef conditionValue,
1950                                           spirv::IdRef trueBlock,
1951                                           spirv::IdRef falseBlock,
1952                                           spirv::IdRef mergeBlock)
1953 {
1954     // Generate the following:
1955     //
1956     //     OpSelectionMerge %mergeBlock None
1957     //     OpBranchConditional %conditionValue %trueBlock %falseBlock
1958     //
1959     spirv::WriteSelectionMerge(getSpirvCurrentFunctionBlock(), mergeBlock,
1960                                spv::SelectionControlMaskNone);
1961     spirv::WriteBranchConditional(getSpirvCurrentFunctionBlock(), conditionValue, trueBlock,
1962                                   falseBlock, {});
1963     terminateCurrentFunctionBlock();
1964 
1965     // Start the true or false block, whichever exists.
1966     nextConditionalBlock();
1967 }
1968 
writeBranchConditionalBlockEnd()1969 void SPIRVBuilder::writeBranchConditionalBlockEnd()
1970 {
1971     if (!isCurrentFunctionBlockTerminated())
1972     {
1973         // Insert a branch to the merge block at the end of each if-else block, unless the block is
1974         // already terminated, such as with a return or discard.
1975         const spirv::IdRef mergeBlock = getCurrentConditional()->blockIds.back();
1976 
1977         spirv::WriteBranch(getSpirvCurrentFunctionBlock(), mergeBlock);
1978         terminateCurrentFunctionBlock();
1979     }
1980 
1981     // Move on to the next block.
1982     nextConditionalBlock();
1983 }
1984 
writeLoopHeader(spirv::IdRef branchToBlock,spirv::IdRef continueBlock,spirv::IdRef mergeBlock)1985 void SPIRVBuilder::writeLoopHeader(spirv::IdRef branchToBlock,
1986                                    spirv::IdRef continueBlock,
1987                                    spirv::IdRef mergeBlock)
1988 {
1989     // First, jump to the header block:
1990     //
1991     //     OpBranch %header
1992     //
1993     const spirv::IdRef headerBlock = mConditionalStack.back().blockIds[0];
1994     spirv::WriteBranch(getSpirvCurrentFunctionBlock(), headerBlock);
1995     terminateCurrentFunctionBlock();
1996 
1997     // Start the header block.
1998     nextConditionalBlock();
1999 
2000     // Generate the following:
2001     //
2002     //     OpLoopMerge %mergeBlock %continueBlock None
2003     //     OpBranch %branchToBlock (%cond or if do-while, %body)
2004     //
2005     spirv::WriteLoopMerge(getSpirvCurrentFunctionBlock(), mergeBlock, continueBlock,
2006                           spv::LoopControlMaskNone);
2007     spirv::WriteBranch(getSpirvCurrentFunctionBlock(), branchToBlock);
2008     terminateCurrentFunctionBlock();
2009 
2010     // Start the next block, which is either %cond or %body.
2011     nextConditionalBlock();
2012 }
2013 
writeLoopConditionEnd(spirv::IdRef conditionValue,spirv::IdRef branchToBlock,spirv::IdRef mergeBlock)2014 void SPIRVBuilder::writeLoopConditionEnd(spirv::IdRef conditionValue,
2015                                          spirv::IdRef branchToBlock,
2016                                          spirv::IdRef mergeBlock)
2017 {
2018     // Generate the following:
2019     //
2020     //     OpBranchConditional %conditionValue %branchToBlock %mergeBlock
2021     //
2022     // %branchToBlock is either %body or if do-while, %header
2023     //
2024     spirv::WriteBranchConditional(getSpirvCurrentFunctionBlock(), conditionValue, branchToBlock,
2025                                   mergeBlock, {});
2026     terminateCurrentFunctionBlock();
2027 
2028     // Start the next block, which is either %continue or %body.
2029     nextConditionalBlock();
2030 }
2031 
writeLoopContinueEnd(spirv::IdRef headerBlock)2032 void SPIRVBuilder::writeLoopContinueEnd(spirv::IdRef headerBlock)
2033 {
2034     // Generate the following:
2035     //
2036     //     OpBranch %headerBlock
2037     //
2038     spirv::WriteBranch(getSpirvCurrentFunctionBlock(), headerBlock);
2039     terminateCurrentFunctionBlock();
2040 
2041     // Start the next block, which is %body.
2042     nextConditionalBlock();
2043 }
2044 
writeLoopBodyEnd(spirv::IdRef continueBlock)2045 void SPIRVBuilder::writeLoopBodyEnd(spirv::IdRef continueBlock)
2046 {
2047     // Generate the following:
2048     //
2049     //     OpBranch %continueBlock
2050     //
2051     // This is only done if the block isn't already terminated in another way, such as with an
2052     // unconditional continue/etc at the end of the loop.
2053     if (!isCurrentFunctionBlockTerminated())
2054     {
2055         spirv::WriteBranch(getSpirvCurrentFunctionBlock(), continueBlock);
2056         terminateCurrentFunctionBlock();
2057     }
2058 
2059     // Start the next block, which is %merge or if while, %continue.
2060     nextConditionalBlock();
2061 }
2062 
writeSwitch(spirv::IdRef conditionValue,spirv::IdRef defaultBlock,const spirv::PairLiteralIntegerIdRefList & targetPairList,spirv::IdRef mergeBlock)2063 void SPIRVBuilder::writeSwitch(spirv::IdRef conditionValue,
2064                                spirv::IdRef defaultBlock,
2065                                const spirv::PairLiteralIntegerIdRefList &targetPairList,
2066                                spirv::IdRef mergeBlock)
2067 {
2068     // Generate the following:
2069     //
2070     //     OpSelectionMerge %mergeBlock None
2071     //     OpSwitch %conditionValue %defaultBlock A %ABlock B %BBlock ...
2072     //
2073     spirv::WriteSelectionMerge(getSpirvCurrentFunctionBlock(), mergeBlock,
2074                                spv::SelectionControlMaskNone);
2075     spirv::WriteSwitch(getSpirvCurrentFunctionBlock(), conditionValue, defaultBlock,
2076                        targetPairList);
2077     terminateCurrentFunctionBlock();
2078 
2079     // Start the next case block.
2080     nextConditionalBlock();
2081 }
2082 
writeSwitchCaseBlockEnd()2083 void SPIRVBuilder::writeSwitchCaseBlockEnd()
2084 {
2085     if (!isCurrentFunctionBlockTerminated())
2086     {
2087         // If a case does not end in branch, insert a branch to the next block, implementing
2088         // fallthrough.  For the last block, the branch target would automatically be the merge
2089         // block.
2090         const SpirvConditional *conditional = getCurrentConditional();
2091         const spirv::IdRef nextBlock        = conditional->blockIds[conditional->nextBlockToWrite];
2092 
2093         spirv::WriteBranch(getSpirvCurrentFunctionBlock(), nextBlock);
2094         terminateCurrentFunctionBlock();
2095     }
2096 
2097     // Move on to the next block.
2098     nextConditionalBlock();
2099 }
2100 
writeMemberDecorations(const SpirvType & type,spirv::IdRef typeId)2101 void SPIRVBuilder::writeMemberDecorations(const SpirvType &type, spirv::IdRef typeId)
2102 {
2103     ASSERT(type.block != nullptr);
2104 
2105     uint32_t fieldIndex = 0;
2106 
2107     for (const TField *field : type.block->fields())
2108     {
2109         const TType &fieldType = *field->type();
2110 
2111         // Add invariant decoration if any.
2112         if (type.typeSpec.isInvariantBlock || fieldType.isInvariant())
2113         {
2114             spirv::WriteMemberDecorate(&mSpirvDecorations, typeId,
2115                                        spirv::LiteralInteger(fieldIndex), spv::DecorationInvariant,
2116                                        {});
2117         }
2118 
2119         // Add memory qualifier decorations to buffer members
2120         if (fieldType.getMemoryQualifier().coherent)
2121         {
2122             spirv::WriteMemberDecorate(&mSpirvDecorations, typeId,
2123                                        spirv::LiteralInteger(fieldIndex), spv::DecorationCoherent,
2124                                        {});
2125         }
2126         if (fieldType.getMemoryQualifier().readonly)
2127         {
2128             spirv::WriteMemberDecorate(&mSpirvDecorations, typeId,
2129                                        spirv::LiteralInteger(fieldIndex),
2130                                        spv::DecorationNonWritable, {});
2131         }
2132         if (fieldType.getMemoryQualifier().writeonly)
2133         {
2134             spirv::WriteMemberDecorate(&mSpirvDecorations, typeId,
2135                                        spirv::LiteralInteger(fieldIndex),
2136                                        spv::DecorationNonReadable, {});
2137         }
2138         if (fieldType.getMemoryQualifier().restrictQualifier)
2139         {
2140             spirv::WriteMemberDecorate(&mSpirvDecorations, typeId,
2141                                        spirv::LiteralInteger(fieldIndex), spv::DecorationRestrict,
2142                                        {});
2143         }
2144         if (fieldType.getMemoryQualifier().volatileQualifier)
2145         {
2146             spirv::WriteMemberDecorate(&mSpirvDecorations, typeId,
2147                                        spirv::LiteralInteger(fieldIndex), spv::DecorationVolatile,
2148                                        {});
2149         }
2150 
2151         // Add matrix decorations if any.
2152         if (fieldType.isMatrix())
2153         {
2154             // ColMajor or RowMajor
2155             const bool isRowMajor =
2156                 IsBlockFieldRowMajorQualified(fieldType, type.typeSpec.isRowMajorQualifiedBlock);
2157             spirv::WriteMemberDecorate(
2158                 &mSpirvDecorations, typeId, spirv::LiteralInteger(fieldIndex),
2159                 isRowMajor ? spv::DecorationRowMajor : spv::DecorationColMajor, {});
2160         }
2161 
2162         // Add interpolation and auxiliary decorations
2163         writeInterpolationDecoration(fieldType.getQualifier(), typeId, fieldIndex);
2164 
2165         // Add patch decoration if any.
2166         if (type.typeSpec.isPatchIOBlock)
2167         {
2168             spirv::WriteMemberDecorate(&mSpirvDecorations, typeId,
2169                                        spirv::LiteralInteger(fieldIndex), spv::DecorationPatch, {});
2170         }
2171 
2172         // Add other decorations.
2173         SpirvDecorations decorations = getDecorations(fieldType);
2174         for (const spv::Decoration decoration : decorations)
2175         {
2176             spirv::WriteMemberDecorate(&mSpirvDecorations, typeId,
2177                                        spirv::LiteralInteger(fieldIndex), decoration, {});
2178         }
2179 
2180         ++fieldIndex;
2181     }
2182 }
2183 
writeInterpolationDecoration(TQualifier qualifier,spirv::IdRef id,uint32_t fieldIndex)2184 void SPIRVBuilder::writeInterpolationDecoration(TQualifier qualifier,
2185                                                 spirv::IdRef id,
2186                                                 uint32_t fieldIndex)
2187 {
2188     switch (qualifier)
2189     {
2190         case EvqSmooth:
2191         case EvqSmoothOut:
2192         case EvqSmoothIn:
2193             // No decoration in SPIR-V for smooth, this is the default interpolation.
2194             return;
2195 
2196         case EvqFlat:
2197         case EvqFlatOut:
2198         case EvqFlatIn:
2199             WriteInterpolationDecoration(spv::DecorationFlat, id, fieldIndex, &mSpirvDecorations);
2200             return;
2201 
2202         case EvqNoPerspective:
2203         case EvqNoPerspectiveOut:
2204         case EvqNoPerspectiveIn:
2205             WriteInterpolationDecoration(spv::DecorationNoPerspective, id, fieldIndex,
2206                                          &mSpirvDecorations);
2207             return;
2208 
2209         case EvqCentroid:
2210         case EvqCentroidOut:
2211         case EvqCentroidIn:
2212             WriteInterpolationDecoration(spv::DecorationCentroid, id, fieldIndex,
2213                                          &mSpirvDecorations);
2214             return;
2215 
2216         case EvqSample:
2217         case EvqSampleOut:
2218         case EvqSampleIn:
2219             WriteInterpolationDecoration(spv::DecorationSample, id, fieldIndex, &mSpirvDecorations);
2220             addCapability(spv::CapabilitySampleRateShading);
2221             return;
2222 
2223         case EvqNoPerspectiveCentroid:
2224         case EvqNoPerspectiveCentroidOut:
2225         case EvqNoPerspectiveCentroidIn:
2226             WriteInterpolationDecoration(spv::DecorationNoPerspective, id, fieldIndex,
2227                                          &mSpirvDecorations);
2228             WriteInterpolationDecoration(spv::DecorationCentroid, id, fieldIndex,
2229                                          &mSpirvDecorations);
2230             return;
2231 
2232         case EvqNoPerspectiveSample:
2233         case EvqNoPerspectiveSampleOut:
2234         case EvqNoPerspectiveSampleIn:
2235             WriteInterpolationDecoration(spv::DecorationNoPerspective, id, fieldIndex,
2236                                          &mSpirvDecorations);
2237             WriteInterpolationDecoration(spv::DecorationSample, id, fieldIndex, &mSpirvDecorations);
2238             addCapability(spv::CapabilitySampleRateShading);
2239             return;
2240 
2241         default:
2242             return;
2243     }
2244 }
2245 
getName(const TSymbol * symbol)2246 ImmutableString SPIRVBuilder::getName(const TSymbol *symbol)
2247 {
2248     return symbol->symbolType() == SymbolType::Empty ? ImmutableString("") : symbol->name();
2249 }
2250 
getFieldName(const TField * field)2251 ImmutableString SPIRVBuilder::getFieldName(const TField *field)
2252 {
2253     ASSERT(field->symbolType() != SymbolType::Empty);
2254     return field->name();
2255 }
2256 
getSpirv()2257 spirv::Blob SPIRVBuilder::getSpirv()
2258 {
2259     ASSERT(mConditionalStack.empty());
2260 
2261     spirv::Blob result;
2262 
2263     const spirv::IdRef nonSemanticOverviewId = getNewId({});
2264 
2265     // Reserve a minimum amount of memory.
2266     //
2267     //   5 for header +
2268     //   a number of capabilities +
2269     //   size of already generated instructions.
2270     //
2271     // The actual size is larger due to other metadata instructions such as extensions,
2272     // OpExtInstImport, OpEntryPoint, OpExecutionMode etc.
2273     result.reserve(5 + mCapabilities.size() * 2 + mSpirvDebug.size() + mSpirvDecorations.size() +
2274                    mSpirvTypeAndConstantDecls.size() + mSpirvTypePointerDecls.size() +
2275                    mSpirvFunctionTypeDecls.size() + mSpirvVariableDecls.size() +
2276                    mSpirvFunctions.size());
2277 
2278     // Generate the SPIR-V header.
2279     spirv::WriteSpirvHeader(&result,
2280                             mCompileOptions.emitSPIRV14 ? spirv::kVersion_1_4 : spirv::kVersion_1_3,
2281                             mNextAvailableId);
2282 
2283     // Generate metadata in the following order:
2284     //
2285     // - OpCapability instructions.
2286     for (spv::Capability capability : mCapabilities)
2287     {
2288         spirv::WriteCapability(&result, capability);
2289     }
2290 
2291     // - OpExtension instructions
2292     writeExtensions(&result);
2293 
2294     // Enable the SPV_KHR_non_semantic_info extension to more efficiently communicate information to
2295     // the SPIR-V transformer in the Vulkan backend.  The relevant instructions are all stripped
2296     // away during SPIR-V transformation so the driver never needs to support it.
2297     spirv::WriteExtension(&result, "SPV_KHR_non_semantic_info");
2298 
2299     // - OpExtInstImport
2300     spirv::WriteExtInstImport(&result, getExtInstImportIdStd(), "GLSL.std.450");
2301     spirv::WriteExtInstImport(&result, spirv::IdRef(vk::spirv::kIdNonSemanticInstructionSet),
2302                               "NonSemantic.ANGLE");
2303 
2304     // - OpMemoryModel
2305     spirv::WriteMemoryModel(&result, spv::AddressingModelLogical, spv::MemoryModelGLSL450);
2306 
2307     // - OpEntryPoint
2308     constexpr gl::ShaderMap<spv::ExecutionModel> kExecutionModels = {
2309         {gl::ShaderType::Vertex, spv::ExecutionModelVertex},
2310         {gl::ShaderType::TessControl, spv::ExecutionModelTessellationControl},
2311         {gl::ShaderType::TessEvaluation, spv::ExecutionModelTessellationEvaluation},
2312         {gl::ShaderType::Geometry, spv::ExecutionModelGeometry},
2313         {gl::ShaderType::Fragment, spv::ExecutionModelFragment},
2314         {gl::ShaderType::Compute, spv::ExecutionModelGLCompute},
2315     };
2316     spirv::WriteEntryPoint(&result, kExecutionModels[mShaderType],
2317                            spirv::IdRef(vk::spirv::kIdEntryPoint), "main",
2318                            mEntryPointInterfaceList);
2319 
2320     // - OpExecutionMode instructions
2321     writeExecutionModes(&result);
2322 
2323     // - OpSource and OpSourceExtension instructions.
2324     //
2325     // This is to support debuggers and capture/replay tools and isn't strictly necessary.
2326     spirv::WriteSource(&result, spv::SourceLanguageGLSL, spirv::LiteralInteger(450), nullptr,
2327                        nullptr);
2328     writeSourceExtensions(&result);
2329 
2330     // Append the already generated sections in order
2331     result.insert(result.end(), mSpirvDebug.begin(), mSpirvDebug.end());
2332     result.insert(result.end(), mSpirvDecorations.begin(), mSpirvDecorations.end());
2333     result.insert(result.end(), mSpirvTypeAndConstantDecls.begin(),
2334                   mSpirvTypeAndConstantDecls.end());
2335     result.insert(result.end(), mSpirvTypePointerDecls.begin(), mSpirvTypePointerDecls.end());
2336     result.insert(result.end(), mSpirvFunctionTypeDecls.begin(), mSpirvFunctionTypeDecls.end());
2337     result.insert(result.end(), mSpirvVariableDecls.begin(), mSpirvVariableDecls.end());
2338 
2339     // The types/constants/variables section is the first place non-semantic instructions can be
2340     // output.  These instructions rely on at least the OpVoid type.  The kNonSemanticTypeSectionEnd
2341     // instruction additionally carries an overview of the SPIR-V and thus requires a few OpConstant
2342     // values.
2343     writeNonSemanticOverview(&result, nonSemanticOverviewId);
2344 
2345     result.insert(result.end(), mSpirvFunctions.begin(), mSpirvFunctions.end());
2346 
2347     result.shrink_to_fit();
2348     return result;
2349 }
2350 
writeExecutionModes(spirv::Blob * blob)2351 void SPIRVBuilder::writeExecutionModes(spirv::Blob *blob)
2352 {
2353     const spirv::IdRef entryPointId(vk::spirv::kIdEntryPoint);
2354 
2355     switch (mShaderType)
2356     {
2357         case gl::ShaderType::Fragment:
2358             spirv::WriteExecutionMode(blob, entryPointId, spv::ExecutionModeOriginUpperLeft, {});
2359 
2360             if (mCompiler->isEarlyFragmentTestsSpecified())
2361             {
2362                 spirv::WriteExecutionMode(blob, entryPointId, spv::ExecutionModeEarlyFragmentTests,
2363                                           {});
2364             }
2365 
2366             break;
2367 
2368         case gl::ShaderType::TessControl:
2369             spirv::WriteExecutionMode(
2370                 blob, entryPointId, spv::ExecutionModeOutputVertices,
2371                 {spirv::LiteralInteger(mCompiler->getTessControlShaderOutputVertices())});
2372             break;
2373 
2374         case gl::ShaderType::TessEvaluation:
2375         {
2376             const spv::ExecutionMode inputExecutionMode = GetTessEvalInputExecutionMode(
2377                 mCompiler->getTessEvaluationShaderInputPrimitiveType());
2378             const spv::ExecutionMode spacingExecutionMode = GetTessEvalSpacingExecutionMode(
2379                 mCompiler->getTessEvaluationShaderInputVertexSpacingType());
2380             const spv::ExecutionMode orderingExecutionMode = GetTessEvalOrderingExecutionMode(
2381                 mCompiler->getTessEvaluationShaderInputOrderingType());
2382 
2383             spirv::WriteExecutionMode(blob, entryPointId, inputExecutionMode, {});
2384             spirv::WriteExecutionMode(blob, entryPointId, spacingExecutionMode, {});
2385             spirv::WriteExecutionMode(blob, entryPointId, orderingExecutionMode, {});
2386             if (mCompiler->getTessEvaluationShaderInputPointType() == EtetPointMode)
2387             {
2388                 spirv::WriteExecutionMode(blob, entryPointId, spv::ExecutionModePointMode, {});
2389             }
2390             break;
2391         }
2392 
2393         case gl::ShaderType::Geometry:
2394         {
2395             const spv::ExecutionMode inputExecutionMode =
2396                 GetGeometryInputExecutionMode(mCompiler->getGeometryShaderInputPrimitiveType());
2397             const spv::ExecutionMode outputExecutionMode =
2398                 GetGeometryOutputExecutionMode(mCompiler->getGeometryShaderOutputPrimitiveType());
2399 
2400             // max_vertices=0 is not valid in Vulkan
2401             const int maxVertices = std::max(1, mCompiler->getGeometryShaderMaxVertices());
2402 
2403             spirv::WriteExecutionMode(blob, entryPointId, inputExecutionMode, {});
2404             spirv::WriteExecutionMode(blob, entryPointId, outputExecutionMode, {});
2405             spirv::WriteExecutionMode(blob, entryPointId, spv::ExecutionModeOutputVertices,
2406                                       {spirv::LiteralInteger(maxVertices)});
2407             spirv::WriteExecutionMode(
2408                 blob, entryPointId, spv::ExecutionModeInvocations,
2409                 {spirv::LiteralInteger(mCompiler->getGeometryShaderInvocations())});
2410 
2411             break;
2412         }
2413 
2414         case gl::ShaderType::Compute:
2415         {
2416             const sh::WorkGroupSize &localSize = mCompiler->getComputeShaderLocalSize();
2417             spirv::WriteExecutionMode(
2418                 blob, entryPointId, spv::ExecutionModeLocalSize,
2419                 {spirv::LiteralInteger(localSize[0]), spirv::LiteralInteger(localSize[1]),
2420                  spirv::LiteralInteger(localSize[2])});
2421             break;
2422         }
2423 
2424         default:
2425             break;
2426     }
2427 
2428     // Add any execution modes that were added due to built-ins used in the shader.
2429     for (spv::ExecutionMode executionMode : mExecutionModes)
2430     {
2431         spirv::WriteExecutionMode(blob, entryPointId, executionMode, {});
2432     }
2433 }
2434 
writeExtensions(spirv::Blob * blob)2435 void SPIRVBuilder::writeExtensions(spirv::Blob *blob)
2436 {
2437     for (SPIRVExtensions extension : mExtensions)
2438     {
2439         switch (extension)
2440         {
2441             case SPIRVExtensions::MultiviewOVR:
2442                 spirv::WriteExtension(blob, "SPV_KHR_multiview");
2443                 break;
2444             case SPIRVExtensions::FragmentShaderInterlockARB:
2445                 spirv::WriteExtension(blob, "SPV_EXT_fragment_shader_interlock");
2446                 break;
2447             default:
2448                 UNREACHABLE();
2449         }
2450     }
2451 }
2452 
writeSourceExtensions(spirv::Blob * blob)2453 void SPIRVBuilder::writeSourceExtensions(spirv::Blob *blob)
2454 {
2455     for (SPIRVExtensions extension : mExtensions)
2456     {
2457         switch (extension)
2458         {
2459             case SPIRVExtensions::MultiviewOVR:
2460                 spirv::WriteSourceExtension(blob, "GL_OVR_multiview");
2461                 break;
2462             case SPIRVExtensions::FragmentShaderInterlockARB:
2463                 spirv::WriteSourceExtension(blob, "GL_ARB_fragment_shader_interlock");
2464                 break;
2465             default:
2466                 UNREACHABLE();
2467         }
2468     }
2469 }
2470 
writeNonSemanticOverview(spirv::Blob * blob,spirv::IdRef id)2471 void SPIRVBuilder::writeNonSemanticOverview(spirv::Blob *blob, spirv::IdRef id)
2472 {
2473     // Output the kNonSemanticOverview non-semantic instruction.  The top unused bits of the
2474     // instruction id are used to communicate addition information already gathered in
2475     // mOverviewFlags (bits defined by kOverview*Bit).
2476 
2477     using namespace vk::spirv;
2478 
2479     ASSERT((mOverviewFlags & vk::spirv::kNonSemanticInstructionMask) == 0);
2480     const uint32_t overview = kNonSemanticOverview | mOverviewFlags;
2481 
2482     spirv::WriteExtInst(blob, spirv::IdResultType(kIdVoid), id,
2483                         spirv::IdRef(kIdNonSemanticInstructionSet),
2484                         spirv::LiteralExtInstInteger(overview), {});
2485 }
2486 
writeNonSemanticInstruction(vk::spirv::NonSemanticInstruction instruction)2487 void SPIRVBuilder::writeNonSemanticInstruction(vk::spirv::NonSemanticInstruction instruction)
2488 {
2489     using namespace vk::spirv;
2490 
2491     const spirv::IdRef id = getNewId({});
2492 
2493     spirv::WriteExtInst(getSpirvCurrentFunctionBlock(), spirv::IdResultType(kIdVoid), id,
2494                         spirv::IdRef(kIdNonSemanticInstructionSet),
2495                         spirv::LiteralExtInstInteger(instruction), {});
2496 }
2497 
2498 }  // namespace sh
2499