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.isOrHasBoolInInterfaceBlock == b.typeSpec.isOrHasBoolInInterfaceBlock;
40     }
41 
42     // Otherwise, match by the type contents.  The AST transformations sometimes recreate types that
43     // are already defined, so we can't rely on pointers being unique.
44     return a.type == b.type && a.primarySize == b.primarySize &&
45            a.secondarySize == b.secondarySize && a.imageInternalFormat == b.imageInternalFormat &&
46            a.isSamplerBaseImage == b.isSamplerBaseImage &&
47            a.typeSpec.blockStorage == b.typeSpec.blockStorage &&
48            a.typeSpec.isRowMajorQualifiedArray == b.typeSpec.isRowMajorQualifiedArray &&
49            a.typeSpec.isOrHasBoolInInterfaceBlock == b.typeSpec.isOrHasBoolInInterfaceBlock;
50 }
51 
GetTotalArrayElements(const TSpan<const unsigned int> & arraySizes)52 uint32_t GetTotalArrayElements(const TSpan<const unsigned int> &arraySizes)
53 {
54     uint32_t arraySizeProduct = 1;
55     for (uint32_t arraySize : arraySizes)
56     {
57         // For runtime arrays, arraySize will be 0 and should be excluded.
58         arraySizeProduct *= arraySize > 0 ? arraySize : 1;
59     }
60 
61     return arraySizeProduct;
62 }
63 
GetOutermostArraySize(const SpirvType & type)64 uint32_t GetOutermostArraySize(const SpirvType &type)
65 {
66     uint32_t size = type.arraySizes.back();
67     return size ? size : 1;
68 }
69 
IsBlockFieldRowMajorQualified(const TType & fieldType,bool isParentBlockRowMajorQualified)70 bool IsBlockFieldRowMajorQualified(const TType &fieldType, bool isParentBlockRowMajorQualified)
71 {
72     // If the field is specifically qualified as row-major, it will be row-major.  Otherwise unless
73     // specifically qualified as column-major, its matrix packing is inherited from the parent
74     // block.
75     const TLayoutMatrixPacking fieldMatrixPacking = fieldType.getLayoutQualifier().matrixPacking;
76     return fieldMatrixPacking == EmpRowMajor ||
77            (fieldMatrixPacking == EmpUnspecified && isParentBlockRowMajorQualified);
78 }
79 
IsNonSquareRowMajorArrayInBlock(const TType & type,const SpirvTypeSpec & parentTypeSpec)80 bool IsNonSquareRowMajorArrayInBlock(const TType &type, const SpirvTypeSpec &parentTypeSpec)
81 {
82     return parentTypeSpec.blockStorage != EbsUnspecified && type.isArray() && type.isMatrix() &&
83            type.getCols() != type.getRows() &&
84            IsBlockFieldRowMajorQualified(type, parentTypeSpec.isRowMajorQualifiedBlock);
85 }
86 
IsInvariant(const TType & type,TCompiler * compiler)87 bool IsInvariant(const TType &type, TCompiler *compiler)
88 {
89     const bool invariantAll = compiler->getPragma().stdgl.invariantAll;
90 
91     // The Invariant decoration is applied to output variables if specified or if globally enabled.
92     return type.isInvariant() || (IsShaderOut(type.getQualifier()) && invariantAll);
93 }
94 
GetBlockStorage(const TType & type)95 TLayoutBlockStorage GetBlockStorage(const TType &type)
96 {
97     // If the type specifies the layout, take it from that.
98     TLayoutBlockStorage blockStorage = type.getLayoutQualifier().blockStorage;
99 
100     // For user-defined interface blocks, the block storage is specified on the symbol itself and
101     // not the type.
102     if (blockStorage == EbsUnspecified && type.getInterfaceBlock() != nullptr)
103     {
104         blockStorage = type.getInterfaceBlock()->blockStorage();
105     }
106 
107     if (IsShaderIoBlock(type.getQualifier()) || blockStorage == EbsStd140 ||
108         blockStorage == EbsStd430)
109     {
110         return blockStorage;
111     }
112 
113     // Default to std140 for uniform and std430 for buffer blocks.
114     return type.getQualifier() == EvqBuffer ? EbsStd430 : EbsStd140;
115 }
116 
ToShaderVariable(const TFieldListCollection * block,GLenum type,const TSpan<const unsigned int> arraySizes,bool isRowMajor)117 ShaderVariable ToShaderVariable(const TFieldListCollection *block,
118                                 GLenum type,
119                                 const TSpan<const unsigned int> arraySizes,
120                                 bool isRowMajor)
121 {
122     ShaderVariable var;
123 
124     var.type             = type;
125     var.arraySizes       = {arraySizes.begin(), arraySizes.end()};
126     var.isRowMajorLayout = isRowMajor;
127 
128     if (block != nullptr)
129     {
130         for (const TField *field : block->fields())
131         {
132             const TType &fieldType = *field->type();
133 
134             const TLayoutMatrixPacking fieldMatrixPacking =
135                 fieldType.getLayoutQualifier().matrixPacking;
136             const bool isFieldRowMajor = fieldMatrixPacking == EmpRowMajor ||
137                                          (fieldMatrixPacking == EmpUnspecified && isRowMajor);
138             const GLenum glType =
139                 fieldType.getStruct() != nullptr ? GL_NONE : GLVariableType(fieldType);
140 
141             var.fields.push_back(ToShaderVariable(fieldType.getStruct(), glType,
142                                                   fieldType.getArraySizes(), isFieldRowMajor));
143         }
144     }
145 
146     return var;
147 }
148 
SpirvTypeToShaderVariable(const SpirvType & type)149 ShaderVariable SpirvTypeToShaderVariable(const SpirvType &type)
150 {
151     const bool isRowMajor =
152         type.typeSpec.isRowMajorQualifiedBlock || type.typeSpec.isRowMajorQualifiedArray;
153     const GLenum glType =
154         type.block != nullptr
155             ? EbtStruct
156             : GLVariableType(TType(type.type, type.primarySize, type.secondarySize));
157 
158     return ToShaderVariable(type.block, glType, type.arraySizes, isRowMajor);
159 }
160 
161 // The following function encodes a variable in a std140 or std430 block.  The variable could be:
162 //
163 // - An interface block: In this case, |decorationsBlob| is provided and SPIR-V decorations are
164 //   output to this blob.
165 // - A struct: In this case, the return value is of interest as the size of the struct in the
166 //   encoding.
167 //
168 // This function ignores arrayness in calculating the struct size.
169 //
Encode(const ShaderVariable & var,bool isStd140,spirv::IdRef blockTypeId,spirv::Blob * decorationsBlob)170 uint32_t Encode(const ShaderVariable &var,
171                 bool isStd140,
172                 spirv::IdRef blockTypeId,
173                 spirv::Blob *decorationsBlob)
174 {
175     Std140BlockEncoder std140;
176     Std430BlockEncoder std430;
177     BlockLayoutEncoder *encoder = isStd140 ? &std140 : &std430;
178 
179     ASSERT(var.isStruct());
180     encoder->enterAggregateType(var);
181 
182     uint32_t fieldIndex = 0;
183 
184     for (const ShaderVariable &fieldVar : var.fields)
185     {
186         BlockMemberInfo fieldInfo;
187 
188         // Encode the variable.
189         if (fieldVar.isStruct())
190         {
191             // For structs, recursively encode it.
192             const uint32_t structSize = Encode(fieldVar, isStd140, {}, nullptr);
193 
194             encoder->enterAggregateType(fieldVar);
195             fieldInfo = encoder->encodeArrayOfPreEncodedStructs(structSize, fieldVar.arraySizes);
196             encoder->exitAggregateType(fieldVar);
197         }
198         else
199         {
200             fieldInfo =
201                 encoder->encodeType(fieldVar.type, fieldVar.arraySizes, fieldVar.isRowMajorLayout);
202         }
203 
204         if (decorationsBlob)
205         {
206             ASSERT(blockTypeId.valid());
207 
208             // Write the Offset decoration.
209             spirv::WriteMemberDecorate(decorationsBlob, blockTypeId,
210                                        spirv::LiteralInteger(fieldIndex), spv::DecorationOffset,
211                                        {spirv::LiteralInteger(fieldInfo.offset)});
212 
213             // For matrix types, write the MatrixStride decoration as well.
214             if (IsMatrixGLType(fieldVar.type))
215             {
216                 ASSERT(fieldInfo.matrixStride > 0);
217 
218                 // MatrixStride
219                 spirv::WriteMemberDecorate(
220                     decorationsBlob, blockTypeId, spirv::LiteralInteger(fieldIndex),
221                     spv::DecorationMatrixStride, {spirv::LiteralInteger(fieldInfo.matrixStride)});
222             }
223         }
224 
225         ++fieldIndex;
226     }
227 
228     encoder->exitAggregateType(var);
229     return static_cast<uint32_t>(encoder->getCurrentOffset());
230 }
231 
GetArrayStrideInBlock(const ShaderVariable & var,bool isStd140)232 uint32_t GetArrayStrideInBlock(const ShaderVariable &var, bool isStd140)
233 {
234     Std140BlockEncoder std140;
235     Std430BlockEncoder std430;
236     BlockLayoutEncoder *encoder = isStd140 ? &std140 : &std430;
237 
238     ASSERT(var.isArray());
239 
240     // For structs, encode the struct to get the size, and calculate the stride based on that.
241     if (var.isStruct())
242     {
243         // Remove arrayness.
244         ShaderVariable element = var;
245         element.arraySizes.clear();
246 
247         const uint32_t structSize = Encode(element, isStd140, {}, nullptr);
248 
249         // Stride is struct size by inner array size
250         return structSize * var.getInnerArraySizeProduct();
251     }
252 
253     // Otherwise encode the basic type.
254     BlockMemberInfo memberInfo =
255         encoder->encodeType(var.type, var.arraySizes, var.isRowMajorLayout);
256 
257     // The encoder returns the array stride for the base element type (which is not an array!), so
258     // need to multiply by the inner array sizes to get the outermost array's stride.
259     return memberInfo.arrayStride * var.getInnerArraySizeProduct();
260 }
261 
inferDefaults(const TType & type,TCompiler * compiler)262 void SpirvTypeSpec::inferDefaults(const TType &type, TCompiler *compiler)
263 {
264     // Infer some defaults based on type.  If necessary, this overrides some fields (if not already
265     // specified).  Otherwise, it leaves the pre-initialized values as-is.
266 
267     // Handle interface blocks and fields of nameless interface blocks.
268     if (type.getInterfaceBlock() != nullptr)
269     {
270         // Calculate the block storage from the interface block automatically.  The fields inherit
271         // from this.  Only blocks and arrays in blocks produce different SPIR-V types based on
272         // block storage.
273         const bool isBlock = type.isInterfaceBlock() || type.getStruct();
274         if (blockStorage == EbsUnspecified && (isBlock || type.isArray()))
275         {
276             blockStorage = GetBlockStorage(type);
277         }
278 
279         // row_major can only be specified on an interface block or one of its fields.  The fields
280         // will inherit this from the interface block itself.
281         if (!isRowMajorQualifiedBlock && isBlock)
282         {
283             isRowMajorQualifiedBlock = type.getLayoutQualifier().matrixPacking == EmpRowMajor;
284         }
285 
286         // Arrays of matrices in a uniform/buffer block may generate a different stride based on
287         // whether they are row- or column-major.  Square matrices are trivially known not to
288         // generate a different type.
289         if (!isRowMajorQualifiedArray)
290         {
291             isRowMajorQualifiedArray = IsNonSquareRowMajorArrayInBlock(type, *this);
292         }
293 
294         // Structs with bools, bool arrays, bool vectors and bools themselves are replaced with uint
295         // when used in an interface block.
296         if (!isOrHasBoolInInterfaceBlock)
297         {
298             isOrHasBoolInInterfaceBlock = type.isInterfaceBlockContainingType(EbtBool) ||
299                                           type.isStructureContainingType(EbtBool) ||
300                                           type.getBasicType() == EbtBool;
301         }
302     }
303 
304     // |invariant| is significant for structs as the fields of the type are decorated with Invariant
305     // in SPIR-V.  This is possible for outputs of struct type, or struct-typed fields of an
306     // interface block.
307     if (type.getStruct() != nullptr)
308     {
309         isInvariantBlock = isInvariantBlock || IsInvariant(type, compiler);
310     }
311 }
312 
onArrayElementSelection(bool isElementTypeBlock,bool isElementTypeArray)313 void SpirvTypeSpec::onArrayElementSelection(bool isElementTypeBlock, bool isElementTypeArray)
314 {
315     // No difference in type for non-block non-array types in std140 and std430 block storage.
316     if (!isElementTypeBlock && !isElementTypeArray)
317     {
318         blockStorage = EbsUnspecified;
319     }
320 
321     // No difference in type for non-array types in std140 and std430 block storage.
322     if (!isElementTypeArray)
323     {
324         isRowMajorQualifiedArray = false;
325     }
326 }
327 
onBlockFieldSelection(const TType & fieldType)328 void SpirvTypeSpec::onBlockFieldSelection(const TType &fieldType)
329 {
330     if (fieldType.getStruct() == nullptr)
331     {
332         // If the field is not a block, no difference if the parent block was invariant or
333         // row-major.
334         isRowMajorQualifiedArray = IsNonSquareRowMajorArrayInBlock(fieldType, *this);
335         isInvariantBlock         = false;
336         isRowMajorQualifiedBlock = false;
337 
338         // If the field is not an array, no difference in storage block.
339         if (!fieldType.isArray())
340         {
341             blockStorage = EbsUnspecified;
342         }
343 
344         if (fieldType.getBasicType() != EbtBool)
345         {
346             isOrHasBoolInInterfaceBlock = false;
347         }
348     }
349     else
350     {
351         // Apply row-major only to structs that contain matrices.
352         isRowMajorQualifiedBlock =
353             IsBlockFieldRowMajorQualified(fieldType, isRowMajorQualifiedBlock) &&
354             fieldType.isStructureContainingMatrices();
355 
356         // Structs without bools aren't affected by |isOrHasBoolInInterfaceBlock|.
357         if (isOrHasBoolInInterfaceBlock)
358         {
359             isOrHasBoolInInterfaceBlock = fieldType.isStructureContainingType(EbtBool);
360         }
361     }
362 }
363 
onMatrixColumnSelection()364 void SpirvTypeSpec::onMatrixColumnSelection()
365 {
366     // The matrix types are never differentiated, so neither would be their columns.
367     ASSERT(!isInvariantBlock && !isRowMajorQualifiedBlock && !isRowMajorQualifiedArray &&
368            !isOrHasBoolInInterfaceBlock && blockStorage == EbsUnspecified);
369 }
370 
onVectorComponentSelection()371 void SpirvTypeSpec::onVectorComponentSelection()
372 {
373     // The vector types are never differentiated, so neither would be their components.  The only
374     // exception is bools in interface blocks, in which case the component and the vector are
375     // similarly differentiated.
376     ASSERT(!isInvariantBlock && !isRowMajorQualifiedBlock && !isRowMajorQualifiedArray &&
377            blockStorage == EbsUnspecified);
378 }
379 
getNewId(const SpirvDecorations & decorations)380 spirv::IdRef SPIRVBuilder::getNewId(const SpirvDecorations &decorations)
381 {
382     spirv::IdRef newId = mNextAvailableId;
383     mNextAvailableId   = spirv::IdRef(mNextAvailableId + 1);
384 
385     for (const spv::Decoration decoration : decorations)
386     {
387         spirv::WriteDecorate(&mSpirvDecorations, newId, decoration, {});
388     }
389 
390     return newId;
391 }
392 
getSpirvType(const TType & type,const SpirvTypeSpec & typeSpec) const393 SpirvType SPIRVBuilder::getSpirvType(const TType &type, const SpirvTypeSpec &typeSpec) const
394 {
395     SpirvType spirvType;
396     spirvType.type                = type.getBasicType();
397     spirvType.primarySize         = static_cast<uint8_t>(type.getNominalSize());
398     spirvType.secondarySize       = static_cast<uint8_t>(type.getSecondarySize());
399     spirvType.arraySizes          = type.getArraySizes();
400     spirvType.imageInternalFormat = type.getLayoutQualifier().imageInternalFormat;
401 
402     switch (spirvType.type)
403     {
404         // External textures are treated as 2D textures in the vulkan back-end.
405         case EbtSamplerExternalOES:
406         case EbtSamplerExternal2DY2YEXT:
407         // WEBGL video textures too.
408         case EbtSamplerVideoWEBGL:
409             spirvType.type = EbtSampler2D;
410             break;
411         default:
412             break;
413     }
414 
415     if (type.getStruct() != nullptr)
416     {
417         spirvType.block = type.getStruct();
418     }
419     else if (type.isInterfaceBlock())
420     {
421         spirvType.block = type.getInterfaceBlock();
422     }
423 
424     // Automatically inherit or infer the type-specializing properties.
425     spirvType.typeSpec = typeSpec;
426     spirvType.typeSpec.inferDefaults(type, mCompiler);
427 
428     return spirvType;
429 }
430 
getTypeData(const TType & type,const SpirvTypeSpec & typeSpec)431 const SpirvTypeData &SPIRVBuilder::getTypeData(const TType &type, const SpirvTypeSpec &typeSpec)
432 {
433     SpirvType spirvType = getSpirvType(type, typeSpec);
434 
435     const TSymbol *block = nullptr;
436     if (type.getStruct() != nullptr)
437     {
438         block = type.getStruct();
439     }
440     else if (type.isInterfaceBlock())
441     {
442         block = type.getInterfaceBlock();
443     }
444 
445     return getSpirvTypeData(spirvType, block);
446 }
447 
getSpirvTypeData(const SpirvType & type,const TSymbol * block)448 const SpirvTypeData &SPIRVBuilder::getSpirvTypeData(const SpirvType &type, const TSymbol *block)
449 {
450     // Structs with bools generate a different type when used in an interface block (where the bool
451     // is replaced with a uint).  The bool, bool vector and bool arrays too generate a different
452     // type when nested in an interface block, but that type is the same as the equivalent uint
453     // type.  To avoid defining duplicate uint types, we switch the basic type here to uint.  From
454     // the outside, therefore bool in an interface block and uint look like different types, but
455     // under the hood will be the same uint.
456     if (type.block == nullptr && type.typeSpec.isOrHasBoolInInterfaceBlock)
457     {
458         ASSERT(type.type == EbtBool);
459 
460         SpirvType uintType                            = type;
461         uintType.type                                 = EbtUInt;
462         uintType.typeSpec.isOrHasBoolInInterfaceBlock = false;
463         return getSpirvTypeData(uintType, block);
464     }
465 
466     auto iter = mTypeMap.find(type);
467     if (iter == mTypeMap.end())
468     {
469         SpirvTypeData newTypeData = declareType(type, block);
470 
471         iter = mTypeMap.insert({type, newTypeData}).first;
472     }
473 
474     return iter->second;
475 }
476 
getBasicTypeId(TBasicType basicType,size_t size)477 spirv::IdRef SPIRVBuilder::getBasicTypeId(TBasicType basicType, size_t size)
478 {
479     SpirvType type;
480     type.type        = basicType;
481     type.primarySize = static_cast<uint8_t>(size);
482     return getSpirvTypeData(type, nullptr).id;
483 }
484 
getTypePointerId(spirv::IdRef typeId,spv::StorageClass storageClass)485 spirv::IdRef SPIRVBuilder::getTypePointerId(spirv::IdRef typeId, spv::StorageClass storageClass)
486 {
487     SpirvIdAndStorageClass key{typeId, storageClass};
488 
489     auto iter = mTypePointerIdMap.find(key);
490     if (iter == mTypePointerIdMap.end())
491     {
492         const spirv::IdRef typePointerId = getNewId({});
493 
494         spirv::WriteTypePointer(&mSpirvTypePointerDecls, typePointerId, storageClass, typeId);
495 
496         iter = mTypePointerIdMap.insert({key, typePointerId}).first;
497     }
498 
499     return iter->second;
500 }
501 
getFunctionTypeId(spirv::IdRef returnTypeId,const spirv::IdRefList & paramTypeIds)502 spirv::IdRef SPIRVBuilder::getFunctionTypeId(spirv::IdRef returnTypeId,
503                                              const spirv::IdRefList &paramTypeIds)
504 {
505     SpirvIdAndIdList key{returnTypeId, paramTypeIds};
506 
507     auto iter = mFunctionTypeIdMap.find(key);
508     if (iter == mFunctionTypeIdMap.end())
509     {
510         const spirv::IdRef functionTypeId = getNewId({});
511 
512         spirv::WriteTypeFunction(&mSpirvFunctionTypeDecls, functionTypeId, returnTypeId,
513                                  paramTypeIds);
514 
515         iter = mFunctionTypeIdMap.insert({key, functionTypeId}).first;
516     }
517 
518     return iter->second;
519 }
520 
getDecorations(const TType & type)521 SpirvDecorations SPIRVBuilder::getDecorations(const TType &type)
522 {
523     const bool enablePrecision = (mCompileOptions & SH_IGNORE_PRECISION_QUALIFIERS) == 0;
524     const TPrecision precision = type.getPrecision();
525 
526     SpirvDecorations decorations;
527 
528     // Handle precision.
529     if (enablePrecision && !mDisableRelaxedPrecision &&
530         (precision == EbpMedium || precision == EbpLow))
531     {
532         decorations.push_back(spv::DecorationRelaxedPrecision);
533     }
534 
535     // TODO: Handle |precise|.  http://anglebug.com/4889.
536 
537     return decorations;
538 }
539 
getExtInstImportIdStd()540 spirv::IdRef SPIRVBuilder::getExtInstImportIdStd()
541 {
542     if (!mExtInstImportIdStd.valid())
543     {
544         mExtInstImportIdStd = getNewId({});
545     }
546     return mExtInstImportIdStd;
547 }
548 
declareType(const SpirvType & type,const TSymbol * block)549 SpirvTypeData SPIRVBuilder::declareType(const SpirvType &type, const TSymbol *block)
550 {
551     // Recursively declare the type.  Type id is allocated afterwards purely for better id order in
552     // output.
553     spirv::IdRef typeId;
554 
555     if (!type.arraySizes.empty())
556     {
557         // Declaring an array.  First, declare the type without the outermost array size, then
558         // declare a new array type based on that.
559 
560         SpirvType subType  = type;
561         subType.arraySizes = type.arraySizes.first(type.arraySizes.size() - 1);
562         subType.typeSpec.onArrayElementSelection(subType.block != nullptr,
563                                                  !subType.arraySizes.empty());
564 
565         const spirv::IdRef subTypeId = getSpirvTypeData(subType, block).id;
566 
567         const unsigned int length = type.arraySizes.back();
568 
569         if (length == 0)
570         {
571             // Storage buffers may include a dynamically-sized array, which is identified by it
572             // having a length of 0.
573             typeId = getNewId({});
574             spirv::WriteTypeRuntimeArray(&mSpirvTypeAndConstantDecls, typeId, subTypeId);
575         }
576         else
577         {
578             const spirv::IdRef lengthId = getUintConstant(length);
579             typeId                      = getNewId({});
580             spirv::WriteTypeArray(&mSpirvTypeAndConstantDecls, typeId, subTypeId, lengthId);
581         }
582     }
583     else if (type.block != nullptr)
584     {
585         // Declaring a block.  First, declare all the fields, then declare a struct based on the
586         // list of field types.
587 
588         spirv::IdRefList fieldTypeIds;
589         for (const TField *field : type.block->fields())
590         {
591             const TType &fieldType = *field->type();
592 
593             SpirvTypeSpec fieldTypeSpec = type.typeSpec;
594             fieldTypeSpec.onBlockFieldSelection(fieldType);
595 
596             const SpirvType fieldSpirvType = getSpirvType(fieldType, fieldTypeSpec);
597             const spirv::IdRef fieldTypeId =
598                 getSpirvTypeData(fieldSpirvType, fieldType.getStruct()).id;
599             fieldTypeIds.push_back(fieldTypeId);
600         }
601 
602         typeId = getNewId({});
603         spirv::WriteTypeStruct(&mSpirvTypeAndConstantDecls, typeId, fieldTypeIds);
604     }
605     else if (IsSampler(type.type) && !type.isSamplerBaseImage)
606     {
607         // Declaring a sampler.  First, declare the non-sampled image and then a combined
608         // image-sampler.
609 
610         SpirvType imageType          = type;
611         imageType.isSamplerBaseImage = true;
612 
613         const spirv::IdRef nonSampledId = getSpirvTypeData(imageType, nullptr).id;
614 
615         typeId = getNewId({});
616         spirv::WriteTypeSampledImage(&mSpirvTypeAndConstantDecls, typeId, nonSampledId);
617     }
618     else if (IsImage(type.type) || type.isSamplerBaseImage)
619     {
620         // Declaring an image.
621 
622         spirv::IdRef sampledType;
623         spv::Dim dim;
624         spirv::LiteralInteger depth;
625         spirv::LiteralInteger arrayed;
626         spirv::LiteralInteger multisampled;
627         spirv::LiteralInteger sampled;
628 
629         getImageTypeParameters(type.type, &sampledType, &dim, &depth, &arrayed, &multisampled,
630                                &sampled);
631         const spv::ImageFormat imageFormat = getImageFormat(type.imageInternalFormat);
632 
633         typeId = getNewId({});
634         spirv::WriteTypeImage(&mSpirvTypeAndConstantDecls, typeId, sampledType, dim, depth, arrayed,
635                               multisampled, sampled, imageFormat, nullptr);
636     }
637     else if (IsSubpassInputType(type.type))
638     {
639         // TODO: add support for framebuffer fetch. http://anglebug.com/4889
640         UNIMPLEMENTED();
641     }
642     else if (type.secondarySize > 1)
643     {
644         // Declaring a matrix.  Declare the column type first, then create a matrix out of it.
645 
646         SpirvType columnType     = type;
647         columnType.primarySize   = columnType.secondarySize;
648         columnType.secondarySize = 1;
649         columnType.typeSpec.onMatrixColumnSelection();
650 
651         const spirv::IdRef columnTypeId = getSpirvTypeData(columnType, nullptr).id;
652 
653         typeId = getNewId({});
654         spirv::WriteTypeMatrix(&mSpirvTypeAndConstantDecls, typeId, columnTypeId,
655                                spirv::LiteralInteger(type.primarySize));
656     }
657     else if (type.primarySize > 1)
658     {
659         // Declaring a vector.  Declare the component type first, then create a vector out of it.
660 
661         SpirvType componentType   = type;
662         componentType.primarySize = 1;
663         componentType.typeSpec.onVectorComponentSelection();
664 
665         const spirv::IdRef componentTypeId = getSpirvTypeData(componentType, nullptr).id;
666 
667         typeId = getNewId({});
668         spirv::WriteTypeVector(&mSpirvTypeAndConstantDecls, typeId, componentTypeId,
669                                spirv::LiteralInteger(type.primarySize));
670     }
671     else
672     {
673         typeId = getNewId({});
674 
675         // Declaring a basic type.  There's a different instruction for each.
676         switch (type.type)
677         {
678             case EbtVoid:
679                 spirv::WriteTypeVoid(&mSpirvTypeAndConstantDecls, typeId);
680                 break;
681             case EbtFloat:
682                 spirv::WriteTypeFloat(&mSpirvTypeAndConstantDecls, typeId,
683                                       spirv::LiteralInteger(32));
684                 break;
685             case EbtDouble:
686                 // TODO: support desktop GLSL.  http://anglebug.com/6197
687                 UNIMPLEMENTED();
688                 break;
689             case EbtInt:
690                 spirv::WriteTypeInt(&mSpirvTypeAndConstantDecls, typeId, spirv::LiteralInteger(32),
691                                     spirv::LiteralInteger(1));
692                 break;
693             case EbtUInt:
694                 spirv::WriteTypeInt(&mSpirvTypeAndConstantDecls, typeId, spirv::LiteralInteger(32),
695                                     spirv::LiteralInteger(0));
696                 break;
697             case EbtBool:
698                 spirv::WriteTypeBool(&mSpirvTypeAndConstantDecls, typeId);
699                 break;
700             default:
701                 UNREACHABLE();
702         }
703     }
704 
705     // If this was a block declaration, add debug information for its type and field names.
706     //
707     // TODO: make this conditional to a compiler flag.  Instead of outputting the debug info
708     // unconditionally and having the SPIR-V transformer remove them, it's better to avoid
709     // generating them in the first place.  This both simplifies the transformer and reduces SPIR-V
710     // binary size that gets written to disk cache.  http://anglebug.com/4889
711     if (block != nullptr && type.arraySizes.empty())
712     {
713         spirv::WriteName(&mSpirvDebug, typeId, hashName(block).data());
714 
715         uint32_t fieldIndex = 0;
716         for (const TField *field : type.block->fields())
717         {
718             spirv::WriteMemberName(&mSpirvDebug, typeId, spirv::LiteralInteger(fieldIndex++),
719                                    hashFieldName(field).data());
720         }
721     }
722 
723     // Write decorations for interface block fields.
724     if (type.typeSpec.blockStorage != EbsUnspecified)
725     {
726         // Cannot have opaque uniforms inside interface blocks.
727         ASSERT(!IsOpaqueType(type.type));
728 
729         const bool isInterfaceBlock = block != nullptr && block->isInterfaceBlock();
730         const bool isStd140         = type.typeSpec.blockStorage != EbsStd430;
731 
732         if (!type.arraySizes.empty() && !isInterfaceBlock)
733         {
734             // Write the ArrayStride decoration for arrays inside interface blocks.  An array of
735             // interface blocks doesn't need a stride.
736             const ShaderVariable var = SpirvTypeToShaderVariable(type);
737             const uint32_t stride    = GetArrayStrideInBlock(var, isStd140);
738 
739             spirv::WriteDecorate(&mSpirvDecorations, typeId, spv::DecorationArrayStride,
740                                  {spirv::LiteralInteger(stride)});
741         }
742         else if (type.arraySizes.empty() && type.block != nullptr)
743         {
744             // Write the Offset decoration for interface blocks and structs in them.
745             const ShaderVariable var = SpirvTypeToShaderVariable(type);
746             Encode(var, isStd140, typeId, &mSpirvDecorations);
747         }
748     }
749 
750     // Write other member decorations.
751     if (block != nullptr && type.arraySizes.empty())
752     {
753         writeMemberDecorations(type, typeId);
754     }
755 
756     return {typeId};
757 }
758 
getImageTypeParameters(TBasicType type,spirv::IdRef * sampledTypeOut,spv::Dim * dimOut,spirv::LiteralInteger * depthOut,spirv::LiteralInteger * arrayedOut,spirv::LiteralInteger * multisampledOut,spirv::LiteralInteger * sampledOut)759 void SPIRVBuilder::getImageTypeParameters(TBasicType type,
760                                           spirv::IdRef *sampledTypeOut,
761                                           spv::Dim *dimOut,
762                                           spirv::LiteralInteger *depthOut,
763                                           spirv::LiteralInteger *arrayedOut,
764                                           spirv::LiteralInteger *multisampledOut,
765                                           spirv::LiteralInteger *sampledOut)
766 {
767     TBasicType sampledType = EbtFloat;
768     *dimOut                = spv::Dim2D;
769     bool isDepth           = false;
770     bool isArrayed         = false;
771     bool isMultisampled    = false;
772 
773     // Decompose the basic type into image properties
774     switch (type)
775     {
776         // Float 2D Images
777         case EbtSampler2D:
778         case EbtImage2D:
779             break;
780         case EbtSamplerExternalOES:
781         case EbtSamplerExternal2DY2YEXT:
782         case EbtSamplerVideoWEBGL:
783             // These must have already been converted to EbtSampler2D.
784             UNREACHABLE();
785             break;
786         case EbtSampler2DArray:
787         case EbtImage2DArray:
788             isArrayed = true;
789             break;
790         case EbtSampler2DMS:
791         case EbtImage2DMS:
792             isMultisampled = true;
793             break;
794         case EbtSampler2DMSArray:
795         case EbtImage2DMSArray:
796             isArrayed      = true;
797             isMultisampled = true;
798             break;
799         case EbtSampler2DShadow:
800             isDepth = true;
801             break;
802         case EbtSampler2DArrayShadow:
803             isDepth   = true;
804             isArrayed = true;
805             break;
806 
807         // Integer 2D images
808         case EbtISampler2D:
809         case EbtIImage2D:
810             sampledType = EbtInt;
811             break;
812         case EbtISampler2DArray:
813         case EbtIImage2DArray:
814             sampledType = EbtInt;
815             isArrayed   = true;
816             break;
817         case EbtISampler2DMS:
818         case EbtIImage2DMS:
819             sampledType    = EbtInt;
820             isMultisampled = true;
821             break;
822         case EbtISampler2DMSArray:
823         case EbtIImage2DMSArray:
824             sampledType    = EbtInt;
825             isArrayed      = true;
826             isMultisampled = true;
827             break;
828 
829         // Unsinged integer 2D images
830         case EbtUSampler2D:
831         case EbtUImage2D:
832             sampledType = EbtUInt;
833             break;
834         case EbtUSampler2DArray:
835         case EbtUImage2DArray:
836             sampledType = EbtUInt;
837             isArrayed   = true;
838             break;
839         case EbtUSampler2DMS:
840         case EbtUImage2DMS:
841             sampledType    = EbtUInt;
842             isMultisampled = true;
843             break;
844         case EbtUSampler2DMSArray:
845         case EbtUImage2DMSArray:
846             sampledType    = EbtUInt;
847             isArrayed      = true;
848             isMultisampled = true;
849             break;
850 
851         // 3D images
852         case EbtSampler3D:
853         case EbtImage3D:
854             *dimOut = spv::Dim3D;
855             break;
856         case EbtISampler3D:
857         case EbtIImage3D:
858             sampledType = EbtInt;
859             *dimOut     = spv::Dim3D;
860             break;
861         case EbtUSampler3D:
862         case EbtUImage3D:
863             sampledType = EbtUInt;
864             *dimOut     = spv::Dim3D;
865             break;
866 
867         // Float cube images
868         case EbtSamplerCube:
869         case EbtImageCube:
870             *dimOut = spv::DimCube;
871             break;
872         case EbtSamplerCubeArray:
873         case EbtImageCubeArray:
874             *dimOut   = spv::DimCube;
875             isArrayed = true;
876             break;
877         case EbtSamplerCubeArrayShadow:
878             *dimOut   = spv::DimCube;
879             isDepth   = true;
880             isArrayed = true;
881             break;
882         case EbtSamplerCubeShadow:
883             *dimOut = spv::DimCube;
884             isDepth = true;
885             break;
886 
887         // Integer cube images
888         case EbtISamplerCube:
889         case EbtIImageCube:
890             sampledType = EbtInt;
891             *dimOut     = spv::DimCube;
892             break;
893         case EbtISamplerCubeArray:
894         case EbtIImageCubeArray:
895             sampledType = EbtInt;
896             *dimOut     = spv::DimCube;
897             isArrayed   = true;
898             break;
899 
900         // Unsigned integer cube images
901         case EbtUSamplerCube:
902         case EbtUImageCube:
903             sampledType = EbtUInt;
904             *dimOut     = spv::DimCube;
905             break;
906         case EbtUSamplerCubeArray:
907         case EbtUImageCubeArray:
908             sampledType = EbtUInt;
909             *dimOut     = spv::DimCube;
910             isArrayed   = true;
911             break;
912 
913         // Float 1D images
914         case EbtSampler1D:
915         case EbtImage1D:
916             *dimOut = spv::Dim1D;
917             break;
918         case EbtSampler1DArray:
919         case EbtImage1DArray:
920             *dimOut   = spv::Dim1D;
921             isArrayed = true;
922             break;
923         case EbtSampler1DShadow:
924             *dimOut = spv::Dim1D;
925             isDepth = true;
926             break;
927         case EbtSampler1DArrayShadow:
928             *dimOut   = spv::Dim1D;
929             isDepth   = true;
930             isArrayed = true;
931             break;
932 
933         // Integer 1D images
934         case EbtISampler1D:
935         case EbtIImage1D:
936             sampledType = EbtInt;
937             *dimOut     = spv::Dim1D;
938             break;
939         case EbtISampler1DArray:
940         case EbtIImage1DArray:
941             sampledType = EbtInt;
942             *dimOut     = spv::Dim1D;
943             isArrayed   = true;
944             break;
945 
946         // Unsigned integer 1D images
947         case EbtUSampler1D:
948         case EbtUImage1D:
949             sampledType = EbtUInt;
950             *dimOut     = spv::Dim1D;
951             break;
952         case EbtUSampler1DArray:
953         case EbtUImage1DArray:
954             sampledType = EbtUInt;
955             *dimOut     = spv::Dim1D;
956             isArrayed   = true;
957             break;
958 
959         // Rect images
960         case EbtSampler2DRect:
961         case EbtImageRect:
962             *dimOut = spv::DimRect;
963             break;
964         case EbtSampler2DRectShadow:
965             *dimOut = spv::DimRect;
966             isDepth = true;
967             break;
968         case EbtISampler2DRect:
969         case EbtIImageRect:
970             sampledType = EbtInt;
971             *dimOut     = spv::DimRect;
972             break;
973         case EbtUSampler2DRect:
974         case EbtUImageRect:
975             sampledType = EbtUInt;
976             *dimOut     = spv::DimRect;
977             break;
978 
979         // Image buffers
980         case EbtSamplerBuffer:
981         case EbtImageBuffer:
982             *dimOut = spv::DimBuffer;
983             break;
984         case EbtISamplerBuffer:
985         case EbtIImageBuffer:
986             sampledType = EbtInt;
987             *dimOut     = spv::DimBuffer;
988             break;
989         case EbtUSamplerBuffer:
990         case EbtUImageBuffer:
991             sampledType = EbtUInt;
992             *dimOut     = spv::DimBuffer;
993             break;
994         default:
995             // TODO: support framebuffer fetch.  http://anglebug.com/4889
996             UNREACHABLE();
997     }
998 
999     // Get id of the component type of the image
1000     SpirvType sampledSpirvType;
1001     sampledSpirvType.type = sampledType;
1002 
1003     *sampledTypeOut = getSpirvTypeData(sampledSpirvType, nullptr).id;
1004 
1005     const bool isSampledImage = IsSampler(type);
1006 
1007     // Set flags based on SPIR-V required values.  See OpTypeImage:
1008     //
1009     // - For depth:        0 = non-depth,      1 = depth
1010     // - For arrayed:      0 = non-arrayed,    1 = arrayed
1011     // - For multisampled: 0 = single-sampled, 1 = multisampled
1012     // - For sampled:      1 = sampled,        2 = storage
1013     //
1014     *depthOut        = spirv::LiteralInteger(isDepth ? 1 : 0);
1015     *arrayedOut      = spirv::LiteralInteger(isArrayed ? 1 : 0);
1016     *multisampledOut = spirv::LiteralInteger(isMultisampled ? 1 : 0);
1017     *sampledOut      = spirv::LiteralInteger(isSampledImage ? 1 : 2);
1018 
1019     // Add the necessary capability based on parameters.  The SPIR-V spec section 3.8 Dim specfies
1020     // the required capabilities:
1021     //
1022     //     Dim          Sampled         Storage            Storage Array
1023     //     --------------------------------------------------------------
1024     //     1D           Sampled1D       Image1D
1025     //     2D           Shader                             ImageMSArray
1026     //     3D
1027     //     Cube         Shader                             ImageCubeArray
1028     //     Rect         SampledRect     ImageRect
1029     //     Buffer       SampledBuffer   ImageBuffer
1030     //
1031     // Note that the Shader capability is always unconditionally added.
1032     //
1033     switch (*dimOut)
1034     {
1035         case spv::Dim1D:
1036             addCapability(isSampledImage ? spv::CapabilitySampled1D : spv::CapabilityImage1D);
1037             break;
1038         case spv::Dim2D:
1039             if (!isSampledImage && isArrayed && isMultisampled)
1040             {
1041                 addCapability(spv::CapabilityImageMSArray);
1042             }
1043             break;
1044         case spv::Dim3D:
1045             break;
1046         case spv::DimCube:
1047             if (!isSampledImage && isArrayed && isMultisampled)
1048             {
1049                 addCapability(spv::CapabilityImageCubeArray);
1050             }
1051             break;
1052         case spv::DimRect:
1053             addCapability(isSampledImage ? spv::CapabilitySampledRect : spv::CapabilityImageRect);
1054             break;
1055         case spv::DimBuffer:
1056             addCapability(isSampledImage ? spv::CapabilitySampledBuffer
1057                                          : spv::CapabilityImageBuffer);
1058             break;
1059         default:
1060             // TODO: support framebuffer fetch.  http://anglebug.com/4889
1061             UNREACHABLE();
1062     }
1063 }
1064 
getImageFormat(TLayoutImageInternalFormat imageInternalFormat)1065 spv::ImageFormat SPIRVBuilder::getImageFormat(TLayoutImageInternalFormat imageInternalFormat)
1066 {
1067     switch (imageInternalFormat)
1068     {
1069         case EiifUnspecified:
1070             return spv::ImageFormatUnknown;
1071         case EiifRGBA32F:
1072             return spv::ImageFormatRgba32f;
1073         case EiifRGBA16F:
1074             return spv::ImageFormatRgba16f;
1075         case EiifR32F:
1076             return spv::ImageFormatR32f;
1077         case EiifRGBA32UI:
1078             return spv::ImageFormatRgba32ui;
1079         case EiifRGBA16UI:
1080             return spv::ImageFormatRgba16ui;
1081         case EiifRGBA8UI:
1082             return spv::ImageFormatRgba8ui;
1083         case EiifR32UI:
1084             return spv::ImageFormatR32ui;
1085         case EiifRGBA32I:
1086             return spv::ImageFormatRgba32i;
1087         case EiifRGBA16I:
1088             return spv::ImageFormatRgba16i;
1089         case EiifRGBA8I:
1090             return spv::ImageFormatRgba8i;
1091         case EiifR32I:
1092             return spv::ImageFormatR32i;
1093         case EiifRGBA8:
1094             return spv::ImageFormatRgba8;
1095         case EiifRGBA8_SNORM:
1096             return spv::ImageFormatRgba8Snorm;
1097         default:
1098             UNREACHABLE();
1099             return spv::ImageFormatUnknown;
1100     }
1101 }
1102 
getBoolConstant(bool value)1103 spirv::IdRef SPIRVBuilder::getBoolConstant(bool value)
1104 {
1105     uint32_t asInt = static_cast<uint32_t>(value);
1106 
1107     spirv::IdRef constantId = mBoolConstants[asInt];
1108 
1109     if (!constantId.valid())
1110     {
1111         SpirvType boolType;
1112         boolType.type = EbtBool;
1113 
1114         const spirv::IdRef boolTypeId = getSpirvTypeData(boolType, nullptr).id;
1115 
1116         mBoolConstants[asInt] = constantId = getNewId({});
1117         if (value)
1118         {
1119             spirv::WriteConstantTrue(&mSpirvTypeAndConstantDecls, boolTypeId, constantId);
1120         }
1121         else
1122         {
1123             spirv::WriteConstantFalse(&mSpirvTypeAndConstantDecls, boolTypeId, constantId);
1124         }
1125     }
1126 
1127     return constantId;
1128 }
1129 
getBasicConstantHelper(uint32_t value,TBasicType type,angle::HashMap<uint32_t,spirv::IdRef> * constants)1130 spirv::IdRef SPIRVBuilder::getBasicConstantHelper(uint32_t value,
1131                                                   TBasicType type,
1132                                                   angle::HashMap<uint32_t, spirv::IdRef> *constants)
1133 {
1134     auto iter = constants->find(value);
1135     if (iter != constants->end())
1136     {
1137         return iter->second;
1138     }
1139 
1140     SpirvType spirvType;
1141     spirvType.type = type;
1142 
1143     const spirv::IdRef typeId     = getSpirvTypeData(spirvType, nullptr).id;
1144     const spirv::IdRef constantId = getNewId({});
1145 
1146     spirv::WriteConstant(&mSpirvTypeAndConstantDecls, typeId, constantId,
1147                          spirv::LiteralContextDependentNumber(value));
1148 
1149     return constants->insert({value, constantId}).first->second;
1150 }
1151 
getUintConstant(uint32_t value)1152 spirv::IdRef SPIRVBuilder::getUintConstant(uint32_t value)
1153 {
1154     return getBasicConstantHelper(value, EbtUInt, &mUintConstants);
1155 }
1156 
getIntConstant(int32_t value)1157 spirv::IdRef SPIRVBuilder::getIntConstant(int32_t value)
1158 {
1159     uint32_t asUint = static_cast<uint32_t>(value);
1160     return getBasicConstantHelper(asUint, EbtInt, &mIntConstants);
1161 }
1162 
getFloatConstant(float value)1163 spirv::IdRef SPIRVBuilder::getFloatConstant(float value)
1164 {
1165     union
1166     {
1167         float f;
1168         uint32_t u;
1169     } asUint;
1170     asUint.f = value;
1171     return getBasicConstantHelper(asUint.u, EbtFloat, &mFloatConstants);
1172 }
1173 
getNullConstant(spirv::IdRef typeId)1174 spirv::IdRef SPIRVBuilder::getNullConstant(spirv::IdRef typeId)
1175 {
1176     if (typeId >= mNullConstants.size())
1177     {
1178         mNullConstants.resize(typeId + 1);
1179     }
1180 
1181     if (!mNullConstants[typeId].valid())
1182     {
1183         const spirv::IdRef constantId = getNewId({});
1184         mNullConstants[typeId]        = constantId;
1185 
1186         spirv::WriteConstantNull(&mSpirvTypeAndConstantDecls, typeId, constantId);
1187     }
1188 
1189     return mNullConstants[typeId];
1190 }
1191 
getNullVectorConstantHelper(TBasicType type,int size)1192 spirv::IdRef SPIRVBuilder::getNullVectorConstantHelper(TBasicType type, int size)
1193 {
1194     SpirvType vecType;
1195     vecType.type        = type;
1196     vecType.primarySize = static_cast<uint8_t>(size);
1197 
1198     return getNullConstant(getSpirvTypeData(vecType, nullptr).id);
1199 }
1200 
getVectorConstantHelper(spirv::IdRef valueId,TBasicType type,int size)1201 spirv::IdRef SPIRVBuilder::getVectorConstantHelper(spirv::IdRef valueId, TBasicType type, int size)
1202 {
1203     if (size == 1)
1204     {
1205         return valueId;
1206     }
1207 
1208     SpirvType vecType;
1209     vecType.type        = type;
1210     vecType.primarySize = static_cast<uint8_t>(size);
1211 
1212     const spirv::IdRef typeId = getSpirvTypeData(vecType, nullptr).id;
1213     const spirv::IdRefList valueIds(size, valueId);
1214 
1215     return getCompositeConstant(typeId, valueIds);
1216 }
1217 
getUvecConstant(uint32_t value,int size)1218 spirv::IdRef SPIRVBuilder::getUvecConstant(uint32_t value, int size)
1219 {
1220     if (value == 0)
1221     {
1222         return getNullVectorConstantHelper(EbtUInt, size);
1223     }
1224 
1225     const spirv::IdRef valueId = getUintConstant(value);
1226     return getVectorConstantHelper(valueId, EbtUInt, size);
1227 }
1228 
getIvecConstant(int32_t value,int size)1229 spirv::IdRef SPIRVBuilder::getIvecConstant(int32_t value, int size)
1230 {
1231     if (value == 0)
1232     {
1233         return getNullVectorConstantHelper(EbtInt, size);
1234     }
1235 
1236     const spirv::IdRef valueId = getIntConstant(value);
1237     return getVectorConstantHelper(valueId, EbtInt, size);
1238 }
1239 
getVecConstant(float value,int size)1240 spirv::IdRef SPIRVBuilder::getVecConstant(float value, int size)
1241 {
1242     if (value == 0)
1243     {
1244         return getNullVectorConstantHelper(EbtFloat, size);
1245     }
1246 
1247     const spirv::IdRef valueId = getFloatConstant(value);
1248     return getVectorConstantHelper(valueId, EbtFloat, size);
1249 }
1250 
getCompositeConstant(spirv::IdRef typeId,const spirv::IdRefList & values)1251 spirv::IdRef SPIRVBuilder::getCompositeConstant(spirv::IdRef typeId, const spirv::IdRefList &values)
1252 {
1253     SpirvIdAndIdList key{typeId, values};
1254 
1255     auto iter = mCompositeConstants.find(key);
1256     if (iter == mCompositeConstants.end())
1257     {
1258         const spirv::IdRef constantId = getNewId({});
1259 
1260         spirv::WriteConstantComposite(&mSpirvTypeAndConstantDecls, typeId, constantId, values);
1261 
1262         iter = mCompositeConstants.insert({key, constantId}).first;
1263     }
1264 
1265     return iter->second;
1266 }
1267 
startNewFunction(spirv::IdRef functionId,const TFunction * func)1268 void SPIRVBuilder::startNewFunction(spirv::IdRef functionId, const TFunction *func)
1269 {
1270     ASSERT(mSpirvCurrentFunctionBlocks.empty());
1271 
1272     // Add the first block of the function.
1273     mSpirvCurrentFunctionBlocks.emplace_back();
1274     mSpirvCurrentFunctionBlocks.back().labelId = getNewId({});
1275 
1276     // Output debug information.
1277     spirv::WriteName(&mSpirvDebug, functionId, hashFunctionName(func).data());
1278 }
1279 
assembleSpirvFunctionBlocks()1280 void SPIRVBuilder::assembleSpirvFunctionBlocks()
1281 {
1282     // Take all the blocks and place them in the functions section of SPIR-V in sequence.
1283     for (const SpirvBlock &block : mSpirvCurrentFunctionBlocks)
1284     {
1285         // Every block must be properly terminated.
1286         ASSERT(block.isTerminated);
1287 
1288         // Generate the OpLabel instruction for the block.
1289         spirv::WriteLabel(&mSpirvFunctions, block.labelId);
1290 
1291         // Add the variable declarations if any.
1292         mSpirvFunctions.insert(mSpirvFunctions.end(), block.localVariables.begin(),
1293                                block.localVariables.end());
1294 
1295         // Add the body of the block.
1296         mSpirvFunctions.insert(mSpirvFunctions.end(), block.body.begin(), block.body.end());
1297     }
1298 
1299     // Clean up.
1300     mSpirvCurrentFunctionBlocks.clear();
1301 }
1302 
declareVariable(spirv::IdRef typeId,spv::StorageClass storageClass,const SpirvDecorations & decorations,spirv::IdRef * initializerId,const char * name)1303 spirv::IdRef SPIRVBuilder::declareVariable(spirv::IdRef typeId,
1304                                            spv::StorageClass storageClass,
1305                                            const SpirvDecorations &decorations,
1306                                            spirv::IdRef *initializerId,
1307                                            const char *name)
1308 {
1309     const bool isFunctionLocal = storageClass == spv::StorageClassFunction;
1310 
1311     // Make sure storage class is consistent with where the variable is declared.
1312     ASSERT(!isFunctionLocal || !mSpirvCurrentFunctionBlocks.empty());
1313 
1314     // Function-local variables go in the first block of the function, while the rest are in the
1315     // global variables section.
1316     spirv::Blob *spirvSection = isFunctionLocal
1317                                     ? &mSpirvCurrentFunctionBlocks.front().localVariables
1318                                     : &mSpirvVariableDecls;
1319 
1320     const spirv::IdRef variableId    = getNewId(decorations);
1321     const spirv::IdRef typePointerId = getTypePointerId(typeId, storageClass);
1322 
1323     spirv::WriteVariable(spirvSection, typePointerId, variableId, storageClass, initializerId);
1324 
1325     // Output debug information.
1326     if (name)
1327     {
1328         spirv::WriteName(&mSpirvDebug, variableId, name);
1329     }
1330 
1331     return variableId;
1332 }
1333 
declareSpecConst(TBasicType type,int id,const char * name)1334 spirv::IdRef SPIRVBuilder::declareSpecConst(TBasicType type, int id, const char *name)
1335 {
1336     SpirvType spirvType;
1337     spirvType.type = type;
1338 
1339     const spirv::IdRef typeId      = getSpirvTypeData(spirvType, nullptr).id;
1340     const spirv::IdRef specConstId = getNewId({});
1341 
1342     // Note: all spec constants are 0 initialized by the translator.
1343     if (type == EbtBool)
1344     {
1345         spirv::WriteSpecConstantFalse(&mSpirvTypeAndConstantDecls, typeId, specConstId);
1346     }
1347     else
1348     {
1349         spirv::WriteSpecConstant(&mSpirvTypeAndConstantDecls, typeId, specConstId,
1350                                  spirv::LiteralContextDependentNumber(0));
1351     }
1352 
1353     // Add the SpecId decoration
1354     spirv::WriteDecorate(&mSpirvDecorations, specConstId, spv::DecorationSpecId,
1355                          {spirv::LiteralInteger(id)});
1356 
1357     // Output debug information.
1358     if (name)
1359     {
1360         spirv::WriteName(&mSpirvDebug, specConstId, name);
1361     }
1362 
1363     return specConstId;
1364 }
1365 
startConditional(size_t blockCount,bool isContinuable,bool isBreakable)1366 void SPIRVBuilder::startConditional(size_t blockCount, bool isContinuable, bool isBreakable)
1367 {
1368     mConditionalStack.emplace_back();
1369     SpirvConditional &conditional = mConditionalStack.back();
1370 
1371     // Create the requested number of block ids.
1372     conditional.blockIds.resize(blockCount);
1373     for (spirv::IdRef &blockId : conditional.blockIds)
1374     {
1375         blockId = getNewId({});
1376     }
1377 
1378     conditional.isContinuable = isContinuable;
1379     conditional.isBreakable   = isBreakable;
1380 
1381     // Don't automatically start the next block.  The caller needs to generate instructions based on
1382     // the ids that were just generated above.
1383 }
1384 
nextConditionalBlock()1385 void SPIRVBuilder::nextConditionalBlock()
1386 {
1387     ASSERT(!mConditionalStack.empty());
1388     SpirvConditional &conditional = mConditionalStack.back();
1389 
1390     ASSERT(conditional.nextBlockToWrite < conditional.blockIds.size());
1391     const spirv::IdRef blockId = conditional.blockIds[conditional.nextBlockToWrite++];
1392 
1393     // The previous block must have properly terminated.
1394     ASSERT(isCurrentFunctionBlockTerminated());
1395 
1396     // Generate a new block.
1397     mSpirvCurrentFunctionBlocks.emplace_back();
1398     mSpirvCurrentFunctionBlocks.back().labelId = blockId;
1399 }
1400 
endConditional()1401 void SPIRVBuilder::endConditional()
1402 {
1403     ASSERT(!mConditionalStack.empty());
1404 
1405     // No blocks should be left.
1406     ASSERT(mConditionalStack.back().nextBlockToWrite == mConditionalStack.back().blockIds.size());
1407 
1408     mConditionalStack.pop_back();
1409 }
1410 
isInLoop() const1411 bool SPIRVBuilder::isInLoop() const
1412 {
1413     for (const SpirvConditional &conditional : mConditionalStack)
1414     {
1415         if (conditional.isContinuable)
1416         {
1417             return true;
1418         }
1419     }
1420 
1421     return false;
1422 }
1423 
getBreakTargetId() const1424 spirv::IdRef SPIRVBuilder::getBreakTargetId() const
1425 {
1426     for (size_t index = mConditionalStack.size(); index > 0; --index)
1427     {
1428         const SpirvConditional &conditional = mConditionalStack[index - 1];
1429 
1430         if (conditional.isBreakable)
1431         {
1432             // The target of break; is always the merge block, and the merge block is always the
1433             // last block.
1434             return conditional.blockIds.back();
1435         }
1436     }
1437 
1438     UNREACHABLE();
1439     return spirv::IdRef{};
1440 }
1441 
getContinueTargetId() const1442 spirv::IdRef SPIRVBuilder::getContinueTargetId() const
1443 {
1444     for (size_t index = mConditionalStack.size(); index > 0; --index)
1445     {
1446         const SpirvConditional &conditional = mConditionalStack[index - 1];
1447 
1448         if (conditional.isContinuable)
1449         {
1450             // The target of continue; is always the block before merge, so it's the one before
1451             // last.
1452             ASSERT(conditional.blockIds.size() > 2);
1453             return conditional.blockIds[conditional.blockIds.size() - 2];
1454         }
1455     }
1456 
1457     UNREACHABLE();
1458     return spirv::IdRef{};
1459 }
1460 
nextUnusedBinding()1461 uint32_t SPIRVBuilder::nextUnusedBinding()
1462 {
1463     return mNextUnusedBinding++;
1464 }
1465 
nextUnusedInputLocation(uint32_t consumedCount)1466 uint32_t SPIRVBuilder::nextUnusedInputLocation(uint32_t consumedCount)
1467 {
1468     uint32_t nextUnused = mNextUnusedInputLocation;
1469     mNextUnusedInputLocation += consumedCount;
1470     return nextUnused;
1471 }
1472 
nextUnusedOutputLocation(uint32_t consumedCount)1473 uint32_t SPIRVBuilder::nextUnusedOutputLocation(uint32_t consumedCount)
1474 {
1475     uint32_t nextUnused = mNextUnusedOutputLocation;
1476     mNextUnusedOutputLocation += consumedCount;
1477     return nextUnused;
1478 }
1479 
isInvariantOutput(const TType & type) const1480 bool SPIRVBuilder::isInvariantOutput(const TType &type) const
1481 {
1482     return IsInvariant(type, mCompiler);
1483 }
1484 
addCapability(spv::Capability capability)1485 void SPIRVBuilder::addCapability(spv::Capability capability)
1486 {
1487     mCapabilities.insert(capability);
1488 }
1489 
setEntryPointId(spirv::IdRef id)1490 void SPIRVBuilder::setEntryPointId(spirv::IdRef id)
1491 {
1492     ASSERT(!mEntryPointId.valid());
1493     mEntryPointId = id;
1494 }
1495 
addEntryPointInterfaceVariableId(spirv::IdRef id)1496 void SPIRVBuilder::addEntryPointInterfaceVariableId(spirv::IdRef id)
1497 {
1498     mEntryPointInterfaceList.push_back(id);
1499 }
1500 
writePerVertexBuiltIns(const TType & type,spirv::IdRef typeId)1501 void SPIRVBuilder::writePerVertexBuiltIns(const TType &type, spirv::IdRef typeId)
1502 {
1503     ASSERT(type.isInterfaceBlock());
1504     const TInterfaceBlock *block = type.getInterfaceBlock();
1505 
1506     uint32_t fieldIndex = 0;
1507     for (const TField *field : block->fields())
1508     {
1509         spv::BuiltIn decorationValue = spv::BuiltInPosition;
1510         switch (field->type()->getQualifier())
1511         {
1512             case EvqPosition:
1513                 decorationValue = spv::BuiltInPosition;
1514                 break;
1515             case EvqPointSize:
1516                 decorationValue = spv::BuiltInPointSize;
1517                 break;
1518             case EvqClipDistance:
1519                 decorationValue = spv::BuiltInClipDistance;
1520                 break;
1521             case EvqCullDistance:
1522                 decorationValue = spv::BuiltInCullDistance;
1523                 break;
1524             default:
1525                 UNREACHABLE();
1526         }
1527 
1528         spirv::WriteMemberDecorate(&mSpirvDecorations, typeId, spirv::LiteralInteger(fieldIndex++),
1529                                    spv::DecorationBuiltIn,
1530                                    {spirv::LiteralInteger(decorationValue)});
1531     }
1532 }
1533 
writeInterfaceVariableDecorations(const TType & type,spirv::IdRef variableId)1534 void SPIRVBuilder::writeInterfaceVariableDecorations(const TType &type, spirv::IdRef variableId)
1535 {
1536     const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
1537 
1538     const bool isVarying = IsVarying(type.getQualifier());
1539     const bool needsSetBinding =
1540         IsSampler(type.getBasicType()) ||
1541         (type.isInterfaceBlock() &&
1542          (type.getQualifier() == EvqUniform || type.getQualifier() == EvqBuffer)) ||
1543         IsImage(type.getBasicType()) || IsSubpassInputType(type.getBasicType());
1544     const bool needsLocation = type.getQualifier() == EvqAttribute ||
1545                                type.getQualifier() == EvqVertexIn ||
1546                                type.getQualifier() == EvqFragmentOut || isVarying;
1547     const bool needsInputAttachmentIndex = IsSubpassInputType(type.getBasicType());
1548     const bool needsBlendIndex =
1549         type.getQualifier() == EvqFragmentOut && layoutQualifier.index >= 0;
1550 
1551     // If the resource declaration requires set & binding, add the DescriptorSet and Binding
1552     // decorations.
1553     if (needsSetBinding)
1554     {
1555         spirv::WriteDecorate(&mSpirvDecorations, variableId, spv::DecorationDescriptorSet,
1556                              {spirv::LiteralInteger(0)});
1557         spirv::WriteDecorate(&mSpirvDecorations, variableId, spv::DecorationBinding,
1558                              {spirv::LiteralInteger(nextUnusedBinding())});
1559     }
1560 
1561     if (needsLocation)
1562     {
1563         const unsigned int locationCount =
1564             CalculateVaryingLocationCount(type, gl::ToGLenum(mShaderType));
1565         const uint32_t location = IsShaderIn(type.getQualifier())
1566                                       ? nextUnusedInputLocation(locationCount)
1567                                       : nextUnusedOutputLocation(locationCount);
1568 
1569         spirv::WriteDecorate(&mSpirvDecorations, variableId, spv::DecorationLocation,
1570                              {spirv::LiteralInteger(location)});
1571     }
1572 
1573     // If the resource declaration is an input attachment, add the InputAttachmentIndex decoration.
1574     if (needsInputAttachmentIndex)
1575     {
1576         spirv::WriteDecorate(&mSpirvDecorations, variableId, spv::DecorationInputAttachmentIndex,
1577                              {spirv::LiteralInteger(layoutQualifier.inputAttachmentIndex)});
1578     }
1579 
1580     if (needsBlendIndex)
1581     {
1582         spirv::WriteDecorate(&mSpirvDecorations, variableId, spv::DecorationIndex,
1583                              {spirv::LiteralInteger(layoutQualifier.index)});
1584     }
1585 
1586     // Handle interpolation and auxiliary decorations on varyings
1587     if (isVarying)
1588     {
1589         writeInterpolationDecoration(type.getQualifier(), variableId,
1590                                      std::numeric_limits<uint32_t>::max());
1591     }
1592 }
1593 
writeBranchConditional(spirv::IdRef conditionValue,spirv::IdRef trueBlock,spirv::IdRef falseBlock,spirv::IdRef mergeBlock)1594 void SPIRVBuilder::writeBranchConditional(spirv::IdRef conditionValue,
1595                                           spirv::IdRef trueBlock,
1596                                           spirv::IdRef falseBlock,
1597                                           spirv::IdRef mergeBlock)
1598 {
1599     // Generate the following:
1600     //
1601     //     OpSelectionMerge %mergeBlock None
1602     //     OpBranchConditional %conditionValue %trueBlock %falseBlock
1603     //
1604     spirv::WriteSelectionMerge(getSpirvCurrentFunctionBlock(), mergeBlock,
1605                                spv::SelectionControlMaskNone);
1606     spirv::WriteBranchConditional(getSpirvCurrentFunctionBlock(), conditionValue, trueBlock,
1607                                   falseBlock, {});
1608     terminateCurrentFunctionBlock();
1609 
1610     // Start the true or false block, whichever exists.
1611     nextConditionalBlock();
1612 }
1613 
writeBranchConditionalBlockEnd()1614 void SPIRVBuilder::writeBranchConditionalBlockEnd()
1615 {
1616     if (!isCurrentFunctionBlockTerminated())
1617     {
1618         // Insert a branch to the merge block at the end of each if-else block, unless the block is
1619         // already terminated, such as with a return or discard.
1620         const spirv::IdRef mergeBlock = getCurrentConditional()->blockIds.back();
1621 
1622         spirv::WriteBranch(getSpirvCurrentFunctionBlock(), mergeBlock);
1623         terminateCurrentFunctionBlock();
1624     }
1625 
1626     // Move on to the next block.
1627     nextConditionalBlock();
1628 }
1629 
writeLoopHeader(spirv::IdRef branchToBlock,spirv::IdRef continueBlock,spirv::IdRef mergeBlock)1630 void SPIRVBuilder::writeLoopHeader(spirv::IdRef branchToBlock,
1631                                    spirv::IdRef continueBlock,
1632                                    spirv::IdRef mergeBlock)
1633 {
1634     // First, jump to the header block:
1635     //
1636     //     OpBranch %header
1637     //
1638     const spirv::IdRef headerBlock = mConditionalStack.back().blockIds[0];
1639     spirv::WriteBranch(getSpirvCurrentFunctionBlock(), headerBlock);
1640     terminateCurrentFunctionBlock();
1641 
1642     // Start the header block.
1643     nextConditionalBlock();
1644 
1645     // Generate the following:
1646     //
1647     //     OpLoopMerge %mergeBlock %continueBlock None
1648     //     OpBranch %branchToBlock (%cond or if do-while, %body)
1649     //
1650     spirv::WriteLoopMerge(getSpirvCurrentFunctionBlock(), mergeBlock, continueBlock,
1651                           spv::LoopControlMaskNone);
1652     spirv::WriteBranch(getSpirvCurrentFunctionBlock(), branchToBlock);
1653     terminateCurrentFunctionBlock();
1654 
1655     // Start the next block, which is either %cond or %body.
1656     nextConditionalBlock();
1657 }
1658 
writeLoopConditionEnd(spirv::IdRef conditionValue,spirv::IdRef branchToBlock,spirv::IdRef mergeBlock)1659 void SPIRVBuilder::writeLoopConditionEnd(spirv::IdRef conditionValue,
1660                                          spirv::IdRef branchToBlock,
1661                                          spirv::IdRef mergeBlock)
1662 {
1663     // Generate the following:
1664     //
1665     //     OpBranchConditional %conditionValue %branchToBlock %mergeBlock
1666     //
1667     // %branchToBlock is either %body or if do-while, %header
1668     //
1669     spirv::WriteBranchConditional(getSpirvCurrentFunctionBlock(), conditionValue, branchToBlock,
1670                                   mergeBlock, {});
1671     terminateCurrentFunctionBlock();
1672 
1673     // Start the next block, which is either %continue or %body.
1674     nextConditionalBlock();
1675 }
1676 
writeLoopContinueEnd(spirv::IdRef headerBlock)1677 void SPIRVBuilder::writeLoopContinueEnd(spirv::IdRef headerBlock)
1678 {
1679     // Generate the following:
1680     //
1681     //     OpBranch %headerBlock
1682     //
1683     spirv::WriteBranch(getSpirvCurrentFunctionBlock(), headerBlock);
1684     terminateCurrentFunctionBlock();
1685 
1686     // Start the next block, which is %body.
1687     nextConditionalBlock();
1688 }
1689 
writeLoopBodyEnd(spirv::IdRef continueBlock)1690 void SPIRVBuilder::writeLoopBodyEnd(spirv::IdRef continueBlock)
1691 {
1692     // Generate the following:
1693     //
1694     //     OpBranch %continueBlock
1695     //
1696     // This is only done if the block isn't already terminated in another way, such as with an
1697     // unconditional continue/etc at the end of the loop.
1698     if (!isCurrentFunctionBlockTerminated())
1699     {
1700         spirv::WriteBranch(getSpirvCurrentFunctionBlock(), continueBlock);
1701         terminateCurrentFunctionBlock();
1702     }
1703 
1704     // Start the next block, which is %merge or if while, %continue.
1705     nextConditionalBlock();
1706 }
1707 
writeSwitch(spirv::IdRef conditionValue,spirv::IdRef defaultBlock,const spirv::PairLiteralIntegerIdRefList & targetPairList,spirv::IdRef mergeBlock)1708 void SPIRVBuilder::writeSwitch(spirv::IdRef conditionValue,
1709                                spirv::IdRef defaultBlock,
1710                                const spirv::PairLiteralIntegerIdRefList &targetPairList,
1711                                spirv::IdRef mergeBlock)
1712 {
1713     // Generate the following:
1714     //
1715     //     OpSelectionMerge %mergeBlock None
1716     //     OpSwitch %conditionValue %defaultBlock A %ABlock B %BBlock ...
1717     //
1718     spirv::WriteSelectionMerge(getSpirvCurrentFunctionBlock(), mergeBlock,
1719                                spv::SelectionControlMaskNone);
1720     spirv::WriteSwitch(getSpirvCurrentFunctionBlock(), conditionValue, defaultBlock,
1721                        targetPairList);
1722     terminateCurrentFunctionBlock();
1723 
1724     // Start the next case block.
1725     nextConditionalBlock();
1726 }
1727 
writeSwitchCaseBlockEnd()1728 void SPIRVBuilder::writeSwitchCaseBlockEnd()
1729 {
1730     if (!isCurrentFunctionBlockTerminated())
1731     {
1732         // If a case does not end in branch, insert a branch to the next block, implementing
1733         // fallthrough.  For the last block, the branch target would automatically be the merge
1734         // block.
1735         const SpirvConditional *conditional = getCurrentConditional();
1736         const spirv::IdRef nextBlock        = conditional->blockIds[conditional->nextBlockToWrite];
1737 
1738         spirv::WriteBranch(getSpirvCurrentFunctionBlock(), nextBlock);
1739         terminateCurrentFunctionBlock();
1740     }
1741 
1742     // Move on to the next block.
1743     nextConditionalBlock();
1744 }
1745 
writeMemberDecorations(const SpirvType & type,spirv::IdRef typeId)1746 void SPIRVBuilder::writeMemberDecorations(const SpirvType &type, spirv::IdRef typeId)
1747 {
1748     ASSERT(type.block != nullptr);
1749 
1750     uint32_t fieldIndex = 0;
1751 
1752     for (const TField *field : type.block->fields())
1753     {
1754         const TType &fieldType = *field->type();
1755 
1756         // Add invariant decoration if any.
1757         if (type.typeSpec.isInvariantBlock || fieldType.isInvariant())
1758         {
1759             spirv::WriteMemberDecorate(&mSpirvDecorations, typeId,
1760                                        spirv::LiteralInteger(fieldIndex), spv::DecorationInvariant,
1761                                        {});
1762         }
1763 
1764         // Add matrix decorations if any.
1765         if (fieldType.isMatrix())
1766         {
1767             // ColMajor or RowMajor
1768             const bool isRowMajor =
1769                 IsBlockFieldRowMajorQualified(fieldType, type.typeSpec.isRowMajorQualifiedBlock);
1770             spirv::WriteMemberDecorate(
1771                 &mSpirvDecorations, typeId, spirv::LiteralInteger(fieldIndex),
1772                 isRowMajor ? spv::DecorationRowMajor : spv::DecorationColMajor, {});
1773         }
1774 
1775         // Add interpolation and auxiliary decorations
1776         writeInterpolationDecoration(fieldType.getQualifier(), typeId, fieldIndex);
1777 
1778         // Add other decorations.
1779         SpirvDecorations decorations = getDecorations(fieldType);
1780         for (const spv::Decoration decoration : decorations)
1781         {
1782             spirv::WriteMemberDecorate(&mSpirvDecorations, typeId,
1783                                        spirv::LiteralInteger(fieldIndex), decoration, {});
1784         }
1785 
1786         ++fieldIndex;
1787     }
1788 }
1789 
writeInterpolationDecoration(TQualifier qualifier,spirv::IdRef id,uint32_t fieldIndex)1790 void SPIRVBuilder::writeInterpolationDecoration(TQualifier qualifier,
1791                                                 spirv::IdRef id,
1792                                                 uint32_t fieldIndex)
1793 {
1794     spv::Decoration decoration = spv::DecorationMax;
1795 
1796     switch (qualifier)
1797     {
1798         case EvqSmooth:
1799         case EvqSmoothOut:
1800         case EvqSmoothIn:
1801             // No decoration in SPIR-V for smooth, this is the default interpolation.
1802             return;
1803 
1804         case EvqFlat:
1805         case EvqFlatOut:
1806         case EvqFlatIn:
1807             decoration = spv::DecorationFlat;
1808             break;
1809 
1810         case EvqNoPerspective:
1811         case EvqNoPerspectiveOut:
1812         case EvqNoPerspectiveIn:
1813             decoration = spv::DecorationNoPerspective;
1814             break;
1815 
1816         case EvqCentroid:
1817         case EvqCentroidOut:
1818         case EvqCentroidIn:
1819             decoration = spv::DecorationCentroid;
1820             break;
1821 
1822         case EvqSample:
1823         case EvqSampleOut:
1824         case EvqSampleIn:
1825             decoration = spv::DecorationSample;
1826             addCapability(spv::CapabilitySampleRateShading);
1827             break;
1828 
1829         default:
1830             return;
1831     }
1832 
1833     if (fieldIndex != std::numeric_limits<uint32_t>::max())
1834     {
1835         spirv::WriteMemberDecorate(&mSpirvDecorations, id, spirv::LiteralInteger(fieldIndex),
1836                                    decoration, {});
1837     }
1838     else
1839     {
1840         spirv::WriteDecorate(&mSpirvDecorations, id, decoration, {});
1841     }
1842 }
1843 
hashName(const TSymbol * symbol)1844 ImmutableString SPIRVBuilder::hashName(const TSymbol *symbol)
1845 {
1846     return HashName(symbol, mHashFunction, &mNameMap);
1847 }
1848 
hashTypeName(const TType & type)1849 ImmutableString SPIRVBuilder::hashTypeName(const TType &type)
1850 {
1851     return GetTypeName(type, mHashFunction, &mNameMap);
1852 }
1853 
hashFieldName(const TField * field)1854 ImmutableString SPIRVBuilder::hashFieldName(const TField *field)
1855 {
1856     ASSERT(field->symbolType() != SymbolType::Empty);
1857     if (field->symbolType() == SymbolType::UserDefined)
1858     {
1859         return HashName(field->name(), mHashFunction, &mNameMap);
1860     }
1861 
1862     return field->name();
1863 }
1864 
hashFunctionName(const TFunction * func)1865 ImmutableString SPIRVBuilder::hashFunctionName(const TFunction *func)
1866 {
1867     if (func->isMain())
1868     {
1869         return func->name();
1870     }
1871 
1872     return hashName(func);
1873 }
1874 
getSpirv()1875 spirv::Blob SPIRVBuilder::getSpirv()
1876 {
1877     ASSERT(mConditionalStack.empty());
1878 
1879     spirv::Blob result;
1880 
1881     // Reserve a minimum amount of memory.
1882     //
1883     //   5 for header +
1884     //   a number of capabilities +
1885     //   size of already generated instructions.
1886     //
1887     // The actual size is larger due to other metadata instructions such as extensions,
1888     // OpExtInstImport, OpEntryPoint, OpExecutionMode etc.
1889     result.reserve(5 + mCapabilities.size() * 2 + mSpirvDebug.size() + mSpirvDecorations.size() +
1890                    mSpirvTypeAndConstantDecls.size() + mSpirvTypePointerDecls.size() +
1891                    mSpirvFunctionTypeDecls.size() + mSpirvVariableDecls.size() +
1892                    mSpirvFunctions.size());
1893 
1894     // Generate the SPIR-V header.
1895     spirv::WriteSpirvHeader(&result, mNextAvailableId);
1896 
1897     // Generate metadata in the following order:
1898     //
1899     // - OpCapability instructions.  The Shader capability is always defined.
1900     spirv::WriteCapability(&result, spv::CapabilityShader);
1901     for (spv::Capability capability : mCapabilities)
1902     {
1903         spirv::WriteCapability(&result, capability);
1904     }
1905 
1906     // - OpExtension instructions (TODO: http://anglebug.com/4889)
1907 
1908     // - OpExtInstImport
1909     if (mExtInstImportIdStd.valid())
1910     {
1911         spirv::WriteExtInstImport(&result, mExtInstImportIdStd, "GLSL.std.450");
1912     }
1913 
1914     // - OpMemoryModel
1915     spirv::WriteMemoryModel(&result, spv::AddressingModelLogical, spv::MemoryModelGLSL450);
1916 
1917     // - OpEntryPoint
1918     constexpr gl::ShaderMap<spv::ExecutionModel> kExecutionModels = {
1919         {gl::ShaderType::Vertex, spv::ExecutionModelVertex},
1920         {gl::ShaderType::TessControl, spv::ExecutionModelTessellationControl},
1921         {gl::ShaderType::TessEvaluation, spv::ExecutionModelTessellationEvaluation},
1922         {gl::ShaderType::Geometry, spv::ExecutionModelGeometry},
1923         {gl::ShaderType::Fragment, spv::ExecutionModelFragment},
1924         {gl::ShaderType::Compute, spv::ExecutionModelGLCompute},
1925     };
1926     spirv::WriteEntryPoint(&result, kExecutionModels[mShaderType], mEntryPointId, "main",
1927                            mEntryPointInterfaceList);
1928 
1929     // - OpExecutionMode instructions
1930     generateExecutionModes(&result);
1931 
1932     // - OpSource instruction.
1933     //
1934     // This is to support debuggers and capture/replay tools and isn't strictly necessary.
1935     spirv::WriteSource(&result, spv::SourceLanguageGLSL, spirv::LiteralInteger(450), nullptr,
1936                        nullptr);
1937 
1938     // Append the already generated sections in order
1939     result.insert(result.end(), mSpirvDebug.begin(), mSpirvDebug.end());
1940     result.insert(result.end(), mSpirvDecorations.begin(), mSpirvDecorations.end());
1941     result.insert(result.end(), mSpirvTypeAndConstantDecls.begin(),
1942                   mSpirvTypeAndConstantDecls.end());
1943     result.insert(result.end(), mSpirvTypePointerDecls.begin(), mSpirvTypePointerDecls.end());
1944     result.insert(result.end(), mSpirvFunctionTypeDecls.begin(), mSpirvFunctionTypeDecls.end());
1945     result.insert(result.end(), mSpirvVariableDecls.begin(), mSpirvVariableDecls.end());
1946     result.insert(result.end(), mSpirvFunctions.begin(), mSpirvFunctions.end());
1947 
1948     result.shrink_to_fit();
1949     return result;
1950 }
1951 
generateExecutionModes(spirv::Blob * blob)1952 void SPIRVBuilder::generateExecutionModes(spirv::Blob *blob)
1953 {
1954     switch (mShaderType)
1955     {
1956         case gl::ShaderType::Fragment:
1957             spirv::WriteExecutionMode(blob, mEntryPointId, spv::ExecutionModeOriginUpperLeft, {});
1958 
1959             if (mCompiler->isEarlyFragmentTestsSpecified() ||
1960                 mCompiler->isEarlyFragmentTestsOptimized())
1961             {
1962                 spirv::WriteExecutionMode(blob, mEntryPointId, spv::ExecutionModeEarlyFragmentTests,
1963                                           {});
1964             }
1965 
1966             break;
1967 
1968         case gl::ShaderType::Compute:
1969         {
1970             const sh::WorkGroupSize &localSize = mCompiler->getComputeShaderLocalSize();
1971             spirv::WriteExecutionMode(
1972                 blob, mEntryPointId, spv::ExecutionModeLocalSize,
1973                 {spirv::LiteralInteger(localSize[0]), spirv::LiteralInteger(localSize[1]),
1974                  spirv::LiteralInteger(localSize[2])});
1975             break;
1976         }
1977         default:
1978             // TODO: other shader types.  http://anglebug.com/4889
1979             break;
1980     }
1981 }
1982 
1983 }  // namespace sh
1984