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 ¶mTypeIds)
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