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