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