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 ¶mTypeIds)
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));
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 EbtDouble:
1067                 // TODO: support desktop GLSL.  http://anglebug.com/6197
1068                 UNIMPLEMENTED();
1069                 break;
1070             case EbtBool:
1071                 spirv::WriteTypeBool(&mSpirvTypeAndConstantDecls, typeId);
1072                 break;
1073             default:
1074                 UNREACHABLE();
1075         }
1076     }
1077 
1078     // If this was a block declaration, add debug information for its type and field names.
1079     if (mCompileOptions.outputDebugInfo && block != nullptr && type.arraySizes.empty())
1080     {
1081         writeBlockDebugNames(type.block, typeId, getName(block).data());
1082     }
1083 
1084     // Write decorations for interface block fields.
1085     if (type.typeSpec.blockStorage != EbsUnspecified)
1086     {
1087         // Cannot have opaque uniforms inside interface blocks.
1088         ASSERT(!IsOpaqueType(type.type));
1089 
1090         const bool isInterfaceBlock = block != nullptr && block->isInterfaceBlock();
1091         const bool isStd140         = type.typeSpec.blockStorage != EbsStd430;
1092 
1093         if (!type.arraySizes.empty() && !isInterfaceBlock)
1094         {
1095             // Write the ArrayStride decoration for arrays inside interface blocks.  An array of
1096             // interface blocks doesn't need a stride.
1097             const ShaderVariable var = SpirvTypeToShaderVariable(type);
1098             const uint32_t stride    = GetArrayStrideInBlock(var, isStd140);
1099 
1100             spirv::WriteDecorate(&mSpirvDecorations, typeId, spv::DecorationArrayStride,
1101                                  {spirv::LiteralInteger(stride)});
1102         }
1103         else if (type.arraySizes.empty() && type.block != nullptr)
1104         {
1105             // Write the Offset decoration for interface blocks and structs in them.
1106             const ShaderVariable var = SpirvTypeToShaderVariable(type);
1107             Encode(var, isStd140, typeId, &mSpirvDecorations);
1108         }
1109     }
1110 
1111     // Write other member decorations.
1112     if (block != nullptr && type.arraySizes.empty())
1113     {
1114         writeMemberDecorations(type, typeId);
1115     }
1116 
1117     return {typeId};
1118 }
1119 
getImageTypeParameters(TBasicType type,spirv::IdRef * sampledTypeOut,spv::Dim * dimOut,spirv::LiteralInteger * depthOut,spirv::LiteralInteger * arrayedOut,spirv::LiteralInteger * multisampledOut,spirv::LiteralInteger * sampledOut)1120 void SPIRVBuilder::getImageTypeParameters(TBasicType type,
1121                                           spirv::IdRef *sampledTypeOut,
1122                                           spv::Dim *dimOut,
1123                                           spirv::LiteralInteger *depthOut,
1124                                           spirv::LiteralInteger *arrayedOut,
1125                                           spirv::LiteralInteger *multisampledOut,
1126                                           spirv::LiteralInteger *sampledOut)
1127 {
1128     TBasicType sampledType = EbtFloat;
1129     *dimOut                = IsSubpassInputType(type) ? spv::DimSubpassData : spv::Dim2D;
1130     bool isDepth           = false;
1131     bool isArrayed         = false;
1132     bool isMultisampled    = false;
1133 
1134     // Decompose the basic type into image properties
1135     switch (type)
1136     {
1137         // Float 2D Images
1138         case EbtSampler2D:
1139         case EbtImage2D:
1140         case EbtSubpassInput:
1141             break;
1142         case EbtSamplerExternalOES:
1143         case EbtSamplerExternal2DY2YEXT:
1144         case EbtSamplerVideoWEBGL:
1145             // These must have already been converted to EbtSampler2D.
1146             UNREACHABLE();
1147             break;
1148         case EbtSampler2DArray:
1149         case EbtImage2DArray:
1150             isArrayed = true;
1151             break;
1152         case EbtSampler2DMS:
1153         case EbtImage2DMS:
1154         case EbtSubpassInputMS:
1155             isMultisampled = true;
1156             break;
1157         case EbtSampler2DMSArray:
1158         case EbtImage2DMSArray:
1159             isArrayed      = true;
1160             isMultisampled = true;
1161             break;
1162         case EbtSampler2DShadow:
1163             isDepth = true;
1164             break;
1165         case EbtSampler2DArrayShadow:
1166             isDepth   = true;
1167             isArrayed = true;
1168             break;
1169 
1170         // Integer 2D images
1171         case EbtISampler2D:
1172         case EbtIImage2D:
1173         case EbtISubpassInput:
1174             sampledType = EbtInt;
1175             break;
1176         case EbtISampler2DArray:
1177         case EbtIImage2DArray:
1178             sampledType = EbtInt;
1179             isArrayed   = true;
1180             break;
1181         case EbtISampler2DMS:
1182         case EbtIImage2DMS:
1183         case EbtISubpassInputMS:
1184             sampledType    = EbtInt;
1185             isMultisampled = true;
1186             break;
1187         case EbtISampler2DMSArray:
1188         case EbtIImage2DMSArray:
1189             sampledType    = EbtInt;
1190             isArrayed      = true;
1191             isMultisampled = true;
1192             break;
1193 
1194         // Unsinged integer 2D images
1195         case EbtUSampler2D:
1196         case EbtUImage2D:
1197         case EbtUSubpassInput:
1198             sampledType = EbtUInt;
1199             break;
1200         case EbtUSampler2DArray:
1201         case EbtUImage2DArray:
1202             sampledType = EbtUInt;
1203             isArrayed   = true;
1204             break;
1205         case EbtUSampler2DMS:
1206         case EbtUImage2DMS:
1207         case EbtUSubpassInputMS:
1208             sampledType    = EbtUInt;
1209             isMultisampled = true;
1210             break;
1211         case EbtUSampler2DMSArray:
1212         case EbtUImage2DMSArray:
1213             sampledType    = EbtUInt;
1214             isArrayed      = true;
1215             isMultisampled = true;
1216             break;
1217 
1218         // 3D images
1219         case EbtSampler3D:
1220         case EbtImage3D:
1221             *dimOut = spv::Dim3D;
1222             break;
1223         case EbtISampler3D:
1224         case EbtIImage3D:
1225             sampledType = EbtInt;
1226             *dimOut     = spv::Dim3D;
1227             break;
1228         case EbtUSampler3D:
1229         case EbtUImage3D:
1230             sampledType = EbtUInt;
1231             *dimOut     = spv::Dim3D;
1232             break;
1233 
1234         // Float cube images
1235         case EbtSamplerCube:
1236         case EbtImageCube:
1237             *dimOut = spv::DimCube;
1238             break;
1239         case EbtSamplerCubeArray:
1240         case EbtImageCubeArray:
1241             *dimOut   = spv::DimCube;
1242             isArrayed = true;
1243             break;
1244         case EbtSamplerCubeArrayShadow:
1245             *dimOut   = spv::DimCube;
1246             isDepth   = true;
1247             isArrayed = true;
1248             break;
1249         case EbtSamplerCubeShadow:
1250             *dimOut = spv::DimCube;
1251             isDepth = true;
1252             break;
1253 
1254         // Integer cube images
1255         case EbtISamplerCube:
1256         case EbtIImageCube:
1257             sampledType = EbtInt;
1258             *dimOut     = spv::DimCube;
1259             break;
1260         case EbtISamplerCubeArray:
1261         case EbtIImageCubeArray:
1262             sampledType = EbtInt;
1263             *dimOut     = spv::DimCube;
1264             isArrayed   = true;
1265             break;
1266 
1267         // Unsigned integer cube images
1268         case EbtUSamplerCube:
1269         case EbtUImageCube:
1270             sampledType = EbtUInt;
1271             *dimOut     = spv::DimCube;
1272             break;
1273         case EbtUSamplerCubeArray:
1274         case EbtUImageCubeArray:
1275             sampledType = EbtUInt;
1276             *dimOut     = spv::DimCube;
1277             isArrayed   = true;
1278             break;
1279 
1280         // Float 1D images
1281         case EbtSampler1D:
1282         case EbtImage1D:
1283             *dimOut = spv::Dim1D;
1284             break;
1285         case EbtSampler1DArray:
1286         case EbtImage1DArray:
1287             *dimOut   = spv::Dim1D;
1288             isArrayed = true;
1289             break;
1290         case EbtSampler1DShadow:
1291             *dimOut = spv::Dim1D;
1292             isDepth = true;
1293             break;
1294         case EbtSampler1DArrayShadow:
1295             *dimOut   = spv::Dim1D;
1296             isDepth   = true;
1297             isArrayed = true;
1298             break;
1299 
1300         // Integer 1D images
1301         case EbtISampler1D:
1302         case EbtIImage1D:
1303             sampledType = EbtInt;
1304             *dimOut     = spv::Dim1D;
1305             break;
1306         case EbtISampler1DArray:
1307         case EbtIImage1DArray:
1308             sampledType = EbtInt;
1309             *dimOut     = spv::Dim1D;
1310             isArrayed   = true;
1311             break;
1312 
1313         // Unsigned integer 1D images
1314         case EbtUSampler1D:
1315         case EbtUImage1D:
1316             sampledType = EbtUInt;
1317             *dimOut     = spv::Dim1D;
1318             break;
1319         case EbtUSampler1DArray:
1320         case EbtUImage1DArray:
1321             sampledType = EbtUInt;
1322             *dimOut     = spv::Dim1D;
1323             isArrayed   = true;
1324             break;
1325 
1326         // Rect images
1327         case EbtSampler2DRect:
1328         case EbtImageRect:
1329             *dimOut = spv::DimRect;
1330             break;
1331         case EbtSampler2DRectShadow:
1332             *dimOut = spv::DimRect;
1333             isDepth = true;
1334             break;
1335         case EbtISampler2DRect:
1336         case EbtIImageRect:
1337             sampledType = EbtInt;
1338             *dimOut     = spv::DimRect;
1339             break;
1340         case EbtUSampler2DRect:
1341         case EbtUImageRect:
1342             sampledType = EbtUInt;
1343             *dimOut     = spv::DimRect;
1344             break;
1345 
1346         // Image buffers
1347         case EbtSamplerBuffer:
1348         case EbtImageBuffer:
1349             *dimOut = spv::DimBuffer;
1350             break;
1351         case EbtISamplerBuffer:
1352         case EbtIImageBuffer:
1353             sampledType = EbtInt;
1354             *dimOut     = spv::DimBuffer;
1355             break;
1356         case EbtUSamplerBuffer:
1357         case EbtUImageBuffer:
1358             sampledType = EbtUInt;
1359             *dimOut     = spv::DimBuffer;
1360             break;
1361         default:
1362             UNREACHABLE();
1363     }
1364 
1365     // Get id of the component type of the image
1366     SpirvType sampledSpirvType;
1367     sampledSpirvType.type = sampledType;
1368 
1369     *sampledTypeOut = getSpirvTypeData(sampledSpirvType, nullptr).id;
1370 
1371     const bool isSampledImage = IsSampler(type);
1372 
1373     // Set flags based on SPIR-V required values.  See OpTypeImage:
1374     //
1375     // - For depth:        0 = non-depth,      1 = depth
1376     // - For arrayed:      0 = non-arrayed,    1 = arrayed
1377     // - For multisampled: 0 = single-sampled, 1 = multisampled
1378     // - For sampled:      1 = sampled,        2 = storage
1379     //
1380     *depthOut        = spirv::LiteralInteger(isDepth ? 1 : 0);
1381     *arrayedOut      = spirv::LiteralInteger(isArrayed ? 1 : 0);
1382     *multisampledOut = spirv::LiteralInteger(isMultisampled ? 1 : 0);
1383     *sampledOut      = spirv::LiteralInteger(isSampledImage ? 1 : 2);
1384 
1385     // Add the necessary capability based on parameters.  The SPIR-V spec section 3.8 Dim specfies
1386     // the required capabilities:
1387     //
1388     //     Dim          Sampled         Storage            Storage Array
1389     //     --------------------------------------------------------------
1390     //     1D           Sampled1D       Image1D
1391     //     2D           Shader                             ImageMSArray
1392     //     3D
1393     //     Cube         Shader                             ImageCubeArray
1394     //     Rect         SampledRect     ImageRect
1395     //     Buffer       SampledBuffer   ImageBuffer
1396     //
1397     // Additionally, the SubpassData Dim requires the InputAttachment capability.
1398     //
1399     // Note that the Shader capability is always unconditionally added.
1400     //
1401     switch (*dimOut)
1402     {
1403         case spv::Dim1D:
1404             addCapability(isSampledImage ? spv::CapabilitySampled1D : spv::CapabilityImage1D);
1405             break;
1406         case spv::Dim2D:
1407             if (!isSampledImage && isArrayed && isMultisampled)
1408             {
1409                 addCapability(spv::CapabilityImageMSArray);
1410             }
1411             break;
1412         case spv::Dim3D:
1413             break;
1414         case spv::DimCube:
1415             if (!isSampledImage && isArrayed)
1416             {
1417                 addCapability(spv::CapabilityImageCubeArray);
1418             }
1419             break;
1420         case spv::DimRect:
1421             addCapability(isSampledImage ? spv::CapabilitySampledRect : spv::CapabilityImageRect);
1422             break;
1423         case spv::DimBuffer:
1424             addCapability(isSampledImage ? spv::CapabilitySampledBuffer
1425                                          : spv::CapabilityImageBuffer);
1426             break;
1427         case spv::DimSubpassData:
1428             addCapability(spv::CapabilityInputAttachment);
1429             break;
1430         default:
1431             UNREACHABLE();
1432     }
1433 }
1434 
getImageFormat(TLayoutImageInternalFormat imageInternalFormat)1435 spv::ImageFormat SPIRVBuilder::getImageFormat(TLayoutImageInternalFormat imageInternalFormat)
1436 {
1437     switch (imageInternalFormat)
1438     {
1439         case EiifUnspecified:
1440             return spv::ImageFormatUnknown;
1441         case EiifRGBA32F:
1442             return spv::ImageFormatRgba32f;
1443         case EiifRGBA16F:
1444             return spv::ImageFormatRgba16f;
1445         case EiifR32F:
1446             return spv::ImageFormatR32f;
1447         case EiifRGBA32UI:
1448             return spv::ImageFormatRgba32ui;
1449         case EiifRGBA16UI:
1450             return spv::ImageFormatRgba16ui;
1451         case EiifRGBA8UI:
1452             return spv::ImageFormatRgba8ui;
1453         case EiifR32UI:
1454             return spv::ImageFormatR32ui;
1455         case EiifRGBA32I:
1456             return spv::ImageFormatRgba32i;
1457         case EiifRGBA16I:
1458             return spv::ImageFormatRgba16i;
1459         case EiifRGBA8I:
1460             return spv::ImageFormatRgba8i;
1461         case EiifR32I:
1462             return spv::ImageFormatR32i;
1463         case EiifRGBA8:
1464             return spv::ImageFormatRgba8;
1465         case EiifRGBA8_SNORM:
1466             return spv::ImageFormatRgba8Snorm;
1467         default:
1468             UNREACHABLE();
1469             return spv::ImageFormatUnknown;
1470     }
1471 }
1472 
getBoolConstant(bool value)1473 spirv::IdRef SPIRVBuilder::getBoolConstant(bool value)
1474 {
1475     uint32_t asInt = static_cast<uint32_t>(value);
1476 
1477     spirv::IdRef constantId = mBoolConstants[asInt];
1478 
1479     if (!constantId.valid())
1480     {
1481         SpirvType boolType;
1482         boolType.type = EbtBool;
1483 
1484         const spirv::IdRef boolTypeId = getSpirvTypeData(boolType, nullptr).id;
1485 
1486         mBoolConstants[asInt] = constantId = getNewId({});
1487         if (value)
1488         {
1489             spirv::WriteConstantTrue(&mSpirvTypeAndConstantDecls, boolTypeId, constantId);
1490         }
1491         else
1492         {
1493             spirv::WriteConstantFalse(&mSpirvTypeAndConstantDecls, boolTypeId, constantId);
1494         }
1495     }
1496 
1497     return constantId;
1498 }
1499 
getBasicConstantHelper(uint32_t value,TBasicType type,angle::HashMap<uint32_t,spirv::IdRef> * constants)1500 spirv::IdRef SPIRVBuilder::getBasicConstantHelper(uint32_t value,
1501                                                   TBasicType type,
1502                                                   angle::HashMap<uint32_t, spirv::IdRef> *constants)
1503 {
1504     auto iter = constants->find(value);
1505     if (iter != constants->end())
1506     {
1507         return iter->second;
1508     }
1509 
1510     SpirvType spirvType;
1511     spirvType.type = type;
1512 
1513     const spirv::IdRef typeId     = getSpirvTypeData(spirvType, nullptr).id;
1514     const spirv::IdRef constantId = getNewId({});
1515 
1516     spirv::WriteConstant(&mSpirvTypeAndConstantDecls, typeId, constantId,
1517                          spirv::LiteralContextDependentNumber(value));
1518 
1519     return constants->insert({value, constantId}).first->second;
1520 }
1521 
getUintConstant(uint32_t value)1522 spirv::IdRef SPIRVBuilder::getUintConstant(uint32_t value)
1523 {
1524     return getBasicConstantHelper(value, EbtUInt, &mUintConstants);
1525 }
1526 
getIntConstant(int32_t value)1527 spirv::IdRef SPIRVBuilder::getIntConstant(int32_t value)
1528 {
1529     uint32_t asUint = static_cast<uint32_t>(value);
1530     return getBasicConstantHelper(asUint, EbtInt, &mIntConstants);
1531 }
1532 
getFloatConstant(float value)1533 spirv::IdRef SPIRVBuilder::getFloatConstant(float value)
1534 {
1535     union
1536     {
1537         float f;
1538         uint32_t u;
1539     } asUint;
1540     asUint.f = value;
1541     return getBasicConstantHelper(asUint.u, EbtFloat, &mFloatConstants);
1542 }
1543 
getNullConstant(spirv::IdRef typeId)1544 spirv::IdRef SPIRVBuilder::getNullConstant(spirv::IdRef typeId)
1545 {
1546     if (typeId >= mNullConstants.size())
1547     {
1548         mNullConstants.resize(typeId + 1);
1549     }
1550 
1551     if (!mNullConstants[typeId].valid())
1552     {
1553         const spirv::IdRef constantId = getNewId({});
1554         mNullConstants[typeId]        = constantId;
1555 
1556         spirv::WriteConstantNull(&mSpirvTypeAndConstantDecls, typeId, constantId);
1557     }
1558 
1559     return mNullConstants[typeId];
1560 }
1561 
getNullVectorConstantHelper(TBasicType type,int size)1562 spirv::IdRef SPIRVBuilder::getNullVectorConstantHelper(TBasicType type, int size)
1563 {
1564     SpirvType vecType;
1565     vecType.type        = type;
1566     vecType.primarySize = static_cast<uint8_t>(size);
1567 
1568     return getNullConstant(getSpirvTypeData(vecType, nullptr).id);
1569 }
1570 
getVectorConstantHelper(spirv::IdRef valueId,TBasicType type,int size)1571 spirv::IdRef SPIRVBuilder::getVectorConstantHelper(spirv::IdRef valueId, TBasicType type, int size)
1572 {
1573     if (size == 1)
1574     {
1575         return valueId;
1576     }
1577 
1578     SpirvType vecType;
1579     vecType.type        = type;
1580     vecType.primarySize = static_cast<uint8_t>(size);
1581 
1582     const spirv::IdRef typeId = getSpirvTypeData(vecType, nullptr).id;
1583     const spirv::IdRefList valueIds(size, valueId);
1584 
1585     return getCompositeConstant(typeId, valueIds);
1586 }
1587 
getUvecConstant(uint32_t value,int size)1588 spirv::IdRef SPIRVBuilder::getUvecConstant(uint32_t value, int size)
1589 {
1590     if (value == 0)
1591     {
1592         return getNullVectorConstantHelper(EbtUInt, size);
1593     }
1594 
1595     const spirv::IdRef valueId = getUintConstant(value);
1596     return getVectorConstantHelper(valueId, EbtUInt, size);
1597 }
1598 
getIvecConstant(int32_t value,int size)1599 spirv::IdRef SPIRVBuilder::getIvecConstant(int32_t value, int size)
1600 {
1601     if (value == 0)
1602     {
1603         return getNullVectorConstantHelper(EbtInt, size);
1604     }
1605 
1606     const spirv::IdRef valueId = getIntConstant(value);
1607     return getVectorConstantHelper(valueId, EbtInt, size);
1608 }
1609 
getVecConstant(float value,int size)1610 spirv::IdRef SPIRVBuilder::getVecConstant(float value, int size)
1611 {
1612     if (value == 0)
1613     {
1614         return getNullVectorConstantHelper(EbtFloat, size);
1615     }
1616 
1617     const spirv::IdRef valueId = getFloatConstant(value);
1618     return getVectorConstantHelper(valueId, EbtFloat, size);
1619 }
1620 
getCompositeConstant(spirv::IdRef typeId,const spirv::IdRefList & values)1621 spirv::IdRef SPIRVBuilder::getCompositeConstant(spirv::IdRef typeId, const spirv::IdRefList &values)
1622 {
1623     SpirvIdAndIdList key{typeId, values};
1624 
1625     auto iter = mCompositeConstants.find(key);
1626     if (iter == mCompositeConstants.end())
1627     {
1628         const spirv::IdRef constantId = getNewId({});
1629 
1630         spirv::WriteConstantComposite(&mSpirvTypeAndConstantDecls, typeId, constantId, values);
1631 
1632         iter = mCompositeConstants.insert({key, constantId}).first;
1633     }
1634 
1635     return iter->second;
1636 }
1637 
startNewFunction(spirv::IdRef functionId,const TFunction * func)1638 void SPIRVBuilder::startNewFunction(spirv::IdRef functionId, const TFunction *func)
1639 {
1640     ASSERT(mSpirvCurrentFunctionBlocks.empty());
1641 
1642     // Add the first block of the function.
1643     mSpirvCurrentFunctionBlocks.emplace_back();
1644     mSpirvCurrentFunctionBlocks.back().labelId = getNewId({});
1645 
1646     // Output debug information.
1647     writeDebugName(functionId, getName(func).data());
1648 }
1649 
assembleSpirvFunctionBlocks()1650 void SPIRVBuilder::assembleSpirvFunctionBlocks()
1651 {
1652     // Take all the blocks and place them in the functions section of SPIR-V in sequence.
1653     for (const SpirvBlock &block : mSpirvCurrentFunctionBlocks)
1654     {
1655         // Every block must be properly terminated.
1656         ASSERT(block.isTerminated);
1657 
1658         // Generate the OpLabel instruction for the block.
1659         spirv::WriteLabel(&mSpirvFunctions, block.labelId);
1660 
1661         // Add the variable declarations if any.
1662         mSpirvFunctions.insert(mSpirvFunctions.end(), block.localVariables.begin(),
1663                                block.localVariables.end());
1664 
1665         // Add the body of the block.
1666         mSpirvFunctions.insert(mSpirvFunctions.end(), block.body.begin(), block.body.end());
1667     }
1668 
1669     // Clean up.
1670     mSpirvCurrentFunctionBlocks.clear();
1671 }
1672 
declareVariable(spirv::IdRef typeId,spv::StorageClass storageClass,const SpirvDecorations & decorations,spirv::IdRef * initializerId,const char * name,const TSymbolUniqueId * uniqueId)1673 spirv::IdRef SPIRVBuilder::declareVariable(spirv::IdRef typeId,
1674                                            spv::StorageClass storageClass,
1675                                            const SpirvDecorations &decorations,
1676                                            spirv::IdRef *initializerId,
1677                                            const char *name,
1678                                            const TSymbolUniqueId *uniqueId)
1679 {
1680     const bool isFunctionLocal = storageClass == spv::StorageClassFunction;
1681 
1682     // Make sure storage class is consistent with where the variable is declared.
1683     ASSERT(!isFunctionLocal || !mSpirvCurrentFunctionBlocks.empty());
1684 
1685     // Function-local variables go in the first block of the function, while the rest are in the
1686     // global variables section.
1687     spirv::Blob *spirvSection = isFunctionLocal
1688                                     ? &mSpirvCurrentFunctionBlocks.front().localVariables
1689                                     : &mSpirvVariableDecls;
1690 
1691     const spirv::IdRef typePointerId = getTypePointerId(typeId, storageClass);
1692     spirv::IdRef variableId;
1693     if (uniqueId)
1694     {
1695         variableId = getReservedOrNewId(*uniqueId, decorations);
1696 
1697         if (variableId == vk::spirv::kIdOutputPerVertexVar)
1698         {
1699             mOverviewFlags |= vk::spirv::kOverviewHasOutputPerVertexMask;
1700         }
1701         else if (variableId == vk::spirv::kIdSampleID)
1702         {
1703             mOverviewFlags |= vk::spirv::kOverviewHasSampleIDMask;
1704         }
1705     }
1706     else
1707     {
1708         variableId = getNewId(decorations);
1709     }
1710 
1711     spirv::WriteVariable(spirvSection, typePointerId, variableId, storageClass, initializerId);
1712 
1713     // Output debug information.
1714     if (name)
1715     {
1716         writeDebugName(variableId, name);
1717     }
1718 
1719     return variableId;
1720 }
1721 
declareSpecConst(TBasicType type,int id,const char * name)1722 spirv::IdRef SPIRVBuilder::declareSpecConst(TBasicType type, int id, const char *name)
1723 {
1724     SpirvType spirvType;
1725     spirvType.type = type;
1726 
1727     const spirv::IdRef typeId      = getSpirvTypeData(spirvType, nullptr).id;
1728     const spirv::IdRef specConstId = getNewId({});
1729 
1730     // Note: all spec constants are 0 initialized by the translator.
1731     if (type == EbtBool)
1732     {
1733         spirv::WriteSpecConstantFalse(&mSpirvTypeAndConstantDecls, typeId, specConstId);
1734     }
1735     else
1736     {
1737         spirv::WriteSpecConstant(&mSpirvTypeAndConstantDecls, typeId, specConstId,
1738                                  spirv::LiteralContextDependentNumber(0));
1739     }
1740 
1741     // Add the SpecId decoration
1742     spirv::WriteDecorate(&mSpirvDecorations, specConstId, spv::DecorationSpecId,
1743                          {spirv::LiteralInteger(id)});
1744 
1745     // Output debug information.
1746     if (name)
1747     {
1748         writeDebugName(specConstId, name);
1749     }
1750 
1751     return specConstId;
1752 }
1753 
startConditional(size_t blockCount,bool isContinuable,bool isBreakable)1754 void SPIRVBuilder::startConditional(size_t blockCount, bool isContinuable, bool isBreakable)
1755 {
1756     mConditionalStack.emplace_back();
1757     SpirvConditional &conditional = mConditionalStack.back();
1758 
1759     // Create the requested number of block ids.
1760     conditional.blockIds.resize(blockCount);
1761     for (spirv::IdRef &blockId : conditional.blockIds)
1762     {
1763         blockId = getNewId({});
1764     }
1765 
1766     conditional.isContinuable = isContinuable;
1767     conditional.isBreakable   = isBreakable;
1768 
1769     // Don't automatically start the next block.  The caller needs to generate instructions based on
1770     // the ids that were just generated above.
1771 }
1772 
nextConditionalBlock()1773 void SPIRVBuilder::nextConditionalBlock()
1774 {
1775     ASSERT(!mConditionalStack.empty());
1776     SpirvConditional &conditional = mConditionalStack.back();
1777 
1778     ASSERT(conditional.nextBlockToWrite < conditional.blockIds.size());
1779     const spirv::IdRef blockId = conditional.blockIds[conditional.nextBlockToWrite++];
1780 
1781     // The previous block must have properly terminated.
1782     ASSERT(isCurrentFunctionBlockTerminated());
1783 
1784     // Generate a new block.
1785     mSpirvCurrentFunctionBlocks.emplace_back();
1786     mSpirvCurrentFunctionBlocks.back().labelId = blockId;
1787 }
1788 
endConditional()1789 void SPIRVBuilder::endConditional()
1790 {
1791     ASSERT(!mConditionalStack.empty());
1792 
1793     // No blocks should be left.
1794     ASSERT(mConditionalStack.back().nextBlockToWrite == mConditionalStack.back().blockIds.size());
1795 
1796     mConditionalStack.pop_back();
1797 }
1798 
isInLoop() const1799 bool SPIRVBuilder::isInLoop() const
1800 {
1801     for (const SpirvConditional &conditional : mConditionalStack)
1802     {
1803         if (conditional.isContinuable)
1804         {
1805             return true;
1806         }
1807     }
1808 
1809     return false;
1810 }
1811 
getBreakTargetId() const1812 spirv::IdRef SPIRVBuilder::getBreakTargetId() const
1813 {
1814     for (size_t index = mConditionalStack.size(); index > 0; --index)
1815     {
1816         const SpirvConditional &conditional = mConditionalStack[index - 1];
1817 
1818         if (conditional.isBreakable)
1819         {
1820             // The target of break; is always the merge block, and the merge block is always the
1821             // last block.
1822             return conditional.blockIds.back();
1823         }
1824     }
1825 
1826     UNREACHABLE();
1827     return spirv::IdRef{};
1828 }
1829 
getContinueTargetId() const1830 spirv::IdRef SPIRVBuilder::getContinueTargetId() const
1831 {
1832     for (size_t index = mConditionalStack.size(); index > 0; --index)
1833     {
1834         const SpirvConditional &conditional = mConditionalStack[index - 1];
1835 
1836         if (conditional.isContinuable)
1837         {
1838             // The target of continue; is always the block before merge, so it's the one before
1839             // last.
1840             ASSERT(conditional.blockIds.size() > 2);
1841             return conditional.blockIds[conditional.blockIds.size() - 2];
1842         }
1843     }
1844 
1845     UNREACHABLE();
1846     return spirv::IdRef{};
1847 }
1848 
nextUnusedBinding()1849 uint32_t SPIRVBuilder::nextUnusedBinding()
1850 {
1851     return mNextUnusedBinding++;
1852 }
1853 
nextUnusedInputLocation(uint32_t consumedCount)1854 uint32_t SPIRVBuilder::nextUnusedInputLocation(uint32_t consumedCount)
1855 {
1856     uint32_t nextUnused = mNextUnusedInputLocation;
1857     mNextUnusedInputLocation += consumedCount;
1858     return nextUnused;
1859 }
1860 
nextUnusedOutputLocation(uint32_t consumedCount)1861 uint32_t SPIRVBuilder::nextUnusedOutputLocation(uint32_t consumedCount)
1862 {
1863     uint32_t nextUnused = mNextUnusedOutputLocation;
1864     mNextUnusedOutputLocation += consumedCount;
1865     return nextUnused;
1866 }
1867 
isInvariantOutput(const TType & type) const1868 bool SPIRVBuilder::isInvariantOutput(const TType &type) const
1869 {
1870     return IsInvariant(type, mCompiler);
1871 }
1872 
addCapability(spv::Capability capability)1873 void SPIRVBuilder::addCapability(spv::Capability capability)
1874 {
1875     mCapabilities.insert(capability);
1876 
1877     if (capability == spv::CapabilitySampleRateShading)
1878     {
1879         mOverviewFlags |= vk::spirv::kOverviewHasSampleRateShadingMask;
1880     }
1881 }
1882 
addExecutionMode(spv::ExecutionMode executionMode)1883 void SPIRVBuilder::addExecutionMode(spv::ExecutionMode executionMode)
1884 {
1885     mExecutionModes.insert(executionMode);
1886 }
1887 
addExtension(SPIRVExtensions extension)1888 void SPIRVBuilder::addExtension(SPIRVExtensions extension)
1889 {
1890     mExtensions.set(extension);
1891 }
1892 
addEntryPointInterfaceVariableId(spirv::IdRef id)1893 void SPIRVBuilder::addEntryPointInterfaceVariableId(spirv::IdRef id)
1894 {
1895     mEntryPointInterfaceList.push_back(id);
1896 }
1897 
writePerVertexBuiltIns(const TType & type,spirv::IdRef typeId)1898 void SPIRVBuilder::writePerVertexBuiltIns(const TType &type, spirv::IdRef typeId)
1899 {
1900     ASSERT(type.isInterfaceBlock());
1901     const TInterfaceBlock *block = type.getInterfaceBlock();
1902 
1903     uint32_t fieldIndex = 0;
1904     for (const TField *field : block->fields())
1905     {
1906         spv::BuiltIn decorationValue = spv::BuiltInPosition;
1907         switch (field->type()->getQualifier())
1908         {
1909             case EvqPosition:
1910                 decorationValue = spv::BuiltInPosition;
1911                 break;
1912             case EvqPointSize:
1913                 decorationValue = spv::BuiltInPointSize;
1914                 break;
1915             case EvqClipDistance:
1916                 decorationValue = spv::BuiltInClipDistance;
1917                 break;
1918             case EvqCullDistance:
1919                 decorationValue = spv::BuiltInCullDistance;
1920                 break;
1921             default:
1922                 UNREACHABLE();
1923         }
1924 
1925         spirv::WriteMemberDecorate(&mSpirvDecorations, typeId, spirv::LiteralInteger(fieldIndex++),
1926                                    spv::DecorationBuiltIn,
1927                                    {spirv::LiteralInteger(decorationValue)});
1928     }
1929 }
1930 
writeInterfaceVariableDecorations(const TType & type,spirv::IdRef variableId)1931 void SPIRVBuilder::writeInterfaceVariableDecorations(const TType &type, spirv::IdRef variableId)
1932 {
1933     const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
1934     const bool isVarying                    = IsVarying(type.getQualifier());
1935     const bool needsSetBinding =
1936         !layoutQualifier.pushConstant &&
1937         (IsSampler(type.getBasicType()) ||
1938          (type.isInterfaceBlock() &&
1939           (type.getQualifier() == EvqUniform || type.getQualifier() == EvqBuffer)) ||
1940          IsImage(type.getBasicType()) || IsSubpassInputType(type.getBasicType()));
1941     const bool needsLocation = type.getQualifier() == EvqAttribute ||
1942                                type.getQualifier() == EvqVertexIn ||
1943                                type.getQualifier() == EvqFragmentOut || isVarying;
1944     const bool needsInputAttachmentIndex = IsSubpassInputType(type.getBasicType());
1945     const bool needsBlendIndex =
1946         type.getQualifier() == EvqFragmentOut && layoutQualifier.index >= 0;
1947     const bool needsYuvDecorate = mCompileOptions.addVulkanYUVLayoutQualifier &&
1948                                   type.getQualifier() == EvqFragmentOut && layoutQualifier.yuv;
1949 
1950     // If the resource declaration requires set & binding, add the DescriptorSet and Binding
1951     // decorations.
1952     if (needsSetBinding)
1953     {
1954         spirv::WriteDecorate(&mSpirvDecorations, variableId, spv::DecorationDescriptorSet,
1955                              {spirv::LiteralInteger(0)});
1956         spirv::WriteDecorate(&mSpirvDecorations, variableId, spv::DecorationBinding,
1957                              {spirv::LiteralInteger(nextUnusedBinding())});
1958     }
1959 
1960     if (needsLocation)
1961     {
1962         const unsigned int locationCount =
1963             CalculateVaryingLocationCount(type, gl::ToGLenum(mShaderType));
1964         const uint32_t location = IsShaderIn(type.getQualifier())
1965                                       ? nextUnusedInputLocation(locationCount)
1966                                       : nextUnusedOutputLocation(locationCount);
1967 
1968         spirv::WriteDecorate(&mSpirvDecorations, variableId, spv::DecorationLocation,
1969                              {spirv::LiteralInteger(location)});
1970     }
1971 
1972     // If the resource declaration is an input attachment, add the InputAttachmentIndex decoration.
1973     if (needsInputAttachmentIndex)
1974     {
1975         spirv::WriteDecorate(&mSpirvDecorations, variableId, spv::DecorationInputAttachmentIndex,
1976                              {spirv::LiteralInteger(layoutQualifier.inputAttachmentIndex)});
1977     }
1978 
1979     if (needsBlendIndex)
1980     {
1981         spirv::WriteDecorate(&mSpirvDecorations, variableId, spv::DecorationIndex,
1982                              {spirv::LiteralInteger(layoutQualifier.index)});
1983     }
1984 
1985     if (needsYuvDecorate)
1986     {
1987         // WIP in spec
1988         const spv::Decoration yuvDecorate = static_cast<spv::Decoration>(6088);
1989         spirv::WriteDecorate(&mSpirvDecorations, variableId, yuvDecorate,
1990                              {spirv::LiteralInteger(layoutQualifier.index)});
1991     }
1992 
1993     // Handle interpolation and auxiliary decorations on varyings
1994     if (isVarying)
1995     {
1996         writeInterpolationDecoration(type.getQualifier(), variableId,
1997                                      std::numeric_limits<uint32_t>::max());
1998     }
1999 }
2000 
writeBranchConditional(spirv::IdRef conditionValue,spirv::IdRef trueBlock,spirv::IdRef falseBlock,spirv::IdRef mergeBlock)2001 void SPIRVBuilder::writeBranchConditional(spirv::IdRef conditionValue,
2002                                           spirv::IdRef trueBlock,
2003                                           spirv::IdRef falseBlock,
2004                                           spirv::IdRef mergeBlock)
2005 {
2006     // Generate the following:
2007     //
2008     //     OpSelectionMerge %mergeBlock None
2009     //     OpBranchConditional %conditionValue %trueBlock %falseBlock
2010     //
2011     spirv::WriteSelectionMerge(getSpirvCurrentFunctionBlock(), mergeBlock,
2012                                spv::SelectionControlMaskNone);
2013     spirv::WriteBranchConditional(getSpirvCurrentFunctionBlock(), conditionValue, trueBlock,
2014                                   falseBlock, {});
2015     terminateCurrentFunctionBlock();
2016 
2017     // Start the true or false block, whichever exists.
2018     nextConditionalBlock();
2019 }
2020 
writeBranchConditionalBlockEnd()2021 void SPIRVBuilder::writeBranchConditionalBlockEnd()
2022 {
2023     if (!isCurrentFunctionBlockTerminated())
2024     {
2025         // Insert a branch to the merge block at the end of each if-else block, unless the block is
2026         // already terminated, such as with a return or discard.
2027         const spirv::IdRef mergeBlock = getCurrentConditional()->blockIds.back();
2028 
2029         spirv::WriteBranch(getSpirvCurrentFunctionBlock(), mergeBlock);
2030         terminateCurrentFunctionBlock();
2031     }
2032 
2033     // Move on to the next block.
2034     nextConditionalBlock();
2035 }
2036 
writeLoopHeader(spirv::IdRef branchToBlock,spirv::IdRef continueBlock,spirv::IdRef mergeBlock)2037 void SPIRVBuilder::writeLoopHeader(spirv::IdRef branchToBlock,
2038                                    spirv::IdRef continueBlock,
2039                                    spirv::IdRef mergeBlock)
2040 {
2041     // First, jump to the header block:
2042     //
2043     //     OpBranch %header
2044     //
2045     const spirv::IdRef headerBlock = mConditionalStack.back().blockIds[0];
2046     spirv::WriteBranch(getSpirvCurrentFunctionBlock(), headerBlock);
2047     terminateCurrentFunctionBlock();
2048 
2049     // Start the header block.
2050     nextConditionalBlock();
2051 
2052     // Generate the following:
2053     //
2054     //     OpLoopMerge %mergeBlock %continueBlock None
2055     //     OpBranch %branchToBlock (%cond or if do-while, %body)
2056     //
2057     spirv::WriteLoopMerge(getSpirvCurrentFunctionBlock(), mergeBlock, continueBlock,
2058                           spv::LoopControlMaskNone);
2059     spirv::WriteBranch(getSpirvCurrentFunctionBlock(), branchToBlock);
2060     terminateCurrentFunctionBlock();
2061 
2062     // Start the next block, which is either %cond or %body.
2063     nextConditionalBlock();
2064 }
2065 
writeLoopConditionEnd(spirv::IdRef conditionValue,spirv::IdRef branchToBlock,spirv::IdRef mergeBlock)2066 void SPIRVBuilder::writeLoopConditionEnd(spirv::IdRef conditionValue,
2067                                          spirv::IdRef branchToBlock,
2068                                          spirv::IdRef mergeBlock)
2069 {
2070     // Generate the following:
2071     //
2072     //     OpBranchConditional %conditionValue %branchToBlock %mergeBlock
2073     //
2074     // %branchToBlock is either %body or if do-while, %header
2075     //
2076     spirv::WriteBranchConditional(getSpirvCurrentFunctionBlock(), conditionValue, branchToBlock,
2077                                   mergeBlock, {});
2078     terminateCurrentFunctionBlock();
2079 
2080     // Start the next block, which is either %continue or %body.
2081     nextConditionalBlock();
2082 }
2083 
writeLoopContinueEnd(spirv::IdRef headerBlock)2084 void SPIRVBuilder::writeLoopContinueEnd(spirv::IdRef headerBlock)
2085 {
2086     // Generate the following:
2087     //
2088     //     OpBranch %headerBlock
2089     //
2090     spirv::WriteBranch(getSpirvCurrentFunctionBlock(), headerBlock);
2091     terminateCurrentFunctionBlock();
2092 
2093     // Start the next block, which is %body.
2094     nextConditionalBlock();
2095 }
2096 
writeLoopBodyEnd(spirv::IdRef continueBlock)2097 void SPIRVBuilder::writeLoopBodyEnd(spirv::IdRef continueBlock)
2098 {
2099     // Generate the following:
2100     //
2101     //     OpBranch %continueBlock
2102     //
2103     // This is only done if the block isn't already terminated in another way, such as with an
2104     // unconditional continue/etc at the end of the loop.
2105     if (!isCurrentFunctionBlockTerminated())
2106     {
2107         spirv::WriteBranch(getSpirvCurrentFunctionBlock(), continueBlock);
2108         terminateCurrentFunctionBlock();
2109     }
2110 
2111     // Start the next block, which is %merge or if while, %continue.
2112     nextConditionalBlock();
2113 }
2114 
writeSwitch(spirv::IdRef conditionValue,spirv::IdRef defaultBlock,const spirv::PairLiteralIntegerIdRefList & targetPairList,spirv::IdRef mergeBlock)2115 void SPIRVBuilder::writeSwitch(spirv::IdRef conditionValue,
2116                                spirv::IdRef defaultBlock,
2117                                const spirv::PairLiteralIntegerIdRefList &targetPairList,
2118                                spirv::IdRef mergeBlock)
2119 {
2120     // Generate the following:
2121     //
2122     //     OpSelectionMerge %mergeBlock None
2123     //     OpSwitch %conditionValue %defaultBlock A %ABlock B %BBlock ...
2124     //
2125     spirv::WriteSelectionMerge(getSpirvCurrentFunctionBlock(), mergeBlock,
2126                                spv::SelectionControlMaskNone);
2127     spirv::WriteSwitch(getSpirvCurrentFunctionBlock(), conditionValue, defaultBlock,
2128                        targetPairList);
2129     terminateCurrentFunctionBlock();
2130 
2131     // Start the next case block.
2132     nextConditionalBlock();
2133 }
2134 
writeSwitchCaseBlockEnd()2135 void SPIRVBuilder::writeSwitchCaseBlockEnd()
2136 {
2137     if (!isCurrentFunctionBlockTerminated())
2138     {
2139         // If a case does not end in branch, insert a branch to the next block, implementing
2140         // fallthrough.  For the last block, the branch target would automatically be the merge
2141         // block.
2142         const SpirvConditional *conditional = getCurrentConditional();
2143         const spirv::IdRef nextBlock        = conditional->blockIds[conditional->nextBlockToWrite];
2144 
2145         spirv::WriteBranch(getSpirvCurrentFunctionBlock(), nextBlock);
2146         terminateCurrentFunctionBlock();
2147     }
2148 
2149     // Move on to the next block.
2150     nextConditionalBlock();
2151 }
2152 
writeMemberDecorations(const SpirvType & type,spirv::IdRef typeId)2153 void SPIRVBuilder::writeMemberDecorations(const SpirvType &type, spirv::IdRef typeId)
2154 {
2155     ASSERT(type.block != nullptr);
2156 
2157     uint32_t fieldIndex = 0;
2158 
2159     for (const TField *field : type.block->fields())
2160     {
2161         const TType &fieldType = *field->type();
2162 
2163         // Add invariant decoration if any.
2164         if (type.typeSpec.isInvariantBlock || fieldType.isInvariant())
2165         {
2166             spirv::WriteMemberDecorate(&mSpirvDecorations, typeId,
2167                                        spirv::LiteralInteger(fieldIndex), spv::DecorationInvariant,
2168                                        {});
2169         }
2170 
2171         // Add memory qualifier decorations to buffer members
2172         if (fieldType.getMemoryQualifier().coherent)
2173         {
2174             spirv::WriteMemberDecorate(&mSpirvDecorations, typeId,
2175                                        spirv::LiteralInteger(fieldIndex), spv::DecorationCoherent,
2176                                        {});
2177         }
2178         if (fieldType.getMemoryQualifier().readonly)
2179         {
2180             spirv::WriteMemberDecorate(&mSpirvDecorations, typeId,
2181                                        spirv::LiteralInteger(fieldIndex),
2182                                        spv::DecorationNonWritable, {});
2183         }
2184         if (fieldType.getMemoryQualifier().writeonly)
2185         {
2186             spirv::WriteMemberDecorate(&mSpirvDecorations, typeId,
2187                                        spirv::LiteralInteger(fieldIndex),
2188                                        spv::DecorationNonReadable, {});
2189         }
2190         if (fieldType.getMemoryQualifier().restrictQualifier)
2191         {
2192             spirv::WriteMemberDecorate(&mSpirvDecorations, typeId,
2193                                        spirv::LiteralInteger(fieldIndex), spv::DecorationRestrict,
2194                                        {});
2195         }
2196         if (fieldType.getMemoryQualifier().volatileQualifier)
2197         {
2198             spirv::WriteMemberDecorate(&mSpirvDecorations, typeId,
2199                                        spirv::LiteralInteger(fieldIndex), spv::DecorationVolatile,
2200                                        {});
2201         }
2202 
2203         // Add matrix decorations if any.
2204         if (fieldType.isMatrix())
2205         {
2206             // ColMajor or RowMajor
2207             const bool isRowMajor =
2208                 IsBlockFieldRowMajorQualified(fieldType, type.typeSpec.isRowMajorQualifiedBlock);
2209             spirv::WriteMemberDecorate(
2210                 &mSpirvDecorations, typeId, spirv::LiteralInteger(fieldIndex),
2211                 isRowMajor ? spv::DecorationRowMajor : spv::DecorationColMajor, {});
2212         }
2213 
2214         // Add interpolation and auxiliary decorations
2215         writeInterpolationDecoration(fieldType.getQualifier(), typeId, fieldIndex);
2216 
2217         // Add patch decoration if any.
2218         if (type.typeSpec.isPatchIOBlock)
2219         {
2220             spirv::WriteMemberDecorate(&mSpirvDecorations, typeId,
2221                                        spirv::LiteralInteger(fieldIndex), spv::DecorationPatch, {});
2222         }
2223 
2224         // Add other decorations.
2225         SpirvDecorations decorations = getDecorations(fieldType);
2226         for (const spv::Decoration decoration : decorations)
2227         {
2228             spirv::WriteMemberDecorate(&mSpirvDecorations, typeId,
2229                                        spirv::LiteralInteger(fieldIndex), decoration, {});
2230         }
2231 
2232         ++fieldIndex;
2233     }
2234 }
2235 
writeInterpolationDecoration(TQualifier qualifier,spirv::IdRef id,uint32_t fieldIndex)2236 void SPIRVBuilder::writeInterpolationDecoration(TQualifier qualifier,
2237                                                 spirv::IdRef id,
2238                                                 uint32_t fieldIndex)
2239 {
2240     switch (qualifier)
2241     {
2242         case EvqSmooth:
2243         case EvqSmoothOut:
2244         case EvqSmoothIn:
2245             // No decoration in SPIR-V for smooth, this is the default interpolation.
2246             return;
2247 
2248         case EvqFlat:
2249         case EvqFlatOut:
2250         case EvqFlatIn:
2251             WriteInterpolationDecoration(spv::DecorationFlat, id, fieldIndex, &mSpirvDecorations);
2252             return;
2253 
2254         case EvqNoPerspective:
2255         case EvqNoPerspectiveOut:
2256         case EvqNoPerspectiveIn:
2257             WriteInterpolationDecoration(spv::DecorationNoPerspective, id, fieldIndex,
2258                                          &mSpirvDecorations);
2259             return;
2260 
2261         case EvqCentroid:
2262         case EvqCentroidOut:
2263         case EvqCentroidIn:
2264             WriteInterpolationDecoration(spv::DecorationCentroid, id, fieldIndex,
2265                                          &mSpirvDecorations);
2266             return;
2267 
2268         case EvqSample:
2269         case EvqSampleOut:
2270         case EvqSampleIn:
2271             WriteInterpolationDecoration(spv::DecorationSample, id, fieldIndex, &mSpirvDecorations);
2272             addCapability(spv::CapabilitySampleRateShading);
2273             return;
2274 
2275         case EvqNoPerspectiveCentroid:
2276         case EvqNoPerspectiveCentroidOut:
2277         case EvqNoPerspectiveCentroidIn:
2278             WriteInterpolationDecoration(spv::DecorationNoPerspective, id, fieldIndex,
2279                                          &mSpirvDecorations);
2280             WriteInterpolationDecoration(spv::DecorationCentroid, id, fieldIndex,
2281                                          &mSpirvDecorations);
2282             return;
2283 
2284         case EvqNoPerspectiveSample:
2285         case EvqNoPerspectiveSampleOut:
2286         case EvqNoPerspectiveSampleIn:
2287             WriteInterpolationDecoration(spv::DecorationNoPerspective, id, fieldIndex,
2288                                          &mSpirvDecorations);
2289             WriteInterpolationDecoration(spv::DecorationSample, id, fieldIndex, &mSpirvDecorations);
2290             addCapability(spv::CapabilitySampleRateShading);
2291             return;
2292 
2293         default:
2294             return;
2295     }
2296 }
2297 
getName(const TSymbol * symbol)2298 ImmutableString SPIRVBuilder::getName(const TSymbol *symbol)
2299 {
2300     return symbol->symbolType() == SymbolType::Empty ? ImmutableString("") : symbol->name();
2301 }
2302 
getFieldName(const TField * field)2303 ImmutableString SPIRVBuilder::getFieldName(const TField *field)
2304 {
2305     ASSERT(field->symbolType() != SymbolType::Empty);
2306     return field->name();
2307 }
2308 
getSpirv()2309 spirv::Blob SPIRVBuilder::getSpirv()
2310 {
2311     ASSERT(mConditionalStack.empty());
2312 
2313     spirv::Blob result;
2314 
2315     const spirv::IdRef nonSemanticOverviewId = getNewId({});
2316 
2317     // Reserve a minimum amount of memory.
2318     //
2319     //   5 for header +
2320     //   a number of capabilities +
2321     //   size of already generated instructions.
2322     //
2323     // The actual size is larger due to other metadata instructions such as extensions,
2324     // OpExtInstImport, OpEntryPoint, OpExecutionMode etc.
2325     result.reserve(5 + mCapabilities.size() * 2 + mSpirvDebug.size() + mSpirvDecorations.size() +
2326                    mSpirvTypeAndConstantDecls.size() + mSpirvTypePointerDecls.size() +
2327                    mSpirvFunctionTypeDecls.size() + mSpirvVariableDecls.size() +
2328                    mSpirvFunctions.size());
2329 
2330     // Generate the SPIR-V header.
2331     spirv::WriteSpirvHeader(&result, mNextAvailableId);
2332 
2333     // Generate metadata in the following order:
2334     //
2335     // - OpCapability instructions.
2336     for (spv::Capability capability : mCapabilities)
2337     {
2338         spirv::WriteCapability(&result, capability);
2339     }
2340 
2341     // - OpExtension instructions
2342     writeExtensions(&result);
2343 
2344     // Enable the SPV_KHR_non_semantic_info extension to more efficiently communicate information to
2345     // the SPIR-V transformer in the Vulkan backend.  The relevant instructions are all stripped
2346     // away during SPIR-V transformation so the driver never needs to support it.
2347     spirv::WriteExtension(&result, "SPV_KHR_non_semantic_info");
2348 
2349     // - OpExtInstImport
2350     spirv::WriteExtInstImport(&result, getExtInstImportIdStd(), "GLSL.std.450");
2351     spirv::WriteExtInstImport(&result, spirv::IdRef(vk::spirv::kIdNonSemanticInstructionSet),
2352                               "NonSemantic.ANGLE");
2353 
2354     // - OpMemoryModel
2355     spirv::WriteMemoryModel(&result, spv::AddressingModelLogical, spv::MemoryModelGLSL450);
2356 
2357     // - OpEntryPoint
2358     constexpr gl::ShaderMap<spv::ExecutionModel> kExecutionModels = {
2359         {gl::ShaderType::Vertex, spv::ExecutionModelVertex},
2360         {gl::ShaderType::TessControl, spv::ExecutionModelTessellationControl},
2361         {gl::ShaderType::TessEvaluation, spv::ExecutionModelTessellationEvaluation},
2362         {gl::ShaderType::Geometry, spv::ExecutionModelGeometry},
2363         {gl::ShaderType::Fragment, spv::ExecutionModelFragment},
2364         {gl::ShaderType::Compute, spv::ExecutionModelGLCompute},
2365     };
2366     spirv::WriteEntryPoint(&result, kExecutionModels[mShaderType],
2367                            spirv::IdRef(vk::spirv::kIdEntryPoint), "main",
2368                            mEntryPointInterfaceList);
2369 
2370     // - OpExecutionMode instructions
2371     writeExecutionModes(&result);
2372 
2373     // - OpSource and OpSourceExtension instructions.
2374     //
2375     // This is to support debuggers and capture/replay tools and isn't strictly necessary.
2376     spirv::WriteSource(&result, spv::SourceLanguageGLSL, spirv::LiteralInteger(450), nullptr,
2377                        nullptr);
2378     writeSourceExtensions(&result);
2379 
2380     // Append the already generated sections in order
2381     result.insert(result.end(), mSpirvDebug.begin(), mSpirvDebug.end());
2382     result.insert(result.end(), mSpirvDecorations.begin(), mSpirvDecorations.end());
2383     result.insert(result.end(), mSpirvTypeAndConstantDecls.begin(),
2384                   mSpirvTypeAndConstantDecls.end());
2385     result.insert(result.end(), mSpirvTypePointerDecls.begin(), mSpirvTypePointerDecls.end());
2386     result.insert(result.end(), mSpirvFunctionTypeDecls.begin(), mSpirvFunctionTypeDecls.end());
2387     result.insert(result.end(), mSpirvVariableDecls.begin(), mSpirvVariableDecls.end());
2388 
2389     // The types/constants/variables section is the first place non-semantic instructions can be
2390     // output.  These instructions rely on at least the OpVoid type.  The kNonSemanticTypeSectionEnd
2391     // instruction additionally carries an overview of the SPIR-V and thus requires a few OpConstant
2392     // values.
2393     writeNonSemanticOverview(&result, nonSemanticOverviewId);
2394 
2395     result.insert(result.end(), mSpirvFunctions.begin(), mSpirvFunctions.end());
2396 
2397     result.shrink_to_fit();
2398     return result;
2399 }
2400 
writeExecutionModes(spirv::Blob * blob)2401 void SPIRVBuilder::writeExecutionModes(spirv::Blob *blob)
2402 {
2403     const spirv::IdRef entryPointId(vk::spirv::kIdEntryPoint);
2404 
2405     switch (mShaderType)
2406     {
2407         case gl::ShaderType::Fragment:
2408             spirv::WriteExecutionMode(blob, entryPointId, spv::ExecutionModeOriginUpperLeft, {});
2409 
2410             if (mCompiler->isEarlyFragmentTestsSpecified())
2411             {
2412                 spirv::WriteExecutionMode(blob, entryPointId, spv::ExecutionModeEarlyFragmentTests,
2413                                           {});
2414             }
2415 
2416             break;
2417 
2418         case gl::ShaderType::TessControl:
2419             spirv::WriteExecutionMode(
2420                 blob, entryPointId, spv::ExecutionModeOutputVertices,
2421                 {spirv::LiteralInteger(mCompiler->getTessControlShaderOutputVertices())});
2422             break;
2423 
2424         case gl::ShaderType::TessEvaluation:
2425         {
2426             const spv::ExecutionMode inputExecutionMode = GetTessEvalInputExecutionMode(
2427                 mCompiler->getTessEvaluationShaderInputPrimitiveType());
2428             const spv::ExecutionMode spacingExecutionMode = GetTessEvalSpacingExecutionMode(
2429                 mCompiler->getTessEvaluationShaderInputVertexSpacingType());
2430             const spv::ExecutionMode orderingExecutionMode = GetTessEvalOrderingExecutionMode(
2431                 mCompiler->getTessEvaluationShaderInputOrderingType());
2432 
2433             spirv::WriteExecutionMode(blob, entryPointId, inputExecutionMode, {});
2434             spirv::WriteExecutionMode(blob, entryPointId, spacingExecutionMode, {});
2435             spirv::WriteExecutionMode(blob, entryPointId, orderingExecutionMode, {});
2436             if (mCompiler->getTessEvaluationShaderInputPointType() == EtetPointMode)
2437             {
2438                 spirv::WriteExecutionMode(blob, entryPointId, spv::ExecutionModePointMode, {});
2439             }
2440             break;
2441         }
2442 
2443         case gl::ShaderType::Geometry:
2444         {
2445             const spv::ExecutionMode inputExecutionMode =
2446                 GetGeometryInputExecutionMode(mCompiler->getGeometryShaderInputPrimitiveType());
2447             const spv::ExecutionMode outputExecutionMode =
2448                 GetGeometryOutputExecutionMode(mCompiler->getGeometryShaderOutputPrimitiveType());
2449 
2450             // max_vertices=0 is not valid in Vulkan
2451             const int maxVertices = std::max(1, mCompiler->getGeometryShaderMaxVertices());
2452 
2453             spirv::WriteExecutionMode(blob, entryPointId, inputExecutionMode, {});
2454             spirv::WriteExecutionMode(blob, entryPointId, outputExecutionMode, {});
2455             spirv::WriteExecutionMode(blob, entryPointId, spv::ExecutionModeOutputVertices,
2456                                       {spirv::LiteralInteger(maxVertices)});
2457             spirv::WriteExecutionMode(
2458                 blob, entryPointId, spv::ExecutionModeInvocations,
2459                 {spirv::LiteralInteger(mCompiler->getGeometryShaderInvocations())});
2460 
2461             break;
2462         }
2463 
2464         case gl::ShaderType::Compute:
2465         {
2466             const sh::WorkGroupSize &localSize = mCompiler->getComputeShaderLocalSize();
2467             spirv::WriteExecutionMode(
2468                 blob, entryPointId, spv::ExecutionModeLocalSize,
2469                 {spirv::LiteralInteger(localSize[0]), spirv::LiteralInteger(localSize[1]),
2470                  spirv::LiteralInteger(localSize[2])});
2471             break;
2472         }
2473 
2474         default:
2475             break;
2476     }
2477 
2478     // Add any execution modes that were added due to built-ins used in the shader.
2479     for (spv::ExecutionMode executionMode : mExecutionModes)
2480     {
2481         spirv::WriteExecutionMode(blob, entryPointId, executionMode, {});
2482     }
2483 }
2484 
writeExtensions(spirv::Blob * blob)2485 void SPIRVBuilder::writeExtensions(spirv::Blob *blob)
2486 {
2487     for (SPIRVExtensions extension : mExtensions)
2488     {
2489         switch (extension)
2490         {
2491             case SPIRVExtensions::MultiviewOVR:
2492                 spirv::WriteExtension(blob, "SPV_KHR_multiview");
2493                 break;
2494             case SPIRVExtensions::FragmentShaderInterlockARB:
2495                 spirv::WriteExtension(blob, "SPV_EXT_fragment_shader_interlock");
2496                 break;
2497             default:
2498                 UNREACHABLE();
2499         }
2500     }
2501 }
2502 
writeSourceExtensions(spirv::Blob * blob)2503 void SPIRVBuilder::writeSourceExtensions(spirv::Blob *blob)
2504 {
2505     for (SPIRVExtensions extension : mExtensions)
2506     {
2507         switch (extension)
2508         {
2509             case SPIRVExtensions::MultiviewOVR:
2510                 spirv::WriteSourceExtension(blob, "GL_OVR_multiview");
2511                 break;
2512             case SPIRVExtensions::FragmentShaderInterlockARB:
2513                 spirv::WriteSourceExtension(blob, "GL_ARB_fragment_shader_interlock");
2514                 break;
2515             default:
2516                 UNREACHABLE();
2517         }
2518     }
2519 }
2520 
writeNonSemanticOverview(spirv::Blob * blob,spirv::IdRef id)2521 void SPIRVBuilder::writeNonSemanticOverview(spirv::Blob *blob, spirv::IdRef id)
2522 {
2523     // Output the kNonSemanticOverview non-semantic instruction.  The top unused bits of the
2524     // instruction id are used to communicate addition information already gathered in
2525     // mOverviewFlags (bits defined by kOverview*Bit).
2526 
2527     using namespace vk::spirv;
2528 
2529     ASSERT((mOverviewFlags & vk::spirv::kNonSemanticInstructionMask) == 0);
2530     const uint32_t overview = kNonSemanticOverview | mOverviewFlags;
2531 
2532     spirv::WriteExtInst(blob, spirv::IdResultType(kIdVoid), id,
2533                         spirv::IdRef(kIdNonSemanticInstructionSet),
2534                         spirv::LiteralExtInstInteger(overview), {});
2535 }
2536 
writeNonSemanticInstruction(vk::spirv::NonSemanticInstruction instruction)2537 void SPIRVBuilder::writeNonSemanticInstruction(vk::spirv::NonSemanticInstruction instruction)
2538 {
2539     using namespace vk::spirv;
2540 
2541     const spirv::IdRef id = getNewId({});
2542 
2543     spirv::WriteExtInst(getSpirvCurrentFunctionBlock(), spirv::IdResultType(kIdVoid), id,
2544                         spirv::IdRef(kIdNonSemanticInstructionSet),
2545                         spirv::LiteralExtInstInteger(instruction), {});
2546 }
2547 
2548 }  // namespace sh
2549