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));
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 EbtDouble:
1067 // TODO: support desktop GLSL. http://anglebug.com/6197
1068 UNIMPLEMENTED();
1069 break;
1070 case EbtBool:
1071 spirv::WriteTypeBool(&mSpirvTypeAndConstantDecls, typeId);
1072 break;
1073 default:
1074 UNREACHABLE();
1075 }
1076 }
1077
1078 // If this was a block declaration, add debug information for its type and field names.
1079 if (mCompileOptions.outputDebugInfo && block != nullptr && type.arraySizes.empty())
1080 {
1081 writeBlockDebugNames(type.block, typeId, getName(block).data());
1082 }
1083
1084 // Write decorations for interface block fields.
1085 if (type.typeSpec.blockStorage != EbsUnspecified)
1086 {
1087 // Cannot have opaque uniforms inside interface blocks.
1088 ASSERT(!IsOpaqueType(type.type));
1089
1090 const bool isInterfaceBlock = block != nullptr && block->isInterfaceBlock();
1091 const bool isStd140 = type.typeSpec.blockStorage != EbsStd430;
1092
1093 if (!type.arraySizes.empty() && !isInterfaceBlock)
1094 {
1095 // Write the ArrayStride decoration for arrays inside interface blocks. An array of
1096 // interface blocks doesn't need a stride.
1097 const ShaderVariable var = SpirvTypeToShaderVariable(type);
1098 const uint32_t stride = GetArrayStrideInBlock(var, isStd140);
1099
1100 spirv::WriteDecorate(&mSpirvDecorations, typeId, spv::DecorationArrayStride,
1101 {spirv::LiteralInteger(stride)});
1102 }
1103 else if (type.arraySizes.empty() && type.block != nullptr)
1104 {
1105 // Write the Offset decoration for interface blocks and structs in them.
1106 const ShaderVariable var = SpirvTypeToShaderVariable(type);
1107 Encode(var, isStd140, typeId, &mSpirvDecorations);
1108 }
1109 }
1110
1111 // Write other member decorations.
1112 if (block != nullptr && type.arraySizes.empty())
1113 {
1114 writeMemberDecorations(type, typeId);
1115 }
1116
1117 return {typeId};
1118 }
1119
getImageTypeParameters(TBasicType type,spirv::IdRef * sampledTypeOut,spv::Dim * dimOut,spirv::LiteralInteger * depthOut,spirv::LiteralInteger * arrayedOut,spirv::LiteralInteger * multisampledOut,spirv::LiteralInteger * sampledOut)1120 void SPIRVBuilder::getImageTypeParameters(TBasicType type,
1121 spirv::IdRef *sampledTypeOut,
1122 spv::Dim *dimOut,
1123 spirv::LiteralInteger *depthOut,
1124 spirv::LiteralInteger *arrayedOut,
1125 spirv::LiteralInteger *multisampledOut,
1126 spirv::LiteralInteger *sampledOut)
1127 {
1128 TBasicType sampledType = EbtFloat;
1129 *dimOut = IsSubpassInputType(type) ? spv::DimSubpassData : spv::Dim2D;
1130 bool isDepth = false;
1131 bool isArrayed = false;
1132 bool isMultisampled = false;
1133
1134 // Decompose the basic type into image properties
1135 switch (type)
1136 {
1137 // Float 2D Images
1138 case EbtSampler2D:
1139 case EbtImage2D:
1140 case EbtSubpassInput:
1141 break;
1142 case EbtSamplerExternalOES:
1143 case EbtSamplerExternal2DY2YEXT:
1144 case EbtSamplerVideoWEBGL:
1145 // These must have already been converted to EbtSampler2D.
1146 UNREACHABLE();
1147 break;
1148 case EbtSampler2DArray:
1149 case EbtImage2DArray:
1150 isArrayed = true;
1151 break;
1152 case EbtSampler2DMS:
1153 case EbtImage2DMS:
1154 case EbtSubpassInputMS:
1155 isMultisampled = true;
1156 break;
1157 case EbtSampler2DMSArray:
1158 case EbtImage2DMSArray:
1159 isArrayed = true;
1160 isMultisampled = true;
1161 break;
1162 case EbtSampler2DShadow:
1163 isDepth = true;
1164 break;
1165 case EbtSampler2DArrayShadow:
1166 isDepth = true;
1167 isArrayed = true;
1168 break;
1169
1170 // Integer 2D images
1171 case EbtISampler2D:
1172 case EbtIImage2D:
1173 case EbtISubpassInput:
1174 sampledType = EbtInt;
1175 break;
1176 case EbtISampler2DArray:
1177 case EbtIImage2DArray:
1178 sampledType = EbtInt;
1179 isArrayed = true;
1180 break;
1181 case EbtISampler2DMS:
1182 case EbtIImage2DMS:
1183 case EbtISubpassInputMS:
1184 sampledType = EbtInt;
1185 isMultisampled = true;
1186 break;
1187 case EbtISampler2DMSArray:
1188 case EbtIImage2DMSArray:
1189 sampledType = EbtInt;
1190 isArrayed = true;
1191 isMultisampled = true;
1192 break;
1193
1194 // Unsinged integer 2D images
1195 case EbtUSampler2D:
1196 case EbtUImage2D:
1197 case EbtUSubpassInput:
1198 sampledType = EbtUInt;
1199 break;
1200 case EbtUSampler2DArray:
1201 case EbtUImage2DArray:
1202 sampledType = EbtUInt;
1203 isArrayed = true;
1204 break;
1205 case EbtUSampler2DMS:
1206 case EbtUImage2DMS:
1207 case EbtUSubpassInputMS:
1208 sampledType = EbtUInt;
1209 isMultisampled = true;
1210 break;
1211 case EbtUSampler2DMSArray:
1212 case EbtUImage2DMSArray:
1213 sampledType = EbtUInt;
1214 isArrayed = true;
1215 isMultisampled = true;
1216 break;
1217
1218 // 3D images
1219 case EbtSampler3D:
1220 case EbtImage3D:
1221 *dimOut = spv::Dim3D;
1222 break;
1223 case EbtISampler3D:
1224 case EbtIImage3D:
1225 sampledType = EbtInt;
1226 *dimOut = spv::Dim3D;
1227 break;
1228 case EbtUSampler3D:
1229 case EbtUImage3D:
1230 sampledType = EbtUInt;
1231 *dimOut = spv::Dim3D;
1232 break;
1233
1234 // Float cube images
1235 case EbtSamplerCube:
1236 case EbtImageCube:
1237 *dimOut = spv::DimCube;
1238 break;
1239 case EbtSamplerCubeArray:
1240 case EbtImageCubeArray:
1241 *dimOut = spv::DimCube;
1242 isArrayed = true;
1243 break;
1244 case EbtSamplerCubeArrayShadow:
1245 *dimOut = spv::DimCube;
1246 isDepth = true;
1247 isArrayed = true;
1248 break;
1249 case EbtSamplerCubeShadow:
1250 *dimOut = spv::DimCube;
1251 isDepth = true;
1252 break;
1253
1254 // Integer cube images
1255 case EbtISamplerCube:
1256 case EbtIImageCube:
1257 sampledType = EbtInt;
1258 *dimOut = spv::DimCube;
1259 break;
1260 case EbtISamplerCubeArray:
1261 case EbtIImageCubeArray:
1262 sampledType = EbtInt;
1263 *dimOut = spv::DimCube;
1264 isArrayed = true;
1265 break;
1266
1267 // Unsigned integer cube images
1268 case EbtUSamplerCube:
1269 case EbtUImageCube:
1270 sampledType = EbtUInt;
1271 *dimOut = spv::DimCube;
1272 break;
1273 case EbtUSamplerCubeArray:
1274 case EbtUImageCubeArray:
1275 sampledType = EbtUInt;
1276 *dimOut = spv::DimCube;
1277 isArrayed = true;
1278 break;
1279
1280 // Float 1D images
1281 case EbtSampler1D:
1282 case EbtImage1D:
1283 *dimOut = spv::Dim1D;
1284 break;
1285 case EbtSampler1DArray:
1286 case EbtImage1DArray:
1287 *dimOut = spv::Dim1D;
1288 isArrayed = true;
1289 break;
1290 case EbtSampler1DShadow:
1291 *dimOut = spv::Dim1D;
1292 isDepth = true;
1293 break;
1294 case EbtSampler1DArrayShadow:
1295 *dimOut = spv::Dim1D;
1296 isDepth = true;
1297 isArrayed = true;
1298 break;
1299
1300 // Integer 1D images
1301 case EbtISampler1D:
1302 case EbtIImage1D:
1303 sampledType = EbtInt;
1304 *dimOut = spv::Dim1D;
1305 break;
1306 case EbtISampler1DArray:
1307 case EbtIImage1DArray:
1308 sampledType = EbtInt;
1309 *dimOut = spv::Dim1D;
1310 isArrayed = true;
1311 break;
1312
1313 // Unsigned integer 1D images
1314 case EbtUSampler1D:
1315 case EbtUImage1D:
1316 sampledType = EbtUInt;
1317 *dimOut = spv::Dim1D;
1318 break;
1319 case EbtUSampler1DArray:
1320 case EbtUImage1DArray:
1321 sampledType = EbtUInt;
1322 *dimOut = spv::Dim1D;
1323 isArrayed = true;
1324 break;
1325
1326 // Rect images
1327 case EbtSampler2DRect:
1328 case EbtImageRect:
1329 *dimOut = spv::DimRect;
1330 break;
1331 case EbtSampler2DRectShadow:
1332 *dimOut = spv::DimRect;
1333 isDepth = true;
1334 break;
1335 case EbtISampler2DRect:
1336 case EbtIImageRect:
1337 sampledType = EbtInt;
1338 *dimOut = spv::DimRect;
1339 break;
1340 case EbtUSampler2DRect:
1341 case EbtUImageRect:
1342 sampledType = EbtUInt;
1343 *dimOut = spv::DimRect;
1344 break;
1345
1346 // Image buffers
1347 case EbtSamplerBuffer:
1348 case EbtImageBuffer:
1349 *dimOut = spv::DimBuffer;
1350 break;
1351 case EbtISamplerBuffer:
1352 case EbtIImageBuffer:
1353 sampledType = EbtInt;
1354 *dimOut = spv::DimBuffer;
1355 break;
1356 case EbtUSamplerBuffer:
1357 case EbtUImageBuffer:
1358 sampledType = EbtUInt;
1359 *dimOut = spv::DimBuffer;
1360 break;
1361 default:
1362 UNREACHABLE();
1363 }
1364
1365 // Get id of the component type of the image
1366 SpirvType sampledSpirvType;
1367 sampledSpirvType.type = sampledType;
1368
1369 *sampledTypeOut = getSpirvTypeData(sampledSpirvType, nullptr).id;
1370
1371 const bool isSampledImage = IsSampler(type);
1372
1373 // Set flags based on SPIR-V required values. See OpTypeImage:
1374 //
1375 // - For depth: 0 = non-depth, 1 = depth
1376 // - For arrayed: 0 = non-arrayed, 1 = arrayed
1377 // - For multisampled: 0 = single-sampled, 1 = multisampled
1378 // - For sampled: 1 = sampled, 2 = storage
1379 //
1380 *depthOut = spirv::LiteralInteger(isDepth ? 1 : 0);
1381 *arrayedOut = spirv::LiteralInteger(isArrayed ? 1 : 0);
1382 *multisampledOut = spirv::LiteralInteger(isMultisampled ? 1 : 0);
1383 *sampledOut = spirv::LiteralInteger(isSampledImage ? 1 : 2);
1384
1385 // Add the necessary capability based on parameters. The SPIR-V spec section 3.8 Dim specfies
1386 // the required capabilities:
1387 //
1388 // Dim Sampled Storage Storage Array
1389 // --------------------------------------------------------------
1390 // 1D Sampled1D Image1D
1391 // 2D Shader ImageMSArray
1392 // 3D
1393 // Cube Shader ImageCubeArray
1394 // Rect SampledRect ImageRect
1395 // Buffer SampledBuffer ImageBuffer
1396 //
1397 // Additionally, the SubpassData Dim requires the InputAttachment capability.
1398 //
1399 // Note that the Shader capability is always unconditionally added.
1400 //
1401 switch (*dimOut)
1402 {
1403 case spv::Dim1D:
1404 addCapability(isSampledImage ? spv::CapabilitySampled1D : spv::CapabilityImage1D);
1405 break;
1406 case spv::Dim2D:
1407 if (!isSampledImage && isArrayed && isMultisampled)
1408 {
1409 addCapability(spv::CapabilityImageMSArray);
1410 }
1411 break;
1412 case spv::Dim3D:
1413 break;
1414 case spv::DimCube:
1415 if (!isSampledImage && isArrayed)
1416 {
1417 addCapability(spv::CapabilityImageCubeArray);
1418 }
1419 break;
1420 case spv::DimRect:
1421 addCapability(isSampledImage ? spv::CapabilitySampledRect : spv::CapabilityImageRect);
1422 break;
1423 case spv::DimBuffer:
1424 addCapability(isSampledImage ? spv::CapabilitySampledBuffer
1425 : spv::CapabilityImageBuffer);
1426 break;
1427 case spv::DimSubpassData:
1428 addCapability(spv::CapabilityInputAttachment);
1429 break;
1430 default:
1431 UNREACHABLE();
1432 }
1433 }
1434
getImageFormat(TLayoutImageInternalFormat imageInternalFormat)1435 spv::ImageFormat SPIRVBuilder::getImageFormat(TLayoutImageInternalFormat imageInternalFormat)
1436 {
1437 switch (imageInternalFormat)
1438 {
1439 case EiifUnspecified:
1440 return spv::ImageFormatUnknown;
1441 case EiifRGBA32F:
1442 return spv::ImageFormatRgba32f;
1443 case EiifRGBA16F:
1444 return spv::ImageFormatRgba16f;
1445 case EiifR32F:
1446 return spv::ImageFormatR32f;
1447 case EiifRGBA32UI:
1448 return spv::ImageFormatRgba32ui;
1449 case EiifRGBA16UI:
1450 return spv::ImageFormatRgba16ui;
1451 case EiifRGBA8UI:
1452 return spv::ImageFormatRgba8ui;
1453 case EiifR32UI:
1454 return spv::ImageFormatR32ui;
1455 case EiifRGBA32I:
1456 return spv::ImageFormatRgba32i;
1457 case EiifRGBA16I:
1458 return spv::ImageFormatRgba16i;
1459 case EiifRGBA8I:
1460 return spv::ImageFormatRgba8i;
1461 case EiifR32I:
1462 return spv::ImageFormatR32i;
1463 case EiifRGBA8:
1464 return spv::ImageFormatRgba8;
1465 case EiifRGBA8_SNORM:
1466 return spv::ImageFormatRgba8Snorm;
1467 default:
1468 UNREACHABLE();
1469 return spv::ImageFormatUnknown;
1470 }
1471 }
1472
getBoolConstant(bool value)1473 spirv::IdRef SPIRVBuilder::getBoolConstant(bool value)
1474 {
1475 uint32_t asInt = static_cast<uint32_t>(value);
1476
1477 spirv::IdRef constantId = mBoolConstants[asInt];
1478
1479 if (!constantId.valid())
1480 {
1481 SpirvType boolType;
1482 boolType.type = EbtBool;
1483
1484 const spirv::IdRef boolTypeId = getSpirvTypeData(boolType, nullptr).id;
1485
1486 mBoolConstants[asInt] = constantId = getNewId({});
1487 if (value)
1488 {
1489 spirv::WriteConstantTrue(&mSpirvTypeAndConstantDecls, boolTypeId, constantId);
1490 }
1491 else
1492 {
1493 spirv::WriteConstantFalse(&mSpirvTypeAndConstantDecls, boolTypeId, constantId);
1494 }
1495 }
1496
1497 return constantId;
1498 }
1499
getBasicConstantHelper(uint32_t value,TBasicType type,angle::HashMap<uint32_t,spirv::IdRef> * constants)1500 spirv::IdRef SPIRVBuilder::getBasicConstantHelper(uint32_t value,
1501 TBasicType type,
1502 angle::HashMap<uint32_t, spirv::IdRef> *constants)
1503 {
1504 auto iter = constants->find(value);
1505 if (iter != constants->end())
1506 {
1507 return iter->second;
1508 }
1509
1510 SpirvType spirvType;
1511 spirvType.type = type;
1512
1513 const spirv::IdRef typeId = getSpirvTypeData(spirvType, nullptr).id;
1514 const spirv::IdRef constantId = getNewId({});
1515
1516 spirv::WriteConstant(&mSpirvTypeAndConstantDecls, typeId, constantId,
1517 spirv::LiteralContextDependentNumber(value));
1518
1519 return constants->insert({value, constantId}).first->second;
1520 }
1521
getUintConstant(uint32_t value)1522 spirv::IdRef SPIRVBuilder::getUintConstant(uint32_t value)
1523 {
1524 return getBasicConstantHelper(value, EbtUInt, &mUintConstants);
1525 }
1526
getIntConstant(int32_t value)1527 spirv::IdRef SPIRVBuilder::getIntConstant(int32_t value)
1528 {
1529 uint32_t asUint = static_cast<uint32_t>(value);
1530 return getBasicConstantHelper(asUint, EbtInt, &mIntConstants);
1531 }
1532
getFloatConstant(float value)1533 spirv::IdRef SPIRVBuilder::getFloatConstant(float value)
1534 {
1535 union
1536 {
1537 float f;
1538 uint32_t u;
1539 } asUint;
1540 asUint.f = value;
1541 return getBasicConstantHelper(asUint.u, EbtFloat, &mFloatConstants);
1542 }
1543
getNullConstant(spirv::IdRef typeId)1544 spirv::IdRef SPIRVBuilder::getNullConstant(spirv::IdRef typeId)
1545 {
1546 if (typeId >= mNullConstants.size())
1547 {
1548 mNullConstants.resize(typeId + 1);
1549 }
1550
1551 if (!mNullConstants[typeId].valid())
1552 {
1553 const spirv::IdRef constantId = getNewId({});
1554 mNullConstants[typeId] = constantId;
1555
1556 spirv::WriteConstantNull(&mSpirvTypeAndConstantDecls, typeId, constantId);
1557 }
1558
1559 return mNullConstants[typeId];
1560 }
1561
getNullVectorConstantHelper(TBasicType type,int size)1562 spirv::IdRef SPIRVBuilder::getNullVectorConstantHelper(TBasicType type, int size)
1563 {
1564 SpirvType vecType;
1565 vecType.type = type;
1566 vecType.primarySize = static_cast<uint8_t>(size);
1567
1568 return getNullConstant(getSpirvTypeData(vecType, nullptr).id);
1569 }
1570
getVectorConstantHelper(spirv::IdRef valueId,TBasicType type,int size)1571 spirv::IdRef SPIRVBuilder::getVectorConstantHelper(spirv::IdRef valueId, TBasicType type, int size)
1572 {
1573 if (size == 1)
1574 {
1575 return valueId;
1576 }
1577
1578 SpirvType vecType;
1579 vecType.type = type;
1580 vecType.primarySize = static_cast<uint8_t>(size);
1581
1582 const spirv::IdRef typeId = getSpirvTypeData(vecType, nullptr).id;
1583 const spirv::IdRefList valueIds(size, valueId);
1584
1585 return getCompositeConstant(typeId, valueIds);
1586 }
1587
getUvecConstant(uint32_t value,int size)1588 spirv::IdRef SPIRVBuilder::getUvecConstant(uint32_t value, int size)
1589 {
1590 if (value == 0)
1591 {
1592 return getNullVectorConstantHelper(EbtUInt, size);
1593 }
1594
1595 const spirv::IdRef valueId = getUintConstant(value);
1596 return getVectorConstantHelper(valueId, EbtUInt, size);
1597 }
1598
getIvecConstant(int32_t value,int size)1599 spirv::IdRef SPIRVBuilder::getIvecConstant(int32_t value, int size)
1600 {
1601 if (value == 0)
1602 {
1603 return getNullVectorConstantHelper(EbtInt, size);
1604 }
1605
1606 const spirv::IdRef valueId = getIntConstant(value);
1607 return getVectorConstantHelper(valueId, EbtInt, size);
1608 }
1609
getVecConstant(float value,int size)1610 spirv::IdRef SPIRVBuilder::getVecConstant(float value, int size)
1611 {
1612 if (value == 0)
1613 {
1614 return getNullVectorConstantHelper(EbtFloat, size);
1615 }
1616
1617 const spirv::IdRef valueId = getFloatConstant(value);
1618 return getVectorConstantHelper(valueId, EbtFloat, size);
1619 }
1620
getCompositeConstant(spirv::IdRef typeId,const spirv::IdRefList & values)1621 spirv::IdRef SPIRVBuilder::getCompositeConstant(spirv::IdRef typeId, const spirv::IdRefList &values)
1622 {
1623 SpirvIdAndIdList key{typeId, values};
1624
1625 auto iter = mCompositeConstants.find(key);
1626 if (iter == mCompositeConstants.end())
1627 {
1628 const spirv::IdRef constantId = getNewId({});
1629
1630 spirv::WriteConstantComposite(&mSpirvTypeAndConstantDecls, typeId, constantId, values);
1631
1632 iter = mCompositeConstants.insert({key, constantId}).first;
1633 }
1634
1635 return iter->second;
1636 }
1637
startNewFunction(spirv::IdRef functionId,const TFunction * func)1638 void SPIRVBuilder::startNewFunction(spirv::IdRef functionId, const TFunction *func)
1639 {
1640 ASSERT(mSpirvCurrentFunctionBlocks.empty());
1641
1642 // Add the first block of the function.
1643 mSpirvCurrentFunctionBlocks.emplace_back();
1644 mSpirvCurrentFunctionBlocks.back().labelId = getNewId({});
1645
1646 // Output debug information.
1647 writeDebugName(functionId, getName(func).data());
1648 }
1649
assembleSpirvFunctionBlocks()1650 void SPIRVBuilder::assembleSpirvFunctionBlocks()
1651 {
1652 // Take all the blocks and place them in the functions section of SPIR-V in sequence.
1653 for (const SpirvBlock &block : mSpirvCurrentFunctionBlocks)
1654 {
1655 // Every block must be properly terminated.
1656 ASSERT(block.isTerminated);
1657
1658 // Generate the OpLabel instruction for the block.
1659 spirv::WriteLabel(&mSpirvFunctions, block.labelId);
1660
1661 // Add the variable declarations if any.
1662 mSpirvFunctions.insert(mSpirvFunctions.end(), block.localVariables.begin(),
1663 block.localVariables.end());
1664
1665 // Add the body of the block.
1666 mSpirvFunctions.insert(mSpirvFunctions.end(), block.body.begin(), block.body.end());
1667 }
1668
1669 // Clean up.
1670 mSpirvCurrentFunctionBlocks.clear();
1671 }
1672
declareVariable(spirv::IdRef typeId,spv::StorageClass storageClass,const SpirvDecorations & decorations,spirv::IdRef * initializerId,const char * name,const TSymbolUniqueId * uniqueId)1673 spirv::IdRef SPIRVBuilder::declareVariable(spirv::IdRef typeId,
1674 spv::StorageClass storageClass,
1675 const SpirvDecorations &decorations,
1676 spirv::IdRef *initializerId,
1677 const char *name,
1678 const TSymbolUniqueId *uniqueId)
1679 {
1680 const bool isFunctionLocal = storageClass == spv::StorageClassFunction;
1681
1682 // Make sure storage class is consistent with where the variable is declared.
1683 ASSERT(!isFunctionLocal || !mSpirvCurrentFunctionBlocks.empty());
1684
1685 // Function-local variables go in the first block of the function, while the rest are in the
1686 // global variables section.
1687 spirv::Blob *spirvSection = isFunctionLocal
1688 ? &mSpirvCurrentFunctionBlocks.front().localVariables
1689 : &mSpirvVariableDecls;
1690
1691 const spirv::IdRef typePointerId = getTypePointerId(typeId, storageClass);
1692 spirv::IdRef variableId;
1693 if (uniqueId)
1694 {
1695 variableId = getReservedOrNewId(*uniqueId, decorations);
1696
1697 if (variableId == vk::spirv::kIdOutputPerVertexVar)
1698 {
1699 mOverviewFlags |= vk::spirv::kOverviewHasOutputPerVertexMask;
1700 }
1701 else if (variableId == vk::spirv::kIdSampleID)
1702 {
1703 mOverviewFlags |= vk::spirv::kOverviewHasSampleIDMask;
1704 }
1705 }
1706 else
1707 {
1708 variableId = getNewId(decorations);
1709 }
1710
1711 spirv::WriteVariable(spirvSection, typePointerId, variableId, storageClass, initializerId);
1712
1713 // Output debug information.
1714 if (name)
1715 {
1716 writeDebugName(variableId, name);
1717 }
1718
1719 return variableId;
1720 }
1721
declareSpecConst(TBasicType type,int id,const char * name)1722 spirv::IdRef SPIRVBuilder::declareSpecConst(TBasicType type, int id, const char *name)
1723 {
1724 SpirvType spirvType;
1725 spirvType.type = type;
1726
1727 const spirv::IdRef typeId = getSpirvTypeData(spirvType, nullptr).id;
1728 const spirv::IdRef specConstId = getNewId({});
1729
1730 // Note: all spec constants are 0 initialized by the translator.
1731 if (type == EbtBool)
1732 {
1733 spirv::WriteSpecConstantFalse(&mSpirvTypeAndConstantDecls, typeId, specConstId);
1734 }
1735 else
1736 {
1737 spirv::WriteSpecConstant(&mSpirvTypeAndConstantDecls, typeId, specConstId,
1738 spirv::LiteralContextDependentNumber(0));
1739 }
1740
1741 // Add the SpecId decoration
1742 spirv::WriteDecorate(&mSpirvDecorations, specConstId, spv::DecorationSpecId,
1743 {spirv::LiteralInteger(id)});
1744
1745 // Output debug information.
1746 if (name)
1747 {
1748 writeDebugName(specConstId, name);
1749 }
1750
1751 return specConstId;
1752 }
1753
startConditional(size_t blockCount,bool isContinuable,bool isBreakable)1754 void SPIRVBuilder::startConditional(size_t blockCount, bool isContinuable, bool isBreakable)
1755 {
1756 mConditionalStack.emplace_back();
1757 SpirvConditional &conditional = mConditionalStack.back();
1758
1759 // Create the requested number of block ids.
1760 conditional.blockIds.resize(blockCount);
1761 for (spirv::IdRef &blockId : conditional.blockIds)
1762 {
1763 blockId = getNewId({});
1764 }
1765
1766 conditional.isContinuable = isContinuable;
1767 conditional.isBreakable = isBreakable;
1768
1769 // Don't automatically start the next block. The caller needs to generate instructions based on
1770 // the ids that were just generated above.
1771 }
1772
nextConditionalBlock()1773 void SPIRVBuilder::nextConditionalBlock()
1774 {
1775 ASSERT(!mConditionalStack.empty());
1776 SpirvConditional &conditional = mConditionalStack.back();
1777
1778 ASSERT(conditional.nextBlockToWrite < conditional.blockIds.size());
1779 const spirv::IdRef blockId = conditional.blockIds[conditional.nextBlockToWrite++];
1780
1781 // The previous block must have properly terminated.
1782 ASSERT(isCurrentFunctionBlockTerminated());
1783
1784 // Generate a new block.
1785 mSpirvCurrentFunctionBlocks.emplace_back();
1786 mSpirvCurrentFunctionBlocks.back().labelId = blockId;
1787 }
1788
endConditional()1789 void SPIRVBuilder::endConditional()
1790 {
1791 ASSERT(!mConditionalStack.empty());
1792
1793 // No blocks should be left.
1794 ASSERT(mConditionalStack.back().nextBlockToWrite == mConditionalStack.back().blockIds.size());
1795
1796 mConditionalStack.pop_back();
1797 }
1798
isInLoop() const1799 bool SPIRVBuilder::isInLoop() const
1800 {
1801 for (const SpirvConditional &conditional : mConditionalStack)
1802 {
1803 if (conditional.isContinuable)
1804 {
1805 return true;
1806 }
1807 }
1808
1809 return false;
1810 }
1811
getBreakTargetId() const1812 spirv::IdRef SPIRVBuilder::getBreakTargetId() const
1813 {
1814 for (size_t index = mConditionalStack.size(); index > 0; --index)
1815 {
1816 const SpirvConditional &conditional = mConditionalStack[index - 1];
1817
1818 if (conditional.isBreakable)
1819 {
1820 // The target of break; is always the merge block, and the merge block is always the
1821 // last block.
1822 return conditional.blockIds.back();
1823 }
1824 }
1825
1826 UNREACHABLE();
1827 return spirv::IdRef{};
1828 }
1829
getContinueTargetId() const1830 spirv::IdRef SPIRVBuilder::getContinueTargetId() const
1831 {
1832 for (size_t index = mConditionalStack.size(); index > 0; --index)
1833 {
1834 const SpirvConditional &conditional = mConditionalStack[index - 1];
1835
1836 if (conditional.isContinuable)
1837 {
1838 // The target of continue; is always the block before merge, so it's the one before
1839 // last.
1840 ASSERT(conditional.blockIds.size() > 2);
1841 return conditional.blockIds[conditional.blockIds.size() - 2];
1842 }
1843 }
1844
1845 UNREACHABLE();
1846 return spirv::IdRef{};
1847 }
1848
nextUnusedBinding()1849 uint32_t SPIRVBuilder::nextUnusedBinding()
1850 {
1851 return mNextUnusedBinding++;
1852 }
1853
nextUnusedInputLocation(uint32_t consumedCount)1854 uint32_t SPIRVBuilder::nextUnusedInputLocation(uint32_t consumedCount)
1855 {
1856 uint32_t nextUnused = mNextUnusedInputLocation;
1857 mNextUnusedInputLocation += consumedCount;
1858 return nextUnused;
1859 }
1860
nextUnusedOutputLocation(uint32_t consumedCount)1861 uint32_t SPIRVBuilder::nextUnusedOutputLocation(uint32_t consumedCount)
1862 {
1863 uint32_t nextUnused = mNextUnusedOutputLocation;
1864 mNextUnusedOutputLocation += consumedCount;
1865 return nextUnused;
1866 }
1867
isInvariantOutput(const TType & type) const1868 bool SPIRVBuilder::isInvariantOutput(const TType &type) const
1869 {
1870 return IsInvariant(type, mCompiler);
1871 }
1872
addCapability(spv::Capability capability)1873 void SPIRVBuilder::addCapability(spv::Capability capability)
1874 {
1875 mCapabilities.insert(capability);
1876
1877 if (capability == spv::CapabilitySampleRateShading)
1878 {
1879 mOverviewFlags |= vk::spirv::kOverviewHasSampleRateShadingMask;
1880 }
1881 }
1882
addExecutionMode(spv::ExecutionMode executionMode)1883 void SPIRVBuilder::addExecutionMode(spv::ExecutionMode executionMode)
1884 {
1885 mExecutionModes.insert(executionMode);
1886 }
1887
addExtension(SPIRVExtensions extension)1888 void SPIRVBuilder::addExtension(SPIRVExtensions extension)
1889 {
1890 mExtensions.set(extension);
1891 }
1892
addEntryPointInterfaceVariableId(spirv::IdRef id)1893 void SPIRVBuilder::addEntryPointInterfaceVariableId(spirv::IdRef id)
1894 {
1895 mEntryPointInterfaceList.push_back(id);
1896 }
1897
writePerVertexBuiltIns(const TType & type,spirv::IdRef typeId)1898 void SPIRVBuilder::writePerVertexBuiltIns(const TType &type, spirv::IdRef typeId)
1899 {
1900 ASSERT(type.isInterfaceBlock());
1901 const TInterfaceBlock *block = type.getInterfaceBlock();
1902
1903 uint32_t fieldIndex = 0;
1904 for (const TField *field : block->fields())
1905 {
1906 spv::BuiltIn decorationValue = spv::BuiltInPosition;
1907 switch (field->type()->getQualifier())
1908 {
1909 case EvqPosition:
1910 decorationValue = spv::BuiltInPosition;
1911 break;
1912 case EvqPointSize:
1913 decorationValue = spv::BuiltInPointSize;
1914 break;
1915 case EvqClipDistance:
1916 decorationValue = spv::BuiltInClipDistance;
1917 break;
1918 case EvqCullDistance:
1919 decorationValue = spv::BuiltInCullDistance;
1920 break;
1921 default:
1922 UNREACHABLE();
1923 }
1924
1925 spirv::WriteMemberDecorate(&mSpirvDecorations, typeId, spirv::LiteralInteger(fieldIndex++),
1926 spv::DecorationBuiltIn,
1927 {spirv::LiteralInteger(decorationValue)});
1928 }
1929 }
1930
writeInterfaceVariableDecorations(const TType & type,spirv::IdRef variableId)1931 void SPIRVBuilder::writeInterfaceVariableDecorations(const TType &type, spirv::IdRef variableId)
1932 {
1933 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
1934 const bool isVarying = IsVarying(type.getQualifier());
1935 const bool needsSetBinding =
1936 !layoutQualifier.pushConstant &&
1937 (IsSampler(type.getBasicType()) ||
1938 (type.isInterfaceBlock() &&
1939 (type.getQualifier() == EvqUniform || type.getQualifier() == EvqBuffer)) ||
1940 IsImage(type.getBasicType()) || IsSubpassInputType(type.getBasicType()));
1941 const bool needsLocation = type.getQualifier() == EvqAttribute ||
1942 type.getQualifier() == EvqVertexIn ||
1943 type.getQualifier() == EvqFragmentOut || isVarying;
1944 const bool needsInputAttachmentIndex = IsSubpassInputType(type.getBasicType());
1945 const bool needsBlendIndex =
1946 type.getQualifier() == EvqFragmentOut && layoutQualifier.index >= 0;
1947 const bool needsYuvDecorate = mCompileOptions.addVulkanYUVLayoutQualifier &&
1948 type.getQualifier() == EvqFragmentOut && layoutQualifier.yuv;
1949
1950 // If the resource declaration requires set & binding, add the DescriptorSet and Binding
1951 // decorations.
1952 if (needsSetBinding)
1953 {
1954 spirv::WriteDecorate(&mSpirvDecorations, variableId, spv::DecorationDescriptorSet,
1955 {spirv::LiteralInteger(0)});
1956 spirv::WriteDecorate(&mSpirvDecorations, variableId, spv::DecorationBinding,
1957 {spirv::LiteralInteger(nextUnusedBinding())});
1958 }
1959
1960 if (needsLocation)
1961 {
1962 const unsigned int locationCount =
1963 CalculateVaryingLocationCount(type, gl::ToGLenum(mShaderType));
1964 const uint32_t location = IsShaderIn(type.getQualifier())
1965 ? nextUnusedInputLocation(locationCount)
1966 : nextUnusedOutputLocation(locationCount);
1967
1968 spirv::WriteDecorate(&mSpirvDecorations, variableId, spv::DecorationLocation,
1969 {spirv::LiteralInteger(location)});
1970 }
1971
1972 // If the resource declaration is an input attachment, add the InputAttachmentIndex decoration.
1973 if (needsInputAttachmentIndex)
1974 {
1975 spirv::WriteDecorate(&mSpirvDecorations, variableId, spv::DecorationInputAttachmentIndex,
1976 {spirv::LiteralInteger(layoutQualifier.inputAttachmentIndex)});
1977 }
1978
1979 if (needsBlendIndex)
1980 {
1981 spirv::WriteDecorate(&mSpirvDecorations, variableId, spv::DecorationIndex,
1982 {spirv::LiteralInteger(layoutQualifier.index)});
1983 }
1984
1985 if (needsYuvDecorate)
1986 {
1987 // WIP in spec
1988 const spv::Decoration yuvDecorate = static_cast<spv::Decoration>(6088);
1989 spirv::WriteDecorate(&mSpirvDecorations, variableId, yuvDecorate,
1990 {spirv::LiteralInteger(layoutQualifier.index)});
1991 }
1992
1993 // Handle interpolation and auxiliary decorations on varyings
1994 if (isVarying)
1995 {
1996 writeInterpolationDecoration(type.getQualifier(), variableId,
1997 std::numeric_limits<uint32_t>::max());
1998 }
1999 }
2000
writeBranchConditional(spirv::IdRef conditionValue,spirv::IdRef trueBlock,spirv::IdRef falseBlock,spirv::IdRef mergeBlock)2001 void SPIRVBuilder::writeBranchConditional(spirv::IdRef conditionValue,
2002 spirv::IdRef trueBlock,
2003 spirv::IdRef falseBlock,
2004 spirv::IdRef mergeBlock)
2005 {
2006 // Generate the following:
2007 //
2008 // OpSelectionMerge %mergeBlock None
2009 // OpBranchConditional %conditionValue %trueBlock %falseBlock
2010 //
2011 spirv::WriteSelectionMerge(getSpirvCurrentFunctionBlock(), mergeBlock,
2012 spv::SelectionControlMaskNone);
2013 spirv::WriteBranchConditional(getSpirvCurrentFunctionBlock(), conditionValue, trueBlock,
2014 falseBlock, {});
2015 terminateCurrentFunctionBlock();
2016
2017 // Start the true or false block, whichever exists.
2018 nextConditionalBlock();
2019 }
2020
writeBranchConditionalBlockEnd()2021 void SPIRVBuilder::writeBranchConditionalBlockEnd()
2022 {
2023 if (!isCurrentFunctionBlockTerminated())
2024 {
2025 // Insert a branch to the merge block at the end of each if-else block, unless the block is
2026 // already terminated, such as with a return or discard.
2027 const spirv::IdRef mergeBlock = getCurrentConditional()->blockIds.back();
2028
2029 spirv::WriteBranch(getSpirvCurrentFunctionBlock(), mergeBlock);
2030 terminateCurrentFunctionBlock();
2031 }
2032
2033 // Move on to the next block.
2034 nextConditionalBlock();
2035 }
2036
writeLoopHeader(spirv::IdRef branchToBlock,spirv::IdRef continueBlock,spirv::IdRef mergeBlock)2037 void SPIRVBuilder::writeLoopHeader(spirv::IdRef branchToBlock,
2038 spirv::IdRef continueBlock,
2039 spirv::IdRef mergeBlock)
2040 {
2041 // First, jump to the header block:
2042 //
2043 // OpBranch %header
2044 //
2045 const spirv::IdRef headerBlock = mConditionalStack.back().blockIds[0];
2046 spirv::WriteBranch(getSpirvCurrentFunctionBlock(), headerBlock);
2047 terminateCurrentFunctionBlock();
2048
2049 // Start the header block.
2050 nextConditionalBlock();
2051
2052 // Generate the following:
2053 //
2054 // OpLoopMerge %mergeBlock %continueBlock None
2055 // OpBranch %branchToBlock (%cond or if do-while, %body)
2056 //
2057 spirv::WriteLoopMerge(getSpirvCurrentFunctionBlock(), mergeBlock, continueBlock,
2058 spv::LoopControlMaskNone);
2059 spirv::WriteBranch(getSpirvCurrentFunctionBlock(), branchToBlock);
2060 terminateCurrentFunctionBlock();
2061
2062 // Start the next block, which is either %cond or %body.
2063 nextConditionalBlock();
2064 }
2065
writeLoopConditionEnd(spirv::IdRef conditionValue,spirv::IdRef branchToBlock,spirv::IdRef mergeBlock)2066 void SPIRVBuilder::writeLoopConditionEnd(spirv::IdRef conditionValue,
2067 spirv::IdRef branchToBlock,
2068 spirv::IdRef mergeBlock)
2069 {
2070 // Generate the following:
2071 //
2072 // OpBranchConditional %conditionValue %branchToBlock %mergeBlock
2073 //
2074 // %branchToBlock is either %body or if do-while, %header
2075 //
2076 spirv::WriteBranchConditional(getSpirvCurrentFunctionBlock(), conditionValue, branchToBlock,
2077 mergeBlock, {});
2078 terminateCurrentFunctionBlock();
2079
2080 // Start the next block, which is either %continue or %body.
2081 nextConditionalBlock();
2082 }
2083
writeLoopContinueEnd(spirv::IdRef headerBlock)2084 void SPIRVBuilder::writeLoopContinueEnd(spirv::IdRef headerBlock)
2085 {
2086 // Generate the following:
2087 //
2088 // OpBranch %headerBlock
2089 //
2090 spirv::WriteBranch(getSpirvCurrentFunctionBlock(), headerBlock);
2091 terminateCurrentFunctionBlock();
2092
2093 // Start the next block, which is %body.
2094 nextConditionalBlock();
2095 }
2096
writeLoopBodyEnd(spirv::IdRef continueBlock)2097 void SPIRVBuilder::writeLoopBodyEnd(spirv::IdRef continueBlock)
2098 {
2099 // Generate the following:
2100 //
2101 // OpBranch %continueBlock
2102 //
2103 // This is only done if the block isn't already terminated in another way, such as with an
2104 // unconditional continue/etc at the end of the loop.
2105 if (!isCurrentFunctionBlockTerminated())
2106 {
2107 spirv::WriteBranch(getSpirvCurrentFunctionBlock(), continueBlock);
2108 terminateCurrentFunctionBlock();
2109 }
2110
2111 // Start the next block, which is %merge or if while, %continue.
2112 nextConditionalBlock();
2113 }
2114
writeSwitch(spirv::IdRef conditionValue,spirv::IdRef defaultBlock,const spirv::PairLiteralIntegerIdRefList & targetPairList,spirv::IdRef mergeBlock)2115 void SPIRVBuilder::writeSwitch(spirv::IdRef conditionValue,
2116 spirv::IdRef defaultBlock,
2117 const spirv::PairLiteralIntegerIdRefList &targetPairList,
2118 spirv::IdRef mergeBlock)
2119 {
2120 // Generate the following:
2121 //
2122 // OpSelectionMerge %mergeBlock None
2123 // OpSwitch %conditionValue %defaultBlock A %ABlock B %BBlock ...
2124 //
2125 spirv::WriteSelectionMerge(getSpirvCurrentFunctionBlock(), mergeBlock,
2126 spv::SelectionControlMaskNone);
2127 spirv::WriteSwitch(getSpirvCurrentFunctionBlock(), conditionValue, defaultBlock,
2128 targetPairList);
2129 terminateCurrentFunctionBlock();
2130
2131 // Start the next case block.
2132 nextConditionalBlock();
2133 }
2134
writeSwitchCaseBlockEnd()2135 void SPIRVBuilder::writeSwitchCaseBlockEnd()
2136 {
2137 if (!isCurrentFunctionBlockTerminated())
2138 {
2139 // If a case does not end in branch, insert a branch to the next block, implementing
2140 // fallthrough. For the last block, the branch target would automatically be the merge
2141 // block.
2142 const SpirvConditional *conditional = getCurrentConditional();
2143 const spirv::IdRef nextBlock = conditional->blockIds[conditional->nextBlockToWrite];
2144
2145 spirv::WriteBranch(getSpirvCurrentFunctionBlock(), nextBlock);
2146 terminateCurrentFunctionBlock();
2147 }
2148
2149 // Move on to the next block.
2150 nextConditionalBlock();
2151 }
2152
writeMemberDecorations(const SpirvType & type,spirv::IdRef typeId)2153 void SPIRVBuilder::writeMemberDecorations(const SpirvType &type, spirv::IdRef typeId)
2154 {
2155 ASSERT(type.block != nullptr);
2156
2157 uint32_t fieldIndex = 0;
2158
2159 for (const TField *field : type.block->fields())
2160 {
2161 const TType &fieldType = *field->type();
2162
2163 // Add invariant decoration if any.
2164 if (type.typeSpec.isInvariantBlock || fieldType.isInvariant())
2165 {
2166 spirv::WriteMemberDecorate(&mSpirvDecorations, typeId,
2167 spirv::LiteralInteger(fieldIndex), spv::DecorationInvariant,
2168 {});
2169 }
2170
2171 // Add memory qualifier decorations to buffer members
2172 if (fieldType.getMemoryQualifier().coherent)
2173 {
2174 spirv::WriteMemberDecorate(&mSpirvDecorations, typeId,
2175 spirv::LiteralInteger(fieldIndex), spv::DecorationCoherent,
2176 {});
2177 }
2178 if (fieldType.getMemoryQualifier().readonly)
2179 {
2180 spirv::WriteMemberDecorate(&mSpirvDecorations, typeId,
2181 spirv::LiteralInteger(fieldIndex),
2182 spv::DecorationNonWritable, {});
2183 }
2184 if (fieldType.getMemoryQualifier().writeonly)
2185 {
2186 spirv::WriteMemberDecorate(&mSpirvDecorations, typeId,
2187 spirv::LiteralInteger(fieldIndex),
2188 spv::DecorationNonReadable, {});
2189 }
2190 if (fieldType.getMemoryQualifier().restrictQualifier)
2191 {
2192 spirv::WriteMemberDecorate(&mSpirvDecorations, typeId,
2193 spirv::LiteralInteger(fieldIndex), spv::DecorationRestrict,
2194 {});
2195 }
2196 if (fieldType.getMemoryQualifier().volatileQualifier)
2197 {
2198 spirv::WriteMemberDecorate(&mSpirvDecorations, typeId,
2199 spirv::LiteralInteger(fieldIndex), spv::DecorationVolatile,
2200 {});
2201 }
2202
2203 // Add matrix decorations if any.
2204 if (fieldType.isMatrix())
2205 {
2206 // ColMajor or RowMajor
2207 const bool isRowMajor =
2208 IsBlockFieldRowMajorQualified(fieldType, type.typeSpec.isRowMajorQualifiedBlock);
2209 spirv::WriteMemberDecorate(
2210 &mSpirvDecorations, typeId, spirv::LiteralInteger(fieldIndex),
2211 isRowMajor ? spv::DecorationRowMajor : spv::DecorationColMajor, {});
2212 }
2213
2214 // Add interpolation and auxiliary decorations
2215 writeInterpolationDecoration(fieldType.getQualifier(), typeId, fieldIndex);
2216
2217 // Add patch decoration if any.
2218 if (type.typeSpec.isPatchIOBlock)
2219 {
2220 spirv::WriteMemberDecorate(&mSpirvDecorations, typeId,
2221 spirv::LiteralInteger(fieldIndex), spv::DecorationPatch, {});
2222 }
2223
2224 // Add other decorations.
2225 SpirvDecorations decorations = getDecorations(fieldType);
2226 for (const spv::Decoration decoration : decorations)
2227 {
2228 spirv::WriteMemberDecorate(&mSpirvDecorations, typeId,
2229 spirv::LiteralInteger(fieldIndex), decoration, {});
2230 }
2231
2232 ++fieldIndex;
2233 }
2234 }
2235
writeInterpolationDecoration(TQualifier qualifier,spirv::IdRef id,uint32_t fieldIndex)2236 void SPIRVBuilder::writeInterpolationDecoration(TQualifier qualifier,
2237 spirv::IdRef id,
2238 uint32_t fieldIndex)
2239 {
2240 switch (qualifier)
2241 {
2242 case EvqSmooth:
2243 case EvqSmoothOut:
2244 case EvqSmoothIn:
2245 // No decoration in SPIR-V for smooth, this is the default interpolation.
2246 return;
2247
2248 case EvqFlat:
2249 case EvqFlatOut:
2250 case EvqFlatIn:
2251 WriteInterpolationDecoration(spv::DecorationFlat, id, fieldIndex, &mSpirvDecorations);
2252 return;
2253
2254 case EvqNoPerspective:
2255 case EvqNoPerspectiveOut:
2256 case EvqNoPerspectiveIn:
2257 WriteInterpolationDecoration(spv::DecorationNoPerspective, id, fieldIndex,
2258 &mSpirvDecorations);
2259 return;
2260
2261 case EvqCentroid:
2262 case EvqCentroidOut:
2263 case EvqCentroidIn:
2264 WriteInterpolationDecoration(spv::DecorationCentroid, id, fieldIndex,
2265 &mSpirvDecorations);
2266 return;
2267
2268 case EvqSample:
2269 case EvqSampleOut:
2270 case EvqSampleIn:
2271 WriteInterpolationDecoration(spv::DecorationSample, id, fieldIndex, &mSpirvDecorations);
2272 addCapability(spv::CapabilitySampleRateShading);
2273 return;
2274
2275 case EvqNoPerspectiveCentroid:
2276 case EvqNoPerspectiveCentroidOut:
2277 case EvqNoPerspectiveCentroidIn:
2278 WriteInterpolationDecoration(spv::DecorationNoPerspective, id, fieldIndex,
2279 &mSpirvDecorations);
2280 WriteInterpolationDecoration(spv::DecorationCentroid, id, fieldIndex,
2281 &mSpirvDecorations);
2282 return;
2283
2284 case EvqNoPerspectiveSample:
2285 case EvqNoPerspectiveSampleOut:
2286 case EvqNoPerspectiveSampleIn:
2287 WriteInterpolationDecoration(spv::DecorationNoPerspective, id, fieldIndex,
2288 &mSpirvDecorations);
2289 WriteInterpolationDecoration(spv::DecorationSample, id, fieldIndex, &mSpirvDecorations);
2290 addCapability(spv::CapabilitySampleRateShading);
2291 return;
2292
2293 default:
2294 return;
2295 }
2296 }
2297
getName(const TSymbol * symbol)2298 ImmutableString SPIRVBuilder::getName(const TSymbol *symbol)
2299 {
2300 return symbol->symbolType() == SymbolType::Empty ? ImmutableString("") : symbol->name();
2301 }
2302
getFieldName(const TField * field)2303 ImmutableString SPIRVBuilder::getFieldName(const TField *field)
2304 {
2305 ASSERT(field->symbolType() != SymbolType::Empty);
2306 return field->name();
2307 }
2308
getSpirv()2309 spirv::Blob SPIRVBuilder::getSpirv()
2310 {
2311 ASSERT(mConditionalStack.empty());
2312
2313 spirv::Blob result;
2314
2315 const spirv::IdRef nonSemanticOverviewId = getNewId({});
2316
2317 // Reserve a minimum amount of memory.
2318 //
2319 // 5 for header +
2320 // a number of capabilities +
2321 // size of already generated instructions.
2322 //
2323 // The actual size is larger due to other metadata instructions such as extensions,
2324 // OpExtInstImport, OpEntryPoint, OpExecutionMode etc.
2325 result.reserve(5 + mCapabilities.size() * 2 + mSpirvDebug.size() + mSpirvDecorations.size() +
2326 mSpirvTypeAndConstantDecls.size() + mSpirvTypePointerDecls.size() +
2327 mSpirvFunctionTypeDecls.size() + mSpirvVariableDecls.size() +
2328 mSpirvFunctions.size());
2329
2330 // Generate the SPIR-V header.
2331 spirv::WriteSpirvHeader(&result, mNextAvailableId);
2332
2333 // Generate metadata in the following order:
2334 //
2335 // - OpCapability instructions.
2336 for (spv::Capability capability : mCapabilities)
2337 {
2338 spirv::WriteCapability(&result, capability);
2339 }
2340
2341 // - OpExtension instructions
2342 writeExtensions(&result);
2343
2344 // Enable the SPV_KHR_non_semantic_info extension to more efficiently communicate information to
2345 // the SPIR-V transformer in the Vulkan backend. The relevant instructions are all stripped
2346 // away during SPIR-V transformation so the driver never needs to support it.
2347 spirv::WriteExtension(&result, "SPV_KHR_non_semantic_info");
2348
2349 // - OpExtInstImport
2350 spirv::WriteExtInstImport(&result, getExtInstImportIdStd(), "GLSL.std.450");
2351 spirv::WriteExtInstImport(&result, spirv::IdRef(vk::spirv::kIdNonSemanticInstructionSet),
2352 "NonSemantic.ANGLE");
2353
2354 // - OpMemoryModel
2355 spirv::WriteMemoryModel(&result, spv::AddressingModelLogical, spv::MemoryModelGLSL450);
2356
2357 // - OpEntryPoint
2358 constexpr gl::ShaderMap<spv::ExecutionModel> kExecutionModels = {
2359 {gl::ShaderType::Vertex, spv::ExecutionModelVertex},
2360 {gl::ShaderType::TessControl, spv::ExecutionModelTessellationControl},
2361 {gl::ShaderType::TessEvaluation, spv::ExecutionModelTessellationEvaluation},
2362 {gl::ShaderType::Geometry, spv::ExecutionModelGeometry},
2363 {gl::ShaderType::Fragment, spv::ExecutionModelFragment},
2364 {gl::ShaderType::Compute, spv::ExecutionModelGLCompute},
2365 };
2366 spirv::WriteEntryPoint(&result, kExecutionModels[mShaderType],
2367 spirv::IdRef(vk::spirv::kIdEntryPoint), "main",
2368 mEntryPointInterfaceList);
2369
2370 // - OpExecutionMode instructions
2371 writeExecutionModes(&result);
2372
2373 // - OpSource and OpSourceExtension instructions.
2374 //
2375 // This is to support debuggers and capture/replay tools and isn't strictly necessary.
2376 spirv::WriteSource(&result, spv::SourceLanguageGLSL, spirv::LiteralInteger(450), nullptr,
2377 nullptr);
2378 writeSourceExtensions(&result);
2379
2380 // Append the already generated sections in order
2381 result.insert(result.end(), mSpirvDebug.begin(), mSpirvDebug.end());
2382 result.insert(result.end(), mSpirvDecorations.begin(), mSpirvDecorations.end());
2383 result.insert(result.end(), mSpirvTypeAndConstantDecls.begin(),
2384 mSpirvTypeAndConstantDecls.end());
2385 result.insert(result.end(), mSpirvTypePointerDecls.begin(), mSpirvTypePointerDecls.end());
2386 result.insert(result.end(), mSpirvFunctionTypeDecls.begin(), mSpirvFunctionTypeDecls.end());
2387 result.insert(result.end(), mSpirvVariableDecls.begin(), mSpirvVariableDecls.end());
2388
2389 // The types/constants/variables section is the first place non-semantic instructions can be
2390 // output. These instructions rely on at least the OpVoid type. The kNonSemanticTypeSectionEnd
2391 // instruction additionally carries an overview of the SPIR-V and thus requires a few OpConstant
2392 // values.
2393 writeNonSemanticOverview(&result, nonSemanticOverviewId);
2394
2395 result.insert(result.end(), mSpirvFunctions.begin(), mSpirvFunctions.end());
2396
2397 result.shrink_to_fit();
2398 return result;
2399 }
2400
writeExecutionModes(spirv::Blob * blob)2401 void SPIRVBuilder::writeExecutionModes(spirv::Blob *blob)
2402 {
2403 const spirv::IdRef entryPointId(vk::spirv::kIdEntryPoint);
2404
2405 switch (mShaderType)
2406 {
2407 case gl::ShaderType::Fragment:
2408 spirv::WriteExecutionMode(blob, entryPointId, spv::ExecutionModeOriginUpperLeft, {});
2409
2410 if (mCompiler->isEarlyFragmentTestsSpecified())
2411 {
2412 spirv::WriteExecutionMode(blob, entryPointId, spv::ExecutionModeEarlyFragmentTests,
2413 {});
2414 }
2415
2416 break;
2417
2418 case gl::ShaderType::TessControl:
2419 spirv::WriteExecutionMode(
2420 blob, entryPointId, spv::ExecutionModeOutputVertices,
2421 {spirv::LiteralInteger(mCompiler->getTessControlShaderOutputVertices())});
2422 break;
2423
2424 case gl::ShaderType::TessEvaluation:
2425 {
2426 const spv::ExecutionMode inputExecutionMode = GetTessEvalInputExecutionMode(
2427 mCompiler->getTessEvaluationShaderInputPrimitiveType());
2428 const spv::ExecutionMode spacingExecutionMode = GetTessEvalSpacingExecutionMode(
2429 mCompiler->getTessEvaluationShaderInputVertexSpacingType());
2430 const spv::ExecutionMode orderingExecutionMode = GetTessEvalOrderingExecutionMode(
2431 mCompiler->getTessEvaluationShaderInputOrderingType());
2432
2433 spirv::WriteExecutionMode(blob, entryPointId, inputExecutionMode, {});
2434 spirv::WriteExecutionMode(blob, entryPointId, spacingExecutionMode, {});
2435 spirv::WriteExecutionMode(blob, entryPointId, orderingExecutionMode, {});
2436 if (mCompiler->getTessEvaluationShaderInputPointType() == EtetPointMode)
2437 {
2438 spirv::WriteExecutionMode(blob, entryPointId, spv::ExecutionModePointMode, {});
2439 }
2440 break;
2441 }
2442
2443 case gl::ShaderType::Geometry:
2444 {
2445 const spv::ExecutionMode inputExecutionMode =
2446 GetGeometryInputExecutionMode(mCompiler->getGeometryShaderInputPrimitiveType());
2447 const spv::ExecutionMode outputExecutionMode =
2448 GetGeometryOutputExecutionMode(mCompiler->getGeometryShaderOutputPrimitiveType());
2449
2450 // max_vertices=0 is not valid in Vulkan
2451 const int maxVertices = std::max(1, mCompiler->getGeometryShaderMaxVertices());
2452
2453 spirv::WriteExecutionMode(blob, entryPointId, inputExecutionMode, {});
2454 spirv::WriteExecutionMode(blob, entryPointId, outputExecutionMode, {});
2455 spirv::WriteExecutionMode(blob, entryPointId, spv::ExecutionModeOutputVertices,
2456 {spirv::LiteralInteger(maxVertices)});
2457 spirv::WriteExecutionMode(
2458 blob, entryPointId, spv::ExecutionModeInvocations,
2459 {spirv::LiteralInteger(mCompiler->getGeometryShaderInvocations())});
2460
2461 break;
2462 }
2463
2464 case gl::ShaderType::Compute:
2465 {
2466 const sh::WorkGroupSize &localSize = mCompiler->getComputeShaderLocalSize();
2467 spirv::WriteExecutionMode(
2468 blob, entryPointId, spv::ExecutionModeLocalSize,
2469 {spirv::LiteralInteger(localSize[0]), spirv::LiteralInteger(localSize[1]),
2470 spirv::LiteralInteger(localSize[2])});
2471 break;
2472 }
2473
2474 default:
2475 break;
2476 }
2477
2478 // Add any execution modes that were added due to built-ins used in the shader.
2479 for (spv::ExecutionMode executionMode : mExecutionModes)
2480 {
2481 spirv::WriteExecutionMode(blob, entryPointId, executionMode, {});
2482 }
2483 }
2484
writeExtensions(spirv::Blob * blob)2485 void SPIRVBuilder::writeExtensions(spirv::Blob *blob)
2486 {
2487 for (SPIRVExtensions extension : mExtensions)
2488 {
2489 switch (extension)
2490 {
2491 case SPIRVExtensions::MultiviewOVR:
2492 spirv::WriteExtension(blob, "SPV_KHR_multiview");
2493 break;
2494 case SPIRVExtensions::FragmentShaderInterlockARB:
2495 spirv::WriteExtension(blob, "SPV_EXT_fragment_shader_interlock");
2496 break;
2497 default:
2498 UNREACHABLE();
2499 }
2500 }
2501 }
2502
writeSourceExtensions(spirv::Blob * blob)2503 void SPIRVBuilder::writeSourceExtensions(spirv::Blob *blob)
2504 {
2505 for (SPIRVExtensions extension : mExtensions)
2506 {
2507 switch (extension)
2508 {
2509 case SPIRVExtensions::MultiviewOVR:
2510 spirv::WriteSourceExtension(blob, "GL_OVR_multiview");
2511 break;
2512 case SPIRVExtensions::FragmentShaderInterlockARB:
2513 spirv::WriteSourceExtension(blob, "GL_ARB_fragment_shader_interlock");
2514 break;
2515 default:
2516 UNREACHABLE();
2517 }
2518 }
2519 }
2520
writeNonSemanticOverview(spirv::Blob * blob,spirv::IdRef id)2521 void SPIRVBuilder::writeNonSemanticOverview(spirv::Blob *blob, spirv::IdRef id)
2522 {
2523 // Output the kNonSemanticOverview non-semantic instruction. The top unused bits of the
2524 // instruction id are used to communicate addition information already gathered in
2525 // mOverviewFlags (bits defined by kOverview*Bit).
2526
2527 using namespace vk::spirv;
2528
2529 ASSERT((mOverviewFlags & vk::spirv::kNonSemanticInstructionMask) == 0);
2530 const uint32_t overview = kNonSemanticOverview | mOverviewFlags;
2531
2532 spirv::WriteExtInst(blob, spirv::IdResultType(kIdVoid), id,
2533 spirv::IdRef(kIdNonSemanticInstructionSet),
2534 spirv::LiteralExtInstInteger(overview), {});
2535 }
2536
writeNonSemanticInstruction(vk::spirv::NonSemanticInstruction instruction)2537 void SPIRVBuilder::writeNonSemanticInstruction(vk::spirv::NonSemanticInstruction instruction)
2538 {
2539 using namespace vk::spirv;
2540
2541 const spirv::IdRef id = getNewId({});
2542
2543 spirv::WriteExtInst(getSpirvCurrentFunctionBlock(), spirv::IdResultType(kIdVoid), id,
2544 spirv::IdRef(kIdNonSemanticInstructionSet),
2545 spirv::LiteralExtInstInteger(instruction), {});
2546 }
2547
2548 } // namespace sh
2549