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