• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/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 }  // anonymous namespace
353 
inferDefaults(const TType & type,TCompiler * compiler)354 void SpirvTypeSpec::inferDefaults(const TType &type, TCompiler *compiler)
355 {
356     // Infer some defaults based on type.  If necessary, this overrides some fields (if not already
357     // specified).  Otherwise, it leaves the pre-initialized values as-is.
358 
359     // Handle interface blocks and fields of nameless interface blocks.
360     if (type.getInterfaceBlock() != nullptr)
361     {
362         // Calculate the block storage from the interface block automatically.  The fields inherit
363         // from this.  Only blocks and arrays in blocks produce different SPIR-V types based on
364         // block storage.
365         const bool isBlock = type.isInterfaceBlock() || type.getStruct();
366         if (blockStorage == EbsUnspecified && (isBlock || type.isArray()))
367         {
368             blockStorage = GetBlockStorage(type);
369         }
370 
371         // row_major can only be specified on an interface block or one of its fields.  The fields
372         // will inherit this from the interface block itself.
373         if (!isRowMajorQualifiedBlock && isBlock)
374         {
375             isRowMajorQualifiedBlock = type.getLayoutQualifier().matrixPacking == EmpRowMajor;
376         }
377 
378         // Arrays of matrices in a uniform/buffer block may generate a different stride based on
379         // whether they are row- or column-major.  Square matrices are trivially known not to
380         // generate a different type.
381         if (!isRowMajorQualifiedArray)
382         {
383             isRowMajorQualifiedArray = IsNonSquareRowMajorArrayInBlock(type, *this);
384         }
385 
386         // Structs with bools, bool arrays, bool vectors and bools themselves are replaced with uint
387         // when used in an interface block.
388         if (!isOrHasBoolInInterfaceBlock)
389         {
390             isOrHasBoolInInterfaceBlock = type.isInterfaceBlockContainingType(EbtBool) ||
391                                           type.isStructureContainingType(EbtBool) ||
392                                           type.getBasicType() == EbtBool;
393         }
394 
395         if (!isPatchIOBlock && type.isInterfaceBlock())
396         {
397             isPatchIOBlock =
398                 type.getQualifier() == EvqPatchIn || type.getQualifier() == EvqPatchOut;
399         }
400     }
401 
402     // |invariant| is significant for structs as the fields of the type are decorated with Invariant
403     // in SPIR-V.  This is possible for outputs of struct type, or struct-typed fields of an
404     // interface block.
405     if (type.getStruct() != nullptr)
406     {
407         isInvariantBlock = isInvariantBlock || IsInvariant(type, compiler);
408     }
409 }
410 
onArrayElementSelection(bool isElementTypeBlock,bool isElementTypeArray)411 void SpirvTypeSpec::onArrayElementSelection(bool isElementTypeBlock, bool isElementTypeArray)
412 {
413     // No difference in type for non-block non-array types in std140 and std430 block storage.
414     if (!isElementTypeBlock && !isElementTypeArray)
415     {
416         blockStorage = EbsUnspecified;
417     }
418 
419     // No difference in type for non-array types in std140 and std430 block storage.
420     if (!isElementTypeArray)
421     {
422         isRowMajorQualifiedArray = false;
423     }
424 }
425 
onBlockFieldSelection(const TType & fieldType)426 void SpirvTypeSpec::onBlockFieldSelection(const TType &fieldType)
427 {
428     // Patch is never recursively applied.
429     isPatchIOBlock = false;
430 
431     if (fieldType.getStruct() == nullptr)
432     {
433         // If the field is not a block, no difference if the parent block was invariant or
434         // row-major.
435         isRowMajorQualifiedArray = IsNonSquareRowMajorArrayInBlock(fieldType, *this);
436         isInvariantBlock         = false;
437         isRowMajorQualifiedBlock = false;
438 
439         // If the field is not an array, no difference in storage block.
440         if (!fieldType.isArray())
441         {
442             blockStorage = EbsUnspecified;
443         }
444 
445         if (fieldType.getBasicType() != EbtBool)
446         {
447             isOrHasBoolInInterfaceBlock = false;
448         }
449     }
450     else
451     {
452         // Apply row-major only to structs that contain matrices.
453         isRowMajorQualifiedBlock =
454             IsBlockFieldRowMajorQualified(fieldType, isRowMajorQualifiedBlock) &&
455             fieldType.isStructureContainingMatrices();
456 
457         // Structs without bools aren't affected by |isOrHasBoolInInterfaceBlock|.
458         if (isOrHasBoolInInterfaceBlock)
459         {
460             isOrHasBoolInInterfaceBlock = fieldType.isStructureContainingType(EbtBool);
461         }
462     }
463 }
464 
onMatrixColumnSelection()465 void SpirvTypeSpec::onMatrixColumnSelection()
466 {
467     // The matrix types are never differentiated, so neither would be their columns.
468     ASSERT(!isInvariantBlock && !isRowMajorQualifiedBlock && !isRowMajorQualifiedArray &&
469            !isOrHasBoolInInterfaceBlock && blockStorage == EbsUnspecified);
470 }
471 
onVectorComponentSelection()472 void SpirvTypeSpec::onVectorComponentSelection()
473 {
474     // The vector types are never differentiated, so neither would be their components.  The only
475     // exception is bools in interface blocks, in which case the component and the vector are
476     // similarly differentiated.
477     ASSERT(!isInvariantBlock && !isRowMajorQualifiedBlock && !isRowMajorQualifiedArray &&
478            blockStorage == EbsUnspecified);
479 }
480 
SPIRVBuilder(TCompiler * compiler,ShCompileOptions compileOptions,ShHashFunction64 hashFunction,NameMap & nameMap)481 SPIRVBuilder::SPIRVBuilder(TCompiler *compiler,
482                            ShCompileOptions compileOptions,
483                            ShHashFunction64 hashFunction,
484                            NameMap &nameMap)
485     : mCompiler(compiler),
486       mCompileOptions(compileOptions),
487       mShaderType(gl::FromGLenum<gl::ShaderType>(compiler->getShaderType())),
488       mNextAvailableId(1),
489       mHashFunction(hashFunction),
490       mNameMap(nameMap),
491       mNextUnusedBinding(0),
492       mNextUnusedInputLocation(0),
493       mNextUnusedOutputLocation(0)
494 {
495     // The Shader capability is always defined.
496     addCapability(spv::CapabilityShader);
497 
498     // Add Geometry or Tessellation capabilities based on shader type.
499     if (mCompiler->getShaderType() == GL_GEOMETRY_SHADER)
500     {
501         addCapability(spv::CapabilityGeometry);
502     }
503     else if (mCompiler->getShaderType() == GL_TESS_CONTROL_SHADER_EXT ||
504              mCompiler->getShaderType() == GL_TESS_EVALUATION_SHADER_EXT)
505     {
506         addCapability(spv::CapabilityTessellation);
507     }
508 }
509 
getNewId(const SpirvDecorations & decorations)510 spirv::IdRef SPIRVBuilder::getNewId(const SpirvDecorations &decorations)
511 {
512     spirv::IdRef newId = mNextAvailableId;
513     mNextAvailableId   = spirv::IdRef(mNextAvailableId + 1);
514 
515     for (const spv::Decoration decoration : decorations)
516     {
517         spirv::WriteDecorate(&mSpirvDecorations, newId, decoration, {});
518     }
519 
520     return newId;
521 }
522 
getSpirvType(const TType & type,const SpirvTypeSpec & typeSpec) const523 SpirvType SPIRVBuilder::getSpirvType(const TType &type, const SpirvTypeSpec &typeSpec) const
524 {
525     SpirvType spirvType;
526     spirvType.type                = type.getBasicType();
527     spirvType.primarySize         = static_cast<uint8_t>(type.getNominalSize());
528     spirvType.secondarySize       = static_cast<uint8_t>(type.getSecondarySize());
529     spirvType.arraySizes          = type.getArraySizes();
530     spirvType.imageInternalFormat = type.getLayoutQualifier().imageInternalFormat;
531 
532     switch (spirvType.type)
533     {
534         // External textures are treated as 2D textures in the vulkan back-end.
535         case EbtSamplerExternalOES:
536         case EbtSamplerExternal2DY2YEXT:
537         // WEBGL video textures too.
538         case EbtSamplerVideoWEBGL:
539             spirvType.type = EbtSampler2D;
540             break;
541         default:
542             break;
543     }
544 
545     if (type.getStruct() != nullptr)
546     {
547         spirvType.block = type.getStruct();
548     }
549     else if (type.isInterfaceBlock())
550     {
551         spirvType.block = type.getInterfaceBlock();
552     }
553 
554     // Automatically inherit or infer the type-specializing properties.
555     spirvType.typeSpec = typeSpec;
556     spirvType.typeSpec.inferDefaults(type, mCompiler);
557 
558     return spirvType;
559 }
560 
getTypeData(const TType & type,const SpirvTypeSpec & typeSpec)561 const SpirvTypeData &SPIRVBuilder::getTypeData(const TType &type, const SpirvTypeSpec &typeSpec)
562 {
563     SpirvType spirvType = getSpirvType(type, typeSpec);
564 
565     const TSymbol *block = nullptr;
566     if (type.getStruct() != nullptr)
567     {
568         block = type.getStruct();
569     }
570     else if (type.isInterfaceBlock())
571     {
572         block = type.getInterfaceBlock();
573     }
574 
575     return getSpirvTypeData(spirvType, block);
576 }
577 
getTypeDataOverrideTypeSpec(const TType & type,const SpirvTypeSpec & typeSpec)578 const SpirvTypeData &SPIRVBuilder::getTypeDataOverrideTypeSpec(const TType &type,
579                                                                const SpirvTypeSpec &typeSpec)
580 {
581     // This is a variant of getTypeData() where type spec is not automatically derived.  It's useful
582     // in cast operations that specifically need to override the spec.
583     SpirvType spirvType = getSpirvType(type, typeSpec);
584     spirvType.typeSpec  = typeSpec;
585 
586     return getSpirvTypeData(spirvType, nullptr);
587 }
588 
getSpirvTypeData(const SpirvType & type,const TSymbol * block)589 const SpirvTypeData &SPIRVBuilder::getSpirvTypeData(const SpirvType &type, const TSymbol *block)
590 {
591     // Structs with bools generate a different type when used in an interface block (where the bool
592     // is replaced with a uint).  The bool, bool vector and bool arrays too generate a different
593     // type when nested in an interface block, but that type is the same as the equivalent uint
594     // type.  To avoid defining duplicate uint types, we switch the basic type here to uint.  From
595     // the outside, therefore bool in an interface block and uint look like different types, but
596     // under the hood will be the same uint.
597     if (type.block == nullptr && type.typeSpec.isOrHasBoolInInterfaceBlock)
598     {
599         ASSERT(type.type == EbtBool);
600 
601         SpirvType uintType                            = type;
602         uintType.type                                 = EbtUInt;
603         uintType.typeSpec.isOrHasBoolInInterfaceBlock = false;
604         return getSpirvTypeData(uintType, block);
605     }
606 
607     auto iter = mTypeMap.find(type);
608     if (iter == mTypeMap.end())
609     {
610         SpirvTypeData newTypeData = declareType(type, block);
611 
612         iter = mTypeMap.insert({type, newTypeData}).first;
613     }
614 
615     return iter->second;
616 }
617 
getBasicTypeId(TBasicType basicType,size_t size)618 spirv::IdRef SPIRVBuilder::getBasicTypeId(TBasicType basicType, size_t size)
619 {
620     SpirvType type;
621     type.type        = basicType;
622     type.primarySize = static_cast<uint8_t>(size);
623     return getSpirvTypeData(type, nullptr).id;
624 }
625 
getTypePointerId(spirv::IdRef typeId,spv::StorageClass storageClass)626 spirv::IdRef SPIRVBuilder::getTypePointerId(spirv::IdRef typeId, spv::StorageClass storageClass)
627 {
628     SpirvIdAndStorageClass key{typeId, storageClass};
629 
630     auto iter = mTypePointerIdMap.find(key);
631     if (iter == mTypePointerIdMap.end())
632     {
633         const spirv::IdRef typePointerId = getNewId({});
634 
635         spirv::WriteTypePointer(&mSpirvTypePointerDecls, typePointerId, storageClass, typeId);
636 
637         iter = mTypePointerIdMap.insert({key, typePointerId}).first;
638     }
639 
640     return iter->second;
641 }
642 
getFunctionTypeId(spirv::IdRef returnTypeId,const spirv::IdRefList & paramTypeIds)643 spirv::IdRef SPIRVBuilder::getFunctionTypeId(spirv::IdRef returnTypeId,
644                                              const spirv::IdRefList &paramTypeIds)
645 {
646     SpirvIdAndIdList key{returnTypeId, paramTypeIds};
647 
648     auto iter = mFunctionTypeIdMap.find(key);
649     if (iter == mFunctionTypeIdMap.end())
650     {
651         const spirv::IdRef functionTypeId = getNewId({});
652 
653         spirv::WriteTypeFunction(&mSpirvFunctionTypeDecls, functionTypeId, returnTypeId,
654                                  paramTypeIds);
655 
656         iter = mFunctionTypeIdMap.insert({key, functionTypeId}).first;
657     }
658 
659     return iter->second;
660 }
661 
getDecorations(const TType & type)662 SpirvDecorations SPIRVBuilder::getDecorations(const TType &type)
663 {
664     const bool enablePrecision = (mCompileOptions & SH_IGNORE_PRECISION_QUALIFIERS) == 0;
665     const TPrecision precision = type.getPrecision();
666 
667     SpirvDecorations decorations;
668 
669     // Handle precision.
670     if (enablePrecision && (precision == EbpMedium || precision == EbpLow))
671     {
672         decorations.push_back(spv::DecorationRelaxedPrecision);
673     }
674 
675     return decorations;
676 }
677 
getArithmeticDecorations(const TType & type,bool isPrecise,TOperator op)678 SpirvDecorations SPIRVBuilder::getArithmeticDecorations(const TType &type,
679                                                         bool isPrecise,
680                                                         TOperator op)
681 {
682     SpirvDecorations decorations = getDecorations(type);
683 
684     // In GLSL, findMsb operates on a highp operand, while returning a lowp result.  In SPIR-V,
685     // RelaxedPrecision cannot be applied on the Find*Msb instructions as that affects the operand
686     // as well:
687     //
688     // > The RelaxedPrecision Decoration can be applied to:
689     // > ...
690     // > The Result <id> of an instruction that operates on numerical types, meaning the instruction
691     // > is to operate at relaxed precision. The instruction's operands may also be truncated to the
692     // > relaxed precision.
693     // > ...
694     //
695     // Here, we remove RelaxedPrecision from such problematic instructions.
696     switch (op)
697     {
698         case EOpFindMSB:
699             // Currently getDecorations() only adds RelaxedPrecision, so removing the
700             // RelaxedPrecision decoration is simply done by clearing the vector.
701             ASSERT(decorations.empty() ||
702                    (decorations.size() == 1 && decorations[0] == spv::DecorationRelaxedPrecision));
703             decorations.clear();
704             break;
705         default:
706             break;
707     }
708 
709     // Handle |precise|.
710     if (isPrecise)
711     {
712         decorations.push_back(spv::DecorationNoContraction);
713     }
714 
715     return decorations;
716 }
717 
getExtInstImportIdStd()718 spirv::IdRef SPIRVBuilder::getExtInstImportIdStd()
719 {
720     if (!mExtInstImportIdStd.valid())
721     {
722         mExtInstImportIdStd = getNewId({});
723     }
724     return mExtInstImportIdStd;
725 }
726 
declareType(const SpirvType & type,const TSymbol * block)727 SpirvTypeData SPIRVBuilder::declareType(const SpirvType &type, const TSymbol *block)
728 {
729     // Recursively declare the type.  Type id is allocated afterwards purely for better id order in
730     // output.
731     spirv::IdRef typeId;
732 
733     if (!type.arraySizes.empty())
734     {
735         // Declaring an array.  First, declare the type without the outermost array size, then
736         // declare a new array type based on that.
737 
738         SpirvType subType  = type;
739         subType.arraySizes = type.arraySizes.first(type.arraySizes.size() - 1);
740         subType.typeSpec.onArrayElementSelection(subType.block != nullptr,
741                                                  !subType.arraySizes.empty());
742 
743         const spirv::IdRef subTypeId = getSpirvTypeData(subType, block).id;
744 
745         const unsigned int length = type.arraySizes.back();
746 
747         if (length == 0)
748         {
749             // Storage buffers may include a dynamically-sized array, which is identified by it
750             // having a length of 0.
751             typeId = getNewId({});
752             spirv::WriteTypeRuntimeArray(&mSpirvTypeAndConstantDecls, typeId, subTypeId);
753         }
754         else
755         {
756             const spirv::IdRef lengthId = getUintConstant(length);
757             typeId                      = getNewId({});
758             spirv::WriteTypeArray(&mSpirvTypeAndConstantDecls, typeId, subTypeId, lengthId);
759         }
760     }
761     else if (type.block != nullptr)
762     {
763         // Declaring a block.  First, declare all the fields, then declare a struct based on the
764         // list of field types.
765 
766         spirv::IdRefList fieldTypeIds;
767         for (const TField *field : type.block->fields())
768         {
769             const TType &fieldType = *field->type();
770 
771             SpirvTypeSpec fieldTypeSpec = type.typeSpec;
772             fieldTypeSpec.onBlockFieldSelection(fieldType);
773 
774             const SpirvType fieldSpirvType = getSpirvType(fieldType, fieldTypeSpec);
775             const spirv::IdRef fieldTypeId =
776                 getSpirvTypeData(fieldSpirvType, fieldType.getStruct()).id;
777             fieldTypeIds.push_back(fieldTypeId);
778         }
779 
780         typeId = getNewId({});
781         spirv::WriteTypeStruct(&mSpirvTypeAndConstantDecls, typeId, fieldTypeIds);
782     }
783     else if (IsSampler(type.type) && !type.isSamplerBaseImage)
784     {
785         // Declaring a sampler.  First, declare the non-sampled image and then a combined
786         // image-sampler.
787 
788         SpirvType imageType          = type;
789         imageType.isSamplerBaseImage = true;
790 
791         const spirv::IdRef nonSampledId = getSpirvTypeData(imageType, nullptr).id;
792 
793         typeId = getNewId({});
794         spirv::WriteTypeSampledImage(&mSpirvTypeAndConstantDecls, typeId, nonSampledId);
795     }
796     else if (IsImage(type.type) || IsSubpassInputType(type.type) || type.isSamplerBaseImage)
797     {
798         // Declaring an image.
799 
800         spirv::IdRef sampledType;
801         spv::Dim dim;
802         spirv::LiteralInteger depth;
803         spirv::LiteralInteger arrayed;
804         spirv::LiteralInteger multisampled;
805         spirv::LiteralInteger sampled;
806 
807         getImageTypeParameters(type.type, &sampledType, &dim, &depth, &arrayed, &multisampled,
808                                &sampled);
809         const spv::ImageFormat imageFormat = getImageFormat(type.imageInternalFormat);
810 
811         typeId = getNewId({});
812         spirv::WriteTypeImage(&mSpirvTypeAndConstantDecls, typeId, sampledType, dim, depth, arrayed,
813                               multisampled, sampled, imageFormat, nullptr);
814     }
815     else if (type.secondarySize > 1)
816     {
817         // Declaring a matrix.  Declare the column type first, then create a matrix out of it.
818 
819         SpirvType columnType     = type;
820         columnType.primarySize   = columnType.secondarySize;
821         columnType.secondarySize = 1;
822         columnType.typeSpec.onMatrixColumnSelection();
823 
824         const spirv::IdRef columnTypeId = getSpirvTypeData(columnType, nullptr).id;
825 
826         typeId = getNewId({});
827         spirv::WriteTypeMatrix(&mSpirvTypeAndConstantDecls, typeId, columnTypeId,
828                                spirv::LiteralInteger(type.primarySize));
829     }
830     else if (type.primarySize > 1)
831     {
832         // Declaring a vector.  Declare the component type first, then create a vector out of it.
833 
834         SpirvType componentType   = type;
835         componentType.primarySize = 1;
836         componentType.typeSpec.onVectorComponentSelection();
837 
838         const spirv::IdRef componentTypeId = getSpirvTypeData(componentType, nullptr).id;
839 
840         typeId = getNewId({});
841         spirv::WriteTypeVector(&mSpirvTypeAndConstantDecls, typeId, componentTypeId,
842                                spirv::LiteralInteger(type.primarySize));
843     }
844     else
845     {
846         typeId = getNewId({});
847 
848         // Declaring a basic type.  There's a different instruction for each.
849         switch (type.type)
850         {
851             case EbtVoid:
852                 spirv::WriteTypeVoid(&mSpirvTypeAndConstantDecls, typeId);
853                 break;
854             case EbtFloat:
855                 spirv::WriteTypeFloat(&mSpirvTypeAndConstantDecls, typeId,
856                                       spirv::LiteralInteger(32));
857                 break;
858             case EbtDouble:
859                 // TODO: support desktop GLSL.  http://anglebug.com/6197
860                 UNIMPLEMENTED();
861                 break;
862             case EbtInt:
863                 spirv::WriteTypeInt(&mSpirvTypeAndConstantDecls, typeId, spirv::LiteralInteger(32),
864                                     spirv::LiteralInteger(1));
865                 break;
866             case EbtUInt:
867                 spirv::WriteTypeInt(&mSpirvTypeAndConstantDecls, typeId, spirv::LiteralInteger(32),
868                                     spirv::LiteralInteger(0));
869                 break;
870             case EbtBool:
871                 spirv::WriteTypeBool(&mSpirvTypeAndConstantDecls, typeId);
872                 break;
873             default:
874                 UNREACHABLE();
875         }
876     }
877 
878     // If this was a block declaration, add debug information for its type and field names.
879     //
880     // TODO: make this conditional to a compiler flag.  Instead of outputting the debug info
881     // unconditionally and having the SPIR-V transformer remove them, it's better to avoid
882     // generating them in the first place.  This both simplifies the transformer and reduces SPIR-V
883     // binary size that gets written to disk cache.  http://anglebug.com/4889
884     if (block != nullptr && type.arraySizes.empty())
885     {
886         spirv::WriteName(&mSpirvDebug, typeId, hashName(block).data());
887 
888         uint32_t fieldIndex = 0;
889         for (const TField *field : type.block->fields())
890         {
891             spirv::WriteMemberName(&mSpirvDebug, typeId, spirv::LiteralInteger(fieldIndex++),
892                                    hashFieldName(field).data());
893         }
894     }
895 
896     // Write decorations for interface block fields.
897     if (type.typeSpec.blockStorage != EbsUnspecified)
898     {
899         // Cannot have opaque uniforms inside interface blocks.
900         ASSERT(!IsOpaqueType(type.type));
901 
902         const bool isInterfaceBlock = block != nullptr && block->isInterfaceBlock();
903         const bool isStd140         = type.typeSpec.blockStorage != EbsStd430;
904 
905         if (!type.arraySizes.empty() && !isInterfaceBlock)
906         {
907             // Write the ArrayStride decoration for arrays inside interface blocks.  An array of
908             // interface blocks doesn't need a stride.
909             const ShaderVariable var = SpirvTypeToShaderVariable(type);
910             const uint32_t stride    = GetArrayStrideInBlock(var, isStd140);
911 
912             spirv::WriteDecorate(&mSpirvDecorations, typeId, spv::DecorationArrayStride,
913                                  {spirv::LiteralInteger(stride)});
914         }
915         else if (type.arraySizes.empty() && type.block != nullptr)
916         {
917             // Write the Offset decoration for interface blocks and structs in them.
918             const ShaderVariable var = SpirvTypeToShaderVariable(type);
919             Encode(var, isStd140, typeId, &mSpirvDecorations);
920         }
921     }
922 
923     // Write other member decorations.
924     if (block != nullptr && type.arraySizes.empty())
925     {
926         writeMemberDecorations(type, typeId);
927     }
928 
929     return {typeId};
930 }
931 
getImageTypeParameters(TBasicType type,spirv::IdRef * sampledTypeOut,spv::Dim * dimOut,spirv::LiteralInteger * depthOut,spirv::LiteralInteger * arrayedOut,spirv::LiteralInteger * multisampledOut,spirv::LiteralInteger * sampledOut)932 void SPIRVBuilder::getImageTypeParameters(TBasicType type,
933                                           spirv::IdRef *sampledTypeOut,
934                                           spv::Dim *dimOut,
935                                           spirv::LiteralInteger *depthOut,
936                                           spirv::LiteralInteger *arrayedOut,
937                                           spirv::LiteralInteger *multisampledOut,
938                                           spirv::LiteralInteger *sampledOut)
939 {
940     TBasicType sampledType = EbtFloat;
941     *dimOut                = IsSubpassInputType(type) ? spv::DimSubpassData : spv::Dim2D;
942     bool isDepth           = false;
943     bool isArrayed         = false;
944     bool isMultisampled    = false;
945 
946     // Decompose the basic type into image properties
947     switch (type)
948     {
949         // Float 2D Images
950         case EbtSampler2D:
951         case EbtImage2D:
952         case EbtSubpassInput:
953             break;
954         case EbtSamplerExternalOES:
955         case EbtSamplerExternal2DY2YEXT:
956         case EbtSamplerVideoWEBGL:
957             // These must have already been converted to EbtSampler2D.
958             UNREACHABLE();
959             break;
960         case EbtSampler2DArray:
961         case EbtImage2DArray:
962             isArrayed = true;
963             break;
964         case EbtSampler2DMS:
965         case EbtImage2DMS:
966         case EbtSubpassInputMS:
967             isMultisampled = true;
968             break;
969         case EbtSampler2DMSArray:
970         case EbtImage2DMSArray:
971             isArrayed      = true;
972             isMultisampled = true;
973             break;
974         case EbtSampler2DShadow:
975             isDepth = true;
976             break;
977         case EbtSampler2DArrayShadow:
978             isDepth   = true;
979             isArrayed = true;
980             break;
981 
982         // Integer 2D images
983         case EbtISampler2D:
984         case EbtIImage2D:
985         case EbtISubpassInput:
986             sampledType = EbtInt;
987             break;
988         case EbtISampler2DArray:
989         case EbtIImage2DArray:
990             sampledType = EbtInt;
991             isArrayed   = true;
992             break;
993         case EbtISampler2DMS:
994         case EbtIImage2DMS:
995         case EbtISubpassInputMS:
996             sampledType    = EbtInt;
997             isMultisampled = true;
998             break;
999         case EbtISampler2DMSArray:
1000         case EbtIImage2DMSArray:
1001             sampledType    = EbtInt;
1002             isArrayed      = true;
1003             isMultisampled = true;
1004             break;
1005 
1006         // Unsinged integer 2D images
1007         case EbtUSampler2D:
1008         case EbtUImage2D:
1009         case EbtUSubpassInput:
1010             sampledType = EbtUInt;
1011             break;
1012         case EbtUSampler2DArray:
1013         case EbtUImage2DArray:
1014             sampledType = EbtUInt;
1015             isArrayed   = true;
1016             break;
1017         case EbtUSampler2DMS:
1018         case EbtUImage2DMS:
1019         case EbtUSubpassInputMS:
1020             sampledType    = EbtUInt;
1021             isMultisampled = true;
1022             break;
1023         case EbtUSampler2DMSArray:
1024         case EbtUImage2DMSArray:
1025             sampledType    = EbtUInt;
1026             isArrayed      = true;
1027             isMultisampled = true;
1028             break;
1029 
1030         // 3D images
1031         case EbtSampler3D:
1032         case EbtImage3D:
1033             *dimOut = spv::Dim3D;
1034             break;
1035         case EbtISampler3D:
1036         case EbtIImage3D:
1037             sampledType = EbtInt;
1038             *dimOut     = spv::Dim3D;
1039             break;
1040         case EbtUSampler3D:
1041         case EbtUImage3D:
1042             sampledType = EbtUInt;
1043             *dimOut     = spv::Dim3D;
1044             break;
1045 
1046         // Float cube images
1047         case EbtSamplerCube:
1048         case EbtImageCube:
1049             *dimOut = spv::DimCube;
1050             break;
1051         case EbtSamplerCubeArray:
1052         case EbtImageCubeArray:
1053             *dimOut   = spv::DimCube;
1054             isArrayed = true;
1055             break;
1056         case EbtSamplerCubeArrayShadow:
1057             *dimOut   = spv::DimCube;
1058             isDepth   = true;
1059             isArrayed = true;
1060             break;
1061         case EbtSamplerCubeShadow:
1062             *dimOut = spv::DimCube;
1063             isDepth = true;
1064             break;
1065 
1066         // Integer cube images
1067         case EbtISamplerCube:
1068         case EbtIImageCube:
1069             sampledType = EbtInt;
1070             *dimOut     = spv::DimCube;
1071             break;
1072         case EbtISamplerCubeArray:
1073         case EbtIImageCubeArray:
1074             sampledType = EbtInt;
1075             *dimOut     = spv::DimCube;
1076             isArrayed   = true;
1077             break;
1078 
1079         // Unsigned integer cube images
1080         case EbtUSamplerCube:
1081         case EbtUImageCube:
1082             sampledType = EbtUInt;
1083             *dimOut     = spv::DimCube;
1084             break;
1085         case EbtUSamplerCubeArray:
1086         case EbtUImageCubeArray:
1087             sampledType = EbtUInt;
1088             *dimOut     = spv::DimCube;
1089             isArrayed   = true;
1090             break;
1091 
1092         // Float 1D images
1093         case EbtSampler1D:
1094         case EbtImage1D:
1095             *dimOut = spv::Dim1D;
1096             break;
1097         case EbtSampler1DArray:
1098         case EbtImage1DArray:
1099             *dimOut   = spv::Dim1D;
1100             isArrayed = true;
1101             break;
1102         case EbtSampler1DShadow:
1103             *dimOut = spv::Dim1D;
1104             isDepth = true;
1105             break;
1106         case EbtSampler1DArrayShadow:
1107             *dimOut   = spv::Dim1D;
1108             isDepth   = true;
1109             isArrayed = true;
1110             break;
1111 
1112         // Integer 1D images
1113         case EbtISampler1D:
1114         case EbtIImage1D:
1115             sampledType = EbtInt;
1116             *dimOut     = spv::Dim1D;
1117             break;
1118         case EbtISampler1DArray:
1119         case EbtIImage1DArray:
1120             sampledType = EbtInt;
1121             *dimOut     = spv::Dim1D;
1122             isArrayed   = true;
1123             break;
1124 
1125         // Unsigned integer 1D images
1126         case EbtUSampler1D:
1127         case EbtUImage1D:
1128             sampledType = EbtUInt;
1129             *dimOut     = spv::Dim1D;
1130             break;
1131         case EbtUSampler1DArray:
1132         case EbtUImage1DArray:
1133             sampledType = EbtUInt;
1134             *dimOut     = spv::Dim1D;
1135             isArrayed   = true;
1136             break;
1137 
1138         // Rect images
1139         case EbtSampler2DRect:
1140         case EbtImageRect:
1141             *dimOut = spv::DimRect;
1142             break;
1143         case EbtSampler2DRectShadow:
1144             *dimOut = spv::DimRect;
1145             isDepth = true;
1146             break;
1147         case EbtISampler2DRect:
1148         case EbtIImageRect:
1149             sampledType = EbtInt;
1150             *dimOut     = spv::DimRect;
1151             break;
1152         case EbtUSampler2DRect:
1153         case EbtUImageRect:
1154             sampledType = EbtUInt;
1155             *dimOut     = spv::DimRect;
1156             break;
1157 
1158         // Image buffers
1159         case EbtSamplerBuffer:
1160         case EbtImageBuffer:
1161             *dimOut = spv::DimBuffer;
1162             break;
1163         case EbtISamplerBuffer:
1164         case EbtIImageBuffer:
1165             sampledType = EbtInt;
1166             *dimOut     = spv::DimBuffer;
1167             break;
1168         case EbtUSamplerBuffer:
1169         case EbtUImageBuffer:
1170             sampledType = EbtUInt;
1171             *dimOut     = spv::DimBuffer;
1172             break;
1173         default:
1174             UNREACHABLE();
1175     }
1176 
1177     // Get id of the component type of the image
1178     SpirvType sampledSpirvType;
1179     sampledSpirvType.type = sampledType;
1180 
1181     *sampledTypeOut = getSpirvTypeData(sampledSpirvType, nullptr).id;
1182 
1183     const bool isSampledImage = IsSampler(type);
1184 
1185     // Set flags based on SPIR-V required values.  See OpTypeImage:
1186     //
1187     // - For depth:        0 = non-depth,      1 = depth
1188     // - For arrayed:      0 = non-arrayed,    1 = arrayed
1189     // - For multisampled: 0 = single-sampled, 1 = multisampled
1190     // - For sampled:      1 = sampled,        2 = storage
1191     //
1192     *depthOut        = spirv::LiteralInteger(isDepth ? 1 : 0);
1193     *arrayedOut      = spirv::LiteralInteger(isArrayed ? 1 : 0);
1194     *multisampledOut = spirv::LiteralInteger(isMultisampled ? 1 : 0);
1195     *sampledOut      = spirv::LiteralInteger(isSampledImage ? 1 : 2);
1196 
1197     // Add the necessary capability based on parameters.  The SPIR-V spec section 3.8 Dim specfies
1198     // the required capabilities:
1199     //
1200     //     Dim          Sampled         Storage            Storage Array
1201     //     --------------------------------------------------------------
1202     //     1D           Sampled1D       Image1D
1203     //     2D           Shader                             ImageMSArray
1204     //     3D
1205     //     Cube         Shader                             ImageCubeArray
1206     //     Rect         SampledRect     ImageRect
1207     //     Buffer       SampledBuffer   ImageBuffer
1208     //
1209     // Additionally, the SubpassData Dim requires the InputAttachment capability.
1210     //
1211     // Note that the Shader capability is always unconditionally added.
1212     //
1213     switch (*dimOut)
1214     {
1215         case spv::Dim1D:
1216             addCapability(isSampledImage ? spv::CapabilitySampled1D : spv::CapabilityImage1D);
1217             break;
1218         case spv::Dim2D:
1219             if (!isSampledImage && isArrayed && isMultisampled)
1220             {
1221                 addCapability(spv::CapabilityImageMSArray);
1222             }
1223             break;
1224         case spv::Dim3D:
1225             break;
1226         case spv::DimCube:
1227             if (!isSampledImage && isArrayed)
1228             {
1229                 addCapability(spv::CapabilityImageCubeArray);
1230             }
1231             break;
1232         case spv::DimRect:
1233             addCapability(isSampledImage ? spv::CapabilitySampledRect : spv::CapabilityImageRect);
1234             break;
1235         case spv::DimBuffer:
1236             addCapability(isSampledImage ? spv::CapabilitySampledBuffer
1237                                          : spv::CapabilityImageBuffer);
1238             break;
1239         case spv::DimSubpassData:
1240             addCapability(spv::CapabilityInputAttachment);
1241             break;
1242         default:
1243             UNREACHABLE();
1244     }
1245 }
1246 
getImageFormat(TLayoutImageInternalFormat imageInternalFormat)1247 spv::ImageFormat SPIRVBuilder::getImageFormat(TLayoutImageInternalFormat imageInternalFormat)
1248 {
1249     switch (imageInternalFormat)
1250     {
1251         case EiifUnspecified:
1252             return spv::ImageFormatUnknown;
1253         case EiifRGBA32F:
1254             return spv::ImageFormatRgba32f;
1255         case EiifRGBA16F:
1256             return spv::ImageFormatRgba16f;
1257         case EiifR32F:
1258             return spv::ImageFormatR32f;
1259         case EiifRGBA32UI:
1260             return spv::ImageFormatRgba32ui;
1261         case EiifRGBA16UI:
1262             return spv::ImageFormatRgba16ui;
1263         case EiifRGBA8UI:
1264             return spv::ImageFormatRgba8ui;
1265         case EiifR32UI:
1266             return spv::ImageFormatR32ui;
1267         case EiifRGBA32I:
1268             return spv::ImageFormatRgba32i;
1269         case EiifRGBA16I:
1270             return spv::ImageFormatRgba16i;
1271         case EiifRGBA8I:
1272             return spv::ImageFormatRgba8i;
1273         case EiifR32I:
1274             return spv::ImageFormatR32i;
1275         case EiifRGBA8:
1276             return spv::ImageFormatRgba8;
1277         case EiifRGBA8_SNORM:
1278             return spv::ImageFormatRgba8Snorm;
1279         default:
1280             UNREACHABLE();
1281             return spv::ImageFormatUnknown;
1282     }
1283 }
1284 
getBoolConstant(bool value)1285 spirv::IdRef SPIRVBuilder::getBoolConstant(bool value)
1286 {
1287     uint32_t asInt = static_cast<uint32_t>(value);
1288 
1289     spirv::IdRef constantId = mBoolConstants[asInt];
1290 
1291     if (!constantId.valid())
1292     {
1293         SpirvType boolType;
1294         boolType.type = EbtBool;
1295 
1296         const spirv::IdRef boolTypeId = getSpirvTypeData(boolType, nullptr).id;
1297 
1298         mBoolConstants[asInt] = constantId = getNewId({});
1299         if (value)
1300         {
1301             spirv::WriteConstantTrue(&mSpirvTypeAndConstantDecls, boolTypeId, constantId);
1302         }
1303         else
1304         {
1305             spirv::WriteConstantFalse(&mSpirvTypeAndConstantDecls, boolTypeId, constantId);
1306         }
1307     }
1308 
1309     return constantId;
1310 }
1311 
getBasicConstantHelper(uint32_t value,TBasicType type,angle::HashMap<uint32_t,spirv::IdRef> * constants)1312 spirv::IdRef SPIRVBuilder::getBasicConstantHelper(uint32_t value,
1313                                                   TBasicType type,
1314                                                   angle::HashMap<uint32_t, spirv::IdRef> *constants)
1315 {
1316     auto iter = constants->find(value);
1317     if (iter != constants->end())
1318     {
1319         return iter->second;
1320     }
1321 
1322     SpirvType spirvType;
1323     spirvType.type = type;
1324 
1325     const spirv::IdRef typeId     = getSpirvTypeData(spirvType, nullptr).id;
1326     const spirv::IdRef constantId = getNewId({});
1327 
1328     spirv::WriteConstant(&mSpirvTypeAndConstantDecls, typeId, constantId,
1329                          spirv::LiteralContextDependentNumber(value));
1330 
1331     return constants->insert({value, constantId}).first->second;
1332 }
1333 
getUintConstant(uint32_t value)1334 spirv::IdRef SPIRVBuilder::getUintConstant(uint32_t value)
1335 {
1336     return getBasicConstantHelper(value, EbtUInt, &mUintConstants);
1337 }
1338 
getIntConstant(int32_t value)1339 spirv::IdRef SPIRVBuilder::getIntConstant(int32_t value)
1340 {
1341     uint32_t asUint = static_cast<uint32_t>(value);
1342     return getBasicConstantHelper(asUint, EbtInt, &mIntConstants);
1343 }
1344 
getFloatConstant(float value)1345 spirv::IdRef SPIRVBuilder::getFloatConstant(float value)
1346 {
1347     union
1348     {
1349         float f;
1350         uint32_t u;
1351     } asUint;
1352     asUint.f = value;
1353     return getBasicConstantHelper(asUint.u, EbtFloat, &mFloatConstants);
1354 }
1355 
getNullConstant(spirv::IdRef typeId)1356 spirv::IdRef SPIRVBuilder::getNullConstant(spirv::IdRef typeId)
1357 {
1358     if (typeId >= mNullConstants.size())
1359     {
1360         mNullConstants.resize(typeId + 1);
1361     }
1362 
1363     if (!mNullConstants[typeId].valid())
1364     {
1365         const spirv::IdRef constantId = getNewId({});
1366         mNullConstants[typeId]        = constantId;
1367 
1368         spirv::WriteConstantNull(&mSpirvTypeAndConstantDecls, typeId, constantId);
1369     }
1370 
1371     return mNullConstants[typeId];
1372 }
1373 
getNullVectorConstantHelper(TBasicType type,int size)1374 spirv::IdRef SPIRVBuilder::getNullVectorConstantHelper(TBasicType type, int size)
1375 {
1376     SpirvType vecType;
1377     vecType.type        = type;
1378     vecType.primarySize = static_cast<uint8_t>(size);
1379 
1380     return getNullConstant(getSpirvTypeData(vecType, nullptr).id);
1381 }
1382 
getVectorConstantHelper(spirv::IdRef valueId,TBasicType type,int size)1383 spirv::IdRef SPIRVBuilder::getVectorConstantHelper(spirv::IdRef valueId, TBasicType type, int size)
1384 {
1385     if (size == 1)
1386     {
1387         return valueId;
1388     }
1389 
1390     SpirvType vecType;
1391     vecType.type        = type;
1392     vecType.primarySize = static_cast<uint8_t>(size);
1393 
1394     const spirv::IdRef typeId = getSpirvTypeData(vecType, nullptr).id;
1395     const spirv::IdRefList valueIds(size, valueId);
1396 
1397     return getCompositeConstant(typeId, valueIds);
1398 }
1399 
getUvecConstant(uint32_t value,int size)1400 spirv::IdRef SPIRVBuilder::getUvecConstant(uint32_t value, int size)
1401 {
1402     if (value == 0)
1403     {
1404         return getNullVectorConstantHelper(EbtUInt, size);
1405     }
1406 
1407     const spirv::IdRef valueId = getUintConstant(value);
1408     return getVectorConstantHelper(valueId, EbtUInt, size);
1409 }
1410 
getIvecConstant(int32_t value,int size)1411 spirv::IdRef SPIRVBuilder::getIvecConstant(int32_t value, int size)
1412 {
1413     if (value == 0)
1414     {
1415         return getNullVectorConstantHelper(EbtInt, size);
1416     }
1417 
1418     const spirv::IdRef valueId = getIntConstant(value);
1419     return getVectorConstantHelper(valueId, EbtInt, size);
1420 }
1421 
getVecConstant(float value,int size)1422 spirv::IdRef SPIRVBuilder::getVecConstant(float value, int size)
1423 {
1424     if (value == 0)
1425     {
1426         return getNullVectorConstantHelper(EbtFloat, size);
1427     }
1428 
1429     const spirv::IdRef valueId = getFloatConstant(value);
1430     return getVectorConstantHelper(valueId, EbtFloat, size);
1431 }
1432 
getCompositeConstant(spirv::IdRef typeId,const spirv::IdRefList & values)1433 spirv::IdRef SPIRVBuilder::getCompositeConstant(spirv::IdRef typeId, const spirv::IdRefList &values)
1434 {
1435     SpirvIdAndIdList key{typeId, values};
1436 
1437     auto iter = mCompositeConstants.find(key);
1438     if (iter == mCompositeConstants.end())
1439     {
1440         const spirv::IdRef constantId = getNewId({});
1441 
1442         spirv::WriteConstantComposite(&mSpirvTypeAndConstantDecls, typeId, constantId, values);
1443 
1444         iter = mCompositeConstants.insert({key, constantId}).first;
1445     }
1446 
1447     return iter->second;
1448 }
1449 
startNewFunction(spirv::IdRef functionId,const TFunction * func)1450 void SPIRVBuilder::startNewFunction(spirv::IdRef functionId, const TFunction *func)
1451 {
1452     ASSERT(mSpirvCurrentFunctionBlocks.empty());
1453 
1454     // Add the first block of the function.
1455     mSpirvCurrentFunctionBlocks.emplace_back();
1456     mSpirvCurrentFunctionBlocks.back().labelId = getNewId({});
1457 
1458     // Output debug information.
1459     spirv::WriteName(&mSpirvDebug, functionId, hashFunctionName(func).data());
1460 }
1461 
assembleSpirvFunctionBlocks()1462 void SPIRVBuilder::assembleSpirvFunctionBlocks()
1463 {
1464     // Take all the blocks and place them in the functions section of SPIR-V in sequence.
1465     for (const SpirvBlock &block : mSpirvCurrentFunctionBlocks)
1466     {
1467         // Every block must be properly terminated.
1468         ASSERT(block.isTerminated);
1469 
1470         // Generate the OpLabel instruction for the block.
1471         spirv::WriteLabel(&mSpirvFunctions, block.labelId);
1472 
1473         // Add the variable declarations if any.
1474         mSpirvFunctions.insert(mSpirvFunctions.end(), block.localVariables.begin(),
1475                                block.localVariables.end());
1476 
1477         // Add the body of the block.
1478         mSpirvFunctions.insert(mSpirvFunctions.end(), block.body.begin(), block.body.end());
1479     }
1480 
1481     // Clean up.
1482     mSpirvCurrentFunctionBlocks.clear();
1483 }
1484 
declareVariable(spirv::IdRef typeId,spv::StorageClass storageClass,const SpirvDecorations & decorations,spirv::IdRef * initializerId,const char * name)1485 spirv::IdRef SPIRVBuilder::declareVariable(spirv::IdRef typeId,
1486                                            spv::StorageClass storageClass,
1487                                            const SpirvDecorations &decorations,
1488                                            spirv::IdRef *initializerId,
1489                                            const char *name)
1490 {
1491     const bool isFunctionLocal = storageClass == spv::StorageClassFunction;
1492 
1493     // Make sure storage class is consistent with where the variable is declared.
1494     ASSERT(!isFunctionLocal || !mSpirvCurrentFunctionBlocks.empty());
1495 
1496     // Function-local variables go in the first block of the function, while the rest are in the
1497     // global variables section.
1498     spirv::Blob *spirvSection = isFunctionLocal
1499                                     ? &mSpirvCurrentFunctionBlocks.front().localVariables
1500                                     : &mSpirvVariableDecls;
1501 
1502     const spirv::IdRef typePointerId = getTypePointerId(typeId, storageClass);
1503     const spirv::IdRef variableId    = getNewId(decorations);
1504 
1505     spirv::WriteVariable(spirvSection, typePointerId, variableId, storageClass, initializerId);
1506 
1507     // Output debug information.
1508     if (name)
1509     {
1510         spirv::WriteName(&mSpirvDebug, variableId, name);
1511     }
1512 
1513     return variableId;
1514 }
1515 
declareSpecConst(TBasicType type,int id,const char * name)1516 spirv::IdRef SPIRVBuilder::declareSpecConst(TBasicType type, int id, const char *name)
1517 {
1518     SpirvType spirvType;
1519     spirvType.type = type;
1520 
1521     const spirv::IdRef typeId      = getSpirvTypeData(spirvType, nullptr).id;
1522     const spirv::IdRef specConstId = getNewId({});
1523 
1524     // Note: all spec constants are 0 initialized by the translator.
1525     if (type == EbtBool)
1526     {
1527         spirv::WriteSpecConstantFalse(&mSpirvTypeAndConstantDecls, typeId, specConstId);
1528     }
1529     else
1530     {
1531         spirv::WriteSpecConstant(&mSpirvTypeAndConstantDecls, typeId, specConstId,
1532                                  spirv::LiteralContextDependentNumber(0));
1533     }
1534 
1535     // Add the SpecId decoration
1536     spirv::WriteDecorate(&mSpirvDecorations, specConstId, spv::DecorationSpecId,
1537                          {spirv::LiteralInteger(id)});
1538 
1539     // Output debug information.
1540     if (name)
1541     {
1542         spirv::WriteName(&mSpirvDebug, specConstId, name);
1543     }
1544 
1545     return specConstId;
1546 }
1547 
startConditional(size_t blockCount,bool isContinuable,bool isBreakable)1548 void SPIRVBuilder::startConditional(size_t blockCount, bool isContinuable, bool isBreakable)
1549 {
1550     mConditionalStack.emplace_back();
1551     SpirvConditional &conditional = mConditionalStack.back();
1552 
1553     // Create the requested number of block ids.
1554     conditional.blockIds.resize(blockCount);
1555     for (spirv::IdRef &blockId : conditional.blockIds)
1556     {
1557         blockId = getNewId({});
1558     }
1559 
1560     conditional.isContinuable = isContinuable;
1561     conditional.isBreakable   = isBreakable;
1562 
1563     // Don't automatically start the next block.  The caller needs to generate instructions based on
1564     // the ids that were just generated above.
1565 }
1566 
nextConditionalBlock()1567 void SPIRVBuilder::nextConditionalBlock()
1568 {
1569     ASSERT(!mConditionalStack.empty());
1570     SpirvConditional &conditional = mConditionalStack.back();
1571 
1572     ASSERT(conditional.nextBlockToWrite < conditional.blockIds.size());
1573     const spirv::IdRef blockId = conditional.blockIds[conditional.nextBlockToWrite++];
1574 
1575     // The previous block must have properly terminated.
1576     ASSERT(isCurrentFunctionBlockTerminated());
1577 
1578     // Generate a new block.
1579     mSpirvCurrentFunctionBlocks.emplace_back();
1580     mSpirvCurrentFunctionBlocks.back().labelId = blockId;
1581 }
1582 
endConditional()1583 void SPIRVBuilder::endConditional()
1584 {
1585     ASSERT(!mConditionalStack.empty());
1586 
1587     // No blocks should be left.
1588     ASSERT(mConditionalStack.back().nextBlockToWrite == mConditionalStack.back().blockIds.size());
1589 
1590     mConditionalStack.pop_back();
1591 }
1592 
isInLoop() const1593 bool SPIRVBuilder::isInLoop() const
1594 {
1595     for (const SpirvConditional &conditional : mConditionalStack)
1596     {
1597         if (conditional.isContinuable)
1598         {
1599             return true;
1600         }
1601     }
1602 
1603     return false;
1604 }
1605 
getBreakTargetId() const1606 spirv::IdRef SPIRVBuilder::getBreakTargetId() const
1607 {
1608     for (size_t index = mConditionalStack.size(); index > 0; --index)
1609     {
1610         const SpirvConditional &conditional = mConditionalStack[index - 1];
1611 
1612         if (conditional.isBreakable)
1613         {
1614             // The target of break; is always the merge block, and the merge block is always the
1615             // last block.
1616             return conditional.blockIds.back();
1617         }
1618     }
1619 
1620     UNREACHABLE();
1621     return spirv::IdRef{};
1622 }
1623 
getContinueTargetId() const1624 spirv::IdRef SPIRVBuilder::getContinueTargetId() const
1625 {
1626     for (size_t index = mConditionalStack.size(); index > 0; --index)
1627     {
1628         const SpirvConditional &conditional = mConditionalStack[index - 1];
1629 
1630         if (conditional.isContinuable)
1631         {
1632             // The target of continue; is always the block before merge, so it's the one before
1633             // last.
1634             ASSERT(conditional.blockIds.size() > 2);
1635             return conditional.blockIds[conditional.blockIds.size() - 2];
1636         }
1637     }
1638 
1639     UNREACHABLE();
1640     return spirv::IdRef{};
1641 }
1642 
nextUnusedBinding()1643 uint32_t SPIRVBuilder::nextUnusedBinding()
1644 {
1645     return mNextUnusedBinding++;
1646 }
1647 
nextUnusedInputLocation(uint32_t consumedCount)1648 uint32_t SPIRVBuilder::nextUnusedInputLocation(uint32_t consumedCount)
1649 {
1650     uint32_t nextUnused = mNextUnusedInputLocation;
1651     mNextUnusedInputLocation += consumedCount;
1652     return nextUnused;
1653 }
1654 
nextUnusedOutputLocation(uint32_t consumedCount)1655 uint32_t SPIRVBuilder::nextUnusedOutputLocation(uint32_t consumedCount)
1656 {
1657     uint32_t nextUnused = mNextUnusedOutputLocation;
1658     mNextUnusedOutputLocation += consumedCount;
1659     return nextUnused;
1660 }
1661 
isInvariantOutput(const TType & type) const1662 bool SPIRVBuilder::isInvariantOutput(const TType &type) const
1663 {
1664     return IsInvariant(type, mCompiler);
1665 }
1666 
addCapability(spv::Capability capability)1667 void SPIRVBuilder::addCapability(spv::Capability capability)
1668 {
1669     mCapabilities.insert(capability);
1670 }
1671 
addExecutionMode(spv::ExecutionMode executionMode)1672 void SPIRVBuilder::addExecutionMode(spv::ExecutionMode executionMode)
1673 {
1674     ASSERT(static_cast<size_t>(executionMode) < mExecutionModes.size());
1675     mExecutionModes.set(executionMode);
1676 }
1677 
addExtension(SPIRVExtensions extension)1678 void SPIRVBuilder::addExtension(SPIRVExtensions extension)
1679 {
1680     mExtensions.set(extension);
1681 }
1682 
setEntryPointId(spirv::IdRef id)1683 void SPIRVBuilder::setEntryPointId(spirv::IdRef id)
1684 {
1685     ASSERT(!mEntryPointId.valid());
1686     mEntryPointId = id;
1687 }
1688 
addEntryPointInterfaceVariableId(spirv::IdRef id)1689 void SPIRVBuilder::addEntryPointInterfaceVariableId(spirv::IdRef id)
1690 {
1691     mEntryPointInterfaceList.push_back(id);
1692 }
1693 
writePerVertexBuiltIns(const TType & type,spirv::IdRef typeId)1694 void SPIRVBuilder::writePerVertexBuiltIns(const TType &type, spirv::IdRef typeId)
1695 {
1696     ASSERT(type.isInterfaceBlock());
1697     const TInterfaceBlock *block = type.getInterfaceBlock();
1698 
1699     uint32_t fieldIndex = 0;
1700     for (const TField *field : block->fields())
1701     {
1702         spv::BuiltIn decorationValue = spv::BuiltInPosition;
1703         switch (field->type()->getQualifier())
1704         {
1705             case EvqPosition:
1706                 decorationValue = spv::BuiltInPosition;
1707                 break;
1708             case EvqPointSize:
1709                 decorationValue = spv::BuiltInPointSize;
1710                 break;
1711             case EvqClipDistance:
1712                 decorationValue = spv::BuiltInClipDistance;
1713                 break;
1714             case EvqCullDistance:
1715                 decorationValue = spv::BuiltInCullDistance;
1716                 break;
1717             default:
1718                 UNREACHABLE();
1719         }
1720 
1721         spirv::WriteMemberDecorate(&mSpirvDecorations, typeId, spirv::LiteralInteger(fieldIndex++),
1722                                    spv::DecorationBuiltIn,
1723                                    {spirv::LiteralInteger(decorationValue)});
1724     }
1725 }
1726 
writeInterfaceVariableDecorations(const TType & type,spirv::IdRef variableId)1727 void SPIRVBuilder::writeInterfaceVariableDecorations(const TType &type, spirv::IdRef variableId)
1728 {
1729     const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
1730 
1731     const bool isVarying = IsVarying(type.getQualifier());
1732     const bool needsSetBinding =
1733         IsSampler(type.getBasicType()) ||
1734         (type.isInterfaceBlock() &&
1735          (type.getQualifier() == EvqUniform || type.getQualifier() == EvqBuffer)) ||
1736         IsImage(type.getBasicType()) || IsSubpassInputType(type.getBasicType());
1737     const bool needsLocation = type.getQualifier() == EvqAttribute ||
1738                                type.getQualifier() == EvqVertexIn ||
1739                                type.getQualifier() == EvqFragmentOut || isVarying;
1740     const bool needsInputAttachmentIndex = IsSubpassInputType(type.getBasicType());
1741     const bool needsBlendIndex =
1742         type.getQualifier() == EvqFragmentOut && layoutQualifier.index >= 0;
1743 
1744     // If the resource declaration requires set & binding, add the DescriptorSet and Binding
1745     // decorations.
1746     if (needsSetBinding)
1747     {
1748         spirv::WriteDecorate(&mSpirvDecorations, variableId, spv::DecorationDescriptorSet,
1749                              {spirv::LiteralInteger(0)});
1750         spirv::WriteDecorate(&mSpirvDecorations, variableId, spv::DecorationBinding,
1751                              {spirv::LiteralInteger(nextUnusedBinding())});
1752     }
1753 
1754     if (needsLocation)
1755     {
1756         const unsigned int locationCount =
1757             CalculateVaryingLocationCount(type, gl::ToGLenum(mShaderType));
1758         const uint32_t location = IsShaderIn(type.getQualifier())
1759                                       ? nextUnusedInputLocation(locationCount)
1760                                       : nextUnusedOutputLocation(locationCount);
1761 
1762         spirv::WriteDecorate(&mSpirvDecorations, variableId, spv::DecorationLocation,
1763                              {spirv::LiteralInteger(location)});
1764     }
1765 
1766     // If the resource declaration is an input attachment, add the InputAttachmentIndex decoration.
1767     if (needsInputAttachmentIndex)
1768     {
1769         spirv::WriteDecorate(&mSpirvDecorations, variableId, spv::DecorationInputAttachmentIndex,
1770                              {spirv::LiteralInteger(layoutQualifier.inputAttachmentIndex)});
1771     }
1772 
1773     if (needsBlendIndex)
1774     {
1775         spirv::WriteDecorate(&mSpirvDecorations, variableId, spv::DecorationIndex,
1776                              {spirv::LiteralInteger(layoutQualifier.index)});
1777     }
1778 
1779     // Handle interpolation and auxiliary decorations on varyings
1780     if (isVarying)
1781     {
1782         writeInterpolationDecoration(type.getQualifier(), variableId,
1783                                      std::numeric_limits<uint32_t>::max());
1784     }
1785 }
1786 
writeBranchConditional(spirv::IdRef conditionValue,spirv::IdRef trueBlock,spirv::IdRef falseBlock,spirv::IdRef mergeBlock)1787 void SPIRVBuilder::writeBranchConditional(spirv::IdRef conditionValue,
1788                                           spirv::IdRef trueBlock,
1789                                           spirv::IdRef falseBlock,
1790                                           spirv::IdRef mergeBlock)
1791 {
1792     // Generate the following:
1793     //
1794     //     OpSelectionMerge %mergeBlock None
1795     //     OpBranchConditional %conditionValue %trueBlock %falseBlock
1796     //
1797     spirv::WriteSelectionMerge(getSpirvCurrentFunctionBlock(), mergeBlock,
1798                                spv::SelectionControlMaskNone);
1799     spirv::WriteBranchConditional(getSpirvCurrentFunctionBlock(), conditionValue, trueBlock,
1800                                   falseBlock, {});
1801     terminateCurrentFunctionBlock();
1802 
1803     // Start the true or false block, whichever exists.
1804     nextConditionalBlock();
1805 }
1806 
writeBranchConditionalBlockEnd()1807 void SPIRVBuilder::writeBranchConditionalBlockEnd()
1808 {
1809     if (!isCurrentFunctionBlockTerminated())
1810     {
1811         // Insert a branch to the merge block at the end of each if-else block, unless the block is
1812         // already terminated, such as with a return or discard.
1813         const spirv::IdRef mergeBlock = getCurrentConditional()->blockIds.back();
1814 
1815         spirv::WriteBranch(getSpirvCurrentFunctionBlock(), mergeBlock);
1816         terminateCurrentFunctionBlock();
1817     }
1818 
1819     // Move on to the next block.
1820     nextConditionalBlock();
1821 }
1822 
writeLoopHeader(spirv::IdRef branchToBlock,spirv::IdRef continueBlock,spirv::IdRef mergeBlock)1823 void SPIRVBuilder::writeLoopHeader(spirv::IdRef branchToBlock,
1824                                    spirv::IdRef continueBlock,
1825                                    spirv::IdRef mergeBlock)
1826 {
1827     // First, jump to the header block:
1828     //
1829     //     OpBranch %header
1830     //
1831     const spirv::IdRef headerBlock = mConditionalStack.back().blockIds[0];
1832     spirv::WriteBranch(getSpirvCurrentFunctionBlock(), headerBlock);
1833     terminateCurrentFunctionBlock();
1834 
1835     // Start the header block.
1836     nextConditionalBlock();
1837 
1838     // Generate the following:
1839     //
1840     //     OpLoopMerge %mergeBlock %continueBlock None
1841     //     OpBranch %branchToBlock (%cond or if do-while, %body)
1842     //
1843     spirv::WriteLoopMerge(getSpirvCurrentFunctionBlock(), mergeBlock, continueBlock,
1844                           spv::LoopControlMaskNone);
1845     spirv::WriteBranch(getSpirvCurrentFunctionBlock(), branchToBlock);
1846     terminateCurrentFunctionBlock();
1847 
1848     // Start the next block, which is either %cond or %body.
1849     nextConditionalBlock();
1850 }
1851 
writeLoopConditionEnd(spirv::IdRef conditionValue,spirv::IdRef branchToBlock,spirv::IdRef mergeBlock)1852 void SPIRVBuilder::writeLoopConditionEnd(spirv::IdRef conditionValue,
1853                                          spirv::IdRef branchToBlock,
1854                                          spirv::IdRef mergeBlock)
1855 {
1856     // Generate the following:
1857     //
1858     //     OpBranchConditional %conditionValue %branchToBlock %mergeBlock
1859     //
1860     // %branchToBlock is either %body or if do-while, %header
1861     //
1862     spirv::WriteBranchConditional(getSpirvCurrentFunctionBlock(), conditionValue, branchToBlock,
1863                                   mergeBlock, {});
1864     terminateCurrentFunctionBlock();
1865 
1866     // Start the next block, which is either %continue or %body.
1867     nextConditionalBlock();
1868 }
1869 
writeLoopContinueEnd(spirv::IdRef headerBlock)1870 void SPIRVBuilder::writeLoopContinueEnd(spirv::IdRef headerBlock)
1871 {
1872     // Generate the following:
1873     //
1874     //     OpBranch %headerBlock
1875     //
1876     spirv::WriteBranch(getSpirvCurrentFunctionBlock(), headerBlock);
1877     terminateCurrentFunctionBlock();
1878 
1879     // Start the next block, which is %body.
1880     nextConditionalBlock();
1881 }
1882 
writeLoopBodyEnd(spirv::IdRef continueBlock)1883 void SPIRVBuilder::writeLoopBodyEnd(spirv::IdRef continueBlock)
1884 {
1885     // Generate the following:
1886     //
1887     //     OpBranch %continueBlock
1888     //
1889     // This is only done if the block isn't already terminated in another way, such as with an
1890     // unconditional continue/etc at the end of the loop.
1891     if (!isCurrentFunctionBlockTerminated())
1892     {
1893         spirv::WriteBranch(getSpirvCurrentFunctionBlock(), continueBlock);
1894         terminateCurrentFunctionBlock();
1895     }
1896 
1897     // Start the next block, which is %merge or if while, %continue.
1898     nextConditionalBlock();
1899 }
1900 
writeSwitch(spirv::IdRef conditionValue,spirv::IdRef defaultBlock,const spirv::PairLiteralIntegerIdRefList & targetPairList,spirv::IdRef mergeBlock)1901 void SPIRVBuilder::writeSwitch(spirv::IdRef conditionValue,
1902                                spirv::IdRef defaultBlock,
1903                                const spirv::PairLiteralIntegerIdRefList &targetPairList,
1904                                spirv::IdRef mergeBlock)
1905 {
1906     // Generate the following:
1907     //
1908     //     OpSelectionMerge %mergeBlock None
1909     //     OpSwitch %conditionValue %defaultBlock A %ABlock B %BBlock ...
1910     //
1911     spirv::WriteSelectionMerge(getSpirvCurrentFunctionBlock(), mergeBlock,
1912                                spv::SelectionControlMaskNone);
1913     spirv::WriteSwitch(getSpirvCurrentFunctionBlock(), conditionValue, defaultBlock,
1914                        targetPairList);
1915     terminateCurrentFunctionBlock();
1916 
1917     // Start the next case block.
1918     nextConditionalBlock();
1919 }
1920 
writeSwitchCaseBlockEnd()1921 void SPIRVBuilder::writeSwitchCaseBlockEnd()
1922 {
1923     if (!isCurrentFunctionBlockTerminated())
1924     {
1925         // If a case does not end in branch, insert a branch to the next block, implementing
1926         // fallthrough.  For the last block, the branch target would automatically be the merge
1927         // block.
1928         const SpirvConditional *conditional = getCurrentConditional();
1929         const spirv::IdRef nextBlock        = conditional->blockIds[conditional->nextBlockToWrite];
1930 
1931         spirv::WriteBranch(getSpirvCurrentFunctionBlock(), nextBlock);
1932         terminateCurrentFunctionBlock();
1933     }
1934 
1935     // Move on to the next block.
1936     nextConditionalBlock();
1937 }
1938 
writeMemberDecorations(const SpirvType & type,spirv::IdRef typeId)1939 void SPIRVBuilder::writeMemberDecorations(const SpirvType &type, spirv::IdRef typeId)
1940 {
1941     ASSERT(type.block != nullptr);
1942 
1943     uint32_t fieldIndex = 0;
1944 
1945     for (const TField *field : type.block->fields())
1946     {
1947         const TType &fieldType = *field->type();
1948 
1949         // Add invariant decoration if any.
1950         if (type.typeSpec.isInvariantBlock || fieldType.isInvariant())
1951         {
1952             spirv::WriteMemberDecorate(&mSpirvDecorations, typeId,
1953                                        spirv::LiteralInteger(fieldIndex), spv::DecorationInvariant,
1954                                        {});
1955         }
1956 
1957         // Add matrix decorations if any.
1958         if (fieldType.isMatrix())
1959         {
1960             // ColMajor or RowMajor
1961             const bool isRowMajor =
1962                 IsBlockFieldRowMajorQualified(fieldType, type.typeSpec.isRowMajorQualifiedBlock);
1963             spirv::WriteMemberDecorate(
1964                 &mSpirvDecorations, typeId, spirv::LiteralInteger(fieldIndex),
1965                 isRowMajor ? spv::DecorationRowMajor : spv::DecorationColMajor, {});
1966         }
1967 
1968         // Add interpolation and auxiliary decorations
1969         writeInterpolationDecoration(fieldType.getQualifier(), typeId, fieldIndex);
1970 
1971         // Add patch decoration if any.
1972         if (type.typeSpec.isPatchIOBlock)
1973         {
1974             spirv::WriteMemberDecorate(&mSpirvDecorations, typeId,
1975                                        spirv::LiteralInteger(fieldIndex), spv::DecorationPatch, {});
1976         }
1977 
1978         // Add other decorations.
1979         SpirvDecorations decorations = getDecorations(fieldType);
1980         for (const spv::Decoration decoration : decorations)
1981         {
1982             spirv::WriteMemberDecorate(&mSpirvDecorations, typeId,
1983                                        spirv::LiteralInteger(fieldIndex), decoration, {});
1984         }
1985 
1986         ++fieldIndex;
1987     }
1988 }
1989 
writeInterpolationDecoration(TQualifier qualifier,spirv::IdRef id,uint32_t fieldIndex)1990 void SPIRVBuilder::writeInterpolationDecoration(TQualifier qualifier,
1991                                                 spirv::IdRef id,
1992                                                 uint32_t fieldIndex)
1993 {
1994     spv::Decoration decoration = spv::DecorationMax;
1995 
1996     switch (qualifier)
1997     {
1998         case EvqSmooth:
1999         case EvqSmoothOut:
2000         case EvqSmoothIn:
2001             // No decoration in SPIR-V for smooth, this is the default interpolation.
2002             return;
2003 
2004         case EvqFlat:
2005         case EvqFlatOut:
2006         case EvqFlatIn:
2007             decoration = spv::DecorationFlat;
2008             break;
2009 
2010         case EvqNoPerspective:
2011         case EvqNoPerspectiveOut:
2012         case EvqNoPerspectiveIn:
2013             decoration = spv::DecorationNoPerspective;
2014             break;
2015 
2016         case EvqCentroid:
2017         case EvqCentroidOut:
2018         case EvqCentroidIn:
2019             decoration = spv::DecorationCentroid;
2020             break;
2021 
2022         case EvqSample:
2023         case EvqSampleOut:
2024         case EvqSampleIn:
2025             decoration = spv::DecorationSample;
2026             addCapability(spv::CapabilitySampleRateShading);
2027             break;
2028 
2029         default:
2030             return;
2031     }
2032 
2033     if (fieldIndex != std::numeric_limits<uint32_t>::max())
2034     {
2035         spirv::WriteMemberDecorate(&mSpirvDecorations, id, spirv::LiteralInteger(fieldIndex),
2036                                    decoration, {});
2037     }
2038     else
2039     {
2040         spirv::WriteDecorate(&mSpirvDecorations, id, decoration, {});
2041     }
2042 }
2043 
hashName(const TSymbol * symbol)2044 ImmutableString SPIRVBuilder::hashName(const TSymbol *symbol)
2045 {
2046     return HashName(symbol, mHashFunction, &mNameMap);
2047 }
2048 
hashTypeName(const TType & type)2049 ImmutableString SPIRVBuilder::hashTypeName(const TType &type)
2050 {
2051     return GetTypeName(type, mHashFunction, &mNameMap);
2052 }
2053 
hashFieldName(const TField * field)2054 ImmutableString SPIRVBuilder::hashFieldName(const TField *field)
2055 {
2056     ASSERT(field->symbolType() != SymbolType::Empty);
2057     if (field->symbolType() == SymbolType::UserDefined)
2058     {
2059         return HashName(field->name(), mHashFunction, &mNameMap);
2060     }
2061 
2062     return field->name();
2063 }
2064 
hashFunctionName(const TFunction * func)2065 ImmutableString SPIRVBuilder::hashFunctionName(const TFunction *func)
2066 {
2067     if (func->isMain())
2068     {
2069         return func->name();
2070     }
2071 
2072     return hashName(func);
2073 }
2074 
getSpirv()2075 spirv::Blob SPIRVBuilder::getSpirv()
2076 {
2077     ASSERT(mConditionalStack.empty());
2078 
2079     spirv::Blob result;
2080 
2081     // Reserve a minimum amount of memory.
2082     //
2083     //   5 for header +
2084     //   a number of capabilities +
2085     //   size of already generated instructions.
2086     //
2087     // The actual size is larger due to other metadata instructions such as extensions,
2088     // OpExtInstImport, OpEntryPoint, OpExecutionMode etc.
2089     result.reserve(5 + mCapabilities.size() * 2 + mSpirvDebug.size() + mSpirvDecorations.size() +
2090                    mSpirvTypeAndConstantDecls.size() + mSpirvTypePointerDecls.size() +
2091                    mSpirvFunctionTypeDecls.size() + mSpirvVariableDecls.size() +
2092                    mSpirvFunctions.size());
2093 
2094     // Generate the SPIR-V header.
2095     spirv::WriteSpirvHeader(&result, mNextAvailableId);
2096 
2097     // Generate metadata in the following order:
2098     //
2099     // - OpCapability instructions.
2100     for (spv::Capability capability : mCapabilities)
2101     {
2102         spirv::WriteCapability(&result, capability);
2103     }
2104 
2105     // - OpExtension instructions
2106     writeExtensions(&result);
2107 
2108     // - OpExtInstImport
2109     if (mExtInstImportIdStd.valid())
2110     {
2111         spirv::WriteExtInstImport(&result, mExtInstImportIdStd, "GLSL.std.450");
2112     }
2113 
2114     // - OpMemoryModel
2115     spirv::WriteMemoryModel(&result, spv::AddressingModelLogical, spv::MemoryModelGLSL450);
2116 
2117     // - OpEntryPoint
2118     constexpr gl::ShaderMap<spv::ExecutionModel> kExecutionModels = {
2119         {gl::ShaderType::Vertex, spv::ExecutionModelVertex},
2120         {gl::ShaderType::TessControl, spv::ExecutionModelTessellationControl},
2121         {gl::ShaderType::TessEvaluation, spv::ExecutionModelTessellationEvaluation},
2122         {gl::ShaderType::Geometry, spv::ExecutionModelGeometry},
2123         {gl::ShaderType::Fragment, spv::ExecutionModelFragment},
2124         {gl::ShaderType::Compute, spv::ExecutionModelGLCompute},
2125     };
2126     spirv::WriteEntryPoint(&result, kExecutionModels[mShaderType], mEntryPointId, "main",
2127                            mEntryPointInterfaceList);
2128 
2129     // - OpExecutionMode instructions
2130     writeExecutionModes(&result);
2131 
2132     // - OpSource and OpSourceExtension instructions.
2133     //
2134     // This is to support debuggers and capture/replay tools and isn't strictly necessary.
2135     spirv::WriteSource(&result, spv::SourceLanguageGLSL, spirv::LiteralInteger(450), nullptr,
2136                        nullptr);
2137     writeSourceExtensions(&result);
2138 
2139     // Append the already generated sections in order
2140     result.insert(result.end(), mSpirvDebug.begin(), mSpirvDebug.end());
2141     result.insert(result.end(), mSpirvDecorations.begin(), mSpirvDecorations.end());
2142     result.insert(result.end(), mSpirvTypeAndConstantDecls.begin(),
2143                   mSpirvTypeAndConstantDecls.end());
2144     result.insert(result.end(), mSpirvTypePointerDecls.begin(), mSpirvTypePointerDecls.end());
2145     result.insert(result.end(), mSpirvFunctionTypeDecls.begin(), mSpirvFunctionTypeDecls.end());
2146     result.insert(result.end(), mSpirvVariableDecls.begin(), mSpirvVariableDecls.end());
2147     result.insert(result.end(), mSpirvFunctions.begin(), mSpirvFunctions.end());
2148 
2149     result.shrink_to_fit();
2150     return result;
2151 }
2152 
writeExecutionModes(spirv::Blob * blob)2153 void SPIRVBuilder::writeExecutionModes(spirv::Blob *blob)
2154 {
2155     switch (mShaderType)
2156     {
2157         case gl::ShaderType::Fragment:
2158             spirv::WriteExecutionMode(blob, mEntryPointId, spv::ExecutionModeOriginUpperLeft, {});
2159 
2160             if (mCompiler->isEarlyFragmentTestsSpecified() ||
2161                 mCompiler->isEarlyFragmentTestsOptimized())
2162             {
2163                 spirv::WriteExecutionMode(blob, mEntryPointId, spv::ExecutionModeEarlyFragmentTests,
2164                                           {});
2165             }
2166 
2167             break;
2168 
2169         case gl::ShaderType::TessControl:
2170             spirv::WriteExecutionMode(
2171                 blob, mEntryPointId, spv::ExecutionModeOutputVertices,
2172                 {spirv::LiteralInteger(mCompiler->getTessControlShaderOutputVertices())});
2173             break;
2174 
2175         case gl::ShaderType::TessEvaluation:
2176         {
2177             const spv::ExecutionMode inputExecutionMode = GetTessEvalInputExecutionMode(
2178                 mCompiler->getTessEvaluationShaderInputPrimitiveType());
2179             const spv::ExecutionMode spacingExecutionMode = GetTessEvalSpacingExecutionMode(
2180                 mCompiler->getTessEvaluationShaderInputVertexSpacingType());
2181             const spv::ExecutionMode orderingExecutionMode = GetTessEvalOrderingExecutionMode(
2182                 mCompiler->getTessEvaluationShaderInputOrderingType());
2183 
2184             spirv::WriteExecutionMode(blob, mEntryPointId, inputExecutionMode, {});
2185             spirv::WriteExecutionMode(blob, mEntryPointId, spacingExecutionMode, {});
2186             spirv::WriteExecutionMode(blob, mEntryPointId, orderingExecutionMode, {});
2187             if (mCompiler->getTessEvaluationShaderInputPointType() == EtetPointMode)
2188             {
2189                 spirv::WriteExecutionMode(blob, mEntryPointId, spv::ExecutionModePointMode, {});
2190             }
2191             break;
2192         }
2193 
2194         case gl::ShaderType::Geometry:
2195         {
2196             const spv::ExecutionMode inputExecutionMode =
2197                 GetGeometryInputExecutionMode(mCompiler->getGeometryShaderInputPrimitiveType());
2198             const spv::ExecutionMode outputExecutionMode =
2199                 GetGeometryOutputExecutionMode(mCompiler->getGeometryShaderOutputPrimitiveType());
2200 
2201             // max_vertices=0 is not valid in Vulkan
2202             const int maxVertices = std::max(1, mCompiler->getGeometryShaderMaxVertices());
2203 
2204             spirv::WriteExecutionMode(blob, mEntryPointId, inputExecutionMode, {});
2205             spirv::WriteExecutionMode(blob, mEntryPointId, outputExecutionMode, {});
2206             spirv::WriteExecutionMode(blob, mEntryPointId, spv::ExecutionModeOutputVertices,
2207                                       {spirv::LiteralInteger(maxVertices)});
2208             spirv::WriteExecutionMode(
2209                 blob, mEntryPointId, spv::ExecutionModeInvocations,
2210                 {spirv::LiteralInteger(mCompiler->getGeometryShaderInvocations())});
2211 
2212             break;
2213         }
2214 
2215         case gl::ShaderType::Compute:
2216         {
2217             const sh::WorkGroupSize &localSize = mCompiler->getComputeShaderLocalSize();
2218             spirv::WriteExecutionMode(
2219                 blob, mEntryPointId, spv::ExecutionModeLocalSize,
2220                 {spirv::LiteralInteger(localSize[0]), spirv::LiteralInteger(localSize[1]),
2221                  spirv::LiteralInteger(localSize[2])});
2222             break;
2223         }
2224 
2225         default:
2226             break;
2227     }
2228 
2229     // Add any execution modes that were added due to built-ins used in the shader.
2230     for (size_t executionMode : mExecutionModes)
2231     {
2232         spirv::WriteExecutionMode(blob, mEntryPointId,
2233                                   static_cast<spv::ExecutionMode>(executionMode), {});
2234     }
2235 }
2236 
writeExtensions(spirv::Blob * blob)2237 void SPIRVBuilder::writeExtensions(spirv::Blob *blob)
2238 {
2239     for (SPIRVExtensions extension : mExtensions)
2240     {
2241         switch (extension)
2242         {
2243             case SPIRVExtensions::MultiviewOVR:
2244                 spirv::WriteExtension(blob, "SPV_KHR_multiview");
2245                 break;
2246             default:
2247                 UNREACHABLE();
2248         }
2249     }
2250 }
2251 
writeSourceExtensions(spirv::Blob * blob)2252 void SPIRVBuilder::writeSourceExtensions(spirv::Blob *blob)
2253 {
2254     for (SPIRVExtensions extension : mExtensions)
2255     {
2256         switch (extension)
2257         {
2258             case SPIRVExtensions::MultiviewOVR:
2259                 spirv::WriteSourceExtension(blob, "GL_OVR_multiview");
2260                 break;
2261             default:
2262                 UNREACHABLE();
2263         }
2264     }
2265 }
2266 
2267 }  // namespace sh
2268