Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/glslang/SPIRV/GlslangToSpv.cpp
9903 views
1
//
2
// Copyright (C) 2014-2016 LunarG, Inc.
3
// Copyright (C) 2015-2020 Google, Inc.
4
// Copyright (C) 2017, 2022-2024 Arm Limited.
5
// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved.
6
//
7
// All rights reserved.
8
//
9
// Redistribution and use in source and binary forms, with or without
10
// modification, are permitted provided that the following conditions
11
// are met:
12
//
13
// Redistributions of source code must retain the above copyright
14
// notice, this list of conditions and the following disclaimer.
15
//
16
// Redistributions in binary form must reproduce the above
17
// copyright notice, this list of conditions and the following
18
// disclaimer in the documentation and/or other materials provided
19
// with the distribution.
20
//
21
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
22
// contributors may be used to endorse or promote products derived
23
// from this software without specific prior written permission.
24
//
25
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
28
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
30
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36
// POSSIBILITY OF SUCH DAMAGE.
37
38
//
39
// Visit the nodes in the glslang intermediate tree representation to
40
// translate them to SPIR-V.
41
//
42
43
#include "spirv.hpp"
44
#include "GlslangToSpv.h"
45
#include "SpvBuilder.h"
46
#include "SpvTools.h"
47
namespace spv {
48
#include "GLSL.std.450.h"
49
#include "GLSL.ext.KHR.h"
50
#include "GLSL.ext.EXT.h"
51
#include "GLSL.ext.AMD.h"
52
#include "GLSL.ext.NV.h"
53
#include "GLSL.ext.ARM.h"
54
#include "GLSL.ext.QCOM.h"
55
#include "NonSemanticDebugPrintf.h"
56
}
57
58
// Glslang includes
59
#include "../glslang/MachineIndependent/localintermediate.h"
60
#include "../glslang/MachineIndependent/SymbolTable.h"
61
#include "../glslang/Include/Common.h"
62
63
// Build-time generated includes
64
#include "glslang/build_info.h"
65
66
#include <fstream>
67
#include <iomanip>
68
#include <list>
69
#include <map>
70
#include <optional>
71
#include <stack>
72
#include <string>
73
#include <vector>
74
75
namespace {
76
77
namespace {
78
class SpecConstantOpModeGuard {
79
public:
80
SpecConstantOpModeGuard(spv::Builder* builder)
81
: builder_(builder) {
82
previous_flag_ = builder->isInSpecConstCodeGenMode();
83
}
84
~SpecConstantOpModeGuard() {
85
previous_flag_ ? builder_->setToSpecConstCodeGenMode()
86
: builder_->setToNormalCodeGenMode();
87
}
88
void turnOnSpecConstantOpMode() {
89
builder_->setToSpecConstCodeGenMode();
90
}
91
92
private:
93
spv::Builder* builder_;
94
bool previous_flag_;
95
};
96
97
struct OpDecorations {
98
public:
99
OpDecorations(spv::Decoration precision, spv::Decoration noContraction, spv::Decoration nonUniform) :
100
precision(precision)
101
,
102
noContraction(noContraction),
103
nonUniform(nonUniform)
104
{ }
105
106
spv::Decoration precision;
107
108
void addNoContraction(spv::Builder& builder, spv::Id t) { builder.addDecoration(t, noContraction); }
109
void addNonUniform(spv::Builder& builder, spv::Id t) { builder.addDecoration(t, nonUniform); }
110
protected:
111
spv::Decoration noContraction;
112
spv::Decoration nonUniform;
113
};
114
115
} // namespace
116
117
//
118
// The main holder of information for translating glslang to SPIR-V.
119
//
120
// Derives from the AST walking base class.
121
//
122
class TGlslangToSpvTraverser : public glslang::TIntermTraverser {
123
public:
124
TGlslangToSpvTraverser(unsigned int spvVersion, const glslang::TIntermediate*, spv::SpvBuildLogger* logger,
125
glslang::SpvOptions& options);
126
virtual ~TGlslangToSpvTraverser() { }
127
128
bool visitAggregate(glslang::TVisit, glslang::TIntermAggregate*);
129
bool visitBinary(glslang::TVisit, glslang::TIntermBinary*);
130
void visitConstantUnion(glslang::TIntermConstantUnion*);
131
bool visitSelection(glslang::TVisit, glslang::TIntermSelection*);
132
bool visitSwitch(glslang::TVisit, glslang::TIntermSwitch*);
133
void visitSymbol(glslang::TIntermSymbol* symbol);
134
bool visitUnary(glslang::TVisit, glslang::TIntermUnary*);
135
bool visitLoop(glslang::TVisit, glslang::TIntermLoop*);
136
bool visitBranch(glslang::TVisit visit, glslang::TIntermBranch*);
137
138
void finishSpv(bool compileOnly);
139
void dumpSpv(std::vector<unsigned int>& out);
140
141
protected:
142
TGlslangToSpvTraverser(TGlslangToSpvTraverser&);
143
TGlslangToSpvTraverser& operator=(TGlslangToSpvTraverser&);
144
145
spv::Decoration TranslateInterpolationDecoration(const glslang::TQualifier& qualifier);
146
spv::Decoration TranslateAuxiliaryStorageDecoration(const glslang::TQualifier& qualifier);
147
spv::Decoration TranslateNonUniformDecoration(const glslang::TQualifier& qualifier);
148
spv::Decoration TranslateNonUniformDecoration(const spv::Builder::AccessChain::CoherentFlags& coherentFlags);
149
spv::Builder::AccessChain::CoherentFlags TranslateCoherent(const glslang::TType& type);
150
spv::MemoryAccessMask TranslateMemoryAccess(const spv::Builder::AccessChain::CoherentFlags &coherentFlags);
151
spv::ImageOperandsMask TranslateImageOperands(const spv::Builder::AccessChain::CoherentFlags &coherentFlags);
152
spv::Scope TranslateMemoryScope(const spv::Builder::AccessChain::CoherentFlags &coherentFlags);
153
spv::BuiltIn TranslateBuiltInDecoration(glslang::TBuiltInVariable, bool memberDeclaration);
154
spv::ImageFormat TranslateImageFormat(const glslang::TType& type);
155
spv::SelectionControlMask TranslateSelectionControl(const glslang::TIntermSelection&) const;
156
spv::SelectionControlMask TranslateSwitchControl(const glslang::TIntermSwitch&) const;
157
spv::LoopControlMask TranslateLoopControl(const glslang::TIntermLoop&, std::vector<unsigned int>& operands) const;
158
spv::StorageClass TranslateStorageClass(const glslang::TType&);
159
void TranslateLiterals(const glslang::TVector<const glslang::TIntermConstantUnion*>&, std::vector<unsigned>&) const;
160
void addIndirectionIndexCapabilities(const glslang::TType& baseType, const glslang::TType& indexType);
161
spv::Id createSpvVariable(const glslang::TIntermSymbol*, spv::Id forcedType);
162
spv::Id getSampledType(const glslang::TSampler&);
163
spv::Id getInvertedSwizzleType(const glslang::TIntermTyped&);
164
spv::Id createInvertedSwizzle(spv::Decoration precision, const glslang::TIntermTyped&, spv::Id parentResult);
165
void convertSwizzle(const glslang::TIntermAggregate&, std::vector<unsigned>& swizzle);
166
spv::Id convertGlslangToSpvType(const glslang::TType& type, bool forwardReferenceOnly = false);
167
spv::Id convertGlslangToSpvType(const glslang::TType& type, glslang::TLayoutPacking, const glslang::TQualifier&,
168
bool lastBufferBlockMember, bool forwardReferenceOnly = false);
169
void applySpirvDecorate(const glslang::TType& type, spv::Id id, std::optional<int> member);
170
bool filterMember(const glslang::TType& member);
171
spv::Id convertGlslangStructToSpvType(const glslang::TType&, const glslang::TTypeList* glslangStruct,
172
glslang::TLayoutPacking, const glslang::TQualifier&);
173
spv::LinkageType convertGlslangLinkageToSpv(glslang::TLinkType glslangLinkType);
174
void decorateStructType(const glslang::TType&, const glslang::TTypeList* glslangStruct, glslang::TLayoutPacking,
175
const glslang::TQualifier&, spv::Id, const std::vector<spv::Id>& spvMembers);
176
spv::Id makeArraySizeId(const glslang::TArraySizes&, int dim, bool allowZero = false);
177
spv::Id accessChainLoad(const glslang::TType& type);
178
void accessChainStore(const glslang::TType& type, spv::Id rvalue);
179
void multiTypeStore(const glslang::TType&, spv::Id rValue);
180
spv::Id convertLoadedBoolInUniformToUint(const glslang::TType& type, spv::Id nominalTypeId, spv::Id loadedId);
181
glslang::TLayoutPacking getExplicitLayout(const glslang::TType& type) const;
182
int getArrayStride(const glslang::TType& arrayType, glslang::TLayoutPacking, glslang::TLayoutMatrix);
183
int getMatrixStride(const glslang::TType& matrixType, glslang::TLayoutPacking, glslang::TLayoutMatrix);
184
void updateMemberOffset(const glslang::TType& structType, const glslang::TType& memberType, int& currentOffset,
185
int& nextOffset, glslang::TLayoutPacking, glslang::TLayoutMatrix);
186
void declareUseOfStructMember(const glslang::TTypeList& members, int glslangMember);
187
188
bool isShaderEntryPoint(const glslang::TIntermAggregate* node);
189
bool writableParam(glslang::TStorageQualifier) const;
190
bool originalParam(glslang::TStorageQualifier, const glslang::TType&, bool implicitThisParam);
191
void makeFunctions(const glslang::TIntermSequence&);
192
void makeGlobalInitializers(const glslang::TIntermSequence&);
193
void collectRayTracingLinkerObjects();
194
void visitFunctions(const glslang::TIntermSequence&);
195
void handleFunctionEntry(const glslang::TIntermAggregate* node);
196
void translateArguments(const glslang::TIntermAggregate& node, std::vector<spv::Id>& arguments,
197
spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags);
198
void translateArguments(glslang::TIntermUnary& node, std::vector<spv::Id>& arguments);
199
spv::Id createImageTextureFunctionCall(glslang::TIntermOperator* node);
200
spv::Id handleUserFunctionCall(const glslang::TIntermAggregate*);
201
202
spv::Id createBinaryOperation(glslang::TOperator op, OpDecorations&, spv::Id typeId, spv::Id left, spv::Id right,
203
glslang::TBasicType typeProxy, bool reduceComparison = true);
204
spv::Id createBinaryMatrixOperation(spv::Op, OpDecorations&, spv::Id typeId, spv::Id left, spv::Id right);
205
spv::Id createUnaryOperation(glslang::TOperator op, OpDecorations&, spv::Id typeId, spv::Id operand,
206
glslang::TBasicType typeProxy,
207
const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags,
208
const glslang::TType &opType);
209
spv::Id createUnaryMatrixOperation(spv::Op op, OpDecorations&, spv::Id typeId, spv::Id operand,
210
glslang::TBasicType typeProxy);
211
spv::Id createConversion(glslang::TOperator op, OpDecorations&, spv::Id destTypeId, spv::Id operand,
212
glslang::TBasicType typeProxy);
213
spv::Id createIntWidthConversion(glslang::TOperator op, spv::Id operand, int vectorSize, spv::Id destType);
214
spv::Id makeSmearedConstant(spv::Id constant, int vectorSize);
215
spv::Id createAtomicOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId,
216
std::vector<spv::Id>& operands, glslang::TBasicType typeProxy,
217
const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags,
218
const glslang::TType &opType);
219
spv::Id createInvocationsOperation(glslang::TOperator op, spv::Id typeId, std::vector<spv::Id>& operands,
220
glslang::TBasicType typeProxy);
221
spv::Id CreateInvocationsVectorOperation(spv::Op op, spv::GroupOperation groupOperation,
222
spv::Id typeId, std::vector<spv::Id>& operands);
223
spv::Id createSubgroupOperation(glslang::TOperator op, spv::Id typeId, std::vector<spv::Id>& operands,
224
glslang::TBasicType typeProxy);
225
spv::Id createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId,
226
std::vector<spv::Id>& operands, glslang::TBasicType typeProxy);
227
spv::Id createNoArgOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId);
228
spv::Id getSymbolId(const glslang::TIntermSymbol* node);
229
void addMeshNVDecoration(spv::Id id, int member, const glslang::TQualifier & qualifier);
230
bool hasQCOMImageProceessingDecoration(spv::Id id, spv::Decoration decor);
231
void addImageProcessingQCOMDecoration(spv::Id id, spv::Decoration decor);
232
void addImageProcessing2QCOMDecoration(spv::Id id, bool isForGather);
233
spv::Id createSpvConstant(const glslang::TIntermTyped&);
234
spv::Id createSpvConstantFromConstUnionArray(const glslang::TType& type, const glslang::TConstUnionArray&,
235
int& nextConst, bool specConstant);
236
bool isTrivialLeaf(const glslang::TIntermTyped* node);
237
bool isTrivial(const glslang::TIntermTyped* node);
238
spv::Id createShortCircuit(glslang::TOperator, glslang::TIntermTyped& left, glslang::TIntermTyped& right);
239
spv::Id getExtBuiltins(const char* name);
240
std::pair<spv::Id, spv::Id> getForcedType(glslang::TBuiltInVariable builtIn, const glslang::TType&);
241
spv::Id translateForcedType(spv::Id object);
242
spv::Id createCompositeConstruct(spv::Id typeId, std::vector<spv::Id> constituents);
243
244
glslang::SpvOptions& options;
245
spv::Function* shaderEntry;
246
spv::Function* currentFunction;
247
spv::Instruction* entryPoint;
248
int sequenceDepth;
249
250
spv::SpvBuildLogger* logger;
251
252
// There is a 1:1 mapping between a spv builder and a module; this is thread safe
253
spv::Builder builder;
254
bool inEntryPoint;
255
bool entryPointTerminated;
256
bool linkageOnly; // true when visiting the set of objects in the AST present only for
257
// establishing interface, whether or not they were statically used
258
std::set<spv::Id> iOSet; // all input/output variables from either static use or declaration of interface
259
const glslang::TIntermediate* glslangIntermediate;
260
bool nanMinMaxClamp; // true if use NMin/NMax/NClamp instead of FMin/FMax/FClamp
261
spv::Id stdBuiltins;
262
spv::Id nonSemanticDebugPrintf;
263
std::unordered_map<std::string, spv::Id> extBuiltinMap;
264
265
std::unordered_map<long long, spv::Id> symbolValues;
266
std::unordered_map<uint32_t, spv::Id> builtInVariableIds;
267
std::unordered_set<long long> rValueParameters; // set of formal function parameters passed as rValues,
268
// rather than a pointer
269
std::unordered_map<std::string, spv::Function*> functionMap;
270
std::unordered_map<const glslang::TTypeList*, spv::Id> structMap[glslang::ElpCount][glslang::ElmCount];
271
// for mapping glslang block indices to spv indices (e.g., due to hidden members):
272
std::unordered_map<long long, std::vector<int>> memberRemapper;
273
// for mapping glslang symbol struct to symbol Id
274
std::unordered_map<const glslang::TTypeList*, long long> glslangTypeToIdMap;
275
std::stack<bool> breakForLoop; // false means break for switch
276
std::unordered_map<std::string, const glslang::TIntermSymbol*> counterOriginator;
277
// Map pointee types for EbtReference to their forward pointers
278
std::map<const glslang::TType *, spv::Id> forwardPointers;
279
// Type forcing, for when SPIR-V wants a different type than the AST,
280
// requiring local translation to and from SPIR-V type on every access.
281
// Maps <builtin-variable-id -> AST-required-type-id>
282
std::unordered_map<spv::Id, spv::Id> forceType;
283
// Used by Task shader while generating opearnds for OpEmitMeshTasksEXT
284
spv::Id taskPayloadID;
285
// Used later for generating OpTraceKHR/OpExecuteCallableKHR/OpHitObjectRecordHit*/OpHitObjectGetShaderBindingTableData
286
std::unordered_map<unsigned int, glslang::TIntermSymbol *> locationToSymbol[4];
287
std::unordered_map<spv::Id, std::vector<spv::Decoration> > idToQCOMDecorations;
288
};
289
290
//
291
// Helper functions for translating glslang representations to SPIR-V enumerants.
292
//
293
294
// Translate glslang profile to SPIR-V source language.
295
spv::SourceLanguage TranslateSourceLanguage(glslang::EShSource source, EProfile profile)
296
{
297
switch (source) {
298
case glslang::EShSourceGlsl:
299
switch (profile) {
300
case ENoProfile:
301
case ECoreProfile:
302
case ECompatibilityProfile:
303
return spv::SourceLanguageGLSL;
304
case EEsProfile:
305
return spv::SourceLanguageESSL;
306
default:
307
return spv::SourceLanguageUnknown;
308
}
309
case glslang::EShSourceHlsl:
310
return spv::SourceLanguageHLSL;
311
default:
312
return spv::SourceLanguageUnknown;
313
}
314
}
315
316
// Translate glslang language (stage) to SPIR-V execution model.
317
spv::ExecutionModel TranslateExecutionModel(EShLanguage stage, bool isMeshShaderEXT = false)
318
{
319
switch (stage) {
320
case EShLangVertex: return spv::ExecutionModelVertex;
321
case EShLangFragment: return spv::ExecutionModelFragment;
322
case EShLangCompute: return spv::ExecutionModelGLCompute;
323
case EShLangTessControl: return spv::ExecutionModelTessellationControl;
324
case EShLangTessEvaluation: return spv::ExecutionModelTessellationEvaluation;
325
case EShLangGeometry: return spv::ExecutionModelGeometry;
326
case EShLangRayGen: return spv::ExecutionModelRayGenerationKHR;
327
case EShLangIntersect: return spv::ExecutionModelIntersectionKHR;
328
case EShLangAnyHit: return spv::ExecutionModelAnyHitKHR;
329
case EShLangClosestHit: return spv::ExecutionModelClosestHitKHR;
330
case EShLangMiss: return spv::ExecutionModelMissKHR;
331
case EShLangCallable: return spv::ExecutionModelCallableKHR;
332
case EShLangTask: return (isMeshShaderEXT)? spv::ExecutionModelTaskEXT : spv::ExecutionModelTaskNV;
333
case EShLangMesh: return (isMeshShaderEXT)? spv::ExecutionModelMeshEXT: spv::ExecutionModelMeshNV;
334
default:
335
assert(0);
336
return spv::ExecutionModelFragment;
337
}
338
}
339
340
// Translate glslang sampler type to SPIR-V dimensionality.
341
spv::Dim TranslateDimensionality(const glslang::TSampler& sampler)
342
{
343
switch (sampler.dim) {
344
case glslang::Esd1D: return spv::Dim1D;
345
case glslang::Esd2D: return spv::Dim2D;
346
case glslang::Esd3D: return spv::Dim3D;
347
case glslang::EsdCube: return spv::DimCube;
348
case glslang::EsdRect: return spv::DimRect;
349
case glslang::EsdBuffer: return spv::DimBuffer;
350
case glslang::EsdSubpass: return spv::DimSubpassData;
351
case glslang::EsdAttachmentEXT: return spv::DimTileImageDataEXT;
352
default:
353
assert(0);
354
return spv::Dim2D;
355
}
356
}
357
358
// Translate glslang precision to SPIR-V precision decorations.
359
spv::Decoration TranslatePrecisionDecoration(glslang::TPrecisionQualifier glslangPrecision)
360
{
361
switch (glslangPrecision) {
362
case glslang::EpqLow: return spv::DecorationRelaxedPrecision;
363
case glslang::EpqMedium: return spv::DecorationRelaxedPrecision;
364
default:
365
return spv::NoPrecision;
366
}
367
}
368
369
// Translate glslang type to SPIR-V precision decorations.
370
spv::Decoration TranslatePrecisionDecoration(const glslang::TType& type)
371
{
372
return TranslatePrecisionDecoration(type.getQualifier().precision);
373
}
374
375
// Translate glslang type to SPIR-V block decorations.
376
spv::Decoration TranslateBlockDecoration(const glslang::TStorageQualifier storage, bool useStorageBuffer)
377
{
378
switch (storage) {
379
case glslang::EvqUniform: return spv::DecorationBlock;
380
case glslang::EvqBuffer: return useStorageBuffer ? spv::DecorationBlock : spv::DecorationBufferBlock;
381
case glslang::EvqVaryingIn: return spv::DecorationBlock;
382
case glslang::EvqVaryingOut: return spv::DecorationBlock;
383
case glslang::EvqShared: return spv::DecorationBlock;
384
case glslang::EvqPayload: return spv::DecorationBlock;
385
case glslang::EvqPayloadIn: return spv::DecorationBlock;
386
case glslang::EvqHitAttr: return spv::DecorationBlock;
387
case glslang::EvqCallableData: return spv::DecorationBlock;
388
case glslang::EvqCallableDataIn: return spv::DecorationBlock;
389
case glslang::EvqHitObjectAttrNV: return spv::DecorationBlock;
390
default:
391
assert(0);
392
break;
393
}
394
395
return spv::DecorationMax;
396
}
397
398
// Translate glslang type to SPIR-V memory decorations.
399
void TranslateMemoryDecoration(const glslang::TQualifier& qualifier, std::vector<spv::Decoration>& memory,
400
bool useVulkanMemoryModel)
401
{
402
if (!useVulkanMemoryModel) {
403
if (qualifier.isVolatile()) {
404
memory.push_back(spv::DecorationVolatile);
405
memory.push_back(spv::DecorationCoherent);
406
} else if (qualifier.isCoherent()) {
407
memory.push_back(spv::DecorationCoherent);
408
}
409
}
410
if (qualifier.isRestrict())
411
memory.push_back(spv::DecorationRestrict);
412
if (qualifier.isReadOnly())
413
memory.push_back(spv::DecorationNonWritable);
414
if (qualifier.isWriteOnly())
415
memory.push_back(spv::DecorationNonReadable);
416
}
417
418
// Translate glslang type to SPIR-V layout decorations.
419
spv::Decoration TranslateLayoutDecoration(const glslang::TType& type, glslang::TLayoutMatrix matrixLayout)
420
{
421
if (type.isMatrix()) {
422
switch (matrixLayout) {
423
case glslang::ElmRowMajor:
424
return spv::DecorationRowMajor;
425
case glslang::ElmColumnMajor:
426
return spv::DecorationColMajor;
427
default:
428
// opaque layouts don't need a majorness
429
return spv::DecorationMax;
430
}
431
} else {
432
switch (type.getBasicType()) {
433
default:
434
return spv::DecorationMax;
435
break;
436
case glslang::EbtBlock:
437
switch (type.getQualifier().storage) {
438
case glslang::EvqShared:
439
case glslang::EvqUniform:
440
case glslang::EvqBuffer:
441
switch (type.getQualifier().layoutPacking) {
442
case glslang::ElpShared: return spv::DecorationGLSLShared;
443
case glslang::ElpPacked: return spv::DecorationGLSLPacked;
444
default:
445
return spv::DecorationMax;
446
}
447
case glslang::EvqVaryingIn:
448
case glslang::EvqVaryingOut:
449
if (type.getQualifier().isTaskMemory()) {
450
switch (type.getQualifier().layoutPacking) {
451
case glslang::ElpShared: return spv::DecorationGLSLShared;
452
case glslang::ElpPacked: return spv::DecorationGLSLPacked;
453
default: break;
454
}
455
} else {
456
assert(type.getQualifier().layoutPacking == glslang::ElpNone);
457
}
458
return spv::DecorationMax;
459
case glslang::EvqPayload:
460
case glslang::EvqPayloadIn:
461
case glslang::EvqHitAttr:
462
case glslang::EvqCallableData:
463
case glslang::EvqCallableDataIn:
464
case glslang::EvqHitObjectAttrNV:
465
return spv::DecorationMax;
466
default:
467
assert(0);
468
return spv::DecorationMax;
469
}
470
}
471
}
472
}
473
474
// Translate glslang type to SPIR-V interpolation decorations.
475
// Returns spv::DecorationMax when no decoration
476
// should be applied.
477
spv::Decoration TGlslangToSpvTraverser::TranslateInterpolationDecoration(const glslang::TQualifier& qualifier)
478
{
479
if (qualifier.smooth)
480
// Smooth decoration doesn't exist in SPIR-V 1.0
481
return spv::DecorationMax;
482
else if (qualifier.isNonPerspective())
483
return spv::DecorationNoPerspective;
484
else if (qualifier.flat)
485
return spv::DecorationFlat;
486
else if (qualifier.isExplicitInterpolation()) {
487
builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
488
return spv::DecorationExplicitInterpAMD;
489
}
490
else
491
return spv::DecorationMax;
492
}
493
494
// Translate glslang type to SPIR-V auxiliary storage decorations.
495
// Returns spv::DecorationMax when no decoration
496
// should be applied.
497
spv::Decoration TGlslangToSpvTraverser::TranslateAuxiliaryStorageDecoration(const glslang::TQualifier& qualifier)
498
{
499
if (qualifier.centroid)
500
return spv::DecorationCentroid;
501
else if (qualifier.patch)
502
return spv::DecorationPatch;
503
else if (qualifier.sample) {
504
builder.addCapability(spv::CapabilitySampleRateShading);
505
return spv::DecorationSample;
506
}
507
508
return spv::DecorationMax;
509
}
510
511
// If glslang type is invariant, return SPIR-V invariant decoration.
512
spv::Decoration TranslateInvariantDecoration(const glslang::TQualifier& qualifier)
513
{
514
if (qualifier.invariant)
515
return spv::DecorationInvariant;
516
else
517
return spv::DecorationMax;
518
}
519
520
// If glslang type is noContraction, return SPIR-V NoContraction decoration.
521
spv::Decoration TranslateNoContractionDecoration(const glslang::TQualifier& qualifier)
522
{
523
if (qualifier.isNoContraction())
524
return spv::DecorationNoContraction;
525
else
526
return spv::DecorationMax;
527
}
528
529
// If glslang type is nonUniform, return SPIR-V NonUniform decoration.
530
spv::Decoration TGlslangToSpvTraverser::TranslateNonUniformDecoration(const glslang::TQualifier& qualifier)
531
{
532
if (qualifier.isNonUniform()) {
533
builder.addIncorporatedExtension("SPV_EXT_descriptor_indexing", spv::Spv_1_5);
534
builder.addCapability(spv::CapabilityShaderNonUniformEXT);
535
return spv::DecorationNonUniformEXT;
536
} else
537
return spv::DecorationMax;
538
}
539
540
// If lvalue flags contains nonUniform, return SPIR-V NonUniform decoration.
541
spv::Decoration TGlslangToSpvTraverser::TranslateNonUniformDecoration(
542
const spv::Builder::AccessChain::CoherentFlags& coherentFlags)
543
{
544
if (coherentFlags.isNonUniform()) {
545
builder.addIncorporatedExtension("SPV_EXT_descriptor_indexing", spv::Spv_1_5);
546
builder.addCapability(spv::CapabilityShaderNonUniformEXT);
547
return spv::DecorationNonUniformEXT;
548
} else
549
return spv::DecorationMax;
550
}
551
552
spv::MemoryAccessMask TGlslangToSpvTraverser::TranslateMemoryAccess(
553
const spv::Builder::AccessChain::CoherentFlags &coherentFlags)
554
{
555
spv::MemoryAccessMask mask = spv::MemoryAccessMaskNone;
556
557
if (!glslangIntermediate->usingVulkanMemoryModel() || coherentFlags.isImage)
558
return mask;
559
560
if (coherentFlags.isVolatile() || coherentFlags.anyCoherent()) {
561
mask = mask | spv::MemoryAccessMakePointerAvailableKHRMask |
562
spv::MemoryAccessMakePointerVisibleKHRMask;
563
}
564
565
if (coherentFlags.nonprivate) {
566
mask = mask | spv::MemoryAccessNonPrivatePointerKHRMask;
567
}
568
if (coherentFlags.volatil) {
569
mask = mask | spv::MemoryAccessVolatileMask;
570
}
571
if (mask != spv::MemoryAccessMaskNone) {
572
builder.addCapability(spv::CapabilityVulkanMemoryModelKHR);
573
}
574
575
return mask;
576
}
577
578
spv::ImageOperandsMask TGlslangToSpvTraverser::TranslateImageOperands(
579
const spv::Builder::AccessChain::CoherentFlags &coherentFlags)
580
{
581
spv::ImageOperandsMask mask = spv::ImageOperandsMaskNone;
582
583
if (!glslangIntermediate->usingVulkanMemoryModel())
584
return mask;
585
586
if (coherentFlags.volatil ||
587
coherentFlags.anyCoherent()) {
588
mask = mask | spv::ImageOperandsMakeTexelAvailableKHRMask |
589
spv::ImageOperandsMakeTexelVisibleKHRMask;
590
}
591
if (coherentFlags.nonprivate) {
592
mask = mask | spv::ImageOperandsNonPrivateTexelKHRMask;
593
}
594
if (coherentFlags.volatil) {
595
mask = mask | spv::ImageOperandsVolatileTexelKHRMask;
596
}
597
if (mask != spv::ImageOperandsMaskNone) {
598
builder.addCapability(spv::CapabilityVulkanMemoryModelKHR);
599
}
600
601
return mask;
602
}
603
604
spv::Builder::AccessChain::CoherentFlags TGlslangToSpvTraverser::TranslateCoherent(const glslang::TType& type)
605
{
606
spv::Builder::AccessChain::CoherentFlags flags = {};
607
flags.coherent = type.getQualifier().coherent;
608
flags.devicecoherent = type.getQualifier().devicecoherent;
609
flags.queuefamilycoherent = type.getQualifier().queuefamilycoherent;
610
// shared variables are implicitly workgroupcoherent in GLSL.
611
flags.workgroupcoherent = type.getQualifier().workgroupcoherent ||
612
type.getQualifier().storage == glslang::EvqShared;
613
flags.subgroupcoherent = type.getQualifier().subgroupcoherent;
614
flags.shadercallcoherent = type.getQualifier().shadercallcoherent;
615
flags.volatil = type.getQualifier().volatil;
616
// *coherent variables are implicitly nonprivate in GLSL
617
flags.nonprivate = type.getQualifier().nonprivate ||
618
flags.anyCoherent() ||
619
flags.volatil;
620
flags.isImage = type.getBasicType() == glslang::EbtSampler;
621
flags.nonUniform = type.getQualifier().nonUniform;
622
return flags;
623
}
624
625
spv::Scope TGlslangToSpvTraverser::TranslateMemoryScope(
626
const spv::Builder::AccessChain::CoherentFlags &coherentFlags)
627
{
628
spv::Scope scope = spv::ScopeMax;
629
630
if (coherentFlags.volatil || coherentFlags.coherent) {
631
// coherent defaults to Device scope in the old model, QueueFamilyKHR scope in the new model
632
scope = glslangIntermediate->usingVulkanMemoryModel() ? spv::ScopeQueueFamilyKHR : spv::ScopeDevice;
633
} else if (coherentFlags.devicecoherent) {
634
scope = spv::ScopeDevice;
635
} else if (coherentFlags.queuefamilycoherent) {
636
scope = spv::ScopeQueueFamilyKHR;
637
} else if (coherentFlags.workgroupcoherent) {
638
scope = spv::ScopeWorkgroup;
639
} else if (coherentFlags.subgroupcoherent) {
640
scope = spv::ScopeSubgroup;
641
} else if (coherentFlags.shadercallcoherent) {
642
scope = spv::ScopeShaderCallKHR;
643
}
644
if (glslangIntermediate->usingVulkanMemoryModel() && scope == spv::ScopeDevice) {
645
builder.addCapability(spv::CapabilityVulkanMemoryModelDeviceScopeKHR);
646
}
647
648
return scope;
649
}
650
651
// Translate a glslang built-in variable to a SPIR-V built in decoration. Also generate
652
// associated capabilities when required. For some built-in variables, a capability
653
// is generated only when using the variable in an executable instruction, but not when
654
// just declaring a struct member variable with it. This is true for PointSize,
655
// ClipDistance, and CullDistance.
656
spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltInVariable builtIn,
657
bool memberDeclaration)
658
{
659
switch (builtIn) {
660
case glslang::EbvPointSize:
661
// Defer adding the capability until the built-in is actually used.
662
if (! memberDeclaration) {
663
switch (glslangIntermediate->getStage()) {
664
case EShLangGeometry:
665
builder.addCapability(spv::CapabilityGeometryPointSize);
666
break;
667
case EShLangTessControl:
668
case EShLangTessEvaluation:
669
builder.addCapability(spv::CapabilityTessellationPointSize);
670
break;
671
default:
672
break;
673
}
674
}
675
return spv::BuiltInPointSize;
676
677
case glslang::EbvPosition: return spv::BuiltInPosition;
678
case glslang::EbvVertexId: return spv::BuiltInVertexId;
679
case glslang::EbvInstanceId: return spv::BuiltInInstanceId;
680
case glslang::EbvVertexIndex: return spv::BuiltInVertexIndex;
681
case glslang::EbvInstanceIndex: return spv::BuiltInInstanceIndex;
682
683
case glslang::EbvFragCoord: return spv::BuiltInFragCoord;
684
case glslang::EbvPointCoord: return spv::BuiltInPointCoord;
685
case glslang::EbvFace: return spv::BuiltInFrontFacing;
686
case glslang::EbvFragDepth: return spv::BuiltInFragDepth;
687
688
case glslang::EbvNumWorkGroups: return spv::BuiltInNumWorkgroups;
689
case glslang::EbvWorkGroupSize: return spv::BuiltInWorkgroupSize;
690
case glslang::EbvWorkGroupId: return spv::BuiltInWorkgroupId;
691
case glslang::EbvLocalInvocationId: return spv::BuiltInLocalInvocationId;
692
case glslang::EbvLocalInvocationIndex: return spv::BuiltInLocalInvocationIndex;
693
case glslang::EbvGlobalInvocationId: return spv::BuiltInGlobalInvocationId;
694
695
// These *Distance capabilities logically belong here, but if the member is declared and
696
// then never used, consumers of SPIR-V prefer the capability not be declared.
697
// They are now generated when used, rather than here when declared.
698
// Potentially, the specification should be more clear what the minimum
699
// use needed is to trigger the capability.
700
//
701
case glslang::EbvClipDistance:
702
if (!memberDeclaration)
703
builder.addCapability(spv::CapabilityClipDistance);
704
return spv::BuiltInClipDistance;
705
706
case glslang::EbvCullDistance:
707
if (!memberDeclaration)
708
builder.addCapability(spv::CapabilityCullDistance);
709
return spv::BuiltInCullDistance;
710
711
case glslang::EbvViewportIndex:
712
if (glslangIntermediate->getStage() == EShLangGeometry ||
713
glslangIntermediate->getStage() == EShLangFragment) {
714
builder.addCapability(spv::CapabilityMultiViewport);
715
}
716
if (glslangIntermediate->getStage() == EShLangVertex ||
717
glslangIntermediate->getStage() == EShLangTessControl ||
718
glslangIntermediate->getStage() == EShLangTessEvaluation) {
719
720
if (builder.getSpvVersion() < spv::Spv_1_5) {
721
builder.addIncorporatedExtension(spv::E_SPV_EXT_shader_viewport_index_layer, spv::Spv_1_5);
722
builder.addCapability(spv::CapabilityShaderViewportIndexLayerEXT);
723
}
724
else
725
builder.addCapability(spv::CapabilityShaderViewportIndex);
726
}
727
return spv::BuiltInViewportIndex;
728
729
case glslang::EbvSampleId:
730
builder.addCapability(spv::CapabilitySampleRateShading);
731
return spv::BuiltInSampleId;
732
733
case glslang::EbvSamplePosition:
734
builder.addCapability(spv::CapabilitySampleRateShading);
735
return spv::BuiltInSamplePosition;
736
737
case glslang::EbvSampleMask:
738
return spv::BuiltInSampleMask;
739
740
case glslang::EbvLayer:
741
if (glslangIntermediate->getStage() == EShLangMesh) {
742
return spv::BuiltInLayer;
743
}
744
if (glslangIntermediate->getStage() == EShLangGeometry ||
745
glslangIntermediate->getStage() == EShLangFragment) {
746
builder.addCapability(spv::CapabilityGeometry);
747
}
748
if (glslangIntermediate->getStage() == EShLangVertex ||
749
glslangIntermediate->getStage() == EShLangTessControl ||
750
glslangIntermediate->getStage() == EShLangTessEvaluation) {
751
752
if (builder.getSpvVersion() < spv::Spv_1_5) {
753
builder.addIncorporatedExtension(spv::E_SPV_EXT_shader_viewport_index_layer, spv::Spv_1_5);
754
builder.addCapability(spv::CapabilityShaderViewportIndexLayerEXT);
755
} else
756
builder.addCapability(spv::CapabilityShaderLayer);
757
}
758
return spv::BuiltInLayer;
759
760
case glslang::EbvBaseVertex:
761
builder.addIncorporatedExtension(spv::E_SPV_KHR_shader_draw_parameters, spv::Spv_1_3);
762
builder.addCapability(spv::CapabilityDrawParameters);
763
return spv::BuiltInBaseVertex;
764
765
case glslang::EbvBaseInstance:
766
builder.addIncorporatedExtension(spv::E_SPV_KHR_shader_draw_parameters, spv::Spv_1_3);
767
builder.addCapability(spv::CapabilityDrawParameters);
768
return spv::BuiltInBaseInstance;
769
770
case glslang::EbvDrawId:
771
builder.addIncorporatedExtension(spv::E_SPV_KHR_shader_draw_parameters, spv::Spv_1_3);
772
builder.addCapability(spv::CapabilityDrawParameters);
773
return spv::BuiltInDrawIndex;
774
775
case glslang::EbvPrimitiveId:
776
if (glslangIntermediate->getStage() == EShLangFragment)
777
builder.addCapability(spv::CapabilityGeometry);
778
return spv::BuiltInPrimitiveId;
779
780
case glslang::EbvFragStencilRef:
781
builder.addExtension(spv::E_SPV_EXT_shader_stencil_export);
782
builder.addCapability(spv::CapabilityStencilExportEXT);
783
return spv::BuiltInFragStencilRefEXT;
784
785
case glslang::EbvShadingRateKHR:
786
builder.addExtension(spv::E_SPV_KHR_fragment_shading_rate);
787
builder.addCapability(spv::CapabilityFragmentShadingRateKHR);
788
return spv::BuiltInShadingRateKHR;
789
790
case glslang::EbvPrimitiveShadingRateKHR:
791
builder.addExtension(spv::E_SPV_KHR_fragment_shading_rate);
792
builder.addCapability(spv::CapabilityFragmentShadingRateKHR);
793
return spv::BuiltInPrimitiveShadingRateKHR;
794
795
case glslang::EbvInvocationId: return spv::BuiltInInvocationId;
796
case glslang::EbvTessLevelInner: return spv::BuiltInTessLevelInner;
797
case glslang::EbvTessLevelOuter: return spv::BuiltInTessLevelOuter;
798
case glslang::EbvTessCoord: return spv::BuiltInTessCoord;
799
case glslang::EbvPatchVertices: return spv::BuiltInPatchVertices;
800
case glslang::EbvHelperInvocation: return spv::BuiltInHelperInvocation;
801
802
case glslang::EbvSubGroupSize:
803
builder.addExtension(spv::E_SPV_KHR_shader_ballot);
804
builder.addCapability(spv::CapabilitySubgroupBallotKHR);
805
return spv::BuiltInSubgroupSize;
806
807
case glslang::EbvSubGroupInvocation:
808
builder.addExtension(spv::E_SPV_KHR_shader_ballot);
809
builder.addCapability(spv::CapabilitySubgroupBallotKHR);
810
return spv::BuiltInSubgroupLocalInvocationId;
811
812
case glslang::EbvSubGroupEqMask:
813
builder.addExtension(spv::E_SPV_KHR_shader_ballot);
814
builder.addCapability(spv::CapabilitySubgroupBallotKHR);
815
return spv::BuiltInSubgroupEqMask;
816
817
case glslang::EbvSubGroupGeMask:
818
builder.addExtension(spv::E_SPV_KHR_shader_ballot);
819
builder.addCapability(spv::CapabilitySubgroupBallotKHR);
820
return spv::BuiltInSubgroupGeMask;
821
822
case glslang::EbvSubGroupGtMask:
823
builder.addExtension(spv::E_SPV_KHR_shader_ballot);
824
builder.addCapability(spv::CapabilitySubgroupBallotKHR);
825
return spv::BuiltInSubgroupGtMask;
826
827
case glslang::EbvSubGroupLeMask:
828
builder.addExtension(spv::E_SPV_KHR_shader_ballot);
829
builder.addCapability(spv::CapabilitySubgroupBallotKHR);
830
return spv::BuiltInSubgroupLeMask;
831
832
case glslang::EbvSubGroupLtMask:
833
builder.addExtension(spv::E_SPV_KHR_shader_ballot);
834
builder.addCapability(spv::CapabilitySubgroupBallotKHR);
835
return spv::BuiltInSubgroupLtMask;
836
837
case glslang::EbvNumSubgroups:
838
builder.addCapability(spv::CapabilityGroupNonUniform);
839
return spv::BuiltInNumSubgroups;
840
841
case glslang::EbvSubgroupID:
842
builder.addCapability(spv::CapabilityGroupNonUniform);
843
return spv::BuiltInSubgroupId;
844
845
case glslang::EbvSubgroupSize2:
846
builder.addCapability(spv::CapabilityGroupNonUniform);
847
return spv::BuiltInSubgroupSize;
848
849
case glslang::EbvSubgroupInvocation2:
850
builder.addCapability(spv::CapabilityGroupNonUniform);
851
return spv::BuiltInSubgroupLocalInvocationId;
852
853
case glslang::EbvSubgroupEqMask2:
854
builder.addCapability(spv::CapabilityGroupNonUniform);
855
builder.addCapability(spv::CapabilityGroupNonUniformBallot);
856
return spv::BuiltInSubgroupEqMask;
857
858
case glslang::EbvSubgroupGeMask2:
859
builder.addCapability(spv::CapabilityGroupNonUniform);
860
builder.addCapability(spv::CapabilityGroupNonUniformBallot);
861
return spv::BuiltInSubgroupGeMask;
862
863
case glslang::EbvSubgroupGtMask2:
864
builder.addCapability(spv::CapabilityGroupNonUniform);
865
builder.addCapability(spv::CapabilityGroupNonUniformBallot);
866
return spv::BuiltInSubgroupGtMask;
867
868
case glslang::EbvSubgroupLeMask2:
869
builder.addCapability(spv::CapabilityGroupNonUniform);
870
builder.addCapability(spv::CapabilityGroupNonUniformBallot);
871
return spv::BuiltInSubgroupLeMask;
872
873
case glslang::EbvSubgroupLtMask2:
874
builder.addCapability(spv::CapabilityGroupNonUniform);
875
builder.addCapability(spv::CapabilityGroupNonUniformBallot);
876
return spv::BuiltInSubgroupLtMask;
877
878
case glslang::EbvBaryCoordNoPersp:
879
builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
880
return spv::BuiltInBaryCoordNoPerspAMD;
881
882
case glslang::EbvBaryCoordNoPerspCentroid:
883
builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
884
return spv::BuiltInBaryCoordNoPerspCentroidAMD;
885
886
case glslang::EbvBaryCoordNoPerspSample:
887
builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
888
return spv::BuiltInBaryCoordNoPerspSampleAMD;
889
890
case glslang::EbvBaryCoordSmooth:
891
builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
892
return spv::BuiltInBaryCoordSmoothAMD;
893
894
case glslang::EbvBaryCoordSmoothCentroid:
895
builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
896
return spv::BuiltInBaryCoordSmoothCentroidAMD;
897
898
case glslang::EbvBaryCoordSmoothSample:
899
builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
900
return spv::BuiltInBaryCoordSmoothSampleAMD;
901
902
case glslang::EbvBaryCoordPullModel:
903
builder.addExtension(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
904
return spv::BuiltInBaryCoordPullModelAMD;
905
906
case glslang::EbvDeviceIndex:
907
builder.addIncorporatedExtension(spv::E_SPV_KHR_device_group, spv::Spv_1_3);
908
builder.addCapability(spv::CapabilityDeviceGroup);
909
return spv::BuiltInDeviceIndex;
910
911
case glslang::EbvViewIndex:
912
builder.addIncorporatedExtension(spv::E_SPV_KHR_multiview, spv::Spv_1_3);
913
builder.addCapability(spv::CapabilityMultiView);
914
return spv::BuiltInViewIndex;
915
916
case glslang::EbvFragSizeEXT:
917
builder.addExtension(spv::E_SPV_EXT_fragment_invocation_density);
918
builder.addCapability(spv::CapabilityFragmentDensityEXT);
919
return spv::BuiltInFragSizeEXT;
920
921
case glslang::EbvFragInvocationCountEXT:
922
builder.addExtension(spv::E_SPV_EXT_fragment_invocation_density);
923
builder.addCapability(spv::CapabilityFragmentDensityEXT);
924
return spv::BuiltInFragInvocationCountEXT;
925
926
case glslang::EbvViewportMaskNV:
927
if (!memberDeclaration) {
928
builder.addExtension(spv::E_SPV_NV_viewport_array2);
929
builder.addCapability(spv::CapabilityShaderViewportMaskNV);
930
}
931
return spv::BuiltInViewportMaskNV;
932
case glslang::EbvSecondaryPositionNV:
933
if (!memberDeclaration) {
934
builder.addExtension(spv::E_SPV_NV_stereo_view_rendering);
935
builder.addCapability(spv::CapabilityShaderStereoViewNV);
936
}
937
return spv::BuiltInSecondaryPositionNV;
938
case glslang::EbvSecondaryViewportMaskNV:
939
if (!memberDeclaration) {
940
builder.addExtension(spv::E_SPV_NV_stereo_view_rendering);
941
builder.addCapability(spv::CapabilityShaderStereoViewNV);
942
}
943
return spv::BuiltInSecondaryViewportMaskNV;
944
case glslang::EbvPositionPerViewNV:
945
if (!memberDeclaration) {
946
builder.addExtension(spv::E_SPV_NVX_multiview_per_view_attributes);
947
builder.addCapability(spv::CapabilityPerViewAttributesNV);
948
}
949
return spv::BuiltInPositionPerViewNV;
950
case glslang::EbvViewportMaskPerViewNV:
951
if (!memberDeclaration) {
952
builder.addExtension(spv::E_SPV_NVX_multiview_per_view_attributes);
953
builder.addCapability(spv::CapabilityPerViewAttributesNV);
954
}
955
return spv::BuiltInViewportMaskPerViewNV;
956
case glslang::EbvFragFullyCoveredNV:
957
builder.addExtension(spv::E_SPV_EXT_fragment_fully_covered);
958
builder.addCapability(spv::CapabilityFragmentFullyCoveredEXT);
959
return spv::BuiltInFullyCoveredEXT;
960
case glslang::EbvFragmentSizeNV:
961
builder.addExtension(spv::E_SPV_NV_shading_rate);
962
builder.addCapability(spv::CapabilityShadingRateNV);
963
return spv::BuiltInFragmentSizeNV;
964
case glslang::EbvInvocationsPerPixelNV:
965
builder.addExtension(spv::E_SPV_NV_shading_rate);
966
builder.addCapability(spv::CapabilityShadingRateNV);
967
return spv::BuiltInInvocationsPerPixelNV;
968
969
// ray tracing
970
case glslang::EbvLaunchId:
971
return spv::BuiltInLaunchIdKHR;
972
case glslang::EbvLaunchSize:
973
return spv::BuiltInLaunchSizeKHR;
974
case glslang::EbvWorldRayOrigin:
975
return spv::BuiltInWorldRayOriginKHR;
976
case glslang::EbvWorldRayDirection:
977
return spv::BuiltInWorldRayDirectionKHR;
978
case glslang::EbvObjectRayOrigin:
979
return spv::BuiltInObjectRayOriginKHR;
980
case glslang::EbvObjectRayDirection:
981
return spv::BuiltInObjectRayDirectionKHR;
982
case glslang::EbvRayTmin:
983
return spv::BuiltInRayTminKHR;
984
case glslang::EbvRayTmax:
985
return spv::BuiltInRayTmaxKHR;
986
case glslang::EbvCullMask:
987
return spv::BuiltInCullMaskKHR;
988
case glslang::EbvPositionFetch:
989
return spv::BuiltInHitTriangleVertexPositionsKHR;
990
case glslang::EbvInstanceCustomIndex:
991
return spv::BuiltInInstanceCustomIndexKHR;
992
case glslang::EbvHitT:
993
{
994
// this is a GLSL alias of RayTmax
995
// in SPV_NV_ray_tracing it has a dedicated builtin
996
// but in SPV_KHR_ray_tracing it gets mapped to RayTmax
997
auto& extensions = glslangIntermediate->getRequestedExtensions();
998
if (extensions.find("GL_NV_ray_tracing") != extensions.end()) {
999
return spv::BuiltInHitTNV;
1000
} else {
1001
return spv::BuiltInRayTmaxKHR;
1002
}
1003
}
1004
case glslang::EbvHitKind:
1005
return spv::BuiltInHitKindKHR;
1006
case glslang::EbvObjectToWorld:
1007
case glslang::EbvObjectToWorld3x4:
1008
return spv::BuiltInObjectToWorldKHR;
1009
case glslang::EbvWorldToObject:
1010
case glslang::EbvWorldToObject3x4:
1011
return spv::BuiltInWorldToObjectKHR;
1012
case glslang::EbvIncomingRayFlags:
1013
return spv::BuiltInIncomingRayFlagsKHR;
1014
case glslang::EbvGeometryIndex:
1015
return spv::BuiltInRayGeometryIndexKHR;
1016
case glslang::EbvCurrentRayTimeNV:
1017
builder.addExtension(spv::E_SPV_NV_ray_tracing_motion_blur);
1018
builder.addCapability(spv::CapabilityRayTracingMotionBlurNV);
1019
return spv::BuiltInCurrentRayTimeNV;
1020
case glslang::EbvMicroTrianglePositionNV:
1021
builder.addCapability(spv::CapabilityRayTracingDisplacementMicromapNV);
1022
builder.addExtension("SPV_NV_displacement_micromap");
1023
return spv::BuiltInHitMicroTriangleVertexPositionsNV;
1024
case glslang::EbvMicroTriangleBaryNV:
1025
builder.addCapability(spv::CapabilityRayTracingDisplacementMicromapNV);
1026
builder.addExtension("SPV_NV_displacement_micromap");
1027
return spv::BuiltInHitMicroTriangleVertexBarycentricsNV;
1028
case glslang::EbvHitKindFrontFacingMicroTriangleNV:
1029
builder.addCapability(spv::CapabilityRayTracingDisplacementMicromapNV);
1030
builder.addExtension("SPV_NV_displacement_micromap");
1031
return spv::BuiltInHitKindFrontFacingMicroTriangleNV;
1032
case glslang::EbvHitKindBackFacingMicroTriangleNV:
1033
builder.addCapability(spv::CapabilityRayTracingDisplacementMicromapNV);
1034
builder.addExtension("SPV_NV_displacement_micromap");
1035
return spv::BuiltInHitKindBackFacingMicroTriangleNV;
1036
1037
// barycentrics
1038
case glslang::EbvBaryCoordNV:
1039
builder.addExtension(spv::E_SPV_NV_fragment_shader_barycentric);
1040
builder.addCapability(spv::CapabilityFragmentBarycentricNV);
1041
return spv::BuiltInBaryCoordNV;
1042
case glslang::EbvBaryCoordNoPerspNV:
1043
builder.addExtension(spv::E_SPV_NV_fragment_shader_barycentric);
1044
builder.addCapability(spv::CapabilityFragmentBarycentricNV);
1045
return spv::BuiltInBaryCoordNoPerspNV;
1046
1047
case glslang::EbvBaryCoordEXT:
1048
builder.addExtension(spv::E_SPV_KHR_fragment_shader_barycentric);
1049
builder.addCapability(spv::CapabilityFragmentBarycentricKHR);
1050
return spv::BuiltInBaryCoordKHR;
1051
case glslang::EbvBaryCoordNoPerspEXT:
1052
builder.addExtension(spv::E_SPV_KHR_fragment_shader_barycentric);
1053
builder.addCapability(spv::CapabilityFragmentBarycentricKHR);
1054
return spv::BuiltInBaryCoordNoPerspKHR;
1055
1056
// mesh shaders
1057
case glslang::EbvTaskCountNV:
1058
return spv::BuiltInTaskCountNV;
1059
case glslang::EbvPrimitiveCountNV:
1060
return spv::BuiltInPrimitiveCountNV;
1061
case glslang::EbvPrimitiveIndicesNV:
1062
return spv::BuiltInPrimitiveIndicesNV;
1063
case glslang::EbvClipDistancePerViewNV:
1064
return spv::BuiltInClipDistancePerViewNV;
1065
case glslang::EbvCullDistancePerViewNV:
1066
return spv::BuiltInCullDistancePerViewNV;
1067
case glslang::EbvLayerPerViewNV:
1068
return spv::BuiltInLayerPerViewNV;
1069
case glslang::EbvMeshViewCountNV:
1070
return spv::BuiltInMeshViewCountNV;
1071
case glslang::EbvMeshViewIndicesNV:
1072
return spv::BuiltInMeshViewIndicesNV;
1073
1074
// SPV_EXT_mesh_shader
1075
case glslang::EbvPrimitivePointIndicesEXT:
1076
return spv::BuiltInPrimitivePointIndicesEXT;
1077
case glslang::EbvPrimitiveLineIndicesEXT:
1078
return spv::BuiltInPrimitiveLineIndicesEXT;
1079
case glslang::EbvPrimitiveTriangleIndicesEXT:
1080
return spv::BuiltInPrimitiveTriangleIndicesEXT;
1081
case glslang::EbvCullPrimitiveEXT:
1082
return spv::BuiltInCullPrimitiveEXT;
1083
1084
// sm builtins
1085
case glslang::EbvWarpsPerSM:
1086
builder.addExtension(spv::E_SPV_NV_shader_sm_builtins);
1087
builder.addCapability(spv::CapabilityShaderSMBuiltinsNV);
1088
return spv::BuiltInWarpsPerSMNV;
1089
case glslang::EbvSMCount:
1090
builder.addExtension(spv::E_SPV_NV_shader_sm_builtins);
1091
builder.addCapability(spv::CapabilityShaderSMBuiltinsNV);
1092
return spv::BuiltInSMCountNV;
1093
case glslang::EbvWarpID:
1094
builder.addExtension(spv::E_SPV_NV_shader_sm_builtins);
1095
builder.addCapability(spv::CapabilityShaderSMBuiltinsNV);
1096
return spv::BuiltInWarpIDNV;
1097
case glslang::EbvSMID:
1098
builder.addExtension(spv::E_SPV_NV_shader_sm_builtins);
1099
builder.addCapability(spv::CapabilityShaderSMBuiltinsNV);
1100
return spv::BuiltInSMIDNV;
1101
1102
// ARM builtins
1103
case glslang::EbvCoreCountARM:
1104
builder.addExtension(spv::E_SPV_ARM_core_builtins);
1105
builder.addCapability(spv::CapabilityCoreBuiltinsARM);
1106
return spv::BuiltInCoreCountARM;
1107
case glslang::EbvCoreIDARM:
1108
builder.addExtension(spv::E_SPV_ARM_core_builtins);
1109
builder.addCapability(spv::CapabilityCoreBuiltinsARM);
1110
return spv::BuiltInCoreIDARM;
1111
case glslang::EbvCoreMaxIDARM:
1112
builder.addExtension(spv::E_SPV_ARM_core_builtins);
1113
builder.addCapability(spv::CapabilityCoreBuiltinsARM);
1114
return spv::BuiltInCoreMaxIDARM;
1115
case glslang::EbvWarpIDARM:
1116
builder.addExtension(spv::E_SPV_ARM_core_builtins);
1117
builder.addCapability(spv::CapabilityCoreBuiltinsARM);
1118
return spv::BuiltInWarpIDARM;
1119
case glslang::EbvWarpMaxIDARM:
1120
builder.addExtension(spv::E_SPV_ARM_core_builtins);
1121
builder.addCapability(spv::CapabilityCoreBuiltinsARM);
1122
return spv::BuiltInWarpMaxIDARM;
1123
1124
default:
1125
return spv::BuiltInMax;
1126
}
1127
}
1128
1129
// Translate glslang image layout format to SPIR-V image format.
1130
spv::ImageFormat TGlslangToSpvTraverser::TranslateImageFormat(const glslang::TType& type)
1131
{
1132
assert(type.getBasicType() == glslang::EbtSampler);
1133
1134
// Check for capabilities
1135
switch (type.getQualifier().getFormat()) {
1136
case glslang::ElfRg32f:
1137
case glslang::ElfRg16f:
1138
case glslang::ElfR11fG11fB10f:
1139
case glslang::ElfR16f:
1140
case glslang::ElfRgba16:
1141
case glslang::ElfRgb10A2:
1142
case glslang::ElfRg16:
1143
case glslang::ElfRg8:
1144
case glslang::ElfR16:
1145
case glslang::ElfR8:
1146
case glslang::ElfRgba16Snorm:
1147
case glslang::ElfRg16Snorm:
1148
case glslang::ElfRg8Snorm:
1149
case glslang::ElfR16Snorm:
1150
case glslang::ElfR8Snorm:
1151
1152
case glslang::ElfRg32i:
1153
case glslang::ElfRg16i:
1154
case glslang::ElfRg8i:
1155
case glslang::ElfR16i:
1156
case glslang::ElfR8i:
1157
1158
case glslang::ElfRgb10a2ui:
1159
case glslang::ElfRg32ui:
1160
case glslang::ElfRg16ui:
1161
case glslang::ElfRg8ui:
1162
case glslang::ElfR16ui:
1163
case glslang::ElfR8ui:
1164
builder.addCapability(spv::CapabilityStorageImageExtendedFormats);
1165
break;
1166
1167
case glslang::ElfR64ui:
1168
case glslang::ElfR64i:
1169
builder.addExtension(spv::E_SPV_EXT_shader_image_int64);
1170
builder.addCapability(spv::CapabilityInt64ImageEXT);
1171
break;
1172
default:
1173
break;
1174
}
1175
1176
// do the translation
1177
switch (type.getQualifier().getFormat()) {
1178
case glslang::ElfNone: return spv::ImageFormatUnknown;
1179
case glslang::ElfRgba32f: return spv::ImageFormatRgba32f;
1180
case glslang::ElfRgba16f: return spv::ImageFormatRgba16f;
1181
case glslang::ElfR32f: return spv::ImageFormatR32f;
1182
case glslang::ElfRgba8: return spv::ImageFormatRgba8;
1183
case glslang::ElfRgba8Snorm: return spv::ImageFormatRgba8Snorm;
1184
case glslang::ElfRg32f: return spv::ImageFormatRg32f;
1185
case glslang::ElfRg16f: return spv::ImageFormatRg16f;
1186
case glslang::ElfR11fG11fB10f: return spv::ImageFormatR11fG11fB10f;
1187
case glslang::ElfR16f: return spv::ImageFormatR16f;
1188
case glslang::ElfRgba16: return spv::ImageFormatRgba16;
1189
case glslang::ElfRgb10A2: return spv::ImageFormatRgb10A2;
1190
case glslang::ElfRg16: return spv::ImageFormatRg16;
1191
case glslang::ElfRg8: return spv::ImageFormatRg8;
1192
case glslang::ElfR16: return spv::ImageFormatR16;
1193
case glslang::ElfR8: return spv::ImageFormatR8;
1194
case glslang::ElfRgba16Snorm: return spv::ImageFormatRgba16Snorm;
1195
case glslang::ElfRg16Snorm: return spv::ImageFormatRg16Snorm;
1196
case glslang::ElfRg8Snorm: return spv::ImageFormatRg8Snorm;
1197
case glslang::ElfR16Snorm: return spv::ImageFormatR16Snorm;
1198
case glslang::ElfR8Snorm: return spv::ImageFormatR8Snorm;
1199
case glslang::ElfRgba32i: return spv::ImageFormatRgba32i;
1200
case glslang::ElfRgba16i: return spv::ImageFormatRgba16i;
1201
case glslang::ElfRgba8i: return spv::ImageFormatRgba8i;
1202
case glslang::ElfR32i: return spv::ImageFormatR32i;
1203
case glslang::ElfRg32i: return spv::ImageFormatRg32i;
1204
case glslang::ElfRg16i: return spv::ImageFormatRg16i;
1205
case glslang::ElfRg8i: return spv::ImageFormatRg8i;
1206
case glslang::ElfR16i: return spv::ImageFormatR16i;
1207
case glslang::ElfR8i: return spv::ImageFormatR8i;
1208
case glslang::ElfRgba32ui: return spv::ImageFormatRgba32ui;
1209
case glslang::ElfRgba16ui: return spv::ImageFormatRgba16ui;
1210
case glslang::ElfRgba8ui: return spv::ImageFormatRgba8ui;
1211
case glslang::ElfR32ui: return spv::ImageFormatR32ui;
1212
case glslang::ElfRg32ui: return spv::ImageFormatRg32ui;
1213
case glslang::ElfRg16ui: return spv::ImageFormatRg16ui;
1214
case glslang::ElfRgb10a2ui: return spv::ImageFormatRgb10a2ui;
1215
case glslang::ElfRg8ui: return spv::ImageFormatRg8ui;
1216
case glslang::ElfR16ui: return spv::ImageFormatR16ui;
1217
case glslang::ElfR8ui: return spv::ImageFormatR8ui;
1218
case glslang::ElfR64ui: return spv::ImageFormatR64ui;
1219
case glslang::ElfR64i: return spv::ImageFormatR64i;
1220
default: return spv::ImageFormatMax;
1221
}
1222
}
1223
1224
spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSelectionControl(
1225
const glslang::TIntermSelection& selectionNode) const
1226
{
1227
if (selectionNode.getFlatten())
1228
return spv::SelectionControlFlattenMask;
1229
if (selectionNode.getDontFlatten())
1230
return spv::SelectionControlDontFlattenMask;
1231
return spv::SelectionControlMaskNone;
1232
}
1233
1234
spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSwitchControl(const glslang::TIntermSwitch& switchNode)
1235
const
1236
{
1237
if (switchNode.getFlatten())
1238
return spv::SelectionControlFlattenMask;
1239
if (switchNode.getDontFlatten())
1240
return spv::SelectionControlDontFlattenMask;
1241
return spv::SelectionControlMaskNone;
1242
}
1243
1244
// return a non-0 dependency if the dependency argument must be set
1245
spv::LoopControlMask TGlslangToSpvTraverser::TranslateLoopControl(const glslang::TIntermLoop& loopNode,
1246
std::vector<unsigned int>& operands) const
1247
{
1248
spv::LoopControlMask control = spv::LoopControlMaskNone;
1249
1250
if (loopNode.getDontUnroll())
1251
control = control | spv::LoopControlDontUnrollMask;
1252
if (loopNode.getUnroll())
1253
control = control | spv::LoopControlUnrollMask;
1254
if (unsigned(loopNode.getLoopDependency()) == glslang::TIntermLoop::dependencyInfinite)
1255
control = control | spv::LoopControlDependencyInfiniteMask;
1256
else if (loopNode.getLoopDependency() > 0) {
1257
control = control | spv::LoopControlDependencyLengthMask;
1258
operands.push_back((unsigned int)loopNode.getLoopDependency());
1259
}
1260
if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_4) {
1261
if (loopNode.getMinIterations() > 0) {
1262
control = control | spv::LoopControlMinIterationsMask;
1263
operands.push_back(loopNode.getMinIterations());
1264
}
1265
if (loopNode.getMaxIterations() < glslang::TIntermLoop::iterationsInfinite) {
1266
control = control | spv::LoopControlMaxIterationsMask;
1267
operands.push_back(loopNode.getMaxIterations());
1268
}
1269
if (loopNode.getIterationMultiple() > 1) {
1270
control = control | spv::LoopControlIterationMultipleMask;
1271
operands.push_back(loopNode.getIterationMultiple());
1272
}
1273
if (loopNode.getPeelCount() > 0) {
1274
control = control | spv::LoopControlPeelCountMask;
1275
operands.push_back(loopNode.getPeelCount());
1276
}
1277
if (loopNode.getPartialCount() > 0) {
1278
control = control | spv::LoopControlPartialCountMask;
1279
operands.push_back(loopNode.getPartialCount());
1280
}
1281
}
1282
1283
return control;
1284
}
1285
1286
// Translate glslang type to SPIR-V storage class.
1287
spv::StorageClass TGlslangToSpvTraverser::TranslateStorageClass(const glslang::TType& type)
1288
{
1289
if (type.getBasicType() == glslang::EbtRayQuery || type.getBasicType() == glslang::EbtHitObjectNV)
1290
return spv::StorageClassPrivate;
1291
if (type.getQualifier().isSpirvByReference()) {
1292
if (type.getQualifier().isParamInput() || type.getQualifier().isParamOutput())
1293
return spv::StorageClassFunction;
1294
}
1295
if (type.getQualifier().isPipeInput())
1296
return spv::StorageClassInput;
1297
if (type.getQualifier().isPipeOutput())
1298
return spv::StorageClassOutput;
1299
if (type.getQualifier().storage == glslang::EvqTileImageEXT || type.isAttachmentEXT()) {
1300
builder.addExtension(spv::E_SPV_EXT_shader_tile_image);
1301
builder.addCapability(spv::CapabilityTileImageColorReadAccessEXT);
1302
return spv::StorageClassTileImageEXT;
1303
}
1304
1305
if (glslangIntermediate->getSource() != glslang::EShSourceHlsl ||
1306
type.getQualifier().storage == glslang::EvqUniform) {
1307
if (type.isAtomic())
1308
return spv::StorageClassAtomicCounter;
1309
if (type.containsOpaque() && !glslangIntermediate->getBindlessMode())
1310
return spv::StorageClassUniformConstant;
1311
}
1312
1313
if (type.getQualifier().isUniformOrBuffer() &&
1314
type.getQualifier().isShaderRecord()) {
1315
return spv::StorageClassShaderRecordBufferKHR;
1316
}
1317
1318
if (glslangIntermediate->usingStorageBuffer() && type.getQualifier().storage == glslang::EvqBuffer) {
1319
builder.addIncorporatedExtension(spv::E_SPV_KHR_storage_buffer_storage_class, spv::Spv_1_3);
1320
return spv::StorageClassStorageBuffer;
1321
}
1322
1323
if (type.getQualifier().isUniformOrBuffer()) {
1324
if (type.getQualifier().isPushConstant())
1325
return spv::StorageClassPushConstant;
1326
if (type.getBasicType() == glslang::EbtBlock)
1327
return spv::StorageClassUniform;
1328
return spv::StorageClassUniformConstant;
1329
}
1330
1331
if (type.getQualifier().storage == glslang::EvqShared && type.getBasicType() == glslang::EbtBlock) {
1332
builder.addExtension(spv::E_SPV_KHR_workgroup_memory_explicit_layout);
1333
builder.addCapability(spv::CapabilityWorkgroupMemoryExplicitLayoutKHR);
1334
return spv::StorageClassWorkgroup;
1335
}
1336
1337
switch (type.getQualifier().storage) {
1338
case glslang::EvqGlobal: return spv::StorageClassPrivate;
1339
case glslang::EvqConstReadOnly: return spv::StorageClassFunction;
1340
case glslang::EvqTemporary: return spv::StorageClassFunction;
1341
case glslang::EvqShared: return spv::StorageClassWorkgroup;
1342
case glslang::EvqPayload: return spv::StorageClassRayPayloadKHR;
1343
case glslang::EvqPayloadIn: return spv::StorageClassIncomingRayPayloadKHR;
1344
case glslang::EvqHitAttr: return spv::StorageClassHitAttributeKHR;
1345
case glslang::EvqCallableData: return spv::StorageClassCallableDataKHR;
1346
case glslang::EvqCallableDataIn: return spv::StorageClassIncomingCallableDataKHR;
1347
case glslang::EvqtaskPayloadSharedEXT : return spv::StorageClassTaskPayloadWorkgroupEXT;
1348
case glslang::EvqHitObjectAttrNV: return spv::StorageClassHitObjectAttributeNV;
1349
case glslang::EvqSpirvStorageClass: return static_cast<spv::StorageClass>(type.getQualifier().spirvStorageClass);
1350
default:
1351
assert(0);
1352
break;
1353
}
1354
1355
return spv::StorageClassFunction;
1356
}
1357
1358
// Translate glslang constants to SPIR-V literals
1359
void TGlslangToSpvTraverser::TranslateLiterals(const glslang::TVector<const glslang::TIntermConstantUnion*>& constants,
1360
std::vector<unsigned>& literals) const
1361
{
1362
for (auto constant : constants) {
1363
if (constant->getBasicType() == glslang::EbtFloat) {
1364
float floatValue = static_cast<float>(constant->getConstArray()[0].getDConst());
1365
unsigned literal;
1366
static_assert(sizeof(literal) == sizeof(floatValue), "sizeof(unsigned) != sizeof(float)");
1367
memcpy(&literal, &floatValue, sizeof(literal));
1368
literals.push_back(literal);
1369
} else if (constant->getBasicType() == glslang::EbtInt) {
1370
unsigned literal = constant->getConstArray()[0].getIConst();
1371
literals.push_back(literal);
1372
} else if (constant->getBasicType() == glslang::EbtUint) {
1373
unsigned literal = constant->getConstArray()[0].getUConst();
1374
literals.push_back(literal);
1375
} else if (constant->getBasicType() == glslang::EbtBool) {
1376
unsigned literal = constant->getConstArray()[0].getBConst();
1377
literals.push_back(literal);
1378
} else if (constant->getBasicType() == glslang::EbtString) {
1379
auto str = constant->getConstArray()[0].getSConst()->c_str();
1380
unsigned literal = 0;
1381
char* literalPtr = reinterpret_cast<char*>(&literal);
1382
unsigned charCount = 0;
1383
char ch = 0;
1384
do {
1385
ch = *(str++);
1386
*(literalPtr++) = ch;
1387
++charCount;
1388
if (charCount == 4) {
1389
literals.push_back(literal);
1390
literalPtr = reinterpret_cast<char*>(&literal);
1391
charCount = 0;
1392
}
1393
} while (ch != 0);
1394
1395
// Partial literal is padded with 0
1396
if (charCount > 0) {
1397
for (; charCount < 4; ++charCount)
1398
*(literalPtr++) = 0;
1399
literals.push_back(literal);
1400
}
1401
} else
1402
assert(0); // Unexpected type
1403
}
1404
}
1405
1406
// Add capabilities pertaining to how an array is indexed.
1407
void TGlslangToSpvTraverser::addIndirectionIndexCapabilities(const glslang::TType& baseType,
1408
const glslang::TType& indexType)
1409
{
1410
if (indexType.getQualifier().isNonUniform()) {
1411
// deal with an asserted non-uniform index
1412
// SPV_EXT_descriptor_indexing already added in TranslateNonUniformDecoration
1413
if (baseType.getBasicType() == glslang::EbtSampler) {
1414
if (baseType.getQualifier().hasAttachment())
1415
builder.addCapability(spv::CapabilityInputAttachmentArrayNonUniformIndexingEXT);
1416
else if (baseType.isImage() && baseType.getSampler().isBuffer())
1417
builder.addCapability(spv::CapabilityStorageTexelBufferArrayNonUniformIndexingEXT);
1418
else if (baseType.isTexture() && baseType.getSampler().isBuffer())
1419
builder.addCapability(spv::CapabilityUniformTexelBufferArrayNonUniformIndexingEXT);
1420
else if (baseType.isImage())
1421
builder.addCapability(spv::CapabilityStorageImageArrayNonUniformIndexingEXT);
1422
else if (baseType.isTexture())
1423
builder.addCapability(spv::CapabilitySampledImageArrayNonUniformIndexingEXT);
1424
} else if (baseType.getBasicType() == glslang::EbtBlock) {
1425
if (baseType.getQualifier().storage == glslang::EvqBuffer)
1426
builder.addCapability(spv::CapabilityStorageBufferArrayNonUniformIndexingEXT);
1427
else if (baseType.getQualifier().storage == glslang::EvqUniform)
1428
builder.addCapability(spv::CapabilityUniformBufferArrayNonUniformIndexingEXT);
1429
}
1430
} else {
1431
// assume a dynamically uniform index
1432
if (baseType.getBasicType() == glslang::EbtSampler) {
1433
if (baseType.getQualifier().hasAttachment()) {
1434
builder.addIncorporatedExtension("SPV_EXT_descriptor_indexing", spv::Spv_1_5);
1435
builder.addCapability(spv::CapabilityInputAttachmentArrayDynamicIndexingEXT);
1436
} else if (baseType.isImage() && baseType.getSampler().isBuffer()) {
1437
builder.addIncorporatedExtension("SPV_EXT_descriptor_indexing", spv::Spv_1_5);
1438
builder.addCapability(spv::CapabilityStorageTexelBufferArrayDynamicIndexingEXT);
1439
} else if (baseType.isTexture() && baseType.getSampler().isBuffer()) {
1440
builder.addIncorporatedExtension("SPV_EXT_descriptor_indexing", spv::Spv_1_5);
1441
builder.addCapability(spv::CapabilityUniformTexelBufferArrayDynamicIndexingEXT);
1442
}
1443
}
1444
}
1445
}
1446
1447
// Return whether or not the given type is something that should be tied to a
1448
// descriptor set.
1449
bool IsDescriptorResource(const glslang::TType& type)
1450
{
1451
// uniform and buffer blocks are included, unless it is a push_constant
1452
if (type.getBasicType() == glslang::EbtBlock)
1453
return type.getQualifier().isUniformOrBuffer() &&
1454
! type.getQualifier().isShaderRecord() &&
1455
! type.getQualifier().isPushConstant();
1456
1457
// non block...
1458
// basically samplerXXX/subpass/sampler/texture are all included
1459
// if they are the global-scope-class, not the function parameter
1460
// (or local, if they ever exist) class.
1461
if (type.getBasicType() == glslang::EbtSampler ||
1462
type.getBasicType() == glslang::EbtAccStruct)
1463
return type.getQualifier().isUniformOrBuffer();
1464
1465
// None of the above.
1466
return false;
1467
}
1468
1469
void InheritQualifiers(glslang::TQualifier& child, const glslang::TQualifier& parent)
1470
{
1471
if (child.layoutMatrix == glslang::ElmNone)
1472
child.layoutMatrix = parent.layoutMatrix;
1473
1474
if (parent.invariant)
1475
child.invariant = true;
1476
if (parent.flat)
1477
child.flat = true;
1478
if (parent.centroid)
1479
child.centroid = true;
1480
if (parent.nopersp)
1481
child.nopersp = true;
1482
if (parent.explicitInterp)
1483
child.explicitInterp = true;
1484
if (parent.perPrimitiveNV)
1485
child.perPrimitiveNV = true;
1486
if (parent.perViewNV)
1487
child.perViewNV = true;
1488
if (parent.perTaskNV)
1489
child.perTaskNV = true;
1490
if (parent.storage == glslang::EvqtaskPayloadSharedEXT)
1491
child.storage = glslang::EvqtaskPayloadSharedEXT;
1492
if (parent.patch)
1493
child.patch = true;
1494
if (parent.sample)
1495
child.sample = true;
1496
if (parent.coherent)
1497
child.coherent = true;
1498
if (parent.devicecoherent)
1499
child.devicecoherent = true;
1500
if (parent.queuefamilycoherent)
1501
child.queuefamilycoherent = true;
1502
if (parent.workgroupcoherent)
1503
child.workgroupcoherent = true;
1504
if (parent.subgroupcoherent)
1505
child.subgroupcoherent = true;
1506
if (parent.shadercallcoherent)
1507
child.shadercallcoherent = true;
1508
if (parent.nonprivate)
1509
child.nonprivate = true;
1510
if (parent.volatil)
1511
child.volatil = true;
1512
if (parent.restrict)
1513
child.restrict = true;
1514
if (parent.readonly)
1515
child.readonly = true;
1516
if (parent.writeonly)
1517
child.writeonly = true;
1518
if (parent.nonUniform)
1519
child.nonUniform = true;
1520
}
1521
1522
bool HasNonLayoutQualifiers(const glslang::TType& type, const glslang::TQualifier& qualifier)
1523
{
1524
// This should list qualifiers that simultaneous satisfy:
1525
// - struct members might inherit from a struct declaration
1526
// (note that non-block structs don't explicitly inherit,
1527
// only implicitly, meaning no decoration involved)
1528
// - affect decorations on the struct members
1529
// (note smooth does not, and expecting something like volatile
1530
// to effect the whole object)
1531
// - are not part of the offset/st430/etc or row/column-major layout
1532
return qualifier.invariant || (qualifier.hasLocation() && type.getBasicType() == glslang::EbtBlock);
1533
}
1534
1535
//
1536
// Implement the TGlslangToSpvTraverser class.
1537
//
1538
1539
TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion,
1540
const glslang::TIntermediate* glslangIntermediate,
1541
spv::SpvBuildLogger* buildLogger, glslang::SpvOptions& options) :
1542
TIntermTraverser(true, false, true),
1543
options(options),
1544
shaderEntry(nullptr), currentFunction(nullptr),
1545
sequenceDepth(0), logger(buildLogger),
1546
builder(spvVersion, (glslang::GetKhronosToolId() << 16) | glslang::GetSpirvGeneratorVersion(), logger),
1547
inEntryPoint(false), entryPointTerminated(false), linkageOnly(false),
1548
glslangIntermediate(glslangIntermediate),
1549
nanMinMaxClamp(glslangIntermediate->getNanMinMaxClamp()),
1550
nonSemanticDebugPrintf(0),
1551
taskPayloadID(0)
1552
{
1553
bool isMeshShaderExt = (glslangIntermediate->getRequestedExtensions().find(glslang::E_GL_EXT_mesh_shader) !=
1554
glslangIntermediate->getRequestedExtensions().end());
1555
spv::ExecutionModel executionModel = TranslateExecutionModel(glslangIntermediate->getStage(), isMeshShaderExt);
1556
1557
builder.clearAccessChain();
1558
builder.setSource(TranslateSourceLanguage(glslangIntermediate->getSource(), glslangIntermediate->getProfile()),
1559
glslangIntermediate->getVersion());
1560
1561
if (options.emitNonSemanticShaderDebugSource)
1562
this->options.emitNonSemanticShaderDebugInfo = true;
1563
if (options.emitNonSemanticShaderDebugInfo)
1564
this->options.generateDebugInfo = true;
1565
1566
if (this->options.generateDebugInfo) {
1567
if (this->options.emitNonSemanticShaderDebugInfo) {
1568
builder.setEmitNonSemanticShaderDebugInfo(this->options.emitNonSemanticShaderDebugSource);
1569
}
1570
else {
1571
builder.setEmitSpirvDebugInfo();
1572
}
1573
builder.setDebugSourceFile(glslangIntermediate->getSourceFile());
1574
1575
// Set the source shader's text. If for SPV version 1.0, include
1576
// a preamble in comments stating the OpModuleProcessed instructions.
1577
// Otherwise, emit those as actual instructions.
1578
std::string text;
1579
const std::vector<std::string>& processes = glslangIntermediate->getProcesses();
1580
for (int p = 0; p < (int)processes.size(); ++p) {
1581
if (glslangIntermediate->getSpv().spv < glslang::EShTargetSpv_1_1) {
1582
text.append("// OpModuleProcessed ");
1583
text.append(processes[p]);
1584
text.append("\n");
1585
} else
1586
builder.addModuleProcessed(processes[p]);
1587
}
1588
if (glslangIntermediate->getSpv().spv < glslang::EShTargetSpv_1_1 && (int)processes.size() > 0)
1589
text.append("#line 1\n");
1590
text.append(glslangIntermediate->getSourceText());
1591
builder.setSourceText(text);
1592
// Pass name and text for all included files
1593
const std::map<std::string, std::string>& include_txt = glslangIntermediate->getIncludeText();
1594
for (auto iItr = include_txt.begin(); iItr != include_txt.end(); ++iItr)
1595
builder.addInclude(iItr->first, iItr->second);
1596
}
1597
1598
stdBuiltins = builder.import("GLSL.std.450");
1599
1600
spv::AddressingModel addressingModel = spv::AddressingModelLogical;
1601
spv::MemoryModel memoryModel = spv::MemoryModelGLSL450;
1602
1603
if (glslangIntermediate->usingPhysicalStorageBuffer()) {
1604
addressingModel = spv::AddressingModelPhysicalStorageBuffer64EXT;
1605
builder.addIncorporatedExtension(spv::E_SPV_KHR_physical_storage_buffer, spv::Spv_1_5);
1606
builder.addCapability(spv::CapabilityPhysicalStorageBufferAddressesEXT);
1607
}
1608
if (glslangIntermediate->usingVulkanMemoryModel()) {
1609
memoryModel = spv::MemoryModelVulkanKHR;
1610
builder.addCapability(spv::CapabilityVulkanMemoryModelKHR);
1611
builder.addIncorporatedExtension(spv::E_SPV_KHR_vulkan_memory_model, spv::Spv_1_5);
1612
}
1613
builder.setMemoryModel(addressingModel, memoryModel);
1614
1615
if (glslangIntermediate->usingVariablePointers()) {
1616
builder.addCapability(spv::CapabilityVariablePointers);
1617
}
1618
1619
// If not linking, there is no entry point
1620
if (!options.compileOnly) {
1621
shaderEntry = builder.makeEntryPoint(glslangIntermediate->getEntryPointName().c_str());
1622
entryPoint =
1623
builder.addEntryPoint(executionModel, shaderEntry, glslangIntermediate->getEntryPointName().c_str());
1624
}
1625
1626
// Add the source extensions
1627
const auto& sourceExtensions = glslangIntermediate->getRequestedExtensions();
1628
for (auto it = sourceExtensions.begin(); it != sourceExtensions.end(); ++it)
1629
builder.addSourceExtension(it->c_str());
1630
1631
// Add the top-level modes for this shader.
1632
1633
if (glslangIntermediate->getXfbMode()) {
1634
builder.addCapability(spv::CapabilityTransformFeedback);
1635
builder.addExecutionMode(shaderEntry, spv::ExecutionModeXfb);
1636
}
1637
1638
if (glslangIntermediate->getLayoutPrimitiveCulling()) {
1639
builder.addCapability(spv::CapabilityRayTraversalPrimitiveCullingKHR);
1640
}
1641
1642
if (glslangIntermediate->getSubgroupUniformControlFlow()) {
1643
builder.addExtension(spv::E_SPV_KHR_subgroup_uniform_control_flow);
1644
builder.addExecutionMode(shaderEntry, spv::ExecutionModeSubgroupUniformControlFlowKHR);
1645
}
1646
if (glslangIntermediate->getMaximallyReconverges()) {
1647
builder.addExtension(spv::E_SPV_KHR_maximal_reconvergence);
1648
builder.addExecutionMode(shaderEntry, spv::ExecutionModeMaximallyReconvergesKHR);
1649
}
1650
1651
if (glslangIntermediate->getQuadDerivMode())
1652
{
1653
builder.addCapability(spv::CapabilityQuadControlKHR);
1654
builder.addExtension(spv::E_SPV_KHR_quad_control);
1655
builder.addExecutionMode(shaderEntry, spv::ExecutionModeQuadDerivativesKHR);
1656
}
1657
1658
if (glslangIntermediate->getReqFullQuadsMode())
1659
{
1660
builder.addCapability(spv::CapabilityQuadControlKHR);
1661
builder.addExtension(spv::E_SPV_KHR_quad_control);
1662
builder.addExecutionMode(shaderEntry, spv::ExecutionModeRequireFullQuadsKHR);
1663
}
1664
1665
unsigned int mode;
1666
switch (glslangIntermediate->getStage()) {
1667
case EShLangVertex:
1668
builder.addCapability(spv::CapabilityShader);
1669
break;
1670
1671
case EShLangFragment:
1672
builder.addCapability(spv::CapabilityShader);
1673
if (glslangIntermediate->getPixelCenterInteger())
1674
builder.addExecutionMode(shaderEntry, spv::ExecutionModePixelCenterInteger);
1675
1676
if (glslangIntermediate->getOriginUpperLeft())
1677
builder.addExecutionMode(shaderEntry, spv::ExecutionModeOriginUpperLeft);
1678
else
1679
builder.addExecutionMode(shaderEntry, spv::ExecutionModeOriginLowerLeft);
1680
1681
if (glslangIntermediate->getEarlyFragmentTests())
1682
builder.addExecutionMode(shaderEntry, spv::ExecutionModeEarlyFragmentTests);
1683
1684
if (glslangIntermediate->getEarlyAndLateFragmentTestsAMD())
1685
{
1686
builder.addExecutionMode(shaderEntry, spv::ExecutionModeEarlyAndLateFragmentTestsAMD);
1687
builder.addExtension(spv::E_SPV_AMD_shader_early_and_late_fragment_tests);
1688
}
1689
1690
if (glslangIntermediate->getPostDepthCoverage()) {
1691
builder.addCapability(spv::CapabilitySampleMaskPostDepthCoverage);
1692
builder.addExecutionMode(shaderEntry, spv::ExecutionModePostDepthCoverage);
1693
builder.addExtension(spv::E_SPV_KHR_post_depth_coverage);
1694
}
1695
1696
if (glslangIntermediate->getNonCoherentColorAttachmentReadEXT()) {
1697
builder.addCapability(spv::CapabilityTileImageColorReadAccessEXT);
1698
builder.addExecutionMode(shaderEntry, spv::ExecutionModeNonCoherentColorAttachmentReadEXT);
1699
builder.addExtension(spv::E_SPV_EXT_shader_tile_image);
1700
}
1701
1702
if (glslangIntermediate->getNonCoherentDepthAttachmentReadEXT()) {
1703
builder.addCapability(spv::CapabilityTileImageDepthReadAccessEXT);
1704
builder.addExecutionMode(shaderEntry, spv::ExecutionModeNonCoherentDepthAttachmentReadEXT);
1705
builder.addExtension(spv::E_SPV_EXT_shader_tile_image);
1706
}
1707
1708
if (glslangIntermediate->getNonCoherentStencilAttachmentReadEXT()) {
1709
builder.addCapability(spv::CapabilityTileImageStencilReadAccessEXT);
1710
builder.addExecutionMode(shaderEntry, spv::ExecutionModeNonCoherentStencilAttachmentReadEXT);
1711
builder.addExtension(spv::E_SPV_EXT_shader_tile_image);
1712
}
1713
1714
if (glslangIntermediate->isDepthReplacing())
1715
builder.addExecutionMode(shaderEntry, spv::ExecutionModeDepthReplacing);
1716
1717
if (glslangIntermediate->isStencilReplacing())
1718
builder.addExecutionMode(shaderEntry, spv::ExecutionModeStencilRefReplacingEXT);
1719
1720
switch(glslangIntermediate->getDepth()) {
1721
case glslang::EldGreater: mode = spv::ExecutionModeDepthGreater; break;
1722
case glslang::EldLess: mode = spv::ExecutionModeDepthLess; break;
1723
case glslang::EldUnchanged: mode = spv::ExecutionModeDepthUnchanged; break;
1724
default: mode = spv::ExecutionModeMax; break;
1725
}
1726
1727
if (mode != spv::ExecutionModeMax)
1728
builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
1729
1730
switch (glslangIntermediate->getStencil()) {
1731
case glslang::ElsRefUnchangedFrontAMD: mode = spv::ExecutionModeStencilRefUnchangedFrontAMD; break;
1732
case glslang::ElsRefGreaterFrontAMD: mode = spv::ExecutionModeStencilRefGreaterFrontAMD; break;
1733
case glslang::ElsRefLessFrontAMD: mode = spv::ExecutionModeStencilRefLessFrontAMD; break;
1734
case glslang::ElsRefUnchangedBackAMD: mode = spv::ExecutionModeStencilRefUnchangedBackAMD; break;
1735
case glslang::ElsRefGreaterBackAMD: mode = spv::ExecutionModeStencilRefGreaterBackAMD; break;
1736
case glslang::ElsRefLessBackAMD: mode = spv::ExecutionModeStencilRefLessBackAMD; break;
1737
default: mode = spv::ExecutionModeMax; break;
1738
}
1739
1740
if (mode != spv::ExecutionModeMax)
1741
builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
1742
switch (glslangIntermediate->getInterlockOrdering()) {
1743
case glslang::EioPixelInterlockOrdered: mode = spv::ExecutionModePixelInterlockOrderedEXT;
1744
break;
1745
case glslang::EioPixelInterlockUnordered: mode = spv::ExecutionModePixelInterlockUnorderedEXT;
1746
break;
1747
case glslang::EioSampleInterlockOrdered: mode = spv::ExecutionModeSampleInterlockOrderedEXT;
1748
break;
1749
case glslang::EioSampleInterlockUnordered: mode = spv::ExecutionModeSampleInterlockUnorderedEXT;
1750
break;
1751
case glslang::EioShadingRateInterlockOrdered: mode = spv::ExecutionModeShadingRateInterlockOrderedEXT;
1752
break;
1753
case glslang::EioShadingRateInterlockUnordered: mode = spv::ExecutionModeShadingRateInterlockUnorderedEXT;
1754
break;
1755
default: mode = spv::ExecutionModeMax;
1756
break;
1757
}
1758
if (mode != spv::ExecutionModeMax) {
1759
builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
1760
if (mode == spv::ExecutionModeShadingRateInterlockOrderedEXT ||
1761
mode == spv::ExecutionModeShadingRateInterlockUnorderedEXT) {
1762
builder.addCapability(spv::CapabilityFragmentShaderShadingRateInterlockEXT);
1763
} else if (mode == spv::ExecutionModePixelInterlockOrderedEXT ||
1764
mode == spv::ExecutionModePixelInterlockUnorderedEXT) {
1765
builder.addCapability(spv::CapabilityFragmentShaderPixelInterlockEXT);
1766
} else {
1767
builder.addCapability(spv::CapabilityFragmentShaderSampleInterlockEXT);
1768
}
1769
builder.addExtension(spv::E_SPV_EXT_fragment_shader_interlock);
1770
}
1771
break;
1772
1773
case EShLangCompute: {
1774
builder.addCapability(spv::CapabilityShader);
1775
bool needSizeId = false;
1776
for (int dim = 0; dim < 3; ++dim) {
1777
if ((glslangIntermediate->getLocalSizeSpecId(dim) != glslang::TQualifier::layoutNotSet)) {
1778
needSizeId = true;
1779
break;
1780
}
1781
}
1782
if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_6 && needSizeId) {
1783
std::vector<spv::Id> dimConstId;
1784
for (int dim = 0; dim < 3; ++dim) {
1785
bool specConst = (glslangIntermediate->getLocalSizeSpecId(dim) != glslang::TQualifier::layoutNotSet);
1786
dimConstId.push_back(builder.makeUintConstant(glslangIntermediate->getLocalSize(dim), specConst));
1787
if (specConst) {
1788
builder.addDecoration(dimConstId.back(), spv::DecorationSpecId,
1789
glslangIntermediate->getLocalSizeSpecId(dim));
1790
needSizeId = true;
1791
}
1792
}
1793
builder.addExecutionModeId(shaderEntry, spv::ExecutionModeLocalSizeId, dimConstId);
1794
} else {
1795
builder.addExecutionMode(shaderEntry, spv::ExecutionModeLocalSize, glslangIntermediate->getLocalSize(0),
1796
glslangIntermediate->getLocalSize(1),
1797
glslangIntermediate->getLocalSize(2));
1798
}
1799
if (glslangIntermediate->getLayoutDerivativeModeNone() == glslang::LayoutDerivativeGroupQuads) {
1800
builder.addCapability(spv::CapabilityComputeDerivativeGroupQuadsNV);
1801
builder.addExecutionMode(shaderEntry, spv::ExecutionModeDerivativeGroupQuadsNV);
1802
builder.addExtension(spv::E_SPV_NV_compute_shader_derivatives);
1803
} else if (glslangIntermediate->getLayoutDerivativeModeNone() == glslang::LayoutDerivativeGroupLinear) {
1804
builder.addCapability(spv::CapabilityComputeDerivativeGroupLinearNV);
1805
builder.addExecutionMode(shaderEntry, spv::ExecutionModeDerivativeGroupLinearNV);
1806
builder.addExtension(spv::E_SPV_NV_compute_shader_derivatives);
1807
}
1808
break;
1809
}
1810
case EShLangTessEvaluation:
1811
case EShLangTessControl:
1812
builder.addCapability(spv::CapabilityTessellation);
1813
1814
glslang::TLayoutGeometry primitive;
1815
1816
if (glslangIntermediate->getStage() == EShLangTessControl) {
1817
builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices,
1818
glslangIntermediate->getVertices());
1819
primitive = glslangIntermediate->getOutputPrimitive();
1820
} else {
1821
primitive = glslangIntermediate->getInputPrimitive();
1822
}
1823
1824
switch (primitive) {
1825
case glslang::ElgTriangles: mode = spv::ExecutionModeTriangles; break;
1826
case glslang::ElgQuads: mode = spv::ExecutionModeQuads; break;
1827
case glslang::ElgIsolines: mode = spv::ExecutionModeIsolines; break;
1828
default: mode = spv::ExecutionModeMax; break;
1829
}
1830
if (mode != spv::ExecutionModeMax)
1831
builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
1832
1833
switch (glslangIntermediate->getVertexSpacing()) {
1834
case glslang::EvsEqual: mode = spv::ExecutionModeSpacingEqual; break;
1835
case glslang::EvsFractionalEven: mode = spv::ExecutionModeSpacingFractionalEven; break;
1836
case glslang::EvsFractionalOdd: mode = spv::ExecutionModeSpacingFractionalOdd; break;
1837
default: mode = spv::ExecutionModeMax; break;
1838
}
1839
if (mode != spv::ExecutionModeMax)
1840
builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
1841
1842
switch (glslangIntermediate->getVertexOrder()) {
1843
case glslang::EvoCw: mode = spv::ExecutionModeVertexOrderCw; break;
1844
case glslang::EvoCcw: mode = spv::ExecutionModeVertexOrderCcw; break;
1845
default: mode = spv::ExecutionModeMax; break;
1846
}
1847
if (mode != spv::ExecutionModeMax)
1848
builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
1849
1850
if (glslangIntermediate->getPointMode())
1851
builder.addExecutionMode(shaderEntry, spv::ExecutionModePointMode);
1852
break;
1853
1854
case EShLangGeometry:
1855
builder.addCapability(spv::CapabilityGeometry);
1856
switch (glslangIntermediate->getInputPrimitive()) {
1857
case glslang::ElgPoints: mode = spv::ExecutionModeInputPoints; break;
1858
case glslang::ElgLines: mode = spv::ExecutionModeInputLines; break;
1859
case glslang::ElgLinesAdjacency: mode = spv::ExecutionModeInputLinesAdjacency; break;
1860
case glslang::ElgTriangles: mode = spv::ExecutionModeTriangles; break;
1861
case glslang::ElgTrianglesAdjacency: mode = spv::ExecutionModeInputTrianglesAdjacency; break;
1862
default: mode = spv::ExecutionModeMax; break;
1863
}
1864
if (mode != spv::ExecutionModeMax)
1865
builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
1866
1867
builder.addExecutionMode(shaderEntry, spv::ExecutionModeInvocations, glslangIntermediate->getInvocations());
1868
1869
switch (glslangIntermediate->getOutputPrimitive()) {
1870
case glslang::ElgPoints: mode = spv::ExecutionModeOutputPoints; break;
1871
case glslang::ElgLineStrip: mode = spv::ExecutionModeOutputLineStrip; break;
1872
case glslang::ElgTriangleStrip: mode = spv::ExecutionModeOutputTriangleStrip; break;
1873
default: mode = spv::ExecutionModeMax; break;
1874
}
1875
if (mode != spv::ExecutionModeMax)
1876
builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
1877
builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices());
1878
break;
1879
1880
case EShLangRayGen:
1881
case EShLangIntersect:
1882
case EShLangAnyHit:
1883
case EShLangClosestHit:
1884
case EShLangMiss:
1885
case EShLangCallable:
1886
{
1887
auto& extensions = glslangIntermediate->getRequestedExtensions();
1888
if (extensions.find("GL_NV_ray_tracing") == extensions.end()) {
1889
builder.addCapability(spv::CapabilityRayTracingKHR);
1890
builder.addExtension("SPV_KHR_ray_tracing");
1891
}
1892
else {
1893
builder.addCapability(spv::CapabilityRayTracingNV);
1894
builder.addExtension("SPV_NV_ray_tracing");
1895
}
1896
if (glslangIntermediate->getStage() != EShLangRayGen && glslangIntermediate->getStage() != EShLangCallable) {
1897
if (extensions.find("GL_EXT_ray_cull_mask") != extensions.end()) {
1898
builder.addCapability(spv::CapabilityRayCullMaskKHR);
1899
builder.addExtension("SPV_KHR_ray_cull_mask");
1900
}
1901
if (extensions.find("GL_EXT_ray_tracing_position_fetch") != extensions.end()) {
1902
builder.addCapability(spv::CapabilityRayTracingPositionFetchKHR);
1903
builder.addExtension("SPV_KHR_ray_tracing_position_fetch");
1904
}
1905
}
1906
break;
1907
}
1908
case EShLangTask:
1909
case EShLangMesh:
1910
if(isMeshShaderExt) {
1911
builder.addCapability(spv::CapabilityMeshShadingEXT);
1912
builder.addExtension(spv::E_SPV_EXT_mesh_shader);
1913
} else {
1914
builder.addCapability(spv::CapabilityMeshShadingNV);
1915
builder.addExtension(spv::E_SPV_NV_mesh_shader);
1916
}
1917
if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_6) {
1918
std::vector<spv::Id> dimConstId;
1919
for (int dim = 0; dim < 3; ++dim) {
1920
bool specConst = (glslangIntermediate->getLocalSizeSpecId(dim) != glslang::TQualifier::layoutNotSet);
1921
dimConstId.push_back(builder.makeUintConstant(glslangIntermediate->getLocalSize(dim), specConst));
1922
if (specConst) {
1923
builder.addDecoration(dimConstId.back(), spv::DecorationSpecId,
1924
glslangIntermediate->getLocalSizeSpecId(dim));
1925
}
1926
}
1927
builder.addExecutionModeId(shaderEntry, spv::ExecutionModeLocalSizeId, dimConstId);
1928
} else {
1929
builder.addExecutionMode(shaderEntry, spv::ExecutionModeLocalSize, glslangIntermediate->getLocalSize(0),
1930
glslangIntermediate->getLocalSize(1),
1931
glslangIntermediate->getLocalSize(2));
1932
}
1933
if (glslangIntermediate->getStage() == EShLangMesh) {
1934
builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices,
1935
glslangIntermediate->getVertices());
1936
builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputPrimitivesNV,
1937
glslangIntermediate->getPrimitives());
1938
1939
switch (glslangIntermediate->getOutputPrimitive()) {
1940
case glslang::ElgPoints: mode = spv::ExecutionModeOutputPoints; break;
1941
case glslang::ElgLines: mode = spv::ExecutionModeOutputLinesNV; break;
1942
case glslang::ElgTriangles: mode = spv::ExecutionModeOutputTrianglesNV; break;
1943
default: mode = spv::ExecutionModeMax; break;
1944
}
1945
if (mode != spv::ExecutionModeMax)
1946
builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode);
1947
}
1948
break;
1949
1950
default:
1951
break;
1952
}
1953
1954
//
1955
// Add SPIR-V requirements (GL_EXT_spirv_intrinsics)
1956
//
1957
if (glslangIntermediate->hasSpirvRequirement()) {
1958
const glslang::TSpirvRequirement& spirvRequirement = glslangIntermediate->getSpirvRequirement();
1959
1960
// Add SPIR-V extension requirement
1961
for (auto& extension : spirvRequirement.extensions)
1962
builder.addExtension(extension.c_str());
1963
1964
// Add SPIR-V capability requirement
1965
for (auto capability : spirvRequirement.capabilities)
1966
builder.addCapability(static_cast<spv::Capability>(capability));
1967
}
1968
1969
//
1970
// Add SPIR-V execution mode qualifiers (GL_EXT_spirv_intrinsics)
1971
//
1972
if (glslangIntermediate->hasSpirvExecutionMode()) {
1973
const glslang::TSpirvExecutionMode spirvExecutionMode = glslangIntermediate->getSpirvExecutionMode();
1974
1975
// Add spirv_execution_mode
1976
for (auto& mode : spirvExecutionMode.modes) {
1977
if (!mode.second.empty()) {
1978
std::vector<unsigned> literals;
1979
TranslateLiterals(mode.second, literals);
1980
builder.addExecutionMode(shaderEntry, static_cast<spv::ExecutionMode>(mode.first), literals);
1981
} else
1982
builder.addExecutionMode(shaderEntry, static_cast<spv::ExecutionMode>(mode.first));
1983
}
1984
1985
// Add spirv_execution_mode_id
1986
for (auto& modeId : spirvExecutionMode.modeIds) {
1987
std::vector<spv::Id> operandIds;
1988
assert(!modeId.second.empty());
1989
for (auto extraOperand : modeId.second) {
1990
if (extraOperand->getType().getQualifier().isSpecConstant())
1991
operandIds.push_back(getSymbolId(extraOperand->getAsSymbolNode()));
1992
else
1993
operandIds.push_back(createSpvConstant(*extraOperand));
1994
}
1995
builder.addExecutionModeId(shaderEntry, static_cast<spv::ExecutionMode>(modeId.first), operandIds);
1996
}
1997
}
1998
}
1999
2000
// Finish creating SPV, after the traversal is complete.
2001
void TGlslangToSpvTraverser::finishSpv(bool compileOnly)
2002
{
2003
// If not linking, an entry point is not expected
2004
if (!compileOnly) {
2005
// Finish the entry point function
2006
if (!entryPointTerminated) {
2007
builder.setBuildPoint(shaderEntry->getLastBlock());
2008
builder.leaveFunction();
2009
}
2010
2011
// finish off the entry-point SPV instruction by adding the Input/Output <id>
2012
entryPoint->reserveOperands(iOSet.size());
2013
for (auto id : iOSet)
2014
entryPoint->addIdOperand(id);
2015
}
2016
2017
// Add capabilities, extensions, remove unneeded decorations, etc.,
2018
// based on the resulting SPIR-V.
2019
// Note: WebGPU code generation must have the opportunity to aggressively
2020
// prune unreachable merge blocks and continue targets.
2021
builder.postProcess(compileOnly);
2022
}
2023
2024
// Write the SPV into 'out'.
2025
void TGlslangToSpvTraverser::dumpSpv(std::vector<unsigned int>& out)
2026
{
2027
builder.dump(out);
2028
}
2029
2030
//
2031
// Implement the traversal functions.
2032
//
2033
// Return true from interior nodes to have the external traversal
2034
// continue on to children. Return false if children were
2035
// already processed.
2036
//
2037
2038
//
2039
// Symbols can turn into
2040
// - uniform/input reads
2041
// - output writes
2042
// - complex lvalue base setups: foo.bar[3].... , where we see foo and start up an access chain
2043
// - something simple that degenerates into the last bullet
2044
//
2045
void TGlslangToSpvTraverser::visitSymbol(glslang::TIntermSymbol* symbol)
2046
{
2047
// We update the line information even though no code might be generated here
2048
// This is helpful to yield correct lines for control flow instructions
2049
if (!linkageOnly) {
2050
builder.setDebugSourceLocation(symbol->getLoc().line, symbol->getLoc().getFilename());
2051
}
2052
2053
SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder);
2054
if (symbol->getType().isStruct())
2055
glslangTypeToIdMap[symbol->getType().getStruct()] = symbol->getId();
2056
2057
if (symbol->getType().getQualifier().isSpecConstant())
2058
spec_constant_op_mode_setter.turnOnSpecConstantOpMode();
2059
#ifdef ENABLE_HLSL
2060
// Skip symbol handling if it is string-typed
2061
if (symbol->getBasicType() == glslang::EbtString)
2062
return;
2063
#endif
2064
2065
// getSymbolId() will set up all the IO decorations on the first call.
2066
// Formal function parameters were mapped during makeFunctions().
2067
spv::Id id = getSymbolId(symbol);
2068
2069
if (symbol->getType().getQualifier().isTaskPayload())
2070
taskPayloadID = id; // cache the taskPayloadID to be used it as operand for OpEmitMeshTasksEXT
2071
2072
if (builder.isPointer(id)) {
2073
if (!symbol->getType().getQualifier().isParamInput() &&
2074
!symbol->getType().getQualifier().isParamOutput()) {
2075
// Include all "static use" and "linkage only" interface variables on the OpEntryPoint instruction
2076
// Consider adding to the OpEntryPoint interface list.
2077
// Only looking at structures if they have at least one member.
2078
if (!symbol->getType().isStruct() || symbol->getType().getStruct()->size() > 0) {
2079
spv::StorageClass sc = builder.getStorageClass(id);
2080
// Before SPIR-V 1.4, we only want to include Input and Output.
2081
// Starting with SPIR-V 1.4, we want all globals.
2082
if ((glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_4 && builder.isGlobalVariable(id)) ||
2083
(sc == spv::StorageClassInput || sc == spv::StorageClassOutput)) {
2084
iOSet.insert(id);
2085
}
2086
}
2087
}
2088
2089
// If the SPIR-V type is required to be different than the AST type
2090
// (for ex SubgroupMasks or 3x4 ObjectToWorld/WorldToObject matrices),
2091
// translate now from the SPIR-V type to the AST type, for the consuming
2092
// operation.
2093
// Note this turns it from an l-value to an r-value.
2094
// Currently, all symbols needing this are inputs; avoid the map lookup when non-input.
2095
if (symbol->getType().getQualifier().storage == glslang::EvqVaryingIn)
2096
id = translateForcedType(id);
2097
}
2098
2099
// Only process non-linkage-only nodes for generating actual static uses
2100
if (! linkageOnly || symbol->getQualifier().isSpecConstant()) {
2101
// Prepare to generate code for the access
2102
2103
// L-value chains will be computed left to right. We're on the symbol now,
2104
// which is the left-most part of the access chain, so now is "clear" time,
2105
// followed by setting the base.
2106
builder.clearAccessChain();
2107
2108
// For now, we consider all user variables as being in memory, so they are pointers,
2109
// except for
2110
// A) R-Value arguments to a function, which are an intermediate object.
2111
// See comments in handleUserFunctionCall().
2112
// B) Specialization constants (normal constants don't even come in as a variable),
2113
// These are also pure R-values.
2114
// C) R-Values from type translation, see above call to translateForcedType()
2115
glslang::TQualifier qualifier = symbol->getQualifier();
2116
if (qualifier.isSpecConstant() || rValueParameters.find(symbol->getId()) != rValueParameters.end() ||
2117
!builder.isPointerType(builder.getTypeId(id)))
2118
builder.setAccessChainRValue(id);
2119
else
2120
builder.setAccessChainLValue(id);
2121
}
2122
2123
#ifdef ENABLE_HLSL
2124
// Process linkage-only nodes for any special additional interface work.
2125
if (linkageOnly) {
2126
if (glslangIntermediate->getHlslFunctionality1()) {
2127
// Map implicit counter buffers to their originating buffers, which should have been
2128
// seen by now, given earlier pruning of unused counters, and preservation of order
2129
// of declaration.
2130
if (symbol->getType().getQualifier().isUniformOrBuffer()) {
2131
if (!glslangIntermediate->hasCounterBufferName(symbol->getName())) {
2132
// Save possible originating buffers for counter buffers, keyed by
2133
// making the potential counter-buffer name.
2134
std::string keyName = symbol->getName().c_str();
2135
keyName = glslangIntermediate->addCounterBufferName(keyName);
2136
counterOriginator[keyName] = symbol;
2137
} else {
2138
// Handle a counter buffer, by finding the saved originating buffer.
2139
std::string keyName = symbol->getName().c_str();
2140
auto it = counterOriginator.find(keyName);
2141
if (it != counterOriginator.end()) {
2142
id = getSymbolId(it->second);
2143
if (id != spv::NoResult) {
2144
spv::Id counterId = getSymbolId(symbol);
2145
if (counterId != spv::NoResult) {
2146
builder.addExtension("SPV_GOOGLE_hlsl_functionality1");
2147
builder.addDecorationId(id, spv::DecorationHlslCounterBufferGOOGLE, counterId);
2148
}
2149
}
2150
}
2151
}
2152
}
2153
}
2154
}
2155
#endif
2156
}
2157
2158
bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::TIntermBinary* node)
2159
{
2160
builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
2161
if (node->getLeft()->getAsSymbolNode() != nullptr && node->getLeft()->getType().isStruct()) {
2162
glslangTypeToIdMap[node->getLeft()->getType().getStruct()] = node->getLeft()->getAsSymbolNode()->getId();
2163
}
2164
if (node->getRight()->getAsSymbolNode() != nullptr && node->getRight()->getType().isStruct()) {
2165
glslangTypeToIdMap[node->getRight()->getType().getStruct()] = node->getRight()->getAsSymbolNode()->getId();
2166
}
2167
2168
SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder);
2169
if (node->getType().getQualifier().isSpecConstant())
2170
spec_constant_op_mode_setter.turnOnSpecConstantOpMode();
2171
2172
// First, handle special cases
2173
switch (node->getOp()) {
2174
case glslang::EOpAssign:
2175
case glslang::EOpAddAssign:
2176
case glslang::EOpSubAssign:
2177
case glslang::EOpMulAssign:
2178
case glslang::EOpVectorTimesMatrixAssign:
2179
case glslang::EOpVectorTimesScalarAssign:
2180
case glslang::EOpMatrixTimesScalarAssign:
2181
case glslang::EOpMatrixTimesMatrixAssign:
2182
case glslang::EOpDivAssign:
2183
case glslang::EOpModAssign:
2184
case glslang::EOpAndAssign:
2185
case glslang::EOpInclusiveOrAssign:
2186
case glslang::EOpExclusiveOrAssign:
2187
case glslang::EOpLeftShiftAssign:
2188
case glslang::EOpRightShiftAssign:
2189
// A bin-op assign "a += b" means the same thing as "a = a + b"
2190
// where a is evaluated before b. For a simple assignment, GLSL
2191
// says to evaluate the left before the right. So, always, left
2192
// node then right node.
2193
{
2194
// get the left l-value, save it away
2195
builder.clearAccessChain();
2196
node->getLeft()->traverse(this);
2197
spv::Builder::AccessChain lValue = builder.getAccessChain();
2198
2199
// evaluate the right
2200
builder.clearAccessChain();
2201
node->getRight()->traverse(this);
2202
spv::Id rValue = accessChainLoad(node->getRight()->getType());
2203
2204
// reset line number for assignment
2205
builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
2206
2207
if (node->getOp() != glslang::EOpAssign) {
2208
// the left is also an r-value
2209
builder.setAccessChain(lValue);
2210
spv::Id leftRValue = accessChainLoad(node->getLeft()->getType());
2211
2212
// do the operation
2213
spv::Builder::AccessChain::CoherentFlags coherentFlags = TranslateCoherent(node->getLeft()->getType());
2214
coherentFlags |= TranslateCoherent(node->getRight()->getType());
2215
OpDecorations decorations = { TranslatePrecisionDecoration(node->getOperationPrecision()),
2216
TranslateNoContractionDecoration(node->getType().getQualifier()),
2217
TranslateNonUniformDecoration(coherentFlags) };
2218
rValue = createBinaryOperation(node->getOp(), decorations,
2219
convertGlslangToSpvType(node->getType()), leftRValue, rValue,
2220
node->getType().getBasicType());
2221
2222
// these all need their counterparts in createBinaryOperation()
2223
assert(rValue != spv::NoResult);
2224
}
2225
2226
// store the result
2227
builder.setAccessChain(lValue);
2228
multiTypeStore(node->getLeft()->getType(), rValue);
2229
2230
// assignments are expressions having an rValue after they are evaluated...
2231
builder.clearAccessChain();
2232
builder.setAccessChainRValue(rValue);
2233
}
2234
return false;
2235
case glslang::EOpIndexDirect:
2236
case glslang::EOpIndexDirectStruct:
2237
{
2238
// Structure, array, matrix, or vector indirection with statically known index.
2239
// Get the left part of the access chain.
2240
node->getLeft()->traverse(this);
2241
2242
// Add the next element in the chain
2243
2244
const int glslangIndex = node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
2245
if (! node->getLeft()->getType().isArray() &&
2246
node->getLeft()->getType().isVector() &&
2247
node->getOp() == glslang::EOpIndexDirect) {
2248
// Swizzle is uniform so propagate uniform into access chain
2249
spv::Builder::AccessChain::CoherentFlags coherentFlags = TranslateCoherent(node->getLeft()->getType());
2250
coherentFlags.nonUniform = 0;
2251
// This is essentially a hard-coded vector swizzle of size 1,
2252
// so short circuit the access-chain stuff with a swizzle.
2253
std::vector<unsigned> swizzle;
2254
swizzle.push_back(glslangIndex);
2255
int dummySize;
2256
builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType()),
2257
coherentFlags,
2258
glslangIntermediate->getBaseAlignmentScalar(
2259
node->getLeft()->getType(), dummySize));
2260
} else {
2261
2262
// Load through a block reference is performed with a dot operator that
2263
// is mapped to EOpIndexDirectStruct. When we get to the actual reference,
2264
// do a load and reset the access chain.
2265
if (node->getLeft()->isReference() &&
2266
!node->getLeft()->getType().isArray() &&
2267
node->getOp() == glslang::EOpIndexDirectStruct)
2268
{
2269
spv::Id left = accessChainLoad(node->getLeft()->getType());
2270
builder.clearAccessChain();
2271
builder.setAccessChainLValue(left);
2272
}
2273
2274
int spvIndex = glslangIndex;
2275
if (node->getLeft()->getBasicType() == glslang::EbtBlock &&
2276
node->getOp() == glslang::EOpIndexDirectStruct)
2277
{
2278
// This may be, e.g., an anonymous block-member selection, which generally need
2279
// index remapping due to hidden members in anonymous blocks.
2280
long long glslangId = glslangTypeToIdMap[node->getLeft()->getType().getStruct()];
2281
if (memberRemapper.find(glslangId) != memberRemapper.end()) {
2282
std::vector<int>& remapper = memberRemapper[glslangId];
2283
assert(remapper.size() > 0);
2284
spvIndex = remapper[glslangIndex];
2285
}
2286
}
2287
2288
// Struct reference propagates uniform lvalue
2289
spv::Builder::AccessChain::CoherentFlags coherentFlags =
2290
TranslateCoherent(node->getLeft()->getType());
2291
coherentFlags.nonUniform = 0;
2292
2293
// normal case for indexing array or structure or block
2294
builder.accessChainPush(builder.makeIntConstant(spvIndex),
2295
coherentFlags,
2296
node->getLeft()->getType().getBufferReferenceAlignment());
2297
2298
// Add capabilities here for accessing PointSize and clip/cull distance.
2299
// We have deferred generation of associated capabilities until now.
2300
if (node->getLeft()->getType().isStruct() && ! node->getLeft()->getType().isArray())
2301
declareUseOfStructMember(*(node->getLeft()->getType().getStruct()), glslangIndex);
2302
}
2303
}
2304
return false;
2305
case glslang::EOpIndexIndirect:
2306
{
2307
// Array, matrix, or vector indirection with variable index.
2308
// Will use native SPIR-V access-chain for and array indirection;
2309
// matrices are arrays of vectors, so will also work for a matrix.
2310
// Will use the access chain's 'component' for variable index into a vector.
2311
2312
// This adapter is building access chains left to right.
2313
// Set up the access chain to the left.
2314
node->getLeft()->traverse(this);
2315
2316
// save it so that computing the right side doesn't trash it
2317
spv::Builder::AccessChain partial = builder.getAccessChain();
2318
2319
// compute the next index in the chain
2320
builder.clearAccessChain();
2321
node->getRight()->traverse(this);
2322
spv::Id index = accessChainLoad(node->getRight()->getType());
2323
2324
addIndirectionIndexCapabilities(node->getLeft()->getType(), node->getRight()->getType());
2325
2326
// restore the saved access chain
2327
builder.setAccessChain(partial);
2328
2329
// Only if index is nonUniform should we propagate nonUniform into access chain
2330
spv::Builder::AccessChain::CoherentFlags index_flags = TranslateCoherent(node->getRight()->getType());
2331
spv::Builder::AccessChain::CoherentFlags coherent_flags = TranslateCoherent(node->getLeft()->getType());
2332
coherent_flags.nonUniform = index_flags.nonUniform;
2333
2334
if (! node->getLeft()->getType().isArray() && node->getLeft()->getType().isVector()) {
2335
int dummySize;
2336
builder.accessChainPushComponent(
2337
index, convertGlslangToSpvType(node->getLeft()->getType()), coherent_flags,
2338
glslangIntermediate->getBaseAlignmentScalar(node->getLeft()->getType(),
2339
dummySize));
2340
} else
2341
builder.accessChainPush(index, coherent_flags,
2342
node->getLeft()->getType().getBufferReferenceAlignment());
2343
}
2344
return false;
2345
case glslang::EOpVectorSwizzle:
2346
{
2347
node->getLeft()->traverse(this);
2348
std::vector<unsigned> swizzle;
2349
convertSwizzle(*node->getRight()->getAsAggregate(), swizzle);
2350
int dummySize;
2351
builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType()),
2352
TranslateCoherent(node->getLeft()->getType()),
2353
glslangIntermediate->getBaseAlignmentScalar(node->getLeft()->getType(),
2354
dummySize));
2355
}
2356
return false;
2357
case glslang::EOpMatrixSwizzle:
2358
logger->missingFunctionality("matrix swizzle");
2359
return true;
2360
case glslang::EOpLogicalOr:
2361
case glslang::EOpLogicalAnd:
2362
{
2363
2364
// These may require short circuiting, but can sometimes be done as straight
2365
// binary operations. The right operand must be short circuited if it has
2366
// side effects, and should probably be if it is complex.
2367
if (isTrivial(node->getRight()->getAsTyped()))
2368
break; // handle below as a normal binary operation
2369
// otherwise, we need to do dynamic short circuiting on the right operand
2370
spv::Id result = createShortCircuit(node->getOp(), *node->getLeft()->getAsTyped(),
2371
*node->getRight()->getAsTyped());
2372
builder.clearAccessChain();
2373
builder.setAccessChainRValue(result);
2374
}
2375
return false;
2376
default:
2377
break;
2378
}
2379
2380
// Assume generic binary op...
2381
2382
// get right operand
2383
builder.clearAccessChain();
2384
node->getLeft()->traverse(this);
2385
spv::Id left = accessChainLoad(node->getLeft()->getType());
2386
2387
// get left operand
2388
builder.clearAccessChain();
2389
node->getRight()->traverse(this);
2390
spv::Id right = accessChainLoad(node->getRight()->getType());
2391
2392
// get result
2393
OpDecorations decorations = { TranslatePrecisionDecoration(node->getOperationPrecision()),
2394
TranslateNoContractionDecoration(node->getType().getQualifier()),
2395
TranslateNonUniformDecoration(node->getType().getQualifier()) };
2396
spv::Id result = createBinaryOperation(node->getOp(), decorations,
2397
convertGlslangToSpvType(node->getType()), left, right,
2398
node->getLeft()->getType().getBasicType());
2399
2400
builder.clearAccessChain();
2401
if (! result) {
2402
logger->missingFunctionality("unknown glslang binary operation");
2403
return true; // pick up a child as the place-holder result
2404
} else {
2405
builder.setAccessChainRValue(result);
2406
return false;
2407
}
2408
}
2409
2410
spv::Id TGlslangToSpvTraverser::convertLoadedBoolInUniformToUint(const glslang::TType& type,
2411
spv::Id nominalTypeId,
2412
spv::Id loadedId)
2413
{
2414
if (builder.isScalarType(nominalTypeId)) {
2415
// Conversion for bool
2416
spv::Id boolType = builder.makeBoolType();
2417
if (nominalTypeId != boolType)
2418
return builder.createBinOp(spv::OpINotEqual, boolType, loadedId, builder.makeUintConstant(0));
2419
} else if (builder.isVectorType(nominalTypeId)) {
2420
// Conversion for bvec
2421
int vecSize = builder.getNumTypeComponents(nominalTypeId);
2422
spv::Id bvecType = builder.makeVectorType(builder.makeBoolType(), vecSize);
2423
if (nominalTypeId != bvecType)
2424
loadedId = builder.createBinOp(spv::OpINotEqual, bvecType, loadedId,
2425
makeSmearedConstant(builder.makeUintConstant(0), vecSize));
2426
} else if (builder.isArrayType(nominalTypeId)) {
2427
// Conversion for bool array
2428
spv::Id boolArrayTypeId = convertGlslangToSpvType(type);
2429
if (nominalTypeId != boolArrayTypeId)
2430
{
2431
// Use OpCopyLogical from SPIR-V 1.4 if available.
2432
if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_4)
2433
return builder.createUnaryOp(spv::OpCopyLogical, boolArrayTypeId, loadedId);
2434
2435
glslang::TType glslangElementType(type, 0);
2436
spv::Id elementNominalTypeId = builder.getContainedTypeId(nominalTypeId);
2437
std::vector<spv::Id> constituents;
2438
for (int index = 0; index < type.getOuterArraySize(); ++index) {
2439
// get the element
2440
spv::Id elementValue = builder.createCompositeExtract(loadedId, elementNominalTypeId, index);
2441
2442
// recursively convert it
2443
spv::Id elementConvertedValue = convertLoadedBoolInUniformToUint(glslangElementType, elementNominalTypeId, elementValue);
2444
constituents.push_back(elementConvertedValue);
2445
}
2446
return builder.createCompositeConstruct(boolArrayTypeId, constituents);
2447
}
2448
}
2449
2450
return loadedId;
2451
}
2452
2453
// Figure out what, if any, type changes are needed when accessing a specific built-in.
2454
// Returns <the type SPIR-V requires for declarion, the type to translate to on use>.
2455
// Also see comment for 'forceType', regarding tracking SPIR-V-required types.
2456
std::pair<spv::Id, spv::Id> TGlslangToSpvTraverser::getForcedType(glslang::TBuiltInVariable glslangBuiltIn,
2457
const glslang::TType& glslangType)
2458
{
2459
switch(glslangBuiltIn)
2460
{
2461
case glslang::EbvSubGroupEqMask:
2462
case glslang::EbvSubGroupGeMask:
2463
case glslang::EbvSubGroupGtMask:
2464
case glslang::EbvSubGroupLeMask:
2465
case glslang::EbvSubGroupLtMask: {
2466
// these require changing a 64-bit scaler -> a vector of 32-bit components
2467
if (glslangType.isVector())
2468
break;
2469
spv::Id ivec4_type = builder.makeVectorType(builder.makeUintType(32), 4);
2470
spv::Id uint64_type = builder.makeUintType(64);
2471
std::pair<spv::Id, spv::Id> ret(ivec4_type, uint64_type);
2472
return ret;
2473
}
2474
// There are no SPIR-V builtins defined for these and map onto original non-transposed
2475
// builtins. During visitBinary we insert a transpose
2476
case glslang::EbvWorldToObject3x4:
2477
case glslang::EbvObjectToWorld3x4: {
2478
spv::Id mat43 = builder.makeMatrixType(builder.makeFloatType(32), 4, 3);
2479
spv::Id mat34 = builder.makeMatrixType(builder.makeFloatType(32), 3, 4);
2480
std::pair<spv::Id, spv::Id> ret(mat43, mat34);
2481
return ret;
2482
}
2483
default:
2484
break;
2485
}
2486
2487
std::pair<spv::Id, spv::Id> ret(spv::NoType, spv::NoType);
2488
return ret;
2489
}
2490
2491
// For an object previously identified (see getForcedType() and forceType)
2492
// as needing type translations, do the translation needed for a load, turning
2493
// an L-value into in R-value.
2494
spv::Id TGlslangToSpvTraverser::translateForcedType(spv::Id object)
2495
{
2496
const auto forceIt = forceType.find(object);
2497
if (forceIt == forceType.end())
2498
return object;
2499
2500
spv::Id desiredTypeId = forceIt->second;
2501
spv::Id objectTypeId = builder.getTypeId(object);
2502
assert(builder.isPointerType(objectTypeId));
2503
objectTypeId = builder.getContainedTypeId(objectTypeId);
2504
if (builder.isVectorType(objectTypeId) &&
2505
builder.getScalarTypeWidth(builder.getContainedTypeId(objectTypeId)) == 32) {
2506
if (builder.getScalarTypeWidth(desiredTypeId) == 64) {
2507
// handle 32-bit v.xy* -> 64-bit
2508
builder.clearAccessChain();
2509
builder.setAccessChainLValue(object);
2510
object = builder.accessChainLoad(spv::NoPrecision, spv::DecorationMax, spv::DecorationMax, objectTypeId);
2511
std::vector<spv::Id> components;
2512
components.push_back(builder.createCompositeExtract(object, builder.getContainedTypeId(objectTypeId), 0));
2513
components.push_back(builder.createCompositeExtract(object, builder.getContainedTypeId(objectTypeId), 1));
2514
2515
spv::Id vecType = builder.makeVectorType(builder.getContainedTypeId(objectTypeId), 2);
2516
return builder.createUnaryOp(spv::OpBitcast, desiredTypeId,
2517
builder.createCompositeConstruct(vecType, components));
2518
} else {
2519
logger->missingFunctionality("forcing 32-bit vector type to non 64-bit scalar");
2520
}
2521
} else if (builder.isMatrixType(objectTypeId)) {
2522
// There are no SPIR-V builtins defined for 3x4 variants of ObjectToWorld/WorldToObject
2523
// and we insert a transpose after loading the original non-transposed builtins
2524
builder.clearAccessChain();
2525
builder.setAccessChainLValue(object);
2526
object = builder.accessChainLoad(spv::NoPrecision, spv::DecorationMax, spv::DecorationMax, objectTypeId);
2527
return builder.createUnaryOp(spv::OpTranspose, desiredTypeId, object);
2528
2529
} else {
2530
logger->missingFunctionality("forcing non 32-bit vector type");
2531
}
2532
2533
return object;
2534
}
2535
2536
bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TIntermUnary* node)
2537
{
2538
builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
2539
2540
SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder);
2541
if (node->getType().getQualifier().isSpecConstant())
2542
spec_constant_op_mode_setter.turnOnSpecConstantOpMode();
2543
2544
spv::Id result = spv::NoResult;
2545
2546
// try texturing first
2547
result = createImageTextureFunctionCall(node);
2548
if (result != spv::NoResult) {
2549
builder.clearAccessChain();
2550
builder.setAccessChainRValue(result);
2551
2552
return false; // done with this node
2553
}
2554
2555
// Non-texturing.
2556
2557
if (node->getOp() == glslang::EOpArrayLength) {
2558
// Quite special; won't want to evaluate the operand.
2559
2560
// Currently, the front-end does not allow .length() on an array until it is sized,
2561
// except for the last block membeor of an SSBO.
2562
// TODO: If this changes, link-time sized arrays might show up here, and need their
2563
// size extracted.
2564
2565
// Normal .length() would have been constant folded by the front-end.
2566
// So, this has to be block.lastMember.length().
2567
// SPV wants "block" and member number as the operands, go get them.
2568
2569
spv::Id length;
2570
if (node->getOperand()->getType().isCoopMat()) {
2571
spv::Id typeId = convertGlslangToSpvType(node->getOperand()->getType());
2572
assert(builder.isCooperativeMatrixType(typeId));
2573
2574
if (node->getOperand()->getType().isCoopMatKHR()) {
2575
length = builder.createCooperativeMatrixLengthKHR(typeId);
2576
} else {
2577
spec_constant_op_mode_setter.turnOnSpecConstantOpMode();
2578
length = builder.createCooperativeMatrixLengthNV(typeId);
2579
}
2580
} else {
2581
glslang::TIntermTyped* block = node->getOperand()->getAsBinaryNode()->getLeft();
2582
block->traverse(this);
2583
unsigned int member = node->getOperand()->getAsBinaryNode()->getRight()->getAsConstantUnion()
2584
->getConstArray()[0].getUConst();
2585
length = builder.createArrayLength(builder.accessChainGetLValue(), member);
2586
}
2587
2588
// GLSL semantics say the result of .length() is an int, while SPIR-V says
2589
// signedness must be 0. So, convert from SPIR-V unsigned back to GLSL's
2590
// AST expectation of a signed result.
2591
if (glslangIntermediate->getSource() == glslang::EShSourceGlsl) {
2592
if (builder.isInSpecConstCodeGenMode()) {
2593
length = builder.createBinOp(spv::OpIAdd, builder.makeIntType(32), length, builder.makeIntConstant(0));
2594
} else {
2595
length = builder.createUnaryOp(spv::OpBitcast, builder.makeIntType(32), length);
2596
}
2597
}
2598
2599
builder.clearAccessChain();
2600
builder.setAccessChainRValue(length);
2601
2602
return false;
2603
}
2604
2605
// Force variable declaration - Debug Mode Only
2606
if (node->getOp() == glslang::EOpDeclare) {
2607
builder.clearAccessChain();
2608
node->getOperand()->traverse(this);
2609
builder.clearAccessChain();
2610
return false;
2611
}
2612
2613
// Start by evaluating the operand
2614
2615
// Does it need a swizzle inversion? If so, evaluation is inverted;
2616
// operate first on the swizzle base, then apply the swizzle.
2617
spv::Id invertedType = spv::NoType;
2618
auto resultType = [&invertedType, &node, this](){ return invertedType != spv::NoType ?
2619
invertedType : convertGlslangToSpvType(node->getType()); };
2620
if (node->getOp() == glslang::EOpInterpolateAtCentroid)
2621
invertedType = getInvertedSwizzleType(*node->getOperand());
2622
2623
builder.clearAccessChain();
2624
TIntermNode *operandNode;
2625
if (invertedType != spv::NoType)
2626
operandNode = node->getOperand()->getAsBinaryNode()->getLeft();
2627
else
2628
operandNode = node->getOperand();
2629
2630
operandNode->traverse(this);
2631
2632
spv::Id operand = spv::NoResult;
2633
2634
spv::Builder::AccessChain::CoherentFlags lvalueCoherentFlags;
2635
2636
const auto hitObjectOpsWithLvalue = [](glslang::TOperator op) {
2637
switch(op) {
2638
case glslang::EOpReorderThreadNV:
2639
case glslang::EOpHitObjectGetCurrentTimeNV:
2640
case glslang::EOpHitObjectGetHitKindNV:
2641
case glslang::EOpHitObjectGetPrimitiveIndexNV:
2642
case glslang::EOpHitObjectGetGeometryIndexNV:
2643
case glslang::EOpHitObjectGetInstanceIdNV:
2644
case glslang::EOpHitObjectGetInstanceCustomIndexNV:
2645
case glslang::EOpHitObjectGetObjectRayDirectionNV:
2646
case glslang::EOpHitObjectGetObjectRayOriginNV:
2647
case glslang::EOpHitObjectGetWorldRayDirectionNV:
2648
case glslang::EOpHitObjectGetWorldRayOriginNV:
2649
case glslang::EOpHitObjectGetWorldToObjectNV:
2650
case glslang::EOpHitObjectGetObjectToWorldNV:
2651
case glslang::EOpHitObjectGetRayTMaxNV:
2652
case glslang::EOpHitObjectGetRayTMinNV:
2653
case glslang::EOpHitObjectIsEmptyNV:
2654
case glslang::EOpHitObjectIsHitNV:
2655
case glslang::EOpHitObjectIsMissNV:
2656
case glslang::EOpHitObjectRecordEmptyNV:
2657
case glslang::EOpHitObjectGetShaderBindingTableRecordIndexNV:
2658
case glslang::EOpHitObjectGetShaderRecordBufferHandleNV:
2659
return true;
2660
default:
2661
return false;
2662
}
2663
};
2664
2665
if (node->getOp() == glslang::EOpAtomicCounterIncrement ||
2666
node->getOp() == glslang::EOpAtomicCounterDecrement ||
2667
node->getOp() == glslang::EOpAtomicCounter ||
2668
(node->getOp() == glslang::EOpInterpolateAtCentroid &&
2669
glslangIntermediate->getSource() != glslang::EShSourceHlsl) ||
2670
node->getOp() == glslang::EOpRayQueryProceed ||
2671
node->getOp() == glslang::EOpRayQueryGetRayTMin ||
2672
node->getOp() == glslang::EOpRayQueryGetRayFlags ||
2673
node->getOp() == glslang::EOpRayQueryGetWorldRayOrigin ||
2674
node->getOp() == glslang::EOpRayQueryGetWorldRayDirection ||
2675
node->getOp() == glslang::EOpRayQueryGetIntersectionCandidateAABBOpaque ||
2676
node->getOp() == glslang::EOpRayQueryTerminate ||
2677
node->getOp() == glslang::EOpRayQueryConfirmIntersection ||
2678
(node->getOp() == glslang::EOpSpirvInst && operandNode->getAsTyped()->getQualifier().isSpirvByReference()) ||
2679
hitObjectOpsWithLvalue(node->getOp())) {
2680
operand = builder.accessChainGetLValue(); // Special case l-value operands
2681
lvalueCoherentFlags = builder.getAccessChain().coherentFlags;
2682
lvalueCoherentFlags |= TranslateCoherent(operandNode->getAsTyped()->getType());
2683
} else if (operandNode->getAsTyped()->getQualifier().isSpirvLiteral()) {
2684
// Will be translated to a literal value, make a placeholder here
2685
operand = spv::NoResult;
2686
} else {
2687
operand = accessChainLoad(node->getOperand()->getType());
2688
}
2689
2690
OpDecorations decorations = { TranslatePrecisionDecoration(node->getOperationPrecision()),
2691
TranslateNoContractionDecoration(node->getType().getQualifier()),
2692
TranslateNonUniformDecoration(node->getType().getQualifier()) };
2693
2694
// it could be a conversion
2695
if (! result)
2696
result = createConversion(node->getOp(), decorations, resultType(), operand,
2697
node->getOperand()->getBasicType());
2698
2699
// if not, then possibly an operation
2700
if (! result)
2701
result = createUnaryOperation(node->getOp(), decorations, resultType(), operand,
2702
node->getOperand()->getBasicType(), lvalueCoherentFlags, node->getType());
2703
2704
// it could be attached to a SPIR-V intruction
2705
if (!result) {
2706
if (node->getOp() == glslang::EOpSpirvInst) {
2707
const auto& spirvInst = node->getSpirvInstruction();
2708
if (spirvInst.set == "") {
2709
spv::IdImmediate idImmOp = {true, operand};
2710
if (operandNode->getAsTyped()->getQualifier().isSpirvLiteral()) {
2711
// Translate the constant to a literal value
2712
std::vector<unsigned> literals;
2713
glslang::TVector<const glslang::TIntermConstantUnion*> constants;
2714
constants.push_back(operandNode->getAsConstantUnion());
2715
TranslateLiterals(constants, literals);
2716
idImmOp = {false, literals[0]};
2717
}
2718
2719
if (node->getBasicType() == glslang::EbtVoid)
2720
builder.createNoResultOp(static_cast<spv::Op>(spirvInst.id), {idImmOp});
2721
else
2722
result = builder.createOp(static_cast<spv::Op>(spirvInst.id), resultType(), {idImmOp});
2723
} else {
2724
result = builder.createBuiltinCall(
2725
resultType(), spirvInst.set == "GLSL.std.450" ? stdBuiltins : getExtBuiltins(spirvInst.set.c_str()),
2726
spirvInst.id, {operand});
2727
}
2728
2729
if (node->getBasicType() == glslang::EbtVoid)
2730
return false; // done with this node
2731
}
2732
}
2733
2734
if (result) {
2735
if (invertedType) {
2736
result = createInvertedSwizzle(decorations.precision, *node->getOperand(), result);
2737
decorations.addNonUniform(builder, result);
2738
}
2739
2740
builder.clearAccessChain();
2741
builder.setAccessChainRValue(result);
2742
2743
return false; // done with this node
2744
}
2745
2746
// it must be a special case, check...
2747
switch (node->getOp()) {
2748
case glslang::EOpPostIncrement:
2749
case glslang::EOpPostDecrement:
2750
case glslang::EOpPreIncrement:
2751
case glslang::EOpPreDecrement:
2752
{
2753
// we need the integer value "1" or the floating point "1.0" to add/subtract
2754
spv::Id one = 0;
2755
if (node->getBasicType() == glslang::EbtFloat)
2756
one = builder.makeFloatConstant(1.0F);
2757
else if (node->getBasicType() == glslang::EbtDouble)
2758
one = builder.makeDoubleConstant(1.0);
2759
else if (node->getBasicType() == glslang::EbtFloat16)
2760
one = builder.makeFloat16Constant(1.0F);
2761
else if (node->getBasicType() == glslang::EbtInt8 || node->getBasicType() == glslang::EbtUint8)
2762
one = builder.makeInt8Constant(1);
2763
else if (node->getBasicType() == glslang::EbtInt16 || node->getBasicType() == glslang::EbtUint16)
2764
one = builder.makeInt16Constant(1);
2765
else if (node->getBasicType() == glslang::EbtInt64 || node->getBasicType() == glslang::EbtUint64)
2766
one = builder.makeInt64Constant(1);
2767
else
2768
one = builder.makeIntConstant(1);
2769
glslang::TOperator op;
2770
if (node->getOp() == glslang::EOpPreIncrement ||
2771
node->getOp() == glslang::EOpPostIncrement)
2772
op = glslang::EOpAdd;
2773
else
2774
op = glslang::EOpSub;
2775
2776
spv::Id result = createBinaryOperation(op, decorations,
2777
convertGlslangToSpvType(node->getType()), operand, one,
2778
node->getType().getBasicType());
2779
assert(result != spv::NoResult);
2780
2781
// The result of operation is always stored, but conditionally the
2782
// consumed result. The consumed result is always an r-value.
2783
builder.accessChainStore(result,
2784
TranslateNonUniformDecoration(builder.getAccessChain().coherentFlags));
2785
builder.clearAccessChain();
2786
if (node->getOp() == glslang::EOpPreIncrement ||
2787
node->getOp() == glslang::EOpPreDecrement)
2788
builder.setAccessChainRValue(result);
2789
else
2790
builder.setAccessChainRValue(operand);
2791
}
2792
2793
return false;
2794
2795
case glslang::EOpAssumeEXT:
2796
builder.addCapability(spv::CapabilityExpectAssumeKHR);
2797
builder.addExtension(spv::E_SPV_KHR_expect_assume);
2798
builder.createNoResultOp(spv::OpAssumeTrueKHR, operand);
2799
return false;
2800
case glslang::EOpEmitStreamVertex:
2801
builder.createNoResultOp(spv::OpEmitStreamVertex, operand);
2802
return false;
2803
case glslang::EOpEndStreamPrimitive:
2804
builder.createNoResultOp(spv::OpEndStreamPrimitive, operand);
2805
return false;
2806
case glslang::EOpRayQueryTerminate:
2807
builder.createNoResultOp(spv::OpRayQueryTerminateKHR, operand);
2808
return false;
2809
case glslang::EOpRayQueryConfirmIntersection:
2810
builder.createNoResultOp(spv::OpRayQueryConfirmIntersectionKHR, operand);
2811
return false;
2812
case glslang::EOpReorderThreadNV:
2813
builder.createNoResultOp(spv::OpReorderThreadWithHitObjectNV, operand);
2814
return false;
2815
case glslang::EOpHitObjectRecordEmptyNV:
2816
builder.createNoResultOp(spv::OpHitObjectRecordEmptyNV, operand);
2817
return false;
2818
2819
default:
2820
logger->missingFunctionality("unknown glslang unary");
2821
return true; // pick up operand as placeholder result
2822
}
2823
}
2824
2825
// Construct a composite object, recursively copying members if their types don't match
2826
spv::Id TGlslangToSpvTraverser::createCompositeConstruct(spv::Id resultTypeId, std::vector<spv::Id> constituents)
2827
{
2828
for (int c = 0; c < (int)constituents.size(); ++c) {
2829
spv::Id& constituent = constituents[c];
2830
spv::Id lType = builder.getContainedTypeId(resultTypeId, c);
2831
spv::Id rType = builder.getTypeId(constituent);
2832
if (lType != rType) {
2833
if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_4) {
2834
constituent = builder.createUnaryOp(spv::OpCopyLogical, lType, constituent);
2835
} else if (builder.isStructType(rType)) {
2836
std::vector<spv::Id> rTypeConstituents;
2837
int numrTypeConstituents = builder.getNumTypeConstituents(rType);
2838
for (int i = 0; i < numrTypeConstituents; ++i) {
2839
rTypeConstituents.push_back(builder.createCompositeExtract(constituent,
2840
builder.getContainedTypeId(rType, i), i));
2841
}
2842
constituents[c] = createCompositeConstruct(lType, rTypeConstituents);
2843
} else {
2844
assert(builder.isArrayType(rType));
2845
std::vector<spv::Id> rTypeConstituents;
2846
int numrTypeConstituents = builder.getNumTypeConstituents(rType);
2847
2848
spv::Id elementRType = builder.getContainedTypeId(rType);
2849
for (int i = 0; i < numrTypeConstituents; ++i) {
2850
rTypeConstituents.push_back(builder.createCompositeExtract(constituent, elementRType, i));
2851
}
2852
constituents[c] = createCompositeConstruct(lType, rTypeConstituents);
2853
}
2854
}
2855
}
2856
return builder.createCompositeConstruct(resultTypeId, constituents);
2857
}
2858
2859
bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TIntermAggregate* node)
2860
{
2861
SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder);
2862
if (node->getType().getQualifier().isSpecConstant())
2863
spec_constant_op_mode_setter.turnOnSpecConstantOpMode();
2864
2865
spv::Id result = spv::NoResult;
2866
spv::Id invertedType = spv::NoType; // to use to override the natural type of the node
2867
std::vector<spv::Builder::AccessChain> complexLvalues; // for holding swizzling l-values too complex for
2868
// SPIR-V, for an out parameter
2869
std::vector<spv::Id> temporaryLvalues; // temporaries to pass, as proxies for complexLValues
2870
2871
auto resultType = [&invertedType, &node, this](){ return invertedType != spv::NoType ?
2872
invertedType :
2873
convertGlslangToSpvType(node->getType()); };
2874
2875
// try texturing
2876
result = createImageTextureFunctionCall(node);
2877
if (result != spv::NoResult) {
2878
builder.clearAccessChain();
2879
builder.setAccessChainRValue(result);
2880
2881
return false;
2882
} else if (node->getOp() == glslang::EOpImageStore ||
2883
node->getOp() == glslang::EOpImageStoreLod ||
2884
node->getOp() == glslang::EOpImageAtomicStore) {
2885
// "imageStore" is a special case, which has no result
2886
return false;
2887
}
2888
2889
glslang::TOperator binOp = glslang::EOpNull;
2890
bool reduceComparison = true;
2891
bool isMatrix = false;
2892
bool noReturnValue = false;
2893
bool atomic = false;
2894
2895
spv::Builder::AccessChain::CoherentFlags lvalueCoherentFlags;
2896
2897
assert(node->getOp());
2898
2899
spv::Decoration precision = TranslatePrecisionDecoration(node->getOperationPrecision());
2900
2901
switch (node->getOp()) {
2902
case glslang::EOpScope:
2903
case glslang::EOpSequence:
2904
{
2905
if (visit == glslang::EvPreVisit) {
2906
++sequenceDepth;
2907
if (sequenceDepth == 1) {
2908
// If this is the parent node of all the functions, we want to see them
2909
// early, so all call points have actual SPIR-V functions to reference.
2910
// In all cases, still let the traverser visit the children for us.
2911
makeFunctions(node->getAsAggregate()->getSequence());
2912
2913
// Global initializers is specific to the shader entry point, which does not exist in compile-only mode
2914
if (!options.compileOnly) {
2915
// Also, we want all globals initializers to go into the beginning of the entry point, before
2916
// anything else gets there, so visit out of order, doing them all now.
2917
makeGlobalInitializers(node->getAsAggregate()->getSequence());
2918
}
2919
2920
//Pre process linker objects for ray tracing stages
2921
if (glslangIntermediate->isRayTracingStage())
2922
collectRayTracingLinkerObjects();
2923
2924
// Initializers are done, don't want to visit again, but functions and link objects need to be processed,
2925
// so do them manually.
2926
visitFunctions(node->getAsAggregate()->getSequence());
2927
2928
return false;
2929
} else {
2930
if (node->getOp() == glslang::EOpScope)
2931
builder.enterLexicalBlock(0);
2932
}
2933
} else {
2934
if (sequenceDepth > 1 && node->getOp() == glslang::EOpScope)
2935
builder.leaveLexicalBlock();
2936
--sequenceDepth;
2937
}
2938
2939
return true;
2940
}
2941
case glslang::EOpLinkerObjects:
2942
{
2943
if (visit == glslang::EvPreVisit)
2944
linkageOnly = true;
2945
else
2946
linkageOnly = false;
2947
2948
return true;
2949
}
2950
case glslang::EOpComma:
2951
{
2952
// processing from left to right naturally leaves the right-most
2953
// lying around in the access chain
2954
glslang::TIntermSequence& glslangOperands = node->getSequence();
2955
for (int i = 0; i < (int)glslangOperands.size(); ++i)
2956
glslangOperands[i]->traverse(this);
2957
2958
return false;
2959
}
2960
case glslang::EOpFunction:
2961
if (visit == glslang::EvPreVisit) {
2962
if (options.generateDebugInfo) {
2963
builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
2964
}
2965
if (isShaderEntryPoint(node)) {
2966
inEntryPoint = true;
2967
builder.setBuildPoint(shaderEntry->getLastBlock());
2968
builder.enterFunction(shaderEntry);
2969
currentFunction = shaderEntry;
2970
} else {
2971
handleFunctionEntry(node);
2972
}
2973
if (options.generateDebugInfo && !options.emitNonSemanticShaderDebugInfo) {
2974
const auto& loc = node->getLoc();
2975
const char* sourceFileName = loc.getFilename();
2976
spv::Id sourceFileId = sourceFileName ? builder.getStringId(sourceFileName) : builder.getMainFileId();
2977
currentFunction->setDebugLineInfo(sourceFileId, loc.line, loc.column);
2978
}
2979
} else {
2980
if (inEntryPoint)
2981
entryPointTerminated = true;
2982
builder.leaveFunction();
2983
inEntryPoint = false;
2984
}
2985
2986
return true;
2987
case glslang::EOpParameters:
2988
// Parameters will have been consumed by EOpFunction processing, but not
2989
// the body, so we still visited the function node's children, making this
2990
// child redundant.
2991
return false;
2992
case glslang::EOpFunctionCall:
2993
{
2994
builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
2995
if (node->isUserDefined())
2996
result = handleUserFunctionCall(node);
2997
if (result) {
2998
builder.clearAccessChain();
2999
builder.setAccessChainRValue(result);
3000
} else
3001
logger->missingFunctionality("missing user function; linker needs to catch that");
3002
3003
return false;
3004
}
3005
case glslang::EOpConstructMat2x2:
3006
case glslang::EOpConstructMat2x3:
3007
case glslang::EOpConstructMat2x4:
3008
case glslang::EOpConstructMat3x2:
3009
case glslang::EOpConstructMat3x3:
3010
case glslang::EOpConstructMat3x4:
3011
case glslang::EOpConstructMat4x2:
3012
case glslang::EOpConstructMat4x3:
3013
case glslang::EOpConstructMat4x4:
3014
case glslang::EOpConstructDMat2x2:
3015
case glslang::EOpConstructDMat2x3:
3016
case glslang::EOpConstructDMat2x4:
3017
case glslang::EOpConstructDMat3x2:
3018
case glslang::EOpConstructDMat3x3:
3019
case glslang::EOpConstructDMat3x4:
3020
case glslang::EOpConstructDMat4x2:
3021
case glslang::EOpConstructDMat4x3:
3022
case glslang::EOpConstructDMat4x4:
3023
case glslang::EOpConstructIMat2x2:
3024
case glslang::EOpConstructIMat2x3:
3025
case glslang::EOpConstructIMat2x4:
3026
case glslang::EOpConstructIMat3x2:
3027
case glslang::EOpConstructIMat3x3:
3028
case glslang::EOpConstructIMat3x4:
3029
case glslang::EOpConstructIMat4x2:
3030
case glslang::EOpConstructIMat4x3:
3031
case glslang::EOpConstructIMat4x4:
3032
case glslang::EOpConstructUMat2x2:
3033
case glslang::EOpConstructUMat2x3:
3034
case glslang::EOpConstructUMat2x4:
3035
case glslang::EOpConstructUMat3x2:
3036
case glslang::EOpConstructUMat3x3:
3037
case glslang::EOpConstructUMat3x4:
3038
case glslang::EOpConstructUMat4x2:
3039
case glslang::EOpConstructUMat4x3:
3040
case glslang::EOpConstructUMat4x4:
3041
case glslang::EOpConstructBMat2x2:
3042
case glslang::EOpConstructBMat2x3:
3043
case glslang::EOpConstructBMat2x4:
3044
case glslang::EOpConstructBMat3x2:
3045
case glslang::EOpConstructBMat3x3:
3046
case glslang::EOpConstructBMat3x4:
3047
case glslang::EOpConstructBMat4x2:
3048
case glslang::EOpConstructBMat4x3:
3049
case glslang::EOpConstructBMat4x4:
3050
case glslang::EOpConstructF16Mat2x2:
3051
case glslang::EOpConstructF16Mat2x3:
3052
case glslang::EOpConstructF16Mat2x4:
3053
case glslang::EOpConstructF16Mat3x2:
3054
case glslang::EOpConstructF16Mat3x3:
3055
case glslang::EOpConstructF16Mat3x4:
3056
case glslang::EOpConstructF16Mat4x2:
3057
case glslang::EOpConstructF16Mat4x3:
3058
case glslang::EOpConstructF16Mat4x4:
3059
isMatrix = true;
3060
[[fallthrough]];
3061
case glslang::EOpConstructFloat:
3062
case glslang::EOpConstructVec2:
3063
case glslang::EOpConstructVec3:
3064
case glslang::EOpConstructVec4:
3065
case glslang::EOpConstructDouble:
3066
case glslang::EOpConstructDVec2:
3067
case glslang::EOpConstructDVec3:
3068
case glslang::EOpConstructDVec4:
3069
case glslang::EOpConstructFloat16:
3070
case glslang::EOpConstructF16Vec2:
3071
case glslang::EOpConstructF16Vec3:
3072
case glslang::EOpConstructF16Vec4:
3073
case glslang::EOpConstructBool:
3074
case glslang::EOpConstructBVec2:
3075
case glslang::EOpConstructBVec3:
3076
case glslang::EOpConstructBVec4:
3077
case glslang::EOpConstructInt8:
3078
case glslang::EOpConstructI8Vec2:
3079
case glslang::EOpConstructI8Vec3:
3080
case glslang::EOpConstructI8Vec4:
3081
case glslang::EOpConstructUint8:
3082
case glslang::EOpConstructU8Vec2:
3083
case glslang::EOpConstructU8Vec3:
3084
case glslang::EOpConstructU8Vec4:
3085
case glslang::EOpConstructInt16:
3086
case glslang::EOpConstructI16Vec2:
3087
case glslang::EOpConstructI16Vec3:
3088
case glslang::EOpConstructI16Vec4:
3089
case glslang::EOpConstructUint16:
3090
case glslang::EOpConstructU16Vec2:
3091
case glslang::EOpConstructU16Vec3:
3092
case glslang::EOpConstructU16Vec4:
3093
case glslang::EOpConstructInt:
3094
case glslang::EOpConstructIVec2:
3095
case glslang::EOpConstructIVec3:
3096
case glslang::EOpConstructIVec4:
3097
case glslang::EOpConstructUint:
3098
case glslang::EOpConstructUVec2:
3099
case glslang::EOpConstructUVec3:
3100
case glslang::EOpConstructUVec4:
3101
case glslang::EOpConstructInt64:
3102
case glslang::EOpConstructI64Vec2:
3103
case glslang::EOpConstructI64Vec3:
3104
case glslang::EOpConstructI64Vec4:
3105
case glslang::EOpConstructUint64:
3106
case glslang::EOpConstructU64Vec2:
3107
case glslang::EOpConstructU64Vec3:
3108
case glslang::EOpConstructU64Vec4:
3109
case glslang::EOpConstructStruct:
3110
case glslang::EOpConstructTextureSampler:
3111
case glslang::EOpConstructReference:
3112
case glslang::EOpConstructCooperativeMatrixNV:
3113
case glslang::EOpConstructCooperativeMatrixKHR:
3114
{
3115
builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
3116
std::vector<spv::Id> arguments;
3117
translateArguments(*node, arguments, lvalueCoherentFlags);
3118
spv::Id constructed;
3119
if (node->getOp() == glslang::EOpConstructTextureSampler) {
3120
const glslang::TType& texType = node->getSequence()[0]->getAsTyped()->getType();
3121
if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_6 &&
3122
texType.getSampler().isBuffer()) {
3123
// SamplerBuffer is not supported in spirv1.6 so
3124
// `samplerBuffer(textureBuffer, sampler)` is a no-op
3125
// and textureBuffer is the result going forward
3126
constructed = arguments[0];
3127
} else
3128
constructed = builder.createOp(spv::OpSampledImage, resultType(), arguments);
3129
} else if (node->getOp() == glslang::EOpConstructStruct ||
3130
node->getOp() == glslang::EOpConstructCooperativeMatrixNV ||
3131
node->getOp() == glslang::EOpConstructCooperativeMatrixKHR ||
3132
node->getType().isArray()) {
3133
std::vector<spv::Id> constituents;
3134
for (int c = 0; c < (int)arguments.size(); ++c)
3135
constituents.push_back(arguments[c]);
3136
constructed = createCompositeConstruct(resultType(), constituents);
3137
} else if (isMatrix)
3138
constructed = builder.createMatrixConstructor(precision, arguments, resultType());
3139
else
3140
constructed = builder.createConstructor(precision, arguments, resultType());
3141
3142
if (node->getType().getQualifier().isNonUniform()) {
3143
builder.addDecoration(constructed, spv::DecorationNonUniformEXT);
3144
}
3145
3146
builder.clearAccessChain();
3147
builder.setAccessChainRValue(constructed);
3148
3149
return false;
3150
}
3151
3152
// These six are component-wise compares with component-wise results.
3153
// Forward on to createBinaryOperation(), requesting a vector result.
3154
case glslang::EOpLessThan:
3155
case glslang::EOpGreaterThan:
3156
case glslang::EOpLessThanEqual:
3157
case glslang::EOpGreaterThanEqual:
3158
case glslang::EOpVectorEqual:
3159
case glslang::EOpVectorNotEqual:
3160
{
3161
// Map the operation to a binary
3162
binOp = node->getOp();
3163
reduceComparison = false;
3164
switch (node->getOp()) {
3165
case glslang::EOpVectorEqual: binOp = glslang::EOpVectorEqual; break;
3166
case glslang::EOpVectorNotEqual: binOp = glslang::EOpVectorNotEqual; break;
3167
default: binOp = node->getOp(); break;
3168
}
3169
3170
break;
3171
}
3172
case glslang::EOpMul:
3173
// component-wise matrix multiply
3174
binOp = glslang::EOpMul;
3175
break;
3176
case glslang::EOpOuterProduct:
3177
// two vectors multiplied to make a matrix
3178
binOp = glslang::EOpOuterProduct;
3179
break;
3180
case glslang::EOpDot:
3181
{
3182
// for scalar dot product, use multiply
3183
glslang::TIntermSequence& glslangOperands = node->getSequence();
3184
if (glslangOperands[0]->getAsTyped()->getVectorSize() == 1)
3185
binOp = glslang::EOpMul;
3186
break;
3187
}
3188
case glslang::EOpMod:
3189
// when an aggregate, this is the floating-point mod built-in function,
3190
// which can be emitted by the one in createBinaryOperation()
3191
binOp = glslang::EOpMod;
3192
break;
3193
3194
case glslang::EOpEmitVertex:
3195
case glslang::EOpEndPrimitive:
3196
case glslang::EOpBarrier:
3197
case glslang::EOpMemoryBarrier:
3198
case glslang::EOpMemoryBarrierAtomicCounter:
3199
case glslang::EOpMemoryBarrierBuffer:
3200
case glslang::EOpMemoryBarrierImage:
3201
case glslang::EOpMemoryBarrierShared:
3202
case glslang::EOpGroupMemoryBarrier:
3203
case glslang::EOpDeviceMemoryBarrier:
3204
case glslang::EOpAllMemoryBarrierWithGroupSync:
3205
case glslang::EOpDeviceMemoryBarrierWithGroupSync:
3206
case glslang::EOpWorkgroupMemoryBarrier:
3207
case glslang::EOpWorkgroupMemoryBarrierWithGroupSync:
3208
case glslang::EOpSubgroupBarrier:
3209
case glslang::EOpSubgroupMemoryBarrier:
3210
case glslang::EOpSubgroupMemoryBarrierBuffer:
3211
case glslang::EOpSubgroupMemoryBarrierImage:
3212
case glslang::EOpSubgroupMemoryBarrierShared:
3213
noReturnValue = true;
3214
// These all have 0 operands and will naturally finish up in the code below for 0 operands
3215
break;
3216
3217
case glslang::EOpAtomicAdd:
3218
case glslang::EOpAtomicSubtract:
3219
case glslang::EOpAtomicMin:
3220
case glslang::EOpAtomicMax:
3221
case glslang::EOpAtomicAnd:
3222
case glslang::EOpAtomicOr:
3223
case glslang::EOpAtomicXor:
3224
case glslang::EOpAtomicExchange:
3225
case glslang::EOpAtomicCompSwap:
3226
atomic = true;
3227
break;
3228
3229
case glslang::EOpAtomicStore:
3230
noReturnValue = true;
3231
[[fallthrough]];
3232
case glslang::EOpAtomicLoad:
3233
atomic = true;
3234
break;
3235
3236
case glslang::EOpAtomicCounterAdd:
3237
case glslang::EOpAtomicCounterSubtract:
3238
case glslang::EOpAtomicCounterMin:
3239
case glslang::EOpAtomicCounterMax:
3240
case glslang::EOpAtomicCounterAnd:
3241
case glslang::EOpAtomicCounterOr:
3242
case glslang::EOpAtomicCounterXor:
3243
case glslang::EOpAtomicCounterExchange:
3244
case glslang::EOpAtomicCounterCompSwap:
3245
builder.addExtension("SPV_KHR_shader_atomic_counter_ops");
3246
builder.addCapability(spv::CapabilityAtomicStorageOps);
3247
atomic = true;
3248
break;
3249
3250
case glslang::EOpAbsDifference:
3251
case glslang::EOpAddSaturate:
3252
case glslang::EOpSubSaturate:
3253
case glslang::EOpAverage:
3254
case glslang::EOpAverageRounded:
3255
case glslang::EOpMul32x16:
3256
builder.addCapability(spv::CapabilityIntegerFunctions2INTEL);
3257
builder.addExtension("SPV_INTEL_shader_integer_functions2");
3258
binOp = node->getOp();
3259
break;
3260
3261
case glslang::EOpExpectEXT:
3262
builder.addCapability(spv::CapabilityExpectAssumeKHR);
3263
builder.addExtension(spv::E_SPV_KHR_expect_assume);
3264
binOp = node->getOp();
3265
break;
3266
3267
case glslang::EOpIgnoreIntersectionNV:
3268
case glslang::EOpTerminateRayNV:
3269
case glslang::EOpTraceNV:
3270
case glslang::EOpTraceRayMotionNV:
3271
case glslang::EOpTraceKHR:
3272
case glslang::EOpExecuteCallableNV:
3273
case glslang::EOpExecuteCallableKHR:
3274
case glslang::EOpWritePackedPrimitiveIndices4x8NV:
3275
case glslang::EOpEmitMeshTasksEXT:
3276
case glslang::EOpSetMeshOutputsEXT:
3277
noReturnValue = true;
3278
break;
3279
case glslang::EOpRayQueryInitialize:
3280
case glslang::EOpRayQueryTerminate:
3281
case glslang::EOpRayQueryGenerateIntersection:
3282
case glslang::EOpRayQueryConfirmIntersection:
3283
builder.addExtension("SPV_KHR_ray_query");
3284
builder.addCapability(spv::CapabilityRayQueryKHR);
3285
noReturnValue = true;
3286
break;
3287
case glslang::EOpRayQueryProceed:
3288
case glslang::EOpRayQueryGetIntersectionType:
3289
case glslang::EOpRayQueryGetRayTMin:
3290
case glslang::EOpRayQueryGetRayFlags:
3291
case glslang::EOpRayQueryGetIntersectionT:
3292
case glslang::EOpRayQueryGetIntersectionInstanceCustomIndex:
3293
case glslang::EOpRayQueryGetIntersectionInstanceId:
3294
case glslang::EOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffset:
3295
case glslang::EOpRayQueryGetIntersectionGeometryIndex:
3296
case glslang::EOpRayQueryGetIntersectionPrimitiveIndex:
3297
case glslang::EOpRayQueryGetIntersectionBarycentrics:
3298
case glslang::EOpRayQueryGetIntersectionFrontFace:
3299
case glslang::EOpRayQueryGetIntersectionCandidateAABBOpaque:
3300
case glslang::EOpRayQueryGetIntersectionObjectRayDirection:
3301
case glslang::EOpRayQueryGetIntersectionObjectRayOrigin:
3302
case glslang::EOpRayQueryGetWorldRayDirection:
3303
case glslang::EOpRayQueryGetWorldRayOrigin:
3304
case glslang::EOpRayQueryGetIntersectionObjectToWorld:
3305
case glslang::EOpRayQueryGetIntersectionWorldToObject:
3306
builder.addExtension("SPV_KHR_ray_query");
3307
builder.addCapability(spv::CapabilityRayQueryKHR);
3308
break;
3309
case glslang::EOpCooperativeMatrixLoad:
3310
case glslang::EOpCooperativeMatrixStore:
3311
case glslang::EOpCooperativeMatrixLoadNV:
3312
case glslang::EOpCooperativeMatrixStoreNV:
3313
noReturnValue = true;
3314
break;
3315
case glslang::EOpBeginInvocationInterlock:
3316
case glslang::EOpEndInvocationInterlock:
3317
builder.addExtension(spv::E_SPV_EXT_fragment_shader_interlock);
3318
noReturnValue = true;
3319
break;
3320
3321
case glslang::EOpHitObjectTraceRayNV:
3322
case glslang::EOpHitObjectTraceRayMotionNV:
3323
case glslang::EOpHitObjectGetAttributesNV:
3324
case glslang::EOpHitObjectExecuteShaderNV:
3325
case glslang::EOpHitObjectRecordEmptyNV:
3326
case glslang::EOpHitObjectRecordMissNV:
3327
case glslang::EOpHitObjectRecordMissMotionNV:
3328
case glslang::EOpHitObjectRecordHitNV:
3329
case glslang::EOpHitObjectRecordHitMotionNV:
3330
case glslang::EOpHitObjectRecordHitWithIndexNV:
3331
case glslang::EOpHitObjectRecordHitWithIndexMotionNV:
3332
case glslang::EOpReorderThreadNV:
3333
noReturnValue = true;
3334
[[fallthrough]];
3335
case glslang::EOpHitObjectIsEmptyNV:
3336
case glslang::EOpHitObjectIsMissNV:
3337
case glslang::EOpHitObjectIsHitNV:
3338
case glslang::EOpHitObjectGetRayTMinNV:
3339
case glslang::EOpHitObjectGetRayTMaxNV:
3340
case glslang::EOpHitObjectGetObjectRayOriginNV:
3341
case glslang::EOpHitObjectGetObjectRayDirectionNV:
3342
case glslang::EOpHitObjectGetWorldRayOriginNV:
3343
case glslang::EOpHitObjectGetWorldRayDirectionNV:
3344
case glslang::EOpHitObjectGetObjectToWorldNV:
3345
case glslang::EOpHitObjectGetWorldToObjectNV:
3346
case glslang::EOpHitObjectGetInstanceCustomIndexNV:
3347
case glslang::EOpHitObjectGetInstanceIdNV:
3348
case glslang::EOpHitObjectGetGeometryIndexNV:
3349
case glslang::EOpHitObjectGetPrimitiveIndexNV:
3350
case glslang::EOpHitObjectGetHitKindNV:
3351
case glslang::EOpHitObjectGetCurrentTimeNV:
3352
case glslang::EOpHitObjectGetShaderBindingTableRecordIndexNV:
3353
case glslang::EOpHitObjectGetShaderRecordBufferHandleNV:
3354
builder.addExtension(spv::E_SPV_NV_shader_invocation_reorder);
3355
builder.addCapability(spv::CapabilityShaderInvocationReorderNV);
3356
break;
3357
case glslang::EOpRayQueryGetIntersectionTriangleVertexPositionsEXT:
3358
builder.addExtension(spv::E_SPV_KHR_ray_tracing_position_fetch);
3359
builder.addCapability(spv::CapabilityRayQueryPositionFetchKHR);
3360
noReturnValue = true;
3361
break;
3362
3363
case glslang::EOpImageSampleWeightedQCOM:
3364
builder.addCapability(spv::CapabilityTextureSampleWeightedQCOM);
3365
builder.addExtension(spv::E_SPV_QCOM_image_processing);
3366
break;
3367
case glslang::EOpImageBoxFilterQCOM:
3368
builder.addCapability(spv::CapabilityTextureBoxFilterQCOM);
3369
builder.addExtension(spv::E_SPV_QCOM_image_processing);
3370
break;
3371
case glslang::EOpImageBlockMatchSADQCOM:
3372
case glslang::EOpImageBlockMatchSSDQCOM:
3373
builder.addCapability(spv::CapabilityTextureBlockMatchQCOM);
3374
builder.addExtension(spv::E_SPV_QCOM_image_processing);
3375
break;
3376
3377
case glslang::EOpImageBlockMatchWindowSSDQCOM:
3378
case glslang::EOpImageBlockMatchWindowSADQCOM:
3379
builder.addCapability(spv::CapabilityTextureBlockMatchQCOM);
3380
builder.addExtension(spv::E_SPV_QCOM_image_processing);
3381
builder.addCapability(spv::CapabilityTextureBlockMatch2QCOM);
3382
builder.addExtension(spv::E_SPV_QCOM_image_processing2);
3383
break;
3384
3385
case glslang::EOpImageBlockMatchGatherSSDQCOM:
3386
case glslang::EOpImageBlockMatchGatherSADQCOM:
3387
builder.addCapability(spv::CapabilityTextureBlockMatchQCOM);
3388
builder.addExtension(spv::E_SPV_QCOM_image_processing);
3389
builder.addCapability(spv::CapabilityTextureBlockMatch2QCOM);
3390
builder.addExtension(spv::E_SPV_QCOM_image_processing2);
3391
break;
3392
3393
case glslang::EOpFetchMicroTriangleVertexPositionNV:
3394
case glslang::EOpFetchMicroTriangleVertexBarycentricNV:
3395
builder.addExtension(spv::E_SPV_NV_displacement_micromap);
3396
builder.addCapability(spv::CapabilityDisplacementMicromapNV);
3397
break;
3398
3399
case glslang::EOpDebugPrintf:
3400
noReturnValue = true;
3401
break;
3402
3403
default:
3404
break;
3405
}
3406
3407
//
3408
// See if it maps to a regular operation.
3409
//
3410
if (binOp != glslang::EOpNull) {
3411
glslang::TIntermTyped* left = node->getSequence()[0]->getAsTyped();
3412
glslang::TIntermTyped* right = node->getSequence()[1]->getAsTyped();
3413
assert(left && right);
3414
3415
builder.clearAccessChain();
3416
left->traverse(this);
3417
spv::Id leftId = accessChainLoad(left->getType());
3418
3419
builder.clearAccessChain();
3420
right->traverse(this);
3421
spv::Id rightId = accessChainLoad(right->getType());
3422
3423
builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
3424
OpDecorations decorations = { precision,
3425
TranslateNoContractionDecoration(node->getType().getQualifier()),
3426
TranslateNonUniformDecoration(node->getType().getQualifier()) };
3427
result = createBinaryOperation(binOp, decorations,
3428
resultType(), leftId, rightId,
3429
left->getType().getBasicType(), reduceComparison);
3430
3431
// code above should only make binOp that exists in createBinaryOperation
3432
assert(result != spv::NoResult);
3433
builder.clearAccessChain();
3434
builder.setAccessChainRValue(result);
3435
3436
return false;
3437
}
3438
3439
//
3440
// Create the list of operands.
3441
//
3442
glslang::TIntermSequence& glslangOperands = node->getSequence();
3443
std::vector<spv::Id> operands;
3444
std::vector<spv::IdImmediate> memoryAccessOperands;
3445
for (int arg = 0; arg < (int)glslangOperands.size(); ++arg) {
3446
// special case l-value operands; there are just a few
3447
bool lvalue = false;
3448
switch (node->getOp()) {
3449
case glslang::EOpModf:
3450
if (arg == 1)
3451
lvalue = true;
3452
break;
3453
3454
3455
3456
case glslang::EOpHitObjectRecordHitNV:
3457
case glslang::EOpHitObjectRecordHitMotionNV:
3458
case glslang::EOpHitObjectRecordHitWithIndexNV:
3459
case glslang::EOpHitObjectRecordHitWithIndexMotionNV:
3460
case glslang::EOpHitObjectTraceRayNV:
3461
case glslang::EOpHitObjectTraceRayMotionNV:
3462
case glslang::EOpHitObjectExecuteShaderNV:
3463
case glslang::EOpHitObjectRecordMissNV:
3464
case glslang::EOpHitObjectRecordMissMotionNV:
3465
case glslang::EOpHitObjectGetAttributesNV:
3466
if (arg == 0)
3467
lvalue = true;
3468
break;
3469
3470
case glslang::EOpRayQueryInitialize:
3471
case glslang::EOpRayQueryTerminate:
3472
case glslang::EOpRayQueryConfirmIntersection:
3473
case glslang::EOpRayQueryProceed:
3474
case glslang::EOpRayQueryGenerateIntersection:
3475
case glslang::EOpRayQueryGetIntersectionType:
3476
case glslang::EOpRayQueryGetIntersectionT:
3477
case glslang::EOpRayQueryGetIntersectionInstanceCustomIndex:
3478
case glslang::EOpRayQueryGetIntersectionInstanceId:
3479
case glslang::EOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffset:
3480
case glslang::EOpRayQueryGetIntersectionGeometryIndex:
3481
case glslang::EOpRayQueryGetIntersectionPrimitiveIndex:
3482
case glslang::EOpRayQueryGetIntersectionBarycentrics:
3483
case glslang::EOpRayQueryGetIntersectionFrontFace:
3484
case glslang::EOpRayQueryGetIntersectionObjectRayDirection:
3485
case glslang::EOpRayQueryGetIntersectionObjectRayOrigin:
3486
case glslang::EOpRayQueryGetIntersectionObjectToWorld:
3487
case glslang::EOpRayQueryGetIntersectionWorldToObject:
3488
if (arg == 0)
3489
lvalue = true;
3490
break;
3491
3492
case glslang::EOpAtomicAdd:
3493
case glslang::EOpAtomicSubtract:
3494
case glslang::EOpAtomicMin:
3495
case glslang::EOpAtomicMax:
3496
case glslang::EOpAtomicAnd:
3497
case glslang::EOpAtomicOr:
3498
case glslang::EOpAtomicXor:
3499
case glslang::EOpAtomicExchange:
3500
case glslang::EOpAtomicCompSwap:
3501
if (arg == 0)
3502
lvalue = true;
3503
break;
3504
3505
case glslang::EOpFrexp:
3506
if (arg == 1)
3507
lvalue = true;
3508
break;
3509
case glslang::EOpInterpolateAtSample:
3510
case glslang::EOpInterpolateAtOffset:
3511
case glslang::EOpInterpolateAtVertex:
3512
if (arg == 0) {
3513
// If GLSL, use the address of the interpolant argument.
3514
// If HLSL, use an internal version of OpInterolates that takes
3515
// the rvalue of the interpolant. A fixup pass in spirv-opt
3516
// legalization will remove the OpLoad and convert to an lvalue.
3517
// Had to do this because legalization will only propagate a
3518
// builtin into an rvalue.
3519
lvalue = glslangIntermediate->getSource() != glslang::EShSourceHlsl;
3520
3521
// Does it need a swizzle inversion? If so, evaluation is inverted;
3522
// operate first on the swizzle base, then apply the swizzle.
3523
// That is, we transform
3524
//
3525
// interpolate(v.zy) -> interpolate(v).zy
3526
//
3527
if (glslangOperands[0]->getAsOperator() &&
3528
glslangOperands[0]->getAsOperator()->getOp() == glslang::EOpVectorSwizzle)
3529
invertedType = convertGlslangToSpvType(
3530
glslangOperands[0]->getAsBinaryNode()->getLeft()->getType());
3531
}
3532
break;
3533
case glslang::EOpAtomicLoad:
3534
case glslang::EOpAtomicStore:
3535
case glslang::EOpAtomicCounterAdd:
3536
case glslang::EOpAtomicCounterSubtract:
3537
case glslang::EOpAtomicCounterMin:
3538
case glslang::EOpAtomicCounterMax:
3539
case glslang::EOpAtomicCounterAnd:
3540
case glslang::EOpAtomicCounterOr:
3541
case glslang::EOpAtomicCounterXor:
3542
case glslang::EOpAtomicCounterExchange:
3543
case glslang::EOpAtomicCounterCompSwap:
3544
if (arg == 0)
3545
lvalue = true;
3546
break;
3547
case glslang::EOpAddCarry:
3548
case glslang::EOpSubBorrow:
3549
if (arg == 2)
3550
lvalue = true;
3551
break;
3552
case glslang::EOpUMulExtended:
3553
case glslang::EOpIMulExtended:
3554
if (arg >= 2)
3555
lvalue = true;
3556
break;
3557
case glslang::EOpCooperativeMatrixLoad:
3558
case glslang::EOpCooperativeMatrixLoadNV:
3559
if (arg == 0 || arg == 1)
3560
lvalue = true;
3561
break;
3562
case glslang::EOpCooperativeMatrixStore:
3563
case glslang::EOpCooperativeMatrixStoreNV:
3564
if (arg == 1)
3565
lvalue = true;
3566
break;
3567
case glslang::EOpSpirvInst:
3568
if (glslangOperands[arg]->getAsTyped()->getQualifier().isSpirvByReference())
3569
lvalue = true;
3570
break;
3571
case glslang::EOpReorderThreadNV:
3572
//Three variants of reorderThreadNV, two of them use hitObjectNV
3573
if (arg == 0 && glslangOperands.size() != 2)
3574
lvalue = true;
3575
break;
3576
case glslang::EOpRayQueryGetIntersectionTriangleVertexPositionsEXT:
3577
if (arg == 0 || arg == 2)
3578
lvalue = true;
3579
break;
3580
default:
3581
break;
3582
}
3583
builder.clearAccessChain();
3584
if (invertedType != spv::NoType && arg == 0)
3585
glslangOperands[0]->getAsBinaryNode()->getLeft()->traverse(this);
3586
else
3587
glslangOperands[arg]->traverse(this);
3588
3589
if (node->getOp() == glslang::EOpCooperativeMatrixLoad ||
3590
node->getOp() == glslang::EOpCooperativeMatrixStore ||
3591
node->getOp() == glslang::EOpCooperativeMatrixLoadNV ||
3592
node->getOp() == glslang::EOpCooperativeMatrixStoreNV) {
3593
3594
if (arg == 1) {
3595
// fold "element" parameter into the access chain
3596
spv::Builder::AccessChain save = builder.getAccessChain();
3597
builder.clearAccessChain();
3598
glslangOperands[2]->traverse(this);
3599
3600
spv::Id elementId = accessChainLoad(glslangOperands[2]->getAsTyped()->getType());
3601
3602
builder.setAccessChain(save);
3603
3604
// Point to the first element of the array.
3605
builder.accessChainPush(elementId,
3606
TranslateCoherent(glslangOperands[arg]->getAsTyped()->getType()),
3607
glslangOperands[arg]->getAsTyped()->getType().getBufferReferenceAlignment());
3608
3609
spv::Builder::AccessChain::CoherentFlags coherentFlags = builder.getAccessChain().coherentFlags;
3610
unsigned int alignment = builder.getAccessChain().alignment;
3611
3612
int memoryAccess = TranslateMemoryAccess(coherentFlags);
3613
if (node->getOp() == glslang::EOpCooperativeMatrixLoad ||
3614
node->getOp() == glslang::EOpCooperativeMatrixLoadNV)
3615
memoryAccess &= ~spv::MemoryAccessMakePointerAvailableKHRMask;
3616
if (node->getOp() == glslang::EOpCooperativeMatrixStore ||
3617
node->getOp() == glslang::EOpCooperativeMatrixStoreNV)
3618
memoryAccess &= ~spv::MemoryAccessMakePointerVisibleKHRMask;
3619
if (builder.getStorageClass(builder.getAccessChain().base) ==
3620
spv::StorageClassPhysicalStorageBufferEXT) {
3621
memoryAccess = (spv::MemoryAccessMask)(memoryAccess | spv::MemoryAccessAlignedMask);
3622
}
3623
3624
memoryAccessOperands.push_back(spv::IdImmediate(false, memoryAccess));
3625
3626
if (memoryAccess & spv::MemoryAccessAlignedMask) {
3627
memoryAccessOperands.push_back(spv::IdImmediate(false, alignment));
3628
}
3629
3630
if (memoryAccess &
3631
(spv::MemoryAccessMakePointerAvailableKHRMask | spv::MemoryAccessMakePointerVisibleKHRMask)) {
3632
memoryAccessOperands.push_back(spv::IdImmediate(true,
3633
builder.makeUintConstant(TranslateMemoryScope(coherentFlags))));
3634
}
3635
} else if (arg == 2) {
3636
continue;
3637
}
3638
}
3639
3640
// for l-values, pass the address, for r-values, pass the value
3641
if (lvalue) {
3642
if (invertedType == spv::NoType && !builder.isSpvLvalue()) {
3643
// SPIR-V cannot represent an l-value containing a swizzle that doesn't
3644
// reduce to a simple access chain. So, we need a temporary vector to
3645
// receive the result, and must later swizzle that into the original
3646
// l-value.
3647
complexLvalues.push_back(builder.getAccessChain());
3648
temporaryLvalues.push_back(builder.createVariable(
3649
spv::NoPrecision, spv::StorageClassFunction,
3650
builder.accessChainGetInferredType(), "swizzleTemp"));
3651
operands.push_back(temporaryLvalues.back());
3652
} else {
3653
operands.push_back(builder.accessChainGetLValue());
3654
}
3655
lvalueCoherentFlags = builder.getAccessChain().coherentFlags;
3656
lvalueCoherentFlags |= TranslateCoherent(glslangOperands[arg]->getAsTyped()->getType());
3657
} else {
3658
builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
3659
glslang::TOperator glslangOp = node->getOp();
3660
if (arg == 1 &&
3661
(glslangOp == glslang::EOpRayQueryGetIntersectionType ||
3662
glslangOp == glslang::EOpRayQueryGetIntersectionT ||
3663
glslangOp == glslang::EOpRayQueryGetIntersectionInstanceCustomIndex ||
3664
glslangOp == glslang::EOpRayQueryGetIntersectionInstanceId ||
3665
glslangOp == glslang::EOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffset ||
3666
glslangOp == glslang::EOpRayQueryGetIntersectionGeometryIndex ||
3667
glslangOp == glslang::EOpRayQueryGetIntersectionPrimitiveIndex ||
3668
glslangOp == glslang::EOpRayQueryGetIntersectionBarycentrics ||
3669
glslangOp == glslang::EOpRayQueryGetIntersectionFrontFace ||
3670
glslangOp == glslang::EOpRayQueryGetIntersectionObjectRayDirection ||
3671
glslangOp == glslang::EOpRayQueryGetIntersectionObjectRayOrigin ||
3672
glslangOp == glslang::EOpRayQueryGetIntersectionObjectToWorld ||
3673
glslangOp == glslang::EOpRayQueryGetIntersectionWorldToObject ||
3674
glslangOp == glslang::EOpRayQueryGetIntersectionTriangleVertexPositionsEXT
3675
)) {
3676
bool cond = glslangOperands[arg]->getAsConstantUnion()->getConstArray()[0].getBConst();
3677
operands.push_back(builder.makeIntConstant(cond ? 1 : 0));
3678
} else if ((arg == 10 && glslangOp == glslang::EOpTraceKHR) ||
3679
(arg == 11 && glslangOp == glslang::EOpTraceRayMotionNV) ||
3680
(arg == 1 && glslangOp == glslang::EOpExecuteCallableKHR) ||
3681
(arg == 1 && glslangOp == glslang::EOpHitObjectExecuteShaderNV) ||
3682
(arg == 11 && glslangOp == glslang::EOpHitObjectTraceRayNV) ||
3683
(arg == 12 && glslangOp == glslang::EOpHitObjectTraceRayMotionNV)) {
3684
const int set = glslangOp == glslang::EOpExecuteCallableKHR ? 1 : 0;
3685
const int location = glslangOperands[arg]->getAsConstantUnion()->getConstArray()[0].getUConst();
3686
auto itNode = locationToSymbol[set].find(location);
3687
visitSymbol(itNode->second);
3688
spv::Id symId = getSymbolId(itNode->second);
3689
operands.push_back(symId);
3690
} else if ((arg == 12 && glslangOp == glslang::EOpHitObjectRecordHitNV) ||
3691
(arg == 13 && glslangOp == glslang::EOpHitObjectRecordHitMotionNV) ||
3692
(arg == 11 && glslangOp == glslang::EOpHitObjectRecordHitWithIndexNV) ||
3693
(arg == 12 && glslangOp == glslang::EOpHitObjectRecordHitWithIndexMotionNV) ||
3694
(arg == 1 && glslangOp == glslang::EOpHitObjectGetAttributesNV)) {
3695
const int location = glslangOperands[arg]->getAsConstantUnion()->getConstArray()[0].getUConst();
3696
const int set = 2;
3697
auto itNode = locationToSymbol[set].find(location);
3698
visitSymbol(itNode->second);
3699
spv::Id symId = getSymbolId(itNode->second);
3700
operands.push_back(symId);
3701
} else if (glslangOperands[arg]->getAsTyped()->getQualifier().isSpirvLiteral()) {
3702
// Will be translated to a literal value, make a placeholder here
3703
operands.push_back(spv::NoResult);
3704
} else {
3705
operands.push_back(accessChainLoad(glslangOperands[arg]->getAsTyped()->getType()));
3706
}
3707
}
3708
}
3709
3710
builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
3711
if (node->getOp() == glslang::EOpCooperativeMatrixLoad ||
3712
node->getOp() == glslang::EOpCooperativeMatrixLoadNV) {
3713
std::vector<spv::IdImmediate> idImmOps;
3714
3715
idImmOps.push_back(spv::IdImmediate(true, operands[1])); // buf
3716
if (node->getOp() == glslang::EOpCooperativeMatrixLoad) {
3717
idImmOps.push_back(spv::IdImmediate(true, operands[3])); // matrixLayout
3718
idImmOps.push_back(spv::IdImmediate(true, operands[2])); // stride
3719
} else {
3720
idImmOps.push_back(spv::IdImmediate(true, operands[2])); // stride
3721
idImmOps.push_back(spv::IdImmediate(true, operands[3])); // colMajor
3722
}
3723
idImmOps.insert(idImmOps.end(), memoryAccessOperands.begin(), memoryAccessOperands.end());
3724
// get the pointee type
3725
spv::Id typeId = builder.getContainedTypeId(builder.getTypeId(operands[0]));
3726
assert(builder.isCooperativeMatrixType(typeId));
3727
// do the op
3728
spv::Id result = node->getOp() == glslang::EOpCooperativeMatrixLoad
3729
? builder.createOp(spv::OpCooperativeMatrixLoadKHR, typeId, idImmOps)
3730
: builder.createOp(spv::OpCooperativeMatrixLoadNV, typeId, idImmOps);
3731
// store the result to the pointer (out param 'm')
3732
builder.createStore(result, operands[0]);
3733
result = 0;
3734
} else if (node->getOp() == glslang::EOpCooperativeMatrixStore ||
3735
node->getOp() == glslang::EOpCooperativeMatrixStoreNV) {
3736
std::vector<spv::IdImmediate> idImmOps;
3737
3738
idImmOps.push_back(spv::IdImmediate(true, operands[1])); // buf
3739
idImmOps.push_back(spv::IdImmediate(true, operands[0])); // object
3740
if (node->getOp() == glslang::EOpCooperativeMatrixStore) {
3741
idImmOps.push_back(spv::IdImmediate(true, operands[3])); // matrixLayout
3742
idImmOps.push_back(spv::IdImmediate(true, operands[2])); // stride
3743
} else {
3744
idImmOps.push_back(spv::IdImmediate(true, operands[2])); // stride
3745
idImmOps.push_back(spv::IdImmediate(true, operands[3])); // colMajor
3746
}
3747
idImmOps.insert(idImmOps.end(), memoryAccessOperands.begin(), memoryAccessOperands.end());
3748
3749
if (node->getOp() == glslang::EOpCooperativeMatrixStore)
3750
builder.createNoResultOp(spv::OpCooperativeMatrixStoreKHR, idImmOps);
3751
else
3752
builder.createNoResultOp(spv::OpCooperativeMatrixStoreNV, idImmOps);
3753
result = 0;
3754
} else if (node->getOp() == glslang::EOpRayQueryGetIntersectionTriangleVertexPositionsEXT) {
3755
std::vector<spv::IdImmediate> idImmOps;
3756
3757
idImmOps.push_back(spv::IdImmediate(true, operands[0])); // q
3758
idImmOps.push_back(spv::IdImmediate(true, operands[1])); // committed
3759
3760
spv::Id typeId = builder.makeArrayType(builder.makeVectorType(builder.makeFloatType(32), 3),
3761
builder.makeUintConstant(3), 0);
3762
// do the op
3763
3764
spv::Op spvOp = spv::OpRayQueryGetIntersectionTriangleVertexPositionsKHR;
3765
3766
spv::Id result = builder.createOp(spvOp, typeId, idImmOps);
3767
// store the result to the pointer (out param 'm')
3768
builder.createStore(result, operands[2]);
3769
result = 0;
3770
} else if (node->getOp() == glslang::EOpCooperativeMatrixMulAdd) {
3771
uint32_t matrixOperands = 0;
3772
3773
// If the optional operand is present, initialize matrixOperands to that value.
3774
if (glslangOperands.size() == 4 && glslangOperands[3]->getAsConstantUnion()) {
3775
matrixOperands = glslangOperands[3]->getAsConstantUnion()->getConstArray()[0].getIConst();
3776
}
3777
3778
// Determine Cooperative Matrix Operands bits from the signedness of the types.
3779
if (isTypeSignedInt(glslangOperands[0]->getAsTyped()->getBasicType()))
3780
matrixOperands |= spv::CooperativeMatrixOperandsMatrixASignedComponentsKHRMask;
3781
if (isTypeSignedInt(glslangOperands[1]->getAsTyped()->getBasicType()))
3782
matrixOperands |= spv::CooperativeMatrixOperandsMatrixBSignedComponentsKHRMask;
3783
if (isTypeSignedInt(glslangOperands[2]->getAsTyped()->getBasicType()))
3784
matrixOperands |= spv::CooperativeMatrixOperandsMatrixCSignedComponentsKHRMask;
3785
if (isTypeSignedInt(node->getBasicType()))
3786
matrixOperands |= spv::CooperativeMatrixOperandsMatrixResultSignedComponentsKHRMask;
3787
3788
std::vector<spv::IdImmediate> idImmOps;
3789
idImmOps.push_back(spv::IdImmediate(true, operands[0]));
3790
idImmOps.push_back(spv::IdImmediate(true, operands[1]));
3791
idImmOps.push_back(spv::IdImmediate(true, operands[2]));
3792
if (matrixOperands != 0)
3793
idImmOps.push_back(spv::IdImmediate(false, matrixOperands));
3794
3795
result = builder.createOp(spv::OpCooperativeMatrixMulAddKHR, resultType(), idImmOps);
3796
} else if (atomic) {
3797
// Handle all atomics
3798
glslang::TBasicType typeProxy = (node->getOp() == glslang::EOpAtomicStore)
3799
? node->getSequence()[0]->getAsTyped()->getBasicType() : node->getBasicType();
3800
result = createAtomicOperation(node->getOp(), precision, resultType(), operands, typeProxy,
3801
lvalueCoherentFlags, node->getType());
3802
} else if (node->getOp() == glslang::EOpSpirvInst) {
3803
const auto& spirvInst = node->getSpirvInstruction();
3804
if (spirvInst.set == "") {
3805
std::vector<spv::IdImmediate> idImmOps;
3806
for (unsigned int i = 0; i < glslangOperands.size(); ++i) {
3807
if (glslangOperands[i]->getAsTyped()->getQualifier().isSpirvLiteral()) {
3808
// Translate the constant to a literal value
3809
std::vector<unsigned> literals;
3810
glslang::TVector<const glslang::TIntermConstantUnion*> constants;
3811
constants.push_back(glslangOperands[i]->getAsConstantUnion());
3812
TranslateLiterals(constants, literals);
3813
idImmOps.push_back({false, literals[0]});
3814
} else
3815
idImmOps.push_back({true, operands[i]});
3816
}
3817
3818
if (node->getBasicType() == glslang::EbtVoid)
3819
builder.createNoResultOp(static_cast<spv::Op>(spirvInst.id), idImmOps);
3820
else
3821
result = builder.createOp(static_cast<spv::Op>(spirvInst.id), resultType(), idImmOps);
3822
} else {
3823
result = builder.createBuiltinCall(
3824
resultType(), spirvInst.set == "GLSL.std.450" ? stdBuiltins : getExtBuiltins(spirvInst.set.c_str()),
3825
spirvInst.id, operands);
3826
}
3827
noReturnValue = node->getBasicType() == glslang::EbtVoid;
3828
} else if (node->getOp() == glslang::EOpDebugPrintf) {
3829
if (!nonSemanticDebugPrintf) {
3830
nonSemanticDebugPrintf = builder.import("NonSemantic.DebugPrintf");
3831
}
3832
result = builder.createBuiltinCall(builder.makeVoidType(), nonSemanticDebugPrintf, spv::NonSemanticDebugPrintfDebugPrintf, operands);
3833
builder.addExtension(spv::E_SPV_KHR_non_semantic_info);
3834
} else {
3835
// Pass through to generic operations.
3836
switch (glslangOperands.size()) {
3837
case 0:
3838
result = createNoArgOperation(node->getOp(), precision, resultType());
3839
break;
3840
case 1:
3841
{
3842
OpDecorations decorations = { precision,
3843
TranslateNoContractionDecoration(node->getType().getQualifier()),
3844
TranslateNonUniformDecoration(node->getType().getQualifier()) };
3845
result = createUnaryOperation(
3846
node->getOp(), decorations,
3847
resultType(), operands.front(),
3848
glslangOperands[0]->getAsTyped()->getBasicType(), lvalueCoherentFlags, node->getType());
3849
}
3850
break;
3851
default:
3852
result = createMiscOperation(node->getOp(), precision, resultType(), operands, node->getBasicType());
3853
break;
3854
}
3855
3856
if (invertedType != spv::NoResult)
3857
result = createInvertedSwizzle(precision, *glslangOperands[0]->getAsBinaryNode(), result);
3858
3859
for (unsigned int i = 0; i < temporaryLvalues.size(); ++i) {
3860
builder.setAccessChain(complexLvalues[i]);
3861
builder.accessChainStore(builder.createLoad(temporaryLvalues[i], spv::NoPrecision),
3862
TranslateNonUniformDecoration(complexLvalues[i].coherentFlags));
3863
}
3864
}
3865
3866
if (noReturnValue)
3867
return false;
3868
3869
if (! result) {
3870
logger->missingFunctionality("unknown glslang aggregate");
3871
return true; // pick up a child as a placeholder operand
3872
} else {
3873
builder.clearAccessChain();
3874
builder.setAccessChainRValue(result);
3875
return false;
3876
}
3877
}
3878
3879
// This path handles both if-then-else and ?:
3880
// The if-then-else has a node type of void, while
3881
// ?: has either a void or a non-void node type
3882
//
3883
// Leaving the result, when not void:
3884
// GLSL only has r-values as the result of a :?, but
3885
// if we have an l-value, that can be more efficient if it will
3886
// become the base of a complex r-value expression, because the
3887
// next layer copies r-values into memory to use the access-chain mechanism
3888
bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang::TIntermSelection* node)
3889
{
3890
// see if OpSelect can handle it
3891
const auto isOpSelectable = [&]() {
3892
if (node->getBasicType() == glslang::EbtVoid)
3893
return false;
3894
// OpSelect can do all other types starting with SPV 1.4
3895
if (glslangIntermediate->getSpv().spv < glslang::EShTargetSpv_1_4) {
3896
// pre-1.4, only scalars and vectors can be handled
3897
if ((!node->getType().isScalar() && !node->getType().isVector()))
3898
return false;
3899
}
3900
return true;
3901
};
3902
3903
// See if it simple and safe, or required, to execute both sides.
3904
// Crucially, side effects must be either semantically required or avoided,
3905
// and there are performance trade-offs.
3906
// Return true if required or a good idea (and safe) to execute both sides,
3907
// false otherwise.
3908
const auto bothSidesPolicy = [&]() -> bool {
3909
// do we have both sides?
3910
if (node->getTrueBlock() == nullptr ||
3911
node->getFalseBlock() == nullptr)
3912
return false;
3913
3914
// required? (unless we write additional code to look for side effects
3915
// and make performance trade-offs if none are present)
3916
if (!node->getShortCircuit())
3917
return true;
3918
3919
// if not required to execute both, decide based on performance/practicality...
3920
3921
if (!isOpSelectable())
3922
return false;
3923
3924
assert(node->getType() == node->getTrueBlock() ->getAsTyped()->getType() &&
3925
node->getType() == node->getFalseBlock()->getAsTyped()->getType());
3926
3927
// return true if a single operand to ? : is okay for OpSelect
3928
const auto operandOkay = [](glslang::TIntermTyped* node) {
3929
return node->getAsSymbolNode() || node->getType().getQualifier().isConstant();
3930
};
3931
3932
return operandOkay(node->getTrueBlock() ->getAsTyped()) &&
3933
operandOkay(node->getFalseBlock()->getAsTyped());
3934
};
3935
3936
spv::Id result = spv::NoResult; // upcoming result selecting between trueValue and falseValue
3937
// emit the condition before doing anything with selection
3938
node->getCondition()->traverse(this);
3939
spv::Id condition = accessChainLoad(node->getCondition()->getType());
3940
3941
// Find a way of executing both sides and selecting the right result.
3942
const auto executeBothSides = [&]() -> void {
3943
// execute both sides
3944
spv::Id resultType = convertGlslangToSpvType(node->getType());
3945
node->getTrueBlock()->traverse(this);
3946
spv::Id trueValue = accessChainLoad(node->getTrueBlock()->getAsTyped()->getType());
3947
node->getFalseBlock()->traverse(this);
3948
spv::Id falseValue = accessChainLoad(node->getFalseBlock()->getAsTyped()->getType());
3949
3950
builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
3951
3952
// done if void
3953
if (node->getBasicType() == glslang::EbtVoid)
3954
return;
3955
3956
// emit code to select between trueValue and falseValue
3957
// see if OpSelect can handle the result type, and that the SPIR-V types
3958
// of the inputs match the result type.
3959
if (isOpSelectable()) {
3960
// Emit OpSelect for this selection.
3961
3962
// smear condition to vector, if necessary (AST is always scalar)
3963
// Before 1.4, smear like for mix(), starting with 1.4, keep it scalar
3964
if (glslangIntermediate->getSpv().spv < glslang::EShTargetSpv_1_4 && builder.isVector(trueValue)) {
3965
condition = builder.smearScalar(spv::NoPrecision, condition,
3966
builder.makeVectorType(builder.makeBoolType(),
3967
builder.getNumComponents(trueValue)));
3968
}
3969
3970
// If the types do not match, it is because of mismatched decorations on aggregates.
3971
// Since isOpSelectable only lets us get here for SPIR-V >= 1.4, we can use OpCopyObject
3972
// to get matching types.
3973
if (builder.getTypeId(trueValue) != resultType) {
3974
trueValue = builder.createUnaryOp(spv::OpCopyLogical, resultType, trueValue);
3975
}
3976
if (builder.getTypeId(falseValue) != resultType) {
3977
falseValue = builder.createUnaryOp(spv::OpCopyLogical, resultType, falseValue);
3978
}
3979
3980
// OpSelect
3981
result = builder.createTriOp(spv::OpSelect, resultType, condition, trueValue, falseValue);
3982
3983
builder.clearAccessChain();
3984
builder.setAccessChainRValue(result);
3985
} else {
3986
// We need control flow to select the result.
3987
// TODO: Once SPIR-V OpSelect allows arbitrary types, eliminate this path.
3988
result = builder.createVariable(TranslatePrecisionDecoration(node->getType()),
3989
spv::StorageClassFunction, resultType);
3990
3991
// Selection control:
3992
const spv::SelectionControlMask control = TranslateSelectionControl(*node);
3993
3994
// make an "if" based on the value created by the condition
3995
spv::Builder::If ifBuilder(condition, control, builder);
3996
3997
// emit the "then" statement
3998
builder.clearAccessChain();
3999
builder.setAccessChainLValue(result);
4000
multiTypeStore(node->getType(), trueValue);
4001
4002
ifBuilder.makeBeginElse();
4003
// emit the "else" statement
4004
builder.clearAccessChain();
4005
builder.setAccessChainLValue(result);
4006
multiTypeStore(node->getType(), falseValue);
4007
4008
// finish off the control flow
4009
ifBuilder.makeEndIf();
4010
4011
builder.clearAccessChain();
4012
builder.setAccessChainLValue(result);
4013
}
4014
};
4015
4016
// Execute the one side needed, as per the condition
4017
const auto executeOneSide = [&]() {
4018
// Always emit control flow.
4019
if (node->getBasicType() != glslang::EbtVoid) {
4020
result = builder.createVariable(TranslatePrecisionDecoration(node->getType()), spv::StorageClassFunction,
4021
convertGlslangToSpvType(node->getType()));
4022
}
4023
4024
// Selection control:
4025
const spv::SelectionControlMask control = TranslateSelectionControl(*node);
4026
4027
// make an "if" based on the value created by the condition
4028
spv::Builder::If ifBuilder(condition, control, builder);
4029
4030
// emit the "then" statement
4031
if (node->getTrueBlock() != nullptr) {
4032
node->getTrueBlock()->traverse(this);
4033
if (result != spv::NoResult) {
4034
spv::Id load = accessChainLoad(node->getTrueBlock()->getAsTyped()->getType());
4035
4036
builder.clearAccessChain();
4037
builder.setAccessChainLValue(result);
4038
multiTypeStore(node->getType(), load);
4039
}
4040
}
4041
4042
if (node->getFalseBlock() != nullptr) {
4043
ifBuilder.makeBeginElse();
4044
// emit the "else" statement
4045
node->getFalseBlock()->traverse(this);
4046
if (result != spv::NoResult) {
4047
spv::Id load = accessChainLoad(node->getFalseBlock()->getAsTyped()->getType());
4048
4049
builder.clearAccessChain();
4050
builder.setAccessChainLValue(result);
4051
multiTypeStore(node->getType(), load);
4052
}
4053
}
4054
4055
// finish off the control flow
4056
ifBuilder.makeEndIf();
4057
4058
if (result != spv::NoResult) {
4059
builder.clearAccessChain();
4060
builder.setAccessChainLValue(result);
4061
}
4062
};
4063
4064
// Try for OpSelect (or a requirement to execute both sides)
4065
if (bothSidesPolicy()) {
4066
SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder);
4067
if (node->getType().getQualifier().isSpecConstant())
4068
spec_constant_op_mode_setter.turnOnSpecConstantOpMode();
4069
executeBothSides();
4070
} else
4071
executeOneSide();
4072
4073
return false;
4074
}
4075
4076
bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::TIntermSwitch* node)
4077
{
4078
// emit and get the condition before doing anything with switch
4079
node->getCondition()->traverse(this);
4080
spv::Id selector = accessChainLoad(node->getCondition()->getAsTyped()->getType());
4081
4082
// Selection control:
4083
const spv::SelectionControlMask control = TranslateSwitchControl(*node);
4084
4085
// browse the children to sort out code segments
4086
int defaultSegment = -1;
4087
std::vector<TIntermNode*> codeSegments;
4088
glslang::TIntermSequence& sequence = node->getBody()->getSequence();
4089
std::vector<int> caseValues;
4090
std::vector<int> valueIndexToSegment(sequence.size()); // note: probably not all are used, it is an overestimate
4091
for (glslang::TIntermSequence::iterator c = sequence.begin(); c != sequence.end(); ++c) {
4092
TIntermNode* child = *c;
4093
if (child->getAsBranchNode() && child->getAsBranchNode()->getFlowOp() == glslang::EOpDefault)
4094
defaultSegment = (int)codeSegments.size();
4095
else if (child->getAsBranchNode() && child->getAsBranchNode()->getFlowOp() == glslang::EOpCase) {
4096
valueIndexToSegment[caseValues.size()] = (int)codeSegments.size();
4097
caseValues.push_back(child->getAsBranchNode()->getExpression()->getAsConstantUnion()
4098
->getConstArray()[0].getIConst());
4099
} else
4100
codeSegments.push_back(child);
4101
}
4102
4103
// handle the case where the last code segment is missing, due to no code
4104
// statements between the last case and the end of the switch statement
4105
if ((caseValues.size() && (int)codeSegments.size() == valueIndexToSegment[caseValues.size() - 1]) ||
4106
(int)codeSegments.size() == defaultSegment)
4107
codeSegments.push_back(nullptr);
4108
4109
// make the switch statement
4110
std::vector<spv::Block*> segmentBlocks; // returned, as the blocks allocated in the call
4111
builder.makeSwitch(selector, control, (int)codeSegments.size(), caseValues, valueIndexToSegment, defaultSegment,
4112
segmentBlocks);
4113
4114
// emit all the code in the segments
4115
breakForLoop.push(false);
4116
for (unsigned int s = 0; s < codeSegments.size(); ++s) {
4117
builder.nextSwitchSegment(segmentBlocks, s);
4118
if (codeSegments[s])
4119
codeSegments[s]->traverse(this);
4120
else
4121
builder.addSwitchBreak();
4122
}
4123
breakForLoop.pop();
4124
4125
builder.endSwitch(segmentBlocks);
4126
4127
return false;
4128
}
4129
4130
void TGlslangToSpvTraverser::visitConstantUnion(glslang::TIntermConstantUnion* node)
4131
{
4132
if (node->getQualifier().isSpirvLiteral())
4133
return; // Translated to a literal value, skip further processing
4134
4135
int nextConst = 0;
4136
spv::Id constant = createSpvConstantFromConstUnionArray(node->getType(), node->getConstArray(), nextConst, false);
4137
4138
builder.clearAccessChain();
4139
builder.setAccessChainRValue(constant);
4140
}
4141
4142
bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIntermLoop* node)
4143
{
4144
auto blocks = builder.makeNewLoop();
4145
builder.createBranch(&blocks.head);
4146
4147
// Loop control:
4148
std::vector<unsigned int> operands;
4149
const spv::LoopControlMask control = TranslateLoopControl(*node, operands);
4150
4151
// Spec requires back edges to target header blocks, and every header block
4152
// must dominate its merge block. Make a header block first to ensure these
4153
// conditions are met. By definition, it will contain OpLoopMerge, followed
4154
// by a block-ending branch. But we don't want to put any other body/test
4155
// instructions in it, since the body/test may have arbitrary instructions,
4156
// including merges of its own.
4157
builder.setBuildPoint(&blocks.head);
4158
builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
4159
builder.createLoopMerge(&blocks.merge, &blocks.continue_target, control, operands);
4160
if (node->testFirst() && node->getTest()) {
4161
spv::Block& test = builder.makeNewBlock();
4162
builder.createBranch(&test);
4163
4164
builder.setBuildPoint(&test);
4165
node->getTest()->traverse(this);
4166
spv::Id condition = accessChainLoad(node->getTest()->getType());
4167
builder.createConditionalBranch(condition, &blocks.body, &blocks.merge);
4168
4169
builder.setBuildPoint(&blocks.body);
4170
breakForLoop.push(true);
4171
if (node->getBody())
4172
node->getBody()->traverse(this);
4173
builder.createBranch(&blocks.continue_target);
4174
breakForLoop.pop();
4175
4176
builder.setBuildPoint(&blocks.continue_target);
4177
if (node->getTerminal())
4178
node->getTerminal()->traverse(this);
4179
builder.createBranch(&blocks.head);
4180
} else {
4181
builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
4182
builder.createBranch(&blocks.body);
4183
4184
breakForLoop.push(true);
4185
builder.setBuildPoint(&blocks.body);
4186
if (node->getBody())
4187
node->getBody()->traverse(this);
4188
builder.createBranch(&blocks.continue_target);
4189
breakForLoop.pop();
4190
4191
builder.setBuildPoint(&blocks.continue_target);
4192
if (node->getTerminal())
4193
node->getTerminal()->traverse(this);
4194
if (node->getTest()) {
4195
node->getTest()->traverse(this);
4196
spv::Id condition =
4197
accessChainLoad(node->getTest()->getType());
4198
builder.createConditionalBranch(condition, &blocks.head, &blocks.merge);
4199
} else {
4200
// TODO: unless there was a break/return/discard instruction
4201
// somewhere in the body, this is an infinite loop, so we should
4202
// issue a warning.
4203
builder.createBranch(&blocks.head);
4204
}
4205
}
4206
builder.setBuildPoint(&blocks.merge);
4207
builder.closeLoop();
4208
return false;
4209
}
4210
4211
bool TGlslangToSpvTraverser::visitBranch(glslang::TVisit /* visit */, glslang::TIntermBranch* node)
4212
{
4213
if (node->getExpression())
4214
node->getExpression()->traverse(this);
4215
4216
builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
4217
4218
switch (node->getFlowOp()) {
4219
case glslang::EOpKill:
4220
if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_6) {
4221
if (glslangIntermediate->getSource() == glslang::EShSourceHlsl) {
4222
builder.addCapability(spv::CapabilityDemoteToHelperInvocation);
4223
builder.createNoResultOp(spv::OpDemoteToHelperInvocationEXT);
4224
} else {
4225
builder.makeStatementTerminator(spv::OpTerminateInvocation, "post-terminate-invocation");
4226
}
4227
} else {
4228
builder.makeStatementTerminator(spv::OpKill, "post-discard");
4229
}
4230
break;
4231
case glslang::EOpTerminateInvocation:
4232
builder.addExtension(spv::E_SPV_KHR_terminate_invocation);
4233
builder.makeStatementTerminator(spv::OpTerminateInvocation, "post-terminate-invocation");
4234
break;
4235
case glslang::EOpBreak:
4236
if (breakForLoop.top())
4237
builder.createLoopExit();
4238
else
4239
builder.addSwitchBreak();
4240
break;
4241
case glslang::EOpContinue:
4242
builder.createLoopContinue();
4243
break;
4244
case glslang::EOpReturn:
4245
if (node->getExpression() != nullptr) {
4246
const glslang::TType& glslangReturnType = node->getExpression()->getType();
4247
spv::Id returnId = accessChainLoad(glslangReturnType);
4248
if (builder.getTypeId(returnId) != currentFunction->getReturnType() ||
4249
TranslatePrecisionDecoration(glslangReturnType) != currentFunction->getReturnPrecision()) {
4250
builder.clearAccessChain();
4251
spv::Id copyId = builder.createVariable(currentFunction->getReturnPrecision(),
4252
spv::StorageClassFunction, currentFunction->getReturnType());
4253
builder.setAccessChainLValue(copyId);
4254
multiTypeStore(glslangReturnType, returnId);
4255
returnId = builder.createLoad(copyId, currentFunction->getReturnPrecision());
4256
}
4257
builder.makeReturn(false, returnId);
4258
} else
4259
builder.makeReturn(false);
4260
4261
builder.clearAccessChain();
4262
break;
4263
4264
case glslang::EOpDemote:
4265
builder.createNoResultOp(spv::OpDemoteToHelperInvocationEXT);
4266
builder.addExtension(spv::E_SPV_EXT_demote_to_helper_invocation);
4267
builder.addCapability(spv::CapabilityDemoteToHelperInvocationEXT);
4268
break;
4269
case glslang::EOpTerminateRayKHR:
4270
builder.makeStatementTerminator(spv::OpTerminateRayKHR, "post-terminateRayKHR");
4271
break;
4272
case glslang::EOpIgnoreIntersectionKHR:
4273
builder.makeStatementTerminator(spv::OpIgnoreIntersectionKHR, "post-ignoreIntersectionKHR");
4274
break;
4275
4276
default:
4277
assert(0);
4278
break;
4279
}
4280
4281
return false;
4282
}
4283
4284
spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol* node, spv::Id forcedType)
4285
{
4286
// First, steer off constants, which are not SPIR-V variables, but
4287
// can still have a mapping to a SPIR-V Id.
4288
// This includes specialization constants.
4289
if (node->getQualifier().isConstant()) {
4290
spv::Id result = createSpvConstant(*node);
4291
if (result != spv::NoResult)
4292
return result;
4293
}
4294
4295
// Now, handle actual variables
4296
spv::StorageClass storageClass = TranslateStorageClass(node->getType());
4297
spv::Id spvType = forcedType == spv::NoType ? convertGlslangToSpvType(node->getType())
4298
: forcedType;
4299
4300
const bool contains16BitType = node->getType().contains16BitFloat() ||
4301
node->getType().contains16BitInt();
4302
if (contains16BitType) {
4303
switch (storageClass) {
4304
case spv::StorageClassInput:
4305
case spv::StorageClassOutput:
4306
builder.addIncorporatedExtension(spv::E_SPV_KHR_16bit_storage, spv::Spv_1_3);
4307
builder.addCapability(spv::CapabilityStorageInputOutput16);
4308
break;
4309
case spv::StorageClassUniform:
4310
builder.addIncorporatedExtension(spv::E_SPV_KHR_16bit_storage, spv::Spv_1_3);
4311
if (node->getType().getQualifier().storage == glslang::EvqBuffer)
4312
builder.addCapability(spv::CapabilityStorageUniformBufferBlock16);
4313
else
4314
builder.addCapability(spv::CapabilityStorageUniform16);
4315
break;
4316
case spv::StorageClassPushConstant:
4317
builder.addIncorporatedExtension(spv::E_SPV_KHR_16bit_storage, spv::Spv_1_3);
4318
builder.addCapability(spv::CapabilityStoragePushConstant16);
4319
break;
4320
case spv::StorageClassStorageBuffer:
4321
case spv::StorageClassPhysicalStorageBufferEXT:
4322
builder.addIncorporatedExtension(spv::E_SPV_KHR_16bit_storage, spv::Spv_1_3);
4323
builder.addCapability(spv::CapabilityStorageUniformBufferBlock16);
4324
break;
4325
default:
4326
if (storageClass == spv::StorageClassWorkgroup &&
4327
node->getType().getBasicType() == glslang::EbtBlock) {
4328
builder.addCapability(spv::CapabilityWorkgroupMemoryExplicitLayout16BitAccessKHR);
4329
break;
4330
}
4331
if (node->getType().contains16BitFloat())
4332
builder.addCapability(spv::CapabilityFloat16);
4333
if (node->getType().contains16BitInt())
4334
builder.addCapability(spv::CapabilityInt16);
4335
break;
4336
}
4337
}
4338
4339
if (node->getType().contains8BitInt()) {
4340
if (storageClass == spv::StorageClassPushConstant) {
4341
builder.addIncorporatedExtension(spv::E_SPV_KHR_8bit_storage, spv::Spv_1_5);
4342
builder.addCapability(spv::CapabilityStoragePushConstant8);
4343
} else if (storageClass == spv::StorageClassUniform) {
4344
builder.addIncorporatedExtension(spv::E_SPV_KHR_8bit_storage, spv::Spv_1_5);
4345
builder.addCapability(spv::CapabilityUniformAndStorageBuffer8BitAccess);
4346
} else if (storageClass == spv::StorageClassStorageBuffer) {
4347
builder.addIncorporatedExtension(spv::E_SPV_KHR_8bit_storage, spv::Spv_1_5);
4348
builder.addCapability(spv::CapabilityStorageBuffer8BitAccess);
4349
} else if (storageClass == spv::StorageClassWorkgroup &&
4350
node->getType().getBasicType() == glslang::EbtBlock) {
4351
builder.addCapability(spv::CapabilityWorkgroupMemoryExplicitLayout8BitAccessKHR);
4352
} else {
4353
builder.addCapability(spv::CapabilityInt8);
4354
}
4355
}
4356
4357
const char* name = node->getName().c_str();
4358
if (glslang::IsAnonymous(name))
4359
name = "";
4360
4361
spv::Id initializer = spv::NoResult;
4362
4363
if (node->getType().getQualifier().storage == glslang::EvqUniform && !node->getConstArray().empty()) {
4364
int nextConst = 0;
4365
initializer = createSpvConstantFromConstUnionArray(node->getType(),
4366
node->getConstArray(),
4367
nextConst,
4368
false /* specConst */);
4369
} else if (node->getType().getQualifier().isNullInit()) {
4370
initializer = builder.makeNullConstant(spvType);
4371
}
4372
4373
return builder.createVariable(spv::NoPrecision, storageClass, spvType, name, initializer, false);
4374
}
4375
4376
// Return type Id of the sampled type.
4377
spv::Id TGlslangToSpvTraverser::getSampledType(const glslang::TSampler& sampler)
4378
{
4379
switch (sampler.type) {
4380
case glslang::EbtInt: return builder.makeIntType(32);
4381
case glslang::EbtUint: return builder.makeUintType(32);
4382
case glslang::EbtFloat: return builder.makeFloatType(32);
4383
case glslang::EbtFloat16:
4384
builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float_fetch);
4385
builder.addCapability(spv::CapabilityFloat16ImageAMD);
4386
return builder.makeFloatType(16);
4387
case glslang::EbtInt64:
4388
builder.addExtension(spv::E_SPV_EXT_shader_image_int64);
4389
builder.addCapability(spv::CapabilityInt64ImageEXT);
4390
return builder.makeIntType(64);
4391
case glslang::EbtUint64:
4392
builder.addExtension(spv::E_SPV_EXT_shader_image_int64);
4393
builder.addCapability(spv::CapabilityInt64ImageEXT);
4394
return builder.makeUintType(64);
4395
default:
4396
assert(0);
4397
return builder.makeFloatType(32);
4398
}
4399
}
4400
4401
// If node is a swizzle operation, return the type that should be used if
4402
// the swizzle base is first consumed by another operation, before the swizzle
4403
// is applied.
4404
spv::Id TGlslangToSpvTraverser::getInvertedSwizzleType(const glslang::TIntermTyped& node)
4405
{
4406
if (node.getAsOperator() &&
4407
node.getAsOperator()->getOp() == glslang::EOpVectorSwizzle)
4408
return convertGlslangToSpvType(node.getAsBinaryNode()->getLeft()->getType());
4409
else
4410
return spv::NoType;
4411
}
4412
4413
// When inverting a swizzle with a parent op, this function
4414
// will apply the swizzle operation to a completed parent operation.
4415
spv::Id TGlslangToSpvTraverser::createInvertedSwizzle(spv::Decoration precision, const glslang::TIntermTyped& node,
4416
spv::Id parentResult)
4417
{
4418
std::vector<unsigned> swizzle;
4419
convertSwizzle(*node.getAsBinaryNode()->getRight()->getAsAggregate(), swizzle);
4420
return builder.createRvalueSwizzle(precision, convertGlslangToSpvType(node.getType()), parentResult, swizzle);
4421
}
4422
4423
// Convert a glslang AST swizzle node to a swizzle vector for building SPIR-V.
4424
void TGlslangToSpvTraverser::convertSwizzle(const glslang::TIntermAggregate& node, std::vector<unsigned>& swizzle)
4425
{
4426
const glslang::TIntermSequence& swizzleSequence = node.getSequence();
4427
for (int i = 0; i < (int)swizzleSequence.size(); ++i)
4428
swizzle.push_back(swizzleSequence[i]->getAsConstantUnion()->getConstArray()[0].getIConst());
4429
}
4430
4431
// Convert from a glslang type to an SPV type, by calling into a
4432
// recursive version of this function. This establishes the inherited
4433
// layout state rooted from the top-level type.
4434
spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type, bool forwardReferenceOnly)
4435
{
4436
return convertGlslangToSpvType(type, getExplicitLayout(type), type.getQualifier(), false, forwardReferenceOnly);
4437
}
4438
4439
spv::LinkageType TGlslangToSpvTraverser::convertGlslangLinkageToSpv(glslang::TLinkType linkType)
4440
{
4441
switch (linkType) {
4442
case glslang::ELinkExport:
4443
return spv::LinkageTypeExport;
4444
default:
4445
return spv::LinkageTypeMax;
4446
}
4447
}
4448
4449
// Do full recursive conversion of an arbitrary glslang type to a SPIR-V Id.
4450
// explicitLayout can be kept the same throughout the hierarchical recursive walk.
4451
// Mutually recursive with convertGlslangStructToSpvType().
4452
spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type,
4453
glslang::TLayoutPacking explicitLayout, const glslang::TQualifier& qualifier,
4454
bool lastBufferBlockMember, bool forwardReferenceOnly)
4455
{
4456
spv::Id spvType = spv::NoResult;
4457
4458
switch (type.getBasicType()) {
4459
case glslang::EbtVoid:
4460
spvType = builder.makeVoidType();
4461
assert (! type.isArray());
4462
break;
4463
case glslang::EbtBool:
4464
// "transparent" bool doesn't exist in SPIR-V. The GLSL convention is
4465
// a 32-bit int where non-0 means true.
4466
if (explicitLayout != glslang::ElpNone)
4467
spvType = builder.makeUintType(32);
4468
else
4469
spvType = builder.makeBoolType();
4470
break;
4471
case glslang::EbtInt:
4472
spvType = builder.makeIntType(32);
4473
break;
4474
case glslang::EbtUint:
4475
spvType = builder.makeUintType(32);
4476
break;
4477
case glslang::EbtFloat:
4478
spvType = builder.makeFloatType(32);
4479
break;
4480
case glslang::EbtDouble:
4481
spvType = builder.makeFloatType(64);
4482
break;
4483
case glslang::EbtFloat16:
4484
spvType = builder.makeFloatType(16);
4485
break;
4486
case glslang::EbtInt8:
4487
spvType = builder.makeIntType(8);
4488
break;
4489
case glslang::EbtUint8:
4490
spvType = builder.makeUintType(8);
4491
break;
4492
case glslang::EbtInt16:
4493
spvType = builder.makeIntType(16);
4494
break;
4495
case glslang::EbtUint16:
4496
spvType = builder.makeUintType(16);
4497
break;
4498
case glslang::EbtInt64:
4499
spvType = builder.makeIntType(64);
4500
break;
4501
case glslang::EbtUint64:
4502
spvType = builder.makeUintType(64);
4503
break;
4504
case glslang::EbtAtomicUint:
4505
builder.addCapability(spv::CapabilityAtomicStorage);
4506
spvType = builder.makeUintType(32);
4507
break;
4508
case glslang::EbtAccStruct:
4509
switch (glslangIntermediate->getStage()) {
4510
case EShLangRayGen:
4511
case EShLangIntersect:
4512
case EShLangAnyHit:
4513
case EShLangClosestHit:
4514
case EShLangMiss:
4515
case EShLangCallable:
4516
// these all should have the RayTracingNV/KHR capability already
4517
break;
4518
default:
4519
{
4520
auto& extensions = glslangIntermediate->getRequestedExtensions();
4521
if (extensions.find("GL_EXT_ray_query") != extensions.end()) {
4522
builder.addExtension(spv::E_SPV_KHR_ray_query);
4523
builder.addCapability(spv::CapabilityRayQueryKHR);
4524
}
4525
}
4526
break;
4527
}
4528
spvType = builder.makeAccelerationStructureType();
4529
break;
4530
case glslang::EbtRayQuery:
4531
{
4532
auto& extensions = glslangIntermediate->getRequestedExtensions();
4533
if (extensions.find("GL_EXT_ray_query") != extensions.end()) {
4534
builder.addExtension(spv::E_SPV_KHR_ray_query);
4535
builder.addCapability(spv::CapabilityRayQueryKHR);
4536
}
4537
spvType = builder.makeRayQueryType();
4538
}
4539
break;
4540
case glslang::EbtReference:
4541
{
4542
// Make the forward pointer, then recurse to convert the structure type, then
4543
// patch up the forward pointer with a real pointer type.
4544
if (forwardPointers.find(type.getReferentType()) == forwardPointers.end()) {
4545
spv::Id forwardId = builder.makeForwardPointer(spv::StorageClassPhysicalStorageBufferEXT);
4546
forwardPointers[type.getReferentType()] = forwardId;
4547
}
4548
spvType = forwardPointers[type.getReferentType()];
4549
if (!forwardReferenceOnly) {
4550
spv::Id referentType = convertGlslangToSpvType(*type.getReferentType());
4551
builder.makePointerFromForwardPointer(spv::StorageClassPhysicalStorageBufferEXT,
4552
forwardPointers[type.getReferentType()],
4553
referentType);
4554
}
4555
}
4556
break;
4557
case glslang::EbtSampler:
4558
{
4559
const glslang::TSampler& sampler = type.getSampler();
4560
if (sampler.isPureSampler()) {
4561
spvType = builder.makeSamplerType();
4562
} else {
4563
// an image is present, make its type
4564
spvType = builder.makeImageType(getSampledType(sampler), TranslateDimensionality(sampler),
4565
sampler.isShadow(), sampler.isArrayed(), sampler.isMultiSample(),
4566
sampler.isImageClass() ? 2 : 1, TranslateImageFormat(type));
4567
if (sampler.isCombined() &&
4568
(!sampler.isBuffer() || glslangIntermediate->getSpv().spv < glslang::EShTargetSpv_1_6)) {
4569
// Already has both image and sampler, make the combined type. Only combine sampler to
4570
// buffer if before SPIR-V 1.6.
4571
spvType = builder.makeSampledImageType(spvType);
4572
}
4573
}
4574
}
4575
break;
4576
case glslang::EbtStruct:
4577
case glslang::EbtBlock:
4578
{
4579
// If we've seen this struct type, return it
4580
const glslang::TTypeList* glslangMembers = type.getStruct();
4581
4582
// Try to share structs for different layouts, but not yet for other
4583
// kinds of qualification (primarily not yet including interpolant qualification).
4584
if (! HasNonLayoutQualifiers(type, qualifier))
4585
spvType = structMap[explicitLayout][qualifier.layoutMatrix][glslangMembers];
4586
if (spvType != spv::NoResult)
4587
break;
4588
4589
// else, we haven't seen it...
4590
if (type.getBasicType() == glslang::EbtBlock)
4591
memberRemapper[glslangTypeToIdMap[glslangMembers]].resize(glslangMembers->size());
4592
spvType = convertGlslangStructToSpvType(type, glslangMembers, explicitLayout, qualifier);
4593
}
4594
break;
4595
case glslang::EbtString:
4596
// no type used for OpString
4597
return 0;
4598
4599
case glslang::EbtHitObjectNV: {
4600
builder.addExtension(spv::E_SPV_NV_shader_invocation_reorder);
4601
builder.addCapability(spv::CapabilityShaderInvocationReorderNV);
4602
spvType = builder.makeHitObjectNVType();
4603
}
4604
break;
4605
case glslang::EbtSpirvType: {
4606
// GL_EXT_spirv_intrinsics
4607
const auto& spirvType = type.getSpirvType();
4608
const auto& spirvInst = spirvType.spirvInst;
4609
4610
std::vector<spv::IdImmediate> operands;
4611
for (const auto& typeParam : spirvType.typeParams) {
4612
if (typeParam.getAsConstant() != nullptr) {
4613
// Constant expression
4614
auto constant = typeParam.getAsConstant();
4615
if (constant->isLiteral()) {
4616
if (constant->getBasicType() == glslang::EbtFloat) {
4617
float floatValue = static_cast<float>(constant->getConstArray()[0].getDConst());
4618
unsigned literal;
4619
static_assert(sizeof(literal) == sizeof(floatValue), "sizeof(unsigned) != sizeof(float)");
4620
memcpy(&literal, &floatValue, sizeof(literal));
4621
operands.push_back({false, literal});
4622
} else if (constant->getBasicType() == glslang::EbtInt) {
4623
unsigned literal = constant->getConstArray()[0].getIConst();
4624
operands.push_back({false, literal});
4625
} else if (constant->getBasicType() == glslang::EbtUint) {
4626
unsigned literal = constant->getConstArray()[0].getUConst();
4627
operands.push_back({false, literal});
4628
} else if (constant->getBasicType() == glslang::EbtBool) {
4629
unsigned literal = constant->getConstArray()[0].getBConst();
4630
operands.push_back({false, literal});
4631
} else if (constant->getBasicType() == glslang::EbtString) {
4632
auto str = constant->getConstArray()[0].getSConst()->c_str();
4633
unsigned literal = 0;
4634
char* literalPtr = reinterpret_cast<char*>(&literal);
4635
unsigned charCount = 0;
4636
char ch = 0;
4637
do {
4638
ch = *(str++);
4639
*(literalPtr++) = ch;
4640
++charCount;
4641
if (charCount == 4) {
4642
operands.push_back({false, literal});
4643
literalPtr = reinterpret_cast<char*>(&literal);
4644
charCount = 0;
4645
}
4646
} while (ch != 0);
4647
4648
// Partial literal is padded with 0
4649
if (charCount > 0) {
4650
for (; charCount < 4; ++charCount)
4651
*(literalPtr++) = 0;
4652
operands.push_back({false, literal});
4653
}
4654
} else
4655
assert(0); // Unexpected type
4656
} else
4657
operands.push_back({true, createSpvConstant(*constant)});
4658
} else {
4659
// Type specifier
4660
assert(typeParam.getAsType() != nullptr);
4661
operands.push_back({true, convertGlslangToSpvType(*typeParam.getAsType())});
4662
}
4663
}
4664
4665
assert(spirvInst.set == ""); // Currently, couldn't be extended instructions.
4666
spvType = builder.makeGenericType(static_cast<spv::Op>(spirvInst.id), operands);
4667
4668
break;
4669
}
4670
default:
4671
assert(0);
4672
break;
4673
}
4674
4675
if (type.isMatrix())
4676
spvType = builder.makeMatrixType(spvType, type.getMatrixCols(), type.getMatrixRows());
4677
else {
4678
// If this variable has a vector element count greater than 1, create a SPIR-V vector
4679
if (type.getVectorSize() > 1)
4680
spvType = builder.makeVectorType(spvType, type.getVectorSize());
4681
}
4682
4683
if (type.isCoopMatNV()) {
4684
builder.addCapability(spv::CapabilityCooperativeMatrixNV);
4685
builder.addExtension(spv::E_SPV_NV_cooperative_matrix);
4686
4687
if (type.getBasicType() == glslang::EbtFloat16)
4688
builder.addCapability(spv::CapabilityFloat16);
4689
if (type.getBasicType() == glslang::EbtUint8 ||
4690
type.getBasicType() == glslang::EbtInt8) {
4691
builder.addCapability(spv::CapabilityInt8);
4692
}
4693
4694
spv::Id scope = makeArraySizeId(*type.getTypeParameters()->arraySizes, 1);
4695
spv::Id rows = makeArraySizeId(*type.getTypeParameters()->arraySizes, 2);
4696
spv::Id cols = makeArraySizeId(*type.getTypeParameters()->arraySizes, 3);
4697
4698
spvType = builder.makeCooperativeMatrixTypeNV(spvType, scope, rows, cols);
4699
}
4700
4701
if (type.isCoopMatKHR()) {
4702
builder.addCapability(spv::CapabilityCooperativeMatrixKHR);
4703
builder.addExtension(spv::E_SPV_KHR_cooperative_matrix);
4704
4705
if (type.getBasicType() == glslang::EbtFloat16)
4706
builder.addCapability(spv::CapabilityFloat16);
4707
if (type.getBasicType() == glslang::EbtUint8 || type.getBasicType() == glslang::EbtInt8) {
4708
builder.addCapability(spv::CapabilityInt8);
4709
}
4710
4711
spv::Id scope = makeArraySizeId(*type.getTypeParameters()->arraySizes, 0);
4712
spv::Id rows = makeArraySizeId(*type.getTypeParameters()->arraySizes, 1);
4713
spv::Id cols = makeArraySizeId(*type.getTypeParameters()->arraySizes, 2);
4714
spv::Id use = builder.makeUintConstant(type.getCoopMatKHRuse());
4715
4716
spvType = builder.makeCooperativeMatrixTypeKHR(spvType, scope, rows, cols, use);
4717
}
4718
4719
if (type.isArray()) {
4720
int stride = 0; // keep this 0 unless doing an explicit layout; 0 will mean no decoration, no stride
4721
4722
// Do all but the outer dimension
4723
if (type.getArraySizes()->getNumDims() > 1) {
4724
// We need to decorate array strides for types needing explicit layout, except blocks.
4725
if (explicitLayout != glslang::ElpNone && type.getBasicType() != glslang::EbtBlock) {
4726
// Use a dummy glslang type for querying internal strides of
4727
// arrays of arrays, but using just a one-dimensional array.
4728
glslang::TType simpleArrayType(type, 0); // deference type of the array
4729
while (simpleArrayType.getArraySizes()->getNumDims() > 1)
4730
simpleArrayType.getArraySizes()->dereference();
4731
4732
// Will compute the higher-order strides here, rather than making a whole
4733
// pile of types and doing repetitive recursion on their contents.
4734
stride = getArrayStride(simpleArrayType, explicitLayout, qualifier.layoutMatrix);
4735
}
4736
4737
// make the arrays
4738
for (int dim = type.getArraySizes()->getNumDims() - 1; dim > 0; --dim) {
4739
spvType = builder.makeArrayType(spvType, makeArraySizeId(*type.getArraySizes(), dim), stride);
4740
if (stride > 0)
4741
builder.addDecoration(spvType, spv::DecorationArrayStride, stride);
4742
stride *= type.getArraySizes()->getDimSize(dim);
4743
}
4744
} else {
4745
// single-dimensional array, and don't yet have stride
4746
4747
// We need to decorate array strides for types needing explicit layout, except blocks.
4748
if (explicitLayout != glslang::ElpNone && type.getBasicType() != glslang::EbtBlock)
4749
stride = getArrayStride(type, explicitLayout, qualifier.layoutMatrix);
4750
}
4751
4752
// Do the outer dimension, which might not be known for a runtime-sized array.
4753
// (Unsized arrays that survive through linking will be runtime-sized arrays)
4754
if (type.isSizedArray())
4755
spvType = builder.makeArrayType(spvType, makeArraySizeId(*type.getArraySizes(), 0), stride);
4756
else {
4757
if (!lastBufferBlockMember) {
4758
builder.addIncorporatedExtension("SPV_EXT_descriptor_indexing", spv::Spv_1_5);
4759
builder.addCapability(spv::CapabilityRuntimeDescriptorArrayEXT);
4760
}
4761
spvType = builder.makeRuntimeArray(spvType);
4762
}
4763
if (stride > 0)
4764
builder.addDecoration(spvType, spv::DecorationArrayStride, stride);
4765
}
4766
4767
return spvType;
4768
}
4769
4770
// Apply SPIR-V decorations to the SPIR-V object (provided by SPIR-V ID). If member index is provided, the
4771
// decorations are applied to this member.
4772
void TGlslangToSpvTraverser::applySpirvDecorate(const glslang::TType& type, spv::Id id, std::optional<int> member)
4773
{
4774
assert(type.getQualifier().hasSpirvDecorate());
4775
4776
const glslang::TSpirvDecorate& spirvDecorate = type.getQualifier().getSpirvDecorate();
4777
4778
// Add spirv_decorate
4779
for (auto& decorate : spirvDecorate.decorates) {
4780
if (!decorate.second.empty()) {
4781
std::vector<unsigned> literals;
4782
TranslateLiterals(decorate.second, literals);
4783
if (member.has_value())
4784
builder.addMemberDecoration(id, *member, static_cast<spv::Decoration>(decorate.first), literals);
4785
else
4786
builder.addDecoration(id, static_cast<spv::Decoration>(decorate.first), literals);
4787
} else {
4788
if (member.has_value())
4789
builder.addMemberDecoration(id, *member, static_cast<spv::Decoration>(decorate.first));
4790
else
4791
builder.addDecoration(id, static_cast<spv::Decoration>(decorate.first));
4792
}
4793
}
4794
4795
// Add spirv_decorate_id
4796
if (member.has_value()) {
4797
// spirv_decorate_id not applied to members
4798
assert(spirvDecorate.decorateIds.empty());
4799
} else {
4800
for (auto& decorateId : spirvDecorate.decorateIds) {
4801
std::vector<spv::Id> operandIds;
4802
assert(!decorateId.second.empty());
4803
for (auto extraOperand : decorateId.second) {
4804
if (extraOperand->getQualifier().isFrontEndConstant())
4805
operandIds.push_back(createSpvConstant(*extraOperand));
4806
else
4807
operandIds.push_back(getSymbolId(extraOperand->getAsSymbolNode()));
4808
}
4809
builder.addDecorationId(id, static_cast<spv::Decoration>(decorateId.first), operandIds);
4810
}
4811
}
4812
4813
// Add spirv_decorate_string
4814
for (auto& decorateString : spirvDecorate.decorateStrings) {
4815
std::vector<const char*> strings;
4816
assert(!decorateString.second.empty());
4817
for (auto extraOperand : decorateString.second) {
4818
const char* string = extraOperand->getConstArray()[0].getSConst()->c_str();
4819
strings.push_back(string);
4820
}
4821
if (member.has_value())
4822
builder.addMemberDecoration(id, *member, static_cast<spv::Decoration>(decorateString.first), strings);
4823
else
4824
builder.addDecoration(id, static_cast<spv::Decoration>(decorateString.first), strings);
4825
}
4826
}
4827
4828
// TODO: this functionality should exist at a higher level, in creating the AST
4829
//
4830
// Identify interface members that don't have their required extension turned on.
4831
//
4832
bool TGlslangToSpvTraverser::filterMember(const glslang::TType& member)
4833
{
4834
auto& extensions = glslangIntermediate->getRequestedExtensions();
4835
4836
if (member.getFieldName() == "gl_SecondaryViewportMaskNV" &&
4837
extensions.find("GL_NV_stereo_view_rendering") == extensions.end())
4838
return true;
4839
if (member.getFieldName() == "gl_SecondaryPositionNV" &&
4840
extensions.find("GL_NV_stereo_view_rendering") == extensions.end())
4841
return true;
4842
4843
if (glslangIntermediate->getStage() == EShLangMesh) {
4844
if (member.getFieldName() == "gl_PrimitiveShadingRateEXT" &&
4845
extensions.find("GL_EXT_fragment_shading_rate") == extensions.end())
4846
return true;
4847
}
4848
4849
if (glslangIntermediate->getStage() != EShLangMesh) {
4850
if (member.getFieldName() == "gl_ViewportMask" &&
4851
extensions.find("GL_NV_viewport_array2") == extensions.end())
4852
return true;
4853
if (member.getFieldName() == "gl_PositionPerViewNV" &&
4854
extensions.find("GL_NVX_multiview_per_view_attributes") == extensions.end())
4855
return true;
4856
if (member.getFieldName() == "gl_ViewportMaskPerViewNV" &&
4857
extensions.find("GL_NVX_multiview_per_view_attributes") == extensions.end())
4858
return true;
4859
}
4860
4861
return false;
4862
};
4863
4864
// Do full recursive conversion of a glslang structure (or block) type to a SPIR-V Id.
4865
// explicitLayout can be kept the same throughout the hierarchical recursive walk.
4866
// Mutually recursive with convertGlslangToSpvType().
4867
spv::Id TGlslangToSpvTraverser::convertGlslangStructToSpvType(const glslang::TType& type,
4868
const glslang::TTypeList* glslangMembers,
4869
glslang::TLayoutPacking explicitLayout,
4870
const glslang::TQualifier& qualifier)
4871
{
4872
// Create a vector of struct types for SPIR-V to consume
4873
std::vector<spv::Id> spvMembers;
4874
int memberDelta = 0; // how much the member's index changes from glslang to SPIR-V, normally 0,
4875
// except sometimes for blocks
4876
std::vector<std::pair<glslang::TType*, glslang::TQualifier> > deferredForwardPointers;
4877
for (int i = 0; i < (int)glslangMembers->size(); i++) {
4878
auto& glslangMember = (*glslangMembers)[i];
4879
if (glslangMember.type->hiddenMember()) {
4880
++memberDelta;
4881
if (type.getBasicType() == glslang::EbtBlock)
4882
memberRemapper[glslangTypeToIdMap[glslangMembers]][i] = -1;
4883
} else {
4884
if (type.getBasicType() == glslang::EbtBlock) {
4885
if (filterMember(*glslangMember.type)) {
4886
memberDelta++;
4887
memberRemapper[glslangTypeToIdMap[glslangMembers]][i] = -1;
4888
continue;
4889
}
4890
memberRemapper[glslangTypeToIdMap[glslangMembers]][i] = i - memberDelta;
4891
}
4892
// modify just this child's view of the qualifier
4893
glslang::TQualifier memberQualifier = glslangMember.type->getQualifier();
4894
InheritQualifiers(memberQualifier, qualifier);
4895
4896
// manually inherit location
4897
if (! memberQualifier.hasLocation() && qualifier.hasLocation())
4898
memberQualifier.layoutLocation = qualifier.layoutLocation;
4899
4900
// recurse
4901
bool lastBufferBlockMember = qualifier.storage == glslang::EvqBuffer &&
4902
i == (int)glslangMembers->size() - 1;
4903
4904
// Make forward pointers for any pointer members.
4905
if (glslangMember.type->isReference() &&
4906
forwardPointers.find(glslangMember.type->getReferentType()) == forwardPointers.end()) {
4907
deferredForwardPointers.push_back(std::make_pair(glslangMember.type, memberQualifier));
4908
}
4909
4910
// Create the member type.
4911
auto const spvMember = convertGlslangToSpvType(*glslangMember.type, explicitLayout, memberQualifier, lastBufferBlockMember,
4912
glslangMember.type->isReference());
4913
spvMembers.push_back(spvMember);
4914
4915
// Update the builder with the type's location so that we can create debug types for the structure members.
4916
// There doesn't exist a "clean" entry point for this information to be passed along to the builder so, for now,
4917
// it is stored in the builder and consumed during the construction of composite debug types.
4918
// TODO: This probably warrants further investigation. This approach was decided to be the least ugly of the
4919
// quick and dirty approaches that were tried.
4920
// Advantages of this approach:
4921
// + Relatively clean. No direct calls into debug type system.
4922
// + Handles nested recursive structures.
4923
// Disadvantages of this approach:
4924
// + Not as clean as desired. Traverser queries/sets persistent state. This is fragile.
4925
// + Table lookup during creation of composite debug types. This really shouldn't be necessary.
4926
if(options.emitNonSemanticShaderDebugInfo) {
4927
builder.debugTypeLocs[spvMember].name = glslangMember.type->getFieldName().c_str();
4928
builder.debugTypeLocs[spvMember].line = glslangMember.loc.line;
4929
builder.debugTypeLocs[spvMember].column = glslangMember.loc.column;
4930
}
4931
}
4932
}
4933
4934
// Make the SPIR-V type
4935
spv::Id spvType = builder.makeStructType(spvMembers, type.getTypeName().c_str(), false);
4936
if (! HasNonLayoutQualifiers(type, qualifier))
4937
structMap[explicitLayout][qualifier.layoutMatrix][glslangMembers] = spvType;
4938
4939
// Decorate it
4940
decorateStructType(type, glslangMembers, explicitLayout, qualifier, spvType, spvMembers);
4941
4942
for (int i = 0; i < (int)deferredForwardPointers.size(); ++i) {
4943
auto it = deferredForwardPointers[i];
4944
convertGlslangToSpvType(*it.first, explicitLayout, it.second, false);
4945
}
4946
4947
return spvType;
4948
}
4949
4950
void TGlslangToSpvTraverser::decorateStructType(const glslang::TType& type,
4951
const glslang::TTypeList* glslangMembers,
4952
glslang::TLayoutPacking explicitLayout,
4953
const glslang::TQualifier& qualifier,
4954
spv::Id spvType,
4955
const std::vector<spv::Id>& spvMembers)
4956
{
4957
// Name and decorate the non-hidden members
4958
int offset = -1;
4959
bool memberLocationInvalid = type.isArrayOfArrays() ||
4960
(type.isArray() && (type.getQualifier().isArrayedIo(glslangIntermediate->getStage()) == false));
4961
for (int i = 0; i < (int)glslangMembers->size(); i++) {
4962
glslang::TType& glslangMember = *(*glslangMembers)[i].type;
4963
int member = i;
4964
if (type.getBasicType() == glslang::EbtBlock) {
4965
member = memberRemapper[glslangTypeToIdMap[glslangMembers]][i];
4966
if (filterMember(glslangMember))
4967
continue;
4968
}
4969
4970
// modify just this child's view of the qualifier
4971
glslang::TQualifier memberQualifier = glslangMember.getQualifier();
4972
InheritQualifiers(memberQualifier, qualifier);
4973
4974
// using -1 above to indicate a hidden member
4975
if (member < 0)
4976
continue;
4977
4978
builder.addMemberName(spvType, member, glslangMember.getFieldName().c_str());
4979
builder.addMemberDecoration(spvType, member,
4980
TranslateLayoutDecoration(glslangMember, memberQualifier.layoutMatrix));
4981
builder.addMemberDecoration(spvType, member, TranslatePrecisionDecoration(glslangMember));
4982
// Add interpolation and auxiliary storage decorations only to
4983
// top-level members of Input and Output storage classes
4984
if (type.getQualifier().storage == glslang::EvqVaryingIn ||
4985
type.getQualifier().storage == glslang::EvqVaryingOut) {
4986
if (type.getBasicType() == glslang::EbtBlock ||
4987
glslangIntermediate->getSource() == glslang::EShSourceHlsl) {
4988
builder.addMemberDecoration(spvType, member, TranslateInterpolationDecoration(memberQualifier));
4989
builder.addMemberDecoration(spvType, member, TranslateAuxiliaryStorageDecoration(memberQualifier));
4990
addMeshNVDecoration(spvType, member, memberQualifier);
4991
}
4992
}
4993
builder.addMemberDecoration(spvType, member, TranslateInvariantDecoration(memberQualifier));
4994
4995
if (type.getBasicType() == glslang::EbtBlock &&
4996
qualifier.storage == glslang::EvqBuffer) {
4997
// Add memory decorations only to top-level members of shader storage block
4998
std::vector<spv::Decoration> memory;
4999
TranslateMemoryDecoration(memberQualifier, memory, glslangIntermediate->usingVulkanMemoryModel());
5000
for (unsigned int i = 0; i < memory.size(); ++i)
5001
builder.addMemberDecoration(spvType, member, memory[i]);
5002
}
5003
5004
// Location assignment was already completed correctly by the front end,
5005
// just track whether a member needs to be decorated.
5006
// Ignore member locations if the container is an array, as that's
5007
// ill-specified and decisions have been made to not allow this.
5008
if (!memberLocationInvalid && memberQualifier.hasLocation())
5009
builder.addMemberDecoration(spvType, member, spv::DecorationLocation, memberQualifier.layoutLocation);
5010
5011
// component, XFB, others
5012
if (glslangMember.getQualifier().hasComponent())
5013
builder.addMemberDecoration(spvType, member, spv::DecorationComponent,
5014
glslangMember.getQualifier().layoutComponent);
5015
if (glslangMember.getQualifier().hasXfbOffset())
5016
builder.addMemberDecoration(spvType, member, spv::DecorationOffset,
5017
glslangMember.getQualifier().layoutXfbOffset);
5018
else if (explicitLayout != glslang::ElpNone) {
5019
// figure out what to do with offset, which is accumulating
5020
int nextOffset;
5021
updateMemberOffset(type, glslangMember, offset, nextOffset, explicitLayout, memberQualifier.layoutMatrix);
5022
if (offset >= 0)
5023
builder.addMemberDecoration(spvType, member, spv::DecorationOffset, offset);
5024
offset = nextOffset;
5025
}
5026
5027
if (glslangMember.isMatrix() && explicitLayout != glslang::ElpNone)
5028
builder.addMemberDecoration(spvType, member, spv::DecorationMatrixStride,
5029
getMatrixStride(glslangMember, explicitLayout, memberQualifier.layoutMatrix));
5030
5031
// built-in variable decorations
5032
spv::BuiltIn builtIn = TranslateBuiltInDecoration(glslangMember.getQualifier().builtIn, true);
5033
if (builtIn != spv::BuiltInMax)
5034
builder.addMemberDecoration(spvType, member, spv::DecorationBuiltIn, (int)builtIn);
5035
5036
// nonuniform
5037
builder.addMemberDecoration(spvType, member, TranslateNonUniformDecoration(glslangMember.getQualifier()));
5038
5039
if (glslangIntermediate->getHlslFunctionality1() && memberQualifier.semanticName != nullptr) {
5040
builder.addExtension("SPV_GOOGLE_hlsl_functionality1");
5041
builder.addMemberDecoration(spvType, member, (spv::Decoration)spv::DecorationHlslSemanticGOOGLE,
5042
memberQualifier.semanticName);
5043
}
5044
5045
if (builtIn == spv::BuiltInLayer) {
5046
// SPV_NV_viewport_array2 extension
5047
if (glslangMember.getQualifier().layoutViewportRelative){
5048
builder.addMemberDecoration(spvType, member, (spv::Decoration)spv::DecorationViewportRelativeNV);
5049
builder.addCapability(spv::CapabilityShaderViewportMaskNV);
5050
builder.addExtension(spv::E_SPV_NV_viewport_array2);
5051
}
5052
if (glslangMember.getQualifier().layoutSecondaryViewportRelativeOffset != -2048){
5053
builder.addMemberDecoration(spvType, member,
5054
(spv::Decoration)spv::DecorationSecondaryViewportRelativeNV,
5055
glslangMember.getQualifier().layoutSecondaryViewportRelativeOffset);
5056
builder.addCapability(spv::CapabilityShaderStereoViewNV);
5057
builder.addExtension(spv::E_SPV_NV_stereo_view_rendering);
5058
}
5059
}
5060
if (glslangMember.getQualifier().layoutPassthrough) {
5061
builder.addMemberDecoration(spvType, member, (spv::Decoration)spv::DecorationPassthroughNV);
5062
builder.addCapability(spv::CapabilityGeometryShaderPassthroughNV);
5063
builder.addExtension(spv::E_SPV_NV_geometry_shader_passthrough);
5064
}
5065
5066
// Add SPIR-V decorations (GL_EXT_spirv_intrinsics)
5067
if (glslangMember.getQualifier().hasSpirvDecorate())
5068
applySpirvDecorate(glslangMember, spvType, member);
5069
}
5070
5071
// Decorate the structure
5072
builder.addDecoration(spvType, TranslateLayoutDecoration(type, qualifier.layoutMatrix));
5073
const auto basicType = type.getBasicType();
5074
const auto typeStorageQualifier = type.getQualifier().storage;
5075
if (basicType == glslang::EbtBlock) {
5076
builder.addDecoration(spvType, TranslateBlockDecoration(typeStorageQualifier, glslangIntermediate->usingStorageBuffer()));
5077
} else if (basicType == glslang::EbtStruct && glslangIntermediate->getSpv().vulkan > 0) {
5078
const auto hasRuntimeArray = !spvMembers.empty() && builder.getOpCode(spvMembers.back()) == spv::OpTypeRuntimeArray;
5079
if (hasRuntimeArray) {
5080
builder.addDecoration(spvType, TranslateBlockDecoration(typeStorageQualifier, glslangIntermediate->usingStorageBuffer()));
5081
}
5082
}
5083
5084
if (qualifier.hasHitObjectShaderRecordNV())
5085
builder.addDecoration(spvType, spv::DecorationHitObjectShaderRecordBufferNV);
5086
}
5087
5088
// Turn the expression forming the array size into an id.
5089
// This is not quite trivial, because of specialization constants.
5090
// Sometimes, a raw constant is turned into an Id, and sometimes
5091
// a specialization constant expression is.
5092
spv::Id TGlslangToSpvTraverser::makeArraySizeId(const glslang::TArraySizes& arraySizes, int dim, bool allowZero)
5093
{
5094
// First, see if this is sized with a node, meaning a specialization constant:
5095
glslang::TIntermTyped* specNode = arraySizes.getDimNode(dim);
5096
if (specNode != nullptr) {
5097
builder.clearAccessChain();
5098
SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder);
5099
spec_constant_op_mode_setter.turnOnSpecConstantOpMode();
5100
specNode->traverse(this);
5101
return accessChainLoad(specNode->getAsTyped()->getType());
5102
}
5103
5104
// Otherwise, need a compile-time (front end) size, get it:
5105
int size = arraySizes.getDimSize(dim);
5106
5107
if (!allowZero)
5108
assert(size > 0);
5109
5110
return builder.makeUintConstant(size);
5111
}
5112
5113
// Wrap the builder's accessChainLoad to:
5114
// - localize handling of RelaxedPrecision
5115
// - use the SPIR-V inferred type instead of another conversion of the glslang type
5116
// (avoids unnecessary work and possible type punning for structures)
5117
// - do conversion of concrete to abstract type
5118
spv::Id TGlslangToSpvTraverser::accessChainLoad(const glslang::TType& type)
5119
{
5120
spv::Id nominalTypeId = builder.accessChainGetInferredType();
5121
5122
spv::Builder::AccessChain::CoherentFlags coherentFlags = builder.getAccessChain().coherentFlags;
5123
coherentFlags |= TranslateCoherent(type);
5124
5125
spv::MemoryAccessMask accessMask = spv::MemoryAccessMask(TranslateMemoryAccess(coherentFlags) & ~spv::MemoryAccessMakePointerAvailableKHRMask);
5126
// If the value being loaded is HelperInvocation, SPIR-V 1.6 is being generated (so that
5127
// SPV_EXT_demote_to_helper_invocation is in core) and the memory model is in use, add
5128
// the Volatile MemoryAccess semantic.
5129
if (type.getQualifier().builtIn == glslang::EbvHelperInvocation &&
5130
glslangIntermediate->usingVulkanMemoryModel() &&
5131
glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_6) {
5132
accessMask = spv::MemoryAccessMask(accessMask | spv::MemoryAccessVolatileMask);
5133
}
5134
5135
unsigned int alignment = builder.getAccessChain().alignment;
5136
alignment |= type.getBufferReferenceAlignment();
5137
5138
spv::Id loadedId = builder.accessChainLoad(TranslatePrecisionDecoration(type),
5139
TranslateNonUniformDecoration(builder.getAccessChain().coherentFlags),
5140
TranslateNonUniformDecoration(type.getQualifier()),
5141
nominalTypeId,
5142
accessMask,
5143
TranslateMemoryScope(coherentFlags),
5144
alignment);
5145
5146
// Need to convert to abstract types when necessary
5147
if (type.getBasicType() == glslang::EbtBool) {
5148
loadedId = convertLoadedBoolInUniformToUint(type, nominalTypeId, loadedId);
5149
}
5150
5151
return loadedId;
5152
}
5153
5154
// Wrap the builder's accessChainStore to:
5155
// - do conversion of concrete to abstract type
5156
//
5157
// Implicitly uses the existing builder.accessChain as the storage target.
5158
void TGlslangToSpvTraverser::accessChainStore(const glslang::TType& type, spv::Id rvalue)
5159
{
5160
// Need to convert to abstract types when necessary
5161
if (type.getBasicType() == glslang::EbtBool) {
5162
spv::Id nominalTypeId = builder.accessChainGetInferredType();
5163
5164
if (builder.isScalarType(nominalTypeId)) {
5165
// Conversion for bool
5166
spv::Id boolType = builder.makeBoolType();
5167
if (nominalTypeId != boolType) {
5168
// keep these outside arguments, for determinant order-of-evaluation
5169
spv::Id one = builder.makeUintConstant(1);
5170
spv::Id zero = builder.makeUintConstant(0);
5171
rvalue = builder.createTriOp(spv::OpSelect, nominalTypeId, rvalue, one, zero);
5172
} else if (builder.getTypeId(rvalue) != boolType)
5173
rvalue = builder.createBinOp(spv::OpINotEqual, boolType, rvalue, builder.makeUintConstant(0));
5174
} else if (builder.isVectorType(nominalTypeId)) {
5175
// Conversion for bvec
5176
int vecSize = builder.getNumTypeComponents(nominalTypeId);
5177
spv::Id bvecType = builder.makeVectorType(builder.makeBoolType(), vecSize);
5178
if (nominalTypeId != bvecType) {
5179
// keep these outside arguments, for determinant order-of-evaluation
5180
spv::Id one = makeSmearedConstant(builder.makeUintConstant(1), vecSize);
5181
spv::Id zero = makeSmearedConstant(builder.makeUintConstant(0), vecSize);
5182
rvalue = builder.createTriOp(spv::OpSelect, nominalTypeId, rvalue, one, zero);
5183
} else if (builder.getTypeId(rvalue) != bvecType)
5184
rvalue = builder.createBinOp(spv::OpINotEqual, bvecType, rvalue,
5185
makeSmearedConstant(builder.makeUintConstant(0), vecSize));
5186
}
5187
}
5188
5189
spv::Builder::AccessChain::CoherentFlags coherentFlags = builder.getAccessChain().coherentFlags;
5190
coherentFlags |= TranslateCoherent(type);
5191
5192
unsigned int alignment = builder.getAccessChain().alignment;
5193
alignment |= type.getBufferReferenceAlignment();
5194
5195
builder.accessChainStore(rvalue, TranslateNonUniformDecoration(builder.getAccessChain().coherentFlags),
5196
spv::MemoryAccessMask(TranslateMemoryAccess(coherentFlags) &
5197
~spv::MemoryAccessMakePointerVisibleKHRMask),
5198
TranslateMemoryScope(coherentFlags), alignment);
5199
}
5200
5201
// For storing when types match at the glslang level, but not might match at the
5202
// SPIR-V level.
5203
//
5204
// This especially happens when a single glslang type expands to multiple
5205
// SPIR-V types, like a struct that is used in a member-undecorated way as well
5206
// as in a member-decorated way.
5207
//
5208
// NOTE: This function can handle any store request; if it's not special it
5209
// simplifies to a simple OpStore.
5210
//
5211
// Implicitly uses the existing builder.accessChain as the storage target.
5212
void TGlslangToSpvTraverser::multiTypeStore(const glslang::TType& type, spv::Id rValue)
5213
{
5214
// we only do the complex path here if it's an aggregate
5215
if (! type.isStruct() && ! type.isArray()) {
5216
accessChainStore(type, rValue);
5217
return;
5218
}
5219
5220
// and, it has to be a case of type aliasing
5221
spv::Id rType = builder.getTypeId(rValue);
5222
spv::Id lValue = builder.accessChainGetLValue();
5223
spv::Id lType = builder.getContainedTypeId(builder.getTypeId(lValue));
5224
if (lType == rType) {
5225
accessChainStore(type, rValue);
5226
return;
5227
}
5228
5229
// Recursively (as needed) copy an aggregate type to a different aggregate type,
5230
// where the two types were the same type in GLSL. This requires member
5231
// by member copy, recursively.
5232
5233
// SPIR-V 1.4 added an instruction to do help do this.
5234
if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_4) {
5235
// However, bool in uniform space is changed to int, so
5236
// OpCopyLogical does not work for that.
5237
// TODO: It would be more robust to do a full recursive verification of the types satisfying SPIR-V rules.
5238
bool rBool = builder.containsType(builder.getTypeId(rValue), spv::OpTypeBool, 0);
5239
bool lBool = builder.containsType(lType, spv::OpTypeBool, 0);
5240
if (lBool == rBool) {
5241
spv::Id logicalCopy = builder.createUnaryOp(spv::OpCopyLogical, lType, rValue);
5242
accessChainStore(type, logicalCopy);
5243
return;
5244
}
5245
}
5246
5247
// If an array, copy element by element.
5248
if (type.isArray()) {
5249
glslang::TType glslangElementType(type, 0);
5250
spv::Id elementRType = builder.getContainedTypeId(rType);
5251
for (int index = 0; index < type.getOuterArraySize(); ++index) {
5252
// get the source member
5253
spv::Id elementRValue = builder.createCompositeExtract(rValue, elementRType, index);
5254
5255
// set up the target storage
5256
builder.clearAccessChain();
5257
builder.setAccessChainLValue(lValue);
5258
builder.accessChainPush(builder.makeIntConstant(index), TranslateCoherent(type),
5259
type.getBufferReferenceAlignment());
5260
5261
// store the member
5262
multiTypeStore(glslangElementType, elementRValue);
5263
}
5264
} else {
5265
assert(type.isStruct());
5266
5267
// loop over structure members
5268
const glslang::TTypeList& members = *type.getStruct();
5269
for (int m = 0; m < (int)members.size(); ++m) {
5270
const glslang::TType& glslangMemberType = *members[m].type;
5271
5272
// get the source member
5273
spv::Id memberRType = builder.getContainedTypeId(rType, m);
5274
spv::Id memberRValue = builder.createCompositeExtract(rValue, memberRType, m);
5275
5276
// set up the target storage
5277
builder.clearAccessChain();
5278
builder.setAccessChainLValue(lValue);
5279
builder.accessChainPush(builder.makeIntConstant(m), TranslateCoherent(type),
5280
type.getBufferReferenceAlignment());
5281
5282
// store the member
5283
multiTypeStore(glslangMemberType, memberRValue);
5284
}
5285
}
5286
}
5287
5288
// Decide whether or not this type should be
5289
// decorated with offsets and strides, and if so
5290
// whether std140 or std430 rules should be applied.
5291
glslang::TLayoutPacking TGlslangToSpvTraverser::getExplicitLayout(const glslang::TType& type) const
5292
{
5293
// has to be a block
5294
if (type.getBasicType() != glslang::EbtBlock)
5295
return glslang::ElpNone;
5296
5297
// has to be a uniform or buffer block or task in/out blocks
5298
if (type.getQualifier().storage != glslang::EvqUniform &&
5299
type.getQualifier().storage != glslang::EvqBuffer &&
5300
type.getQualifier().storage != glslang::EvqShared &&
5301
!type.getQualifier().isTaskMemory())
5302
return glslang::ElpNone;
5303
5304
// return the layout to use
5305
switch (type.getQualifier().layoutPacking) {
5306
case glslang::ElpStd140:
5307
case glslang::ElpStd430:
5308
case glslang::ElpScalar:
5309
return type.getQualifier().layoutPacking;
5310
default:
5311
return glslang::ElpNone;
5312
}
5313
}
5314
5315
// Given an array type, returns the integer stride required for that array
5316
int TGlslangToSpvTraverser::getArrayStride(const glslang::TType& arrayType, glslang::TLayoutPacking explicitLayout,
5317
glslang::TLayoutMatrix matrixLayout)
5318
{
5319
int size;
5320
int stride;
5321
glslangIntermediate->getMemberAlignment(arrayType, size, stride, explicitLayout,
5322
matrixLayout == glslang::ElmRowMajor);
5323
5324
return stride;
5325
}
5326
5327
// Given a matrix type, or array (of array) of matrixes type, returns the integer stride required for that matrix
5328
// when used as a member of an interface block
5329
int TGlslangToSpvTraverser::getMatrixStride(const glslang::TType& matrixType, glslang::TLayoutPacking explicitLayout,
5330
glslang::TLayoutMatrix matrixLayout)
5331
{
5332
glslang::TType elementType;
5333
elementType.shallowCopy(matrixType);
5334
elementType.clearArraySizes();
5335
5336
int size;
5337
int stride;
5338
glslangIntermediate->getMemberAlignment(elementType, size, stride, explicitLayout,
5339
matrixLayout == glslang::ElmRowMajor);
5340
5341
return stride;
5342
}
5343
5344
// Given a member type of a struct, realign the current offset for it, and compute
5345
// the next (not yet aligned) offset for the next member, which will get aligned
5346
// on the next call.
5347
// 'currentOffset' should be passed in already initialized, ready to modify, and reflecting
5348
// the migration of data from nextOffset -> currentOffset. It should be -1 on the first call.
5349
// -1 means a non-forced member offset (no decoration needed).
5350
void TGlslangToSpvTraverser::updateMemberOffset(const glslang::TType& structType, const glslang::TType& memberType,
5351
int& currentOffset, int& nextOffset, glslang::TLayoutPacking explicitLayout, glslang::TLayoutMatrix matrixLayout)
5352
{
5353
// this will get a positive value when deemed necessary
5354
nextOffset = -1;
5355
5356
// override anything in currentOffset with user-set offset
5357
if (memberType.getQualifier().hasOffset())
5358
currentOffset = memberType.getQualifier().layoutOffset;
5359
5360
// It could be that current linker usage in glslang updated all the layoutOffset,
5361
// in which case the following code does not matter. But, that's not quite right
5362
// once cross-compilation unit GLSL validation is done, as the original user
5363
// settings are needed in layoutOffset, and then the following will come into play.
5364
5365
if (explicitLayout == glslang::ElpNone) {
5366
if (! memberType.getQualifier().hasOffset())
5367
currentOffset = -1;
5368
5369
return;
5370
}
5371
5372
// Getting this far means we need explicit offsets
5373
if (currentOffset < 0)
5374
currentOffset = 0;
5375
5376
// Now, currentOffset is valid (either 0, or from a previous nextOffset),
5377
// but possibly not yet correctly aligned.
5378
5379
int memberSize;
5380
int dummyStride;
5381
int memberAlignment = glslangIntermediate->getMemberAlignment(memberType, memberSize, dummyStride, explicitLayout,
5382
matrixLayout == glslang::ElmRowMajor);
5383
5384
bool isVectorLike = memberType.isVector();
5385
if (memberType.isMatrix()) {
5386
if (matrixLayout == glslang::ElmRowMajor)
5387
isVectorLike = memberType.getMatrixRows() == 1;
5388
else
5389
isVectorLike = memberType.getMatrixCols() == 1;
5390
}
5391
5392
// Adjust alignment for HLSL rules
5393
// TODO: make this consistent in early phases of code:
5394
// adjusting this late means inconsistencies with earlier code, which for reflection is an issue
5395
// Until reflection is brought in sync with these adjustments, don't apply to $Global,
5396
// which is the most likely to rely on reflection, and least likely to rely implicit layouts
5397
if (glslangIntermediate->usingHlslOffsets() &&
5398
! memberType.isStruct() && structType.getTypeName().compare("$Global") != 0) {
5399
int componentSize;
5400
int componentAlignment = glslangIntermediate->getBaseAlignmentScalar(memberType, componentSize);
5401
if (! memberType.isArray() && isVectorLike && componentAlignment <= 4)
5402
memberAlignment = componentAlignment;
5403
5404
// Don't add unnecessary padding after this member
5405
if (memberType.isMatrix()) {
5406
if (matrixLayout == glslang::ElmRowMajor)
5407
memberSize -= componentSize * (4 - memberType.getMatrixCols());
5408
else
5409
memberSize -= componentSize * (4 - memberType.getMatrixRows());
5410
} else if (memberType.isArray())
5411
memberSize -= componentSize * (4 - memberType.getVectorSize());
5412
}
5413
5414
// Bump up to member alignment
5415
glslang::RoundToPow2(currentOffset, memberAlignment);
5416
5417
// Bump up to vec4 if there is a bad straddle
5418
if (explicitLayout != glslang::ElpScalar && glslangIntermediate->improperStraddle(memberType, memberSize,
5419
currentOffset, isVectorLike))
5420
glslang::RoundToPow2(currentOffset, 16);
5421
5422
nextOffset = currentOffset + memberSize;
5423
}
5424
5425
void TGlslangToSpvTraverser::declareUseOfStructMember(const glslang::TTypeList& members, int glslangMember)
5426
{
5427
const glslang::TBuiltInVariable glslangBuiltIn = members[glslangMember].type->getQualifier().builtIn;
5428
switch (glslangBuiltIn)
5429
{
5430
case glslang::EbvPointSize:
5431
case glslang::EbvClipDistance:
5432
case glslang::EbvCullDistance:
5433
case glslang::EbvViewportMaskNV:
5434
case glslang::EbvSecondaryPositionNV:
5435
case glslang::EbvSecondaryViewportMaskNV:
5436
case glslang::EbvPositionPerViewNV:
5437
case glslang::EbvViewportMaskPerViewNV:
5438
case glslang::EbvTaskCountNV:
5439
case glslang::EbvPrimitiveCountNV:
5440
case glslang::EbvPrimitiveIndicesNV:
5441
case glslang::EbvClipDistancePerViewNV:
5442
case glslang::EbvCullDistancePerViewNV:
5443
case glslang::EbvLayerPerViewNV:
5444
case glslang::EbvMeshViewCountNV:
5445
case glslang::EbvMeshViewIndicesNV:
5446
// Generate the associated capability. Delegate to TranslateBuiltInDecoration.
5447
// Alternately, we could just call this for any glslang built-in, since the
5448
// capability already guards against duplicates.
5449
TranslateBuiltInDecoration(glslangBuiltIn, false);
5450
break;
5451
default:
5452
// Capabilities were already generated when the struct was declared.
5453
break;
5454
}
5455
}
5456
5457
bool TGlslangToSpvTraverser::isShaderEntryPoint(const glslang::TIntermAggregate* node)
5458
{
5459
return node->getName().compare(glslangIntermediate->getEntryPointMangledName().c_str()) == 0;
5460
}
5461
5462
// Does parameter need a place to keep writes, separate from the original?
5463
// Assumes called after originalParam(), which filters out block/buffer/opaque-based
5464
// qualifiers such that we should have only in/out/inout/constreadonly here.
5465
bool TGlslangToSpvTraverser::writableParam(glslang::TStorageQualifier qualifier) const
5466
{
5467
assert(qualifier == glslang::EvqIn ||
5468
qualifier == glslang::EvqOut ||
5469
qualifier == glslang::EvqInOut ||
5470
qualifier == glslang::EvqUniform ||
5471
qualifier == glslang::EvqConstReadOnly);
5472
return qualifier != glslang::EvqConstReadOnly &&
5473
qualifier != glslang::EvqUniform;
5474
}
5475
5476
// Is parameter pass-by-original?
5477
bool TGlslangToSpvTraverser::originalParam(glslang::TStorageQualifier qualifier, const glslang::TType& paramType,
5478
bool implicitThisParam)
5479
{
5480
if (implicitThisParam) // implicit this
5481
return true;
5482
if (glslangIntermediate->getSource() == glslang::EShSourceHlsl)
5483
return paramType.getBasicType() == glslang::EbtBlock;
5484
return (paramType.containsOpaque() && !glslangIntermediate->getBindlessMode()) || // sampler, etc.
5485
paramType.getQualifier().isSpirvByReference() || // spirv_by_reference
5486
(paramType.getBasicType() == glslang::EbtBlock && qualifier == glslang::EvqBuffer); // SSBO
5487
}
5488
5489
// Make all the functions, skeletally, without actually visiting their bodies.
5490
void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslFunctions)
5491
{
5492
const auto getParamDecorations = [&](std::vector<spv::Decoration>& decorations, const glslang::TType& type,
5493
bool useVulkanMemoryModel) {
5494
spv::Decoration paramPrecision = TranslatePrecisionDecoration(type);
5495
if (paramPrecision != spv::NoPrecision)
5496
decorations.push_back(paramPrecision);
5497
TranslateMemoryDecoration(type.getQualifier(), decorations, useVulkanMemoryModel);
5498
if (type.isReference()) {
5499
// Original and non-writable params pass the pointer directly and
5500
// use restrict/aliased, others are stored to a pointer in Function
5501
// memory and use RestrictPointer/AliasedPointer.
5502
if (originalParam(type.getQualifier().storage, type, false) ||
5503
!writableParam(type.getQualifier().storage)) {
5504
// TranslateMemoryDecoration added Restrict decoration already.
5505
if (!type.getQualifier().isRestrict()) {
5506
decorations.push_back(spv::DecorationAliased);
5507
}
5508
} else {
5509
decorations.push_back(type.getQualifier().isRestrict() ? spv::DecorationRestrictPointerEXT :
5510
spv::DecorationAliasedPointerEXT);
5511
}
5512
}
5513
};
5514
5515
for (int f = 0; f < (int)glslFunctions.size(); ++f) {
5516
glslang::TIntermAggregate* glslFunction = glslFunctions[f]->getAsAggregate();
5517
if (! glslFunction || glslFunction->getOp() != glslang::EOpFunction)
5518
continue;
5519
if (isShaderEntryPoint(glslFunction)) {
5520
if (glslangIntermediate->getSource() != glslang::EShSourceHlsl) {
5521
builder.setupDebugFunctionEntry(shaderEntry, glslangIntermediate->getEntryPointMangledName().c_str(),
5522
glslFunction->getLoc().line,
5523
std::vector<spv::Id>(), // main function has no param
5524
std::vector<char const*>());
5525
}
5526
continue;
5527
}
5528
// We're on a user function. Set up the basic interface for the function now,
5529
// so that it's available to call. Translating the body will happen later.
5530
//
5531
// Typically (except for a "const in" parameter), an address will be passed to the
5532
// function. What it is an address of varies:
5533
//
5534
// - "in" parameters not marked as "const" can be written to without modifying the calling
5535
// argument so that write needs to be to a copy, hence the address of a copy works.
5536
//
5537
// - "const in" parameters can just be the r-value, as no writes need occur.
5538
//
5539
// - "out" and "inout" arguments can't be done as pointers to the calling argument, because
5540
// GLSL has copy-in/copy-out semantics. They can be handled though with a pointer to a copy.
5541
5542
std::vector<spv::Id> paramTypes;
5543
std::vector<char const*> paramNames;
5544
std::vector<std::vector<spv::Decoration>> paramDecorations; // list of decorations per parameter
5545
glslang::TIntermSequence& parameters = glslFunction->getSequence()[0]->getAsAggregate()->getSequence();
5546
5547
#ifdef ENABLE_HLSL
5548
bool implicitThis = (int)parameters.size() > 0 && parameters[0]->getAsSymbolNode()->getName() ==
5549
glslangIntermediate->implicitThisName;
5550
#else
5551
bool implicitThis = false;
5552
#endif
5553
5554
paramDecorations.resize(parameters.size());
5555
for (int p = 0; p < (int)parameters.size(); ++p) {
5556
const glslang::TType& paramType = parameters[p]->getAsTyped()->getType();
5557
spv::Id typeId = convertGlslangToSpvType(paramType);
5558
if (originalParam(paramType.getQualifier().storage, paramType, implicitThis && p == 0))
5559
typeId = builder.makePointer(TranslateStorageClass(paramType), typeId);
5560
else if (writableParam(paramType.getQualifier().storage))
5561
typeId = builder.makePointer(spv::StorageClassFunction, typeId);
5562
else
5563
rValueParameters.insert(parameters[p]->getAsSymbolNode()->getId());
5564
getParamDecorations(paramDecorations[p], paramType, glslangIntermediate->usingVulkanMemoryModel());
5565
paramTypes.push_back(typeId);
5566
}
5567
5568
for (auto const parameter:parameters) {
5569
paramNames.push_back(parameter->getAsSymbolNode()->getName().c_str());
5570
}
5571
5572
spv::Block* functionBlock;
5573
spv::Function* function = builder.makeFunctionEntry(
5574
TranslatePrecisionDecoration(glslFunction->getType()), convertGlslangToSpvType(glslFunction->getType()),
5575
glslFunction->getName().c_str(), convertGlslangLinkageToSpv(glslFunction->getLinkType()), paramTypes,
5576
paramDecorations, &functionBlock);
5577
builder.setupDebugFunctionEntry(function, glslFunction->getName().c_str(), glslFunction->getLoc().line,
5578
paramTypes, paramNames);
5579
if (implicitThis)
5580
function->setImplicitThis();
5581
5582
// Track function to emit/call later
5583
functionMap[glslFunction->getName().c_str()] = function;
5584
5585
// Set the parameter id's
5586
for (int p = 0; p < (int)parameters.size(); ++p) {
5587
symbolValues[parameters[p]->getAsSymbolNode()->getId()] = function->getParamId(p);
5588
// give a name too
5589
builder.addName(function->getParamId(p), parameters[p]->getAsSymbolNode()->getName().c_str());
5590
5591
const glslang::TType& paramType = parameters[p]->getAsTyped()->getType();
5592
if (paramType.contains8BitInt())
5593
builder.addCapability(spv::CapabilityInt8);
5594
if (paramType.contains16BitInt())
5595
builder.addCapability(spv::CapabilityInt16);
5596
if (paramType.contains16BitFloat())
5597
builder.addCapability(spv::CapabilityFloat16);
5598
}
5599
}
5600
}
5601
5602
// Process all the initializers, while skipping the functions and link objects
5603
void TGlslangToSpvTraverser::makeGlobalInitializers(const glslang::TIntermSequence& initializers)
5604
{
5605
builder.setBuildPoint(shaderEntry->getLastBlock());
5606
for (int i = 0; i < (int)initializers.size(); ++i) {
5607
glslang::TIntermAggregate* initializer = initializers[i]->getAsAggregate();
5608
if (initializer && initializer->getOp() != glslang::EOpFunction && initializer->getOp() !=
5609
glslang::EOpLinkerObjects) {
5610
5611
// We're on a top-level node that's not a function. Treat as an initializer, whose
5612
// code goes into the beginning of the entry point.
5613
initializer->traverse(this);
5614
}
5615
}
5616
}
5617
// Walk over all linker objects to create a map for payload and callable data linker objects
5618
// and their location to be used during codegen for OpTraceKHR and OpExecuteCallableKHR
5619
// This is done here since it is possible that these linker objects are not be referenced in the AST
5620
void TGlslangToSpvTraverser::collectRayTracingLinkerObjects()
5621
{
5622
glslang::TIntermAggregate* linkerObjects = glslangIntermediate->findLinkerObjects();
5623
for (auto& objSeq : linkerObjects->getSequence()) {
5624
auto objNode = objSeq->getAsSymbolNode();
5625
if (objNode != nullptr) {
5626
if (objNode->getQualifier().hasLocation()) {
5627
unsigned int location = objNode->getQualifier().layoutLocation;
5628
auto st = objNode->getQualifier().storage;
5629
int set;
5630
switch (st)
5631
{
5632
case glslang::EvqPayload:
5633
case glslang::EvqPayloadIn:
5634
set = 0;
5635
break;
5636
case glslang::EvqCallableData:
5637
case glslang::EvqCallableDataIn:
5638
set = 1;
5639
break;
5640
5641
case glslang::EvqHitObjectAttrNV:
5642
set = 2;
5643
break;
5644
5645
default:
5646
set = -1;
5647
}
5648
if (set != -1)
5649
locationToSymbol[set].insert(std::make_pair(location, objNode));
5650
}
5651
}
5652
}
5653
}
5654
// Process all the functions, while skipping initializers.
5655
void TGlslangToSpvTraverser::visitFunctions(const glslang::TIntermSequence& glslFunctions)
5656
{
5657
for (int f = 0; f < (int)glslFunctions.size(); ++f) {
5658
glslang::TIntermAggregate* node = glslFunctions[f]->getAsAggregate();
5659
if (node && (node->getOp() == glslang::EOpFunction || node->getOp() == glslang::EOpLinkerObjects))
5660
node->traverse(this);
5661
}
5662
}
5663
5664
void TGlslangToSpvTraverser::handleFunctionEntry(const glslang::TIntermAggregate* node)
5665
{
5666
// SPIR-V functions should already be in the functionMap from the prepass
5667
// that called makeFunctions().
5668
currentFunction = functionMap[node->getName().c_str()];
5669
spv::Block* functionBlock = currentFunction->getEntryBlock();
5670
builder.setBuildPoint(functionBlock);
5671
builder.enterFunction(currentFunction);
5672
}
5673
5674
void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermAggregate& node, std::vector<spv::Id>& arguments,
5675
spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags)
5676
{
5677
const glslang::TIntermSequence& glslangArguments = node.getSequence();
5678
5679
glslang::TSampler sampler = {};
5680
bool cubeCompare = false;
5681
bool f16ShadowCompare = false;
5682
if (node.isTexture() || node.isImage()) {
5683
sampler = glslangArguments[0]->getAsTyped()->getType().getSampler();
5684
cubeCompare = sampler.dim == glslang::EsdCube && sampler.arrayed && sampler.shadow;
5685
f16ShadowCompare = sampler.shadow &&
5686
glslangArguments[1]->getAsTyped()->getType().getBasicType() == glslang::EbtFloat16;
5687
}
5688
5689
for (int i = 0; i < (int)glslangArguments.size(); ++i) {
5690
builder.clearAccessChain();
5691
glslangArguments[i]->traverse(this);
5692
5693
// Special case l-value operands
5694
bool lvalue = false;
5695
switch (node.getOp()) {
5696
case glslang::EOpImageAtomicAdd:
5697
case glslang::EOpImageAtomicMin:
5698
case glslang::EOpImageAtomicMax:
5699
case glslang::EOpImageAtomicAnd:
5700
case glslang::EOpImageAtomicOr:
5701
case glslang::EOpImageAtomicXor:
5702
case glslang::EOpImageAtomicExchange:
5703
case glslang::EOpImageAtomicCompSwap:
5704
case glslang::EOpImageAtomicLoad:
5705
case glslang::EOpImageAtomicStore:
5706
if (i == 0)
5707
lvalue = true;
5708
break;
5709
case glslang::EOpSparseImageLoad:
5710
if ((sampler.ms && i == 3) || (! sampler.ms && i == 2))
5711
lvalue = true;
5712
break;
5713
case glslang::EOpSparseTexture:
5714
if (((cubeCompare || f16ShadowCompare) && i == 3) || (! (cubeCompare || f16ShadowCompare) && i == 2))
5715
lvalue = true;
5716
break;
5717
case glslang::EOpSparseTextureClamp:
5718
if (((cubeCompare || f16ShadowCompare) && i == 4) || (! (cubeCompare || f16ShadowCompare) && i == 3))
5719
lvalue = true;
5720
break;
5721
case glslang::EOpSparseTextureLod:
5722
case glslang::EOpSparseTextureOffset:
5723
if ((f16ShadowCompare && i == 4) || (! f16ShadowCompare && i == 3))
5724
lvalue = true;
5725
break;
5726
case glslang::EOpSparseTextureFetch:
5727
if ((sampler.dim != glslang::EsdRect && i == 3) || (sampler.dim == glslang::EsdRect && i == 2))
5728
lvalue = true;
5729
break;
5730
case glslang::EOpSparseTextureFetchOffset:
5731
if ((sampler.dim != glslang::EsdRect && i == 4) || (sampler.dim == glslang::EsdRect && i == 3))
5732
lvalue = true;
5733
break;
5734
case glslang::EOpSparseTextureLodOffset:
5735
case glslang::EOpSparseTextureGrad:
5736
case glslang::EOpSparseTextureOffsetClamp:
5737
if ((f16ShadowCompare && i == 5) || (! f16ShadowCompare && i == 4))
5738
lvalue = true;
5739
break;
5740
case glslang::EOpSparseTextureGradOffset:
5741
case glslang::EOpSparseTextureGradClamp:
5742
if ((f16ShadowCompare && i == 6) || (! f16ShadowCompare && i == 5))
5743
lvalue = true;
5744
break;
5745
case glslang::EOpSparseTextureGradOffsetClamp:
5746
if ((f16ShadowCompare && i == 7) || (! f16ShadowCompare && i == 6))
5747
lvalue = true;
5748
break;
5749
case glslang::EOpSparseTextureGather:
5750
if ((sampler.shadow && i == 3) || (! sampler.shadow && i == 2))
5751
lvalue = true;
5752
break;
5753
case glslang::EOpSparseTextureGatherOffset:
5754
case glslang::EOpSparseTextureGatherOffsets:
5755
if ((sampler.shadow && i == 4) || (! sampler.shadow && i == 3))
5756
lvalue = true;
5757
break;
5758
case glslang::EOpSparseTextureGatherLod:
5759
if (i == 3)
5760
lvalue = true;
5761
break;
5762
case glslang::EOpSparseTextureGatherLodOffset:
5763
case glslang::EOpSparseTextureGatherLodOffsets:
5764
if (i == 4)
5765
lvalue = true;
5766
break;
5767
case glslang::EOpSparseImageLoadLod:
5768
if (i == 3)
5769
lvalue = true;
5770
break;
5771
case glslang::EOpImageSampleFootprintNV:
5772
if (i == 4)
5773
lvalue = true;
5774
break;
5775
case glslang::EOpImageSampleFootprintClampNV:
5776
case glslang::EOpImageSampleFootprintLodNV:
5777
if (i == 5)
5778
lvalue = true;
5779
break;
5780
case glslang::EOpImageSampleFootprintGradNV:
5781
if (i == 6)
5782
lvalue = true;
5783
break;
5784
case glslang::EOpImageSampleFootprintGradClampNV:
5785
if (i == 7)
5786
lvalue = true;
5787
break;
5788
case glslang::EOpRayQueryGetIntersectionTriangleVertexPositionsEXT:
5789
if (i == 2)
5790
lvalue = true;
5791
break;
5792
default:
5793
break;
5794
}
5795
5796
if (lvalue) {
5797
spv::Id lvalue_id = builder.accessChainGetLValue();
5798
arguments.push_back(lvalue_id);
5799
lvalueCoherentFlags = builder.getAccessChain().coherentFlags;
5800
builder.addDecoration(lvalue_id, TranslateNonUniformDecoration(lvalueCoherentFlags));
5801
lvalueCoherentFlags |= TranslateCoherent(glslangArguments[i]->getAsTyped()->getType());
5802
} else
5803
arguments.push_back(accessChainLoad(glslangArguments[i]->getAsTyped()->getType()));
5804
}
5805
}
5806
5807
void TGlslangToSpvTraverser::translateArguments(glslang::TIntermUnary& node, std::vector<spv::Id>& arguments)
5808
{
5809
builder.clearAccessChain();
5810
node.getOperand()->traverse(this);
5811
arguments.push_back(accessChainLoad(node.getOperand()->getType()));
5812
}
5813
5814
spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermOperator* node)
5815
{
5816
if (! node->isImage() && ! node->isTexture())
5817
return spv::NoResult;
5818
5819
builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
5820
5821
// Process a GLSL texturing op (will be SPV image)
5822
5823
const glslang::TType &imageType = node->getAsAggregate()
5824
? node->getAsAggregate()->getSequence()[0]->getAsTyped()->getType()
5825
: node->getAsUnaryNode()->getOperand()->getAsTyped()->getType();
5826
const glslang::TSampler sampler = imageType.getSampler();
5827
bool f16ShadowCompare = (sampler.shadow && node->getAsAggregate())
5828
? node->getAsAggregate()->getSequence()[1]->getAsTyped()->getType().getBasicType() == glslang::EbtFloat16
5829
: false;
5830
5831
const auto signExtensionMask = [&]() {
5832
if (builder.getSpvVersion() >= spv::Spv_1_4) {
5833
if (sampler.type == glslang::EbtUint)
5834
return spv::ImageOperandsZeroExtendMask;
5835
else if (sampler.type == glslang::EbtInt)
5836
return spv::ImageOperandsSignExtendMask;
5837
}
5838
return spv::ImageOperandsMaskNone;
5839
};
5840
5841
spv::Builder::AccessChain::CoherentFlags lvalueCoherentFlags;
5842
5843
std::vector<spv::Id> arguments;
5844
if (node->getAsAggregate())
5845
translateArguments(*node->getAsAggregate(), arguments, lvalueCoherentFlags);
5846
else
5847
translateArguments(*node->getAsUnaryNode(), arguments);
5848
spv::Decoration precision = TranslatePrecisionDecoration(node->getType());
5849
5850
spv::Builder::TextureParameters params = { };
5851
params.sampler = arguments[0];
5852
5853
glslang::TCrackedTextureOp cracked;
5854
node->crackTexture(sampler, cracked);
5855
5856
const bool isUnsignedResult = node->getType().getBasicType() == glslang::EbtUint;
5857
5858
if (builder.isSampledImage(params.sampler) &&
5859
((cracked.query && node->getOp() != glslang::EOpTextureQueryLod) || cracked.fragMask || cracked.fetch)) {
5860
params.sampler = builder.createUnaryOp(spv::OpImage, builder.getImageType(params.sampler), params.sampler);
5861
if (imageType.getQualifier().isNonUniform()) {
5862
builder.addDecoration(params.sampler, spv::DecorationNonUniformEXT);
5863
}
5864
}
5865
// Check for queries
5866
if (cracked.query) {
5867
switch (node->getOp()) {
5868
case glslang::EOpImageQuerySize:
5869
case glslang::EOpTextureQuerySize:
5870
if (arguments.size() > 1) {
5871
params.lod = arguments[1];
5872
return builder.createTextureQueryCall(spv::OpImageQuerySizeLod, params, isUnsignedResult);
5873
} else
5874
return builder.createTextureQueryCall(spv::OpImageQuerySize, params, isUnsignedResult);
5875
case glslang::EOpImageQuerySamples:
5876
case glslang::EOpTextureQuerySamples:
5877
return builder.createTextureQueryCall(spv::OpImageQuerySamples, params, isUnsignedResult);
5878
case glslang::EOpTextureQueryLod:
5879
params.coords = arguments[1];
5880
return builder.createTextureQueryCall(spv::OpImageQueryLod, params, isUnsignedResult);
5881
case glslang::EOpTextureQueryLevels:
5882
return builder.createTextureQueryCall(spv::OpImageQueryLevels, params, isUnsignedResult);
5883
case glslang::EOpSparseTexelsResident:
5884
return builder.createUnaryOp(spv::OpImageSparseTexelsResident, builder.makeBoolType(), arguments[0]);
5885
default:
5886
assert(0);
5887
break;
5888
}
5889
}
5890
5891
int components = node->getType().getVectorSize();
5892
5893
if (node->getOp() == glslang::EOpImageLoad ||
5894
node->getOp() == glslang::EOpImageLoadLod ||
5895
node->getOp() == glslang::EOpTextureFetch ||
5896
node->getOp() == glslang::EOpTextureFetchOffset) {
5897
// These must produce 4 components, per SPIR-V spec. We'll add a conversion constructor if needed.
5898
// This will only happen through the HLSL path for operator[], so we do not have to handle e.g.
5899
// the EOpTexture/Proj/Lod/etc family. It would be harmless to do so, but would need more logic
5900
// here around e.g. which ones return scalars or other types.
5901
components = 4;
5902
}
5903
5904
glslang::TType returnType(node->getType().getBasicType(), glslang::EvqTemporary, components);
5905
5906
auto resultType = [&returnType,this]{ return convertGlslangToSpvType(returnType); };
5907
5908
// Check for image functions other than queries
5909
if (node->isImage()) {
5910
std::vector<spv::IdImmediate> operands;
5911
auto opIt = arguments.begin();
5912
spv::IdImmediate image = { true, *(opIt++) };
5913
operands.push_back(image);
5914
5915
// Handle subpass operations
5916
// TODO: GLSL should change to have the "MS" only on the type rather than the
5917
// built-in function.
5918
if (cracked.subpass) {
5919
// add on the (0,0) coordinate
5920
spv::Id zero = builder.makeIntConstant(0);
5921
std::vector<spv::Id> comps;
5922
comps.push_back(zero);
5923
comps.push_back(zero);
5924
spv::IdImmediate coord = { true,
5925
builder.makeCompositeConstant(builder.makeVectorType(builder.makeIntType(32), 2), comps) };
5926
operands.push_back(coord);
5927
spv::IdImmediate imageOperands = { false, spv::ImageOperandsMaskNone };
5928
imageOperands.word = imageOperands.word | signExtensionMask();
5929
if (sampler.isMultiSample()) {
5930
imageOperands.word = imageOperands.word | spv::ImageOperandsSampleMask;
5931
}
5932
if (imageOperands.word != spv::ImageOperandsMaskNone) {
5933
operands.push_back(imageOperands);
5934
if (sampler.isMultiSample()) {
5935
spv::IdImmediate imageOperand = { true, *(opIt++) };
5936
operands.push_back(imageOperand);
5937
}
5938
}
5939
spv::Id result = builder.createOp(spv::OpImageRead, resultType(), operands);
5940
builder.setPrecision(result, precision);
5941
return result;
5942
}
5943
5944
if (cracked.attachmentEXT) {
5945
if (opIt != arguments.end()) {
5946
spv::IdImmediate sample = { true, *opIt };
5947
operands.push_back(sample);
5948
}
5949
spv::Id result = builder.createOp(spv::OpColorAttachmentReadEXT, resultType(), operands);
5950
builder.addExtension(spv::E_SPV_EXT_shader_tile_image);
5951
builder.setPrecision(result, precision);
5952
return result;
5953
}
5954
5955
spv::IdImmediate coord = { true, *(opIt++) };
5956
operands.push_back(coord);
5957
if (node->getOp() == glslang::EOpImageLoad || node->getOp() == glslang::EOpImageLoadLod) {
5958
spv::ImageOperandsMask mask = spv::ImageOperandsMaskNone;
5959
if (sampler.isMultiSample()) {
5960
mask = mask | spv::ImageOperandsSampleMask;
5961
}
5962
if (cracked.lod) {
5963
builder.addExtension(spv::E_SPV_AMD_shader_image_load_store_lod);
5964
builder.addCapability(spv::CapabilityImageReadWriteLodAMD);
5965
mask = mask | spv::ImageOperandsLodMask;
5966
}
5967
mask = mask | TranslateImageOperands(TranslateCoherent(imageType));
5968
mask = (spv::ImageOperandsMask)(mask & ~spv::ImageOperandsMakeTexelAvailableKHRMask);
5969
mask = mask | signExtensionMask();
5970
if (mask != spv::ImageOperandsMaskNone) {
5971
spv::IdImmediate imageOperands = { false, (unsigned int)mask };
5972
operands.push_back(imageOperands);
5973
}
5974
if (mask & spv::ImageOperandsSampleMask) {
5975
spv::IdImmediate imageOperand = { true, *opIt++ };
5976
operands.push_back(imageOperand);
5977
}
5978
if (mask & spv::ImageOperandsLodMask) {
5979
spv::IdImmediate imageOperand = { true, *opIt++ };
5980
operands.push_back(imageOperand);
5981
}
5982
if (mask & spv::ImageOperandsMakeTexelVisibleKHRMask) {
5983
spv::IdImmediate imageOperand = { true,
5984
builder.makeUintConstant(TranslateMemoryScope(TranslateCoherent(imageType))) };
5985
operands.push_back(imageOperand);
5986
}
5987
5988
if (builder.getImageTypeFormat(builder.getImageType(operands.front().word)) == spv::ImageFormatUnknown)
5989
builder.addCapability(spv::CapabilityStorageImageReadWithoutFormat);
5990
5991
std::vector<spv::Id> result(1, builder.createOp(spv::OpImageRead, resultType(), operands));
5992
builder.setPrecision(result[0], precision);
5993
5994
// If needed, add a conversion constructor to the proper size.
5995
if (components != node->getType().getVectorSize())
5996
result[0] = builder.createConstructor(precision, result, convertGlslangToSpvType(node->getType()));
5997
5998
return result[0];
5999
} else if (node->getOp() == glslang::EOpImageStore || node->getOp() == glslang::EOpImageStoreLod) {
6000
6001
// Push the texel value before the operands
6002
if (sampler.isMultiSample() || cracked.lod) {
6003
spv::IdImmediate texel = { true, *(opIt + 1) };
6004
operands.push_back(texel);
6005
} else {
6006
spv::IdImmediate texel = { true, *opIt };
6007
operands.push_back(texel);
6008
}
6009
6010
spv::ImageOperandsMask mask = spv::ImageOperandsMaskNone;
6011
if (sampler.isMultiSample()) {
6012
mask = mask | spv::ImageOperandsSampleMask;
6013
}
6014
if (cracked.lod) {
6015
builder.addExtension(spv::E_SPV_AMD_shader_image_load_store_lod);
6016
builder.addCapability(spv::CapabilityImageReadWriteLodAMD);
6017
mask = mask | spv::ImageOperandsLodMask;
6018
}
6019
mask = mask | TranslateImageOperands(TranslateCoherent(imageType));
6020
mask = (spv::ImageOperandsMask)(mask & ~spv::ImageOperandsMakeTexelVisibleKHRMask);
6021
mask = mask | signExtensionMask();
6022
if (mask != spv::ImageOperandsMaskNone) {
6023
spv::IdImmediate imageOperands = { false, (unsigned int)mask };
6024
operands.push_back(imageOperands);
6025
}
6026
if (mask & spv::ImageOperandsSampleMask) {
6027
spv::IdImmediate imageOperand = { true, *opIt++ };
6028
operands.push_back(imageOperand);
6029
}
6030
if (mask & spv::ImageOperandsLodMask) {
6031
spv::IdImmediate imageOperand = { true, *opIt++ };
6032
operands.push_back(imageOperand);
6033
}
6034
if (mask & spv::ImageOperandsMakeTexelAvailableKHRMask) {
6035
spv::IdImmediate imageOperand = { true,
6036
builder.makeUintConstant(TranslateMemoryScope(TranslateCoherent(imageType))) };
6037
operands.push_back(imageOperand);
6038
}
6039
6040
builder.createNoResultOp(spv::OpImageWrite, operands);
6041
if (builder.getImageTypeFormat(builder.getImageType(operands.front().word)) == spv::ImageFormatUnknown)
6042
builder.addCapability(spv::CapabilityStorageImageWriteWithoutFormat);
6043
return spv::NoResult;
6044
} else if (node->getOp() == glslang::EOpSparseImageLoad ||
6045
node->getOp() == glslang::EOpSparseImageLoadLod) {
6046
builder.addCapability(spv::CapabilitySparseResidency);
6047
if (builder.getImageTypeFormat(builder.getImageType(operands.front().word)) == spv::ImageFormatUnknown)
6048
builder.addCapability(spv::CapabilityStorageImageReadWithoutFormat);
6049
6050
spv::ImageOperandsMask mask = spv::ImageOperandsMaskNone;
6051
if (sampler.isMultiSample()) {
6052
mask = mask | spv::ImageOperandsSampleMask;
6053
}
6054
if (cracked.lod) {
6055
builder.addExtension(spv::E_SPV_AMD_shader_image_load_store_lod);
6056
builder.addCapability(spv::CapabilityImageReadWriteLodAMD);
6057
6058
mask = mask | spv::ImageOperandsLodMask;
6059
}
6060
mask = mask | TranslateImageOperands(TranslateCoherent(imageType));
6061
mask = (spv::ImageOperandsMask)(mask & ~spv::ImageOperandsMakeTexelAvailableKHRMask);
6062
mask = mask | signExtensionMask();
6063
if (mask != spv::ImageOperandsMaskNone) {
6064
spv::IdImmediate imageOperands = { false, (unsigned int)mask };
6065
operands.push_back(imageOperands);
6066
}
6067
if (mask & spv::ImageOperandsSampleMask) {
6068
spv::IdImmediate imageOperand = { true, *opIt++ };
6069
operands.push_back(imageOperand);
6070
}
6071
if (mask & spv::ImageOperandsLodMask) {
6072
spv::IdImmediate imageOperand = { true, *opIt++ };
6073
operands.push_back(imageOperand);
6074
}
6075
if (mask & spv::ImageOperandsMakeTexelVisibleKHRMask) {
6076
spv::IdImmediate imageOperand = { true, builder.makeUintConstant(TranslateMemoryScope(
6077
TranslateCoherent(imageType))) };
6078
operands.push_back(imageOperand);
6079
}
6080
6081
// Create the return type that was a special structure
6082
spv::Id texelOut = *opIt;
6083
spv::Id typeId0 = resultType();
6084
spv::Id typeId1 = builder.getDerefTypeId(texelOut);
6085
spv::Id resultTypeId = builder.makeStructResultType(typeId0, typeId1);
6086
6087
spv::Id resultId = builder.createOp(spv::OpImageSparseRead, resultTypeId, operands);
6088
6089
// Decode the return type
6090
builder.createStore(builder.createCompositeExtract(resultId, typeId1, 1), texelOut);
6091
return builder.createCompositeExtract(resultId, typeId0, 0);
6092
} else {
6093
// Process image atomic operations
6094
6095
// GLSL "IMAGE_PARAMS" will involve in constructing an image texel pointer and this pointer,
6096
// as the first source operand, is required by SPIR-V atomic operations.
6097
// For non-MS, the sample value should be 0
6098
spv::IdImmediate sample = { true, sampler.isMultiSample() ? *(opIt++) : builder.makeUintConstant(0) };
6099
operands.push_back(sample);
6100
6101
spv::Id resultTypeId;
6102
glslang::TBasicType typeProxy = node->getBasicType();
6103
// imageAtomicStore has a void return type so base the pointer type on
6104
// the type of the value operand.
6105
if (node->getOp() == glslang::EOpImageAtomicStore) {
6106
resultTypeId = builder.makePointer(spv::StorageClassImage, builder.getTypeId(*opIt));
6107
typeProxy = node->getAsAggregate()->getSequence()[0]->getAsTyped()->getType().getSampler().type;
6108
} else {
6109
resultTypeId = builder.makePointer(spv::StorageClassImage, resultType());
6110
}
6111
spv::Id pointer = builder.createOp(spv::OpImageTexelPointer, resultTypeId, operands);
6112
if (imageType.getQualifier().nonUniform) {
6113
builder.addDecoration(pointer, spv::DecorationNonUniformEXT);
6114
}
6115
6116
std::vector<spv::Id> operands;
6117
operands.push_back(pointer);
6118
for (; opIt != arguments.end(); ++opIt)
6119
operands.push_back(*opIt);
6120
6121
return createAtomicOperation(node->getOp(), precision, resultType(), operands, typeProxy,
6122
lvalueCoherentFlags, node->getType());
6123
}
6124
}
6125
6126
// Check for fragment mask functions other than queries
6127
if (cracked.fragMask) {
6128
assert(sampler.ms);
6129
6130
auto opIt = arguments.begin();
6131
std::vector<spv::Id> operands;
6132
6133
operands.push_back(params.sampler);
6134
++opIt;
6135
6136
if (sampler.isSubpass()) {
6137
// add on the (0,0) coordinate
6138
spv::Id zero = builder.makeIntConstant(0);
6139
std::vector<spv::Id> comps;
6140
comps.push_back(zero);
6141
comps.push_back(zero);
6142
operands.push_back(builder.makeCompositeConstant(
6143
builder.makeVectorType(builder.makeIntType(32), 2), comps));
6144
}
6145
6146
for (; opIt != arguments.end(); ++opIt)
6147
operands.push_back(*opIt);
6148
6149
spv::Op fragMaskOp = spv::OpNop;
6150
if (node->getOp() == glslang::EOpFragmentMaskFetch)
6151
fragMaskOp = spv::OpFragmentMaskFetchAMD;
6152
else if (node->getOp() == glslang::EOpFragmentFetch)
6153
fragMaskOp = spv::OpFragmentFetchAMD;
6154
6155
builder.addExtension(spv::E_SPV_AMD_shader_fragment_mask);
6156
builder.addCapability(spv::CapabilityFragmentMaskAMD);
6157
return builder.createOp(fragMaskOp, resultType(), operands);
6158
}
6159
6160
// Check for texture functions other than queries
6161
bool sparse = node->isSparseTexture();
6162
bool imageFootprint = node->isImageFootprint();
6163
bool cubeCompare = sampler.dim == glslang::EsdCube && sampler.isArrayed() && sampler.isShadow();
6164
6165
// check for bias argument
6166
bool bias = false;
6167
if (! cracked.lod && ! cracked.grad && ! cracked.fetch && ! cubeCompare) {
6168
int nonBiasArgCount = 2;
6169
if (cracked.gather)
6170
++nonBiasArgCount; // comp argument should be present when bias argument is present
6171
6172
if (f16ShadowCompare)
6173
++nonBiasArgCount;
6174
if (cracked.offset)
6175
++nonBiasArgCount;
6176
else if (cracked.offsets)
6177
++nonBiasArgCount;
6178
if (cracked.grad)
6179
nonBiasArgCount += 2;
6180
if (cracked.lodClamp)
6181
++nonBiasArgCount;
6182
if (sparse)
6183
++nonBiasArgCount;
6184
if (imageFootprint)
6185
//Following three extra arguments
6186
// int granularity, bool coarse, out gl_TextureFootprint2DNV footprint
6187
nonBiasArgCount += 3;
6188
if ((int)arguments.size() > nonBiasArgCount)
6189
bias = true;
6190
}
6191
6192
if (cracked.gather) {
6193
const auto& sourceExtensions = glslangIntermediate->getRequestedExtensions();
6194
if (bias || cracked.lod ||
6195
sourceExtensions.find(glslang::E_GL_AMD_texture_gather_bias_lod) != sourceExtensions.end()) {
6196
builder.addExtension(spv::E_SPV_AMD_texture_gather_bias_lod);
6197
builder.addCapability(spv::CapabilityImageGatherBiasLodAMD);
6198
}
6199
}
6200
6201
// set the rest of the arguments
6202
6203
params.coords = arguments[1];
6204
int extraArgs = 0;
6205
bool noImplicitLod = false;
6206
6207
// sort out where Dref is coming from
6208
if (cubeCompare || f16ShadowCompare) {
6209
params.Dref = arguments[2];
6210
++extraArgs;
6211
} else if (sampler.shadow && cracked.gather) {
6212
params.Dref = arguments[2];
6213
++extraArgs;
6214
} else if (sampler.shadow) {
6215
std::vector<spv::Id> indexes;
6216
int dRefComp;
6217
if (cracked.proj)
6218
dRefComp = 2; // "The resulting 3rd component of P in the shadow forms is used as Dref"
6219
else
6220
dRefComp = builder.getNumComponents(params.coords) - 1;
6221
indexes.push_back(dRefComp);
6222
params.Dref = builder.createCompositeExtract(params.coords,
6223
builder.getScalarTypeId(builder.getTypeId(params.coords)), indexes);
6224
}
6225
6226
// lod
6227
if (cracked.lod) {
6228
params.lod = arguments[2 + extraArgs];
6229
++extraArgs;
6230
} else if (glslangIntermediate->getStage() != EShLangFragment &&
6231
!(glslangIntermediate->getStage() == EShLangCompute &&
6232
glslangIntermediate->hasLayoutDerivativeModeNone())) {
6233
// we need to invent the default lod for an explicit lod instruction for a non-fragment stage
6234
noImplicitLod = true;
6235
}
6236
6237
// multisample
6238
if (sampler.isMultiSample()) {
6239
params.sample = arguments[2 + extraArgs]; // For MS, "sample" should be specified
6240
++extraArgs;
6241
}
6242
6243
// gradient
6244
if (cracked.grad) {
6245
params.gradX = arguments[2 + extraArgs];
6246
params.gradY = arguments[3 + extraArgs];
6247
extraArgs += 2;
6248
}
6249
6250
// offset and offsets
6251
if (cracked.offset) {
6252
params.offset = arguments[2 + extraArgs];
6253
++extraArgs;
6254
} else if (cracked.offsets) {
6255
params.offsets = arguments[2 + extraArgs];
6256
++extraArgs;
6257
}
6258
6259
// lod clamp
6260
if (cracked.lodClamp) {
6261
params.lodClamp = arguments[2 + extraArgs];
6262
++extraArgs;
6263
}
6264
// sparse
6265
if (sparse) {
6266
params.texelOut = arguments[2 + extraArgs];
6267
++extraArgs;
6268
}
6269
// gather component
6270
if (cracked.gather && ! sampler.shadow) {
6271
// default component is 0, if missing, otherwise an argument
6272
if (2 + extraArgs < (int)arguments.size()) {
6273
params.component = arguments[2 + extraArgs];
6274
++extraArgs;
6275
} else
6276
params.component = builder.makeIntConstant(0);
6277
}
6278
spv::Id resultStruct = spv::NoResult;
6279
if (imageFootprint) {
6280
//Following three extra arguments
6281
// int granularity, bool coarse, out gl_TextureFootprint2DNV footprint
6282
params.granularity = arguments[2 + extraArgs];
6283
params.coarse = arguments[3 + extraArgs];
6284
resultStruct = arguments[4 + extraArgs];
6285
extraArgs += 3;
6286
}
6287
6288
// bias
6289
if (bias) {
6290
params.bias = arguments[2 + extraArgs];
6291
++extraArgs;
6292
}
6293
6294
if (imageFootprint) {
6295
builder.addExtension(spv::E_SPV_NV_shader_image_footprint);
6296
builder.addCapability(spv::CapabilityImageFootprintNV);
6297
6298
6299
//resultStructType(OpenGL type) contains 5 elements:
6300
//struct gl_TextureFootprint2DNV {
6301
// uvec2 anchor;
6302
// uvec2 offset;
6303
// uvec2 mask;
6304
// uint lod;
6305
// uint granularity;
6306
//};
6307
//or
6308
//struct gl_TextureFootprint3DNV {
6309
// uvec3 anchor;
6310
// uvec3 offset;
6311
// uvec2 mask;
6312
// uint lod;
6313
// uint granularity;
6314
//};
6315
spv::Id resultStructType = builder.getContainedTypeId(builder.getTypeId(resultStruct));
6316
assert(builder.isStructType(resultStructType));
6317
6318
//resType (SPIR-V type) contains 6 elements:
6319
//Member 0 must be a Boolean type scalar(LOD),
6320
//Member 1 must be a vector of integer type, whose Signedness operand is 0(anchor),
6321
//Member 2 must be a vector of integer type, whose Signedness operand is 0(offset),
6322
//Member 3 must be a vector of integer type, whose Signedness operand is 0(mask),
6323
//Member 4 must be a scalar of integer type, whose Signedness operand is 0(lod),
6324
//Member 5 must be a scalar of integer type, whose Signedness operand is 0(granularity).
6325
std::vector<spv::Id> members;
6326
members.push_back(resultType());
6327
for (int i = 0; i < 5; i++) {
6328
members.push_back(builder.getContainedTypeId(resultStructType, i));
6329
}
6330
spv::Id resType = builder.makeStructType(members, "ResType");
6331
6332
//call ImageFootprintNV
6333
spv::Id res = builder.createTextureCall(precision, resType, sparse, cracked.fetch, cracked.proj,
6334
cracked.gather, noImplicitLod, params, signExtensionMask());
6335
6336
//copy resType (SPIR-V type) to resultStructType(OpenGL type)
6337
for (int i = 0; i < 5; i++) {
6338
builder.clearAccessChain();
6339
builder.setAccessChainLValue(resultStruct);
6340
6341
//Accessing to a struct we created, no coherent flag is set
6342
spv::Builder::AccessChain::CoherentFlags flags;
6343
flags.clear();
6344
6345
builder.accessChainPush(builder.makeIntConstant(i), flags, 0);
6346
builder.accessChainStore(builder.createCompositeExtract(res, builder.getContainedTypeId(resType, i+1),
6347
i+1), TranslateNonUniformDecoration(imageType.getQualifier()));
6348
}
6349
return builder.createCompositeExtract(res, resultType(), 0);
6350
}
6351
6352
// projective component (might not to move)
6353
// GLSL: "The texture coordinates consumed from P, not including the last component of P,
6354
// are divided by the last component of P."
6355
// SPIR-V: "... (u [, v] [, w], q)... It may be a vector larger than needed, but all
6356
// unused components will appear after all used components."
6357
if (cracked.proj) {
6358
int projSourceComp = builder.getNumComponents(params.coords) - 1;
6359
int projTargetComp;
6360
switch (sampler.dim) {
6361
case glslang::Esd1D: projTargetComp = 1; break;
6362
case glslang::Esd2D: projTargetComp = 2; break;
6363
case glslang::EsdRect: projTargetComp = 2; break;
6364
default: projTargetComp = projSourceComp; break;
6365
}
6366
// copy the projective coordinate if we have to
6367
if (projTargetComp != projSourceComp) {
6368
spv::Id projComp = builder.createCompositeExtract(params.coords,
6369
builder.getScalarTypeId(builder.getTypeId(params.coords)), projSourceComp);
6370
params.coords = builder.createCompositeInsert(projComp, params.coords,
6371
builder.getTypeId(params.coords), projTargetComp);
6372
}
6373
}
6374
6375
// nonprivate
6376
if (imageType.getQualifier().nonprivate) {
6377
params.nonprivate = true;
6378
}
6379
6380
// volatile
6381
if (imageType.getQualifier().volatil) {
6382
params.volatil = true;
6383
}
6384
6385
std::vector<spv::Id> result( 1,
6386
builder.createTextureCall(precision, resultType(), sparse, cracked.fetch, cracked.proj, cracked.gather,
6387
noImplicitLod, params, signExtensionMask())
6388
);
6389
6390
if (components != node->getType().getVectorSize())
6391
result[0] = builder.createConstructor(precision, result, convertGlslangToSpvType(node->getType()));
6392
6393
return result[0];
6394
}
6395
6396
spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAggregate* node)
6397
{
6398
// Grab the function's pointer from the previously created function
6399
spv::Function* function = functionMap[node->getName().c_str()];
6400
if (! function)
6401
return 0;
6402
6403
const glslang::TIntermSequence& glslangArgs = node->getSequence();
6404
const glslang::TQualifierList& qualifiers = node->getQualifierList();
6405
6406
// See comments in makeFunctions() for details about the semantics for parameter passing.
6407
//
6408
// These imply we need a four step process:
6409
// 1. Evaluate the arguments
6410
// 2. Allocate and make copies of in, out, and inout arguments
6411
// 3. Make the call
6412
// 4. Copy back the results
6413
6414
// 1. Evaluate the arguments and their types
6415
std::vector<spv::Builder::AccessChain> lValues;
6416
std::vector<spv::Id> rValues;
6417
std::vector<const glslang::TType*> argTypes;
6418
for (int a = 0; a < (int)glslangArgs.size(); ++a) {
6419
argTypes.push_back(&glslangArgs[a]->getAsTyped()->getType());
6420
// build l-value
6421
builder.clearAccessChain();
6422
glslangArgs[a]->traverse(this);
6423
// keep outputs and pass-by-originals as l-values, evaluate others as r-values
6424
if (originalParam(qualifiers[a], *argTypes[a], function->hasImplicitThis() && a == 0) ||
6425
writableParam(qualifiers[a])) {
6426
// save l-value
6427
lValues.push_back(builder.getAccessChain());
6428
} else {
6429
// process r-value
6430
rValues.push_back(accessChainLoad(*argTypes.back()));
6431
}
6432
}
6433
6434
// 2. Allocate space for anything needing a copy, and if it's "in" or "inout"
6435
// copy the original into that space.
6436
//
6437
// Also, build up the list of actual arguments to pass in for the call
6438
int lValueCount = 0;
6439
int rValueCount = 0;
6440
std::vector<spv::Id> spvArgs;
6441
for (int a = 0; a < (int)glslangArgs.size(); ++a) {
6442
spv::Id arg;
6443
if (originalParam(qualifiers[a], *argTypes[a], function->hasImplicitThis() && a == 0)) {
6444
builder.setAccessChain(lValues[lValueCount]);
6445
arg = builder.accessChainGetLValue();
6446
++lValueCount;
6447
} else if (writableParam(qualifiers[a])) {
6448
// need space to hold the copy
6449
arg = builder.createVariable(function->getParamPrecision(a), spv::StorageClassFunction,
6450
builder.getContainedTypeId(function->getParamType(a)), "param");
6451
if (qualifiers[a] == glslang::EvqIn || qualifiers[a] == glslang::EvqInOut) {
6452
// need to copy the input into output space
6453
builder.setAccessChain(lValues[lValueCount]);
6454
spv::Id copy = accessChainLoad(*argTypes[a]);
6455
builder.clearAccessChain();
6456
builder.setAccessChainLValue(arg);
6457
multiTypeStore(*argTypes[a], copy);
6458
}
6459
++lValueCount;
6460
} else {
6461
// process r-value, which involves a copy for a type mismatch
6462
if (function->getParamType(a) != builder.getTypeId(rValues[rValueCount]) ||
6463
TranslatePrecisionDecoration(*argTypes[a]) != function->getParamPrecision(a))
6464
{
6465
spv::Id argCopy = builder.createVariable(function->getParamPrecision(a), spv::StorageClassFunction, function->getParamType(a), "arg");
6466
builder.clearAccessChain();
6467
builder.setAccessChainLValue(argCopy);
6468
multiTypeStore(*argTypes[a], rValues[rValueCount]);
6469
arg = builder.createLoad(argCopy, function->getParamPrecision(a));
6470
} else
6471
arg = rValues[rValueCount];
6472
++rValueCount;
6473
}
6474
spvArgs.push_back(arg);
6475
}
6476
6477
// 3. Make the call.
6478
spv::Id result = builder.createFunctionCall(function, spvArgs);
6479
builder.setPrecision(result, TranslatePrecisionDecoration(node->getType()));
6480
builder.addDecoration(result, TranslateNonUniformDecoration(node->getType().getQualifier()));
6481
6482
// 4. Copy back out an "out" arguments.
6483
lValueCount = 0;
6484
for (int a = 0; a < (int)glslangArgs.size(); ++a) {
6485
if (originalParam(qualifiers[a], *argTypes[a], function->hasImplicitThis() && a == 0))
6486
++lValueCount;
6487
else if (writableParam(qualifiers[a])) {
6488
if (qualifiers[a] == glslang::EvqOut || qualifiers[a] == glslang::EvqInOut) {
6489
spv::Id copy = builder.createLoad(spvArgs[a], spv::NoPrecision);
6490
builder.addDecoration(copy, TranslateNonUniformDecoration(argTypes[a]->getQualifier()));
6491
builder.setAccessChain(lValues[lValueCount]);
6492
multiTypeStore(*argTypes[a], copy);
6493
}
6494
++lValueCount;
6495
}
6496
}
6497
6498
return result;
6499
}
6500
6501
// Translate AST operation to SPV operation, already having SPV-based operands/types.
6502
spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, OpDecorations& decorations,
6503
spv::Id typeId, spv::Id left, spv::Id right,
6504
glslang::TBasicType typeProxy, bool reduceComparison)
6505
{
6506
bool isUnsigned = isTypeUnsignedInt(typeProxy);
6507
bool isFloat = isTypeFloat(typeProxy);
6508
bool isBool = typeProxy == glslang::EbtBool;
6509
6510
spv::Op binOp = spv::OpNop;
6511
bool needMatchingVectors = true; // for non-matrix ops, would a scalar need to smear to match a vector?
6512
bool comparison = false;
6513
6514
switch (op) {
6515
case glslang::EOpAdd:
6516
case glslang::EOpAddAssign:
6517
if (isFloat)
6518
binOp = spv::OpFAdd;
6519
else
6520
binOp = spv::OpIAdd;
6521
break;
6522
case glslang::EOpSub:
6523
case glslang::EOpSubAssign:
6524
if (isFloat)
6525
binOp = spv::OpFSub;
6526
else
6527
binOp = spv::OpISub;
6528
break;
6529
case glslang::EOpMul:
6530
case glslang::EOpMulAssign:
6531
if (isFloat)
6532
binOp = spv::OpFMul;
6533
else
6534
binOp = spv::OpIMul;
6535
break;
6536
case glslang::EOpVectorTimesScalar:
6537
case glslang::EOpVectorTimesScalarAssign:
6538
if (isFloat && (builder.isVector(left) || builder.isVector(right))) {
6539
if (builder.isVector(right))
6540
std::swap(left, right);
6541
assert(builder.isScalar(right));
6542
needMatchingVectors = false;
6543
binOp = spv::OpVectorTimesScalar;
6544
} else if (isFloat)
6545
binOp = spv::OpFMul;
6546
else
6547
binOp = spv::OpIMul;
6548
break;
6549
case glslang::EOpVectorTimesMatrix:
6550
case glslang::EOpVectorTimesMatrixAssign:
6551
binOp = spv::OpVectorTimesMatrix;
6552
break;
6553
case glslang::EOpMatrixTimesVector:
6554
binOp = spv::OpMatrixTimesVector;
6555
break;
6556
case glslang::EOpMatrixTimesScalar:
6557
case glslang::EOpMatrixTimesScalarAssign:
6558
binOp = spv::OpMatrixTimesScalar;
6559
break;
6560
case glslang::EOpMatrixTimesMatrix:
6561
case glslang::EOpMatrixTimesMatrixAssign:
6562
binOp = spv::OpMatrixTimesMatrix;
6563
break;
6564
case glslang::EOpOuterProduct:
6565
binOp = spv::OpOuterProduct;
6566
needMatchingVectors = false;
6567
break;
6568
6569
case glslang::EOpDiv:
6570
case glslang::EOpDivAssign:
6571
if (isFloat)
6572
binOp = spv::OpFDiv;
6573
else if (isUnsigned)
6574
binOp = spv::OpUDiv;
6575
else
6576
binOp = spv::OpSDiv;
6577
break;
6578
case glslang::EOpMod:
6579
case glslang::EOpModAssign:
6580
if (isFloat)
6581
binOp = spv::OpFMod;
6582
else if (isUnsigned)
6583
binOp = spv::OpUMod;
6584
else
6585
binOp = spv::OpSMod;
6586
break;
6587
case glslang::EOpRightShift:
6588
case glslang::EOpRightShiftAssign:
6589
if (isUnsigned)
6590
binOp = spv::OpShiftRightLogical;
6591
else
6592
binOp = spv::OpShiftRightArithmetic;
6593
break;
6594
case glslang::EOpLeftShift:
6595
case glslang::EOpLeftShiftAssign:
6596
binOp = spv::OpShiftLeftLogical;
6597
break;
6598
case glslang::EOpAnd:
6599
case glslang::EOpAndAssign:
6600
binOp = spv::OpBitwiseAnd;
6601
break;
6602
case glslang::EOpLogicalAnd:
6603
needMatchingVectors = false;
6604
binOp = spv::OpLogicalAnd;
6605
break;
6606
case glslang::EOpInclusiveOr:
6607
case glslang::EOpInclusiveOrAssign:
6608
binOp = spv::OpBitwiseOr;
6609
break;
6610
case glslang::EOpLogicalOr:
6611
needMatchingVectors = false;
6612
binOp = spv::OpLogicalOr;
6613
break;
6614
case glslang::EOpExclusiveOr:
6615
case glslang::EOpExclusiveOrAssign:
6616
binOp = spv::OpBitwiseXor;
6617
break;
6618
case glslang::EOpLogicalXor:
6619
needMatchingVectors = false;
6620
binOp = spv::OpLogicalNotEqual;
6621
break;
6622
6623
case glslang::EOpAbsDifference:
6624
binOp = isUnsigned ? spv::OpAbsUSubINTEL : spv::OpAbsISubINTEL;
6625
break;
6626
6627
case glslang::EOpAddSaturate:
6628
binOp = isUnsigned ? spv::OpUAddSatINTEL : spv::OpIAddSatINTEL;
6629
break;
6630
6631
case glslang::EOpSubSaturate:
6632
binOp = isUnsigned ? spv::OpUSubSatINTEL : spv::OpISubSatINTEL;
6633
break;
6634
6635
case glslang::EOpAverage:
6636
binOp = isUnsigned ? spv::OpUAverageINTEL : spv::OpIAverageINTEL;
6637
break;
6638
6639
case glslang::EOpAverageRounded:
6640
binOp = isUnsigned ? spv::OpUAverageRoundedINTEL : spv::OpIAverageRoundedINTEL;
6641
break;
6642
6643
case glslang::EOpMul32x16:
6644
binOp = isUnsigned ? spv::OpUMul32x16INTEL : spv::OpIMul32x16INTEL;
6645
break;
6646
6647
case glslang::EOpExpectEXT:
6648
binOp = spv::OpExpectKHR;
6649
break;
6650
6651
case glslang::EOpLessThan:
6652
case glslang::EOpGreaterThan:
6653
case glslang::EOpLessThanEqual:
6654
case glslang::EOpGreaterThanEqual:
6655
case glslang::EOpEqual:
6656
case glslang::EOpNotEqual:
6657
case glslang::EOpVectorEqual:
6658
case glslang::EOpVectorNotEqual:
6659
comparison = true;
6660
break;
6661
default:
6662
break;
6663
}
6664
6665
// handle mapped binary operations (should be non-comparison)
6666
if (binOp != spv::OpNop) {
6667
assert(comparison == false);
6668
if (builder.isMatrix(left) || builder.isMatrix(right) ||
6669
builder.isCooperativeMatrix(left) || builder.isCooperativeMatrix(right))
6670
return createBinaryMatrixOperation(binOp, decorations, typeId, left, right);
6671
6672
// No matrix involved; make both operands be the same number of components, if needed
6673
if (needMatchingVectors)
6674
builder.promoteScalar(decorations.precision, left, right);
6675
6676
spv::Id result = builder.createBinOp(binOp, typeId, left, right);
6677
decorations.addNoContraction(builder, result);
6678
decorations.addNonUniform(builder, result);
6679
return builder.setPrecision(result, decorations.precision);
6680
}
6681
6682
if (! comparison)
6683
return 0;
6684
6685
// Handle comparison instructions
6686
6687
if (reduceComparison && (op == glslang::EOpEqual || op == glslang::EOpNotEqual)
6688
&& (builder.isVector(left) || builder.isMatrix(left) || builder.isAggregate(left))) {
6689
spv::Id result = builder.createCompositeCompare(decorations.precision, left, right, op == glslang::EOpEqual);
6690
decorations.addNonUniform(builder, result);
6691
return result;
6692
}
6693
6694
switch (op) {
6695
case glslang::EOpLessThan:
6696
if (isFloat)
6697
binOp = spv::OpFOrdLessThan;
6698
else if (isUnsigned)
6699
binOp = spv::OpULessThan;
6700
else
6701
binOp = spv::OpSLessThan;
6702
break;
6703
case glslang::EOpGreaterThan:
6704
if (isFloat)
6705
binOp = spv::OpFOrdGreaterThan;
6706
else if (isUnsigned)
6707
binOp = spv::OpUGreaterThan;
6708
else
6709
binOp = spv::OpSGreaterThan;
6710
break;
6711
case glslang::EOpLessThanEqual:
6712
if (isFloat)
6713
binOp = spv::OpFOrdLessThanEqual;
6714
else if (isUnsigned)
6715
binOp = spv::OpULessThanEqual;
6716
else
6717
binOp = spv::OpSLessThanEqual;
6718
break;
6719
case glslang::EOpGreaterThanEqual:
6720
if (isFloat)
6721
binOp = spv::OpFOrdGreaterThanEqual;
6722
else if (isUnsigned)
6723
binOp = spv::OpUGreaterThanEqual;
6724
else
6725
binOp = spv::OpSGreaterThanEqual;
6726
break;
6727
case glslang::EOpEqual:
6728
case glslang::EOpVectorEqual:
6729
if (isFloat)
6730
binOp = spv::OpFOrdEqual;
6731
else if (isBool)
6732
binOp = spv::OpLogicalEqual;
6733
else
6734
binOp = spv::OpIEqual;
6735
break;
6736
case glslang::EOpNotEqual:
6737
case glslang::EOpVectorNotEqual:
6738
if (isFloat)
6739
binOp = spv::OpFUnordNotEqual;
6740
else if (isBool)
6741
binOp = spv::OpLogicalNotEqual;
6742
else
6743
binOp = spv::OpINotEqual;
6744
break;
6745
default:
6746
break;
6747
}
6748
6749
if (binOp != spv::OpNop) {
6750
spv::Id result = builder.createBinOp(binOp, typeId, left, right);
6751
decorations.addNoContraction(builder, result);
6752
decorations.addNonUniform(builder, result);
6753
return builder.setPrecision(result, decorations.precision);
6754
}
6755
6756
return 0;
6757
}
6758
6759
//
6760
// Translate AST matrix operation to SPV operation, already having SPV-based operands/types.
6761
// These can be any of:
6762
//
6763
// matrix * scalar
6764
// scalar * matrix
6765
// matrix * matrix linear algebraic
6766
// matrix * vector
6767
// vector * matrix
6768
// matrix * matrix componentwise
6769
// matrix op matrix op in {+, -, /}
6770
// matrix op scalar op in {+, -, /}
6771
// scalar op matrix op in {+, -, /}
6772
//
6773
spv::Id TGlslangToSpvTraverser::createBinaryMatrixOperation(spv::Op op, OpDecorations& decorations, spv::Id typeId,
6774
spv::Id left, spv::Id right)
6775
{
6776
bool firstClass = true;
6777
6778
// First, handle first-class matrix operations (* and matrix/scalar)
6779
switch (op) {
6780
case spv::OpFDiv:
6781
if (builder.isMatrix(left) && builder.isScalar(right)) {
6782
// turn matrix / scalar into a multiply...
6783
spv::Id resultType = builder.getTypeId(right);
6784
right = builder.createBinOp(spv::OpFDiv, resultType, builder.makeFpConstant(resultType, 1.0), right);
6785
op = spv::OpMatrixTimesScalar;
6786
} else
6787
firstClass = false;
6788
break;
6789
case spv::OpMatrixTimesScalar:
6790
if (builder.isMatrix(right) || builder.isCooperativeMatrix(right))
6791
std::swap(left, right);
6792
assert(builder.isScalar(right));
6793
break;
6794
case spv::OpVectorTimesMatrix:
6795
assert(builder.isVector(left));
6796
assert(builder.isMatrix(right));
6797
break;
6798
case spv::OpMatrixTimesVector:
6799
assert(builder.isMatrix(left));
6800
assert(builder.isVector(right));
6801
break;
6802
case spv::OpMatrixTimesMatrix:
6803
assert(builder.isMatrix(left));
6804
assert(builder.isMatrix(right));
6805
break;
6806
default:
6807
firstClass = false;
6808
break;
6809
}
6810
6811
if (builder.isCooperativeMatrix(left) || builder.isCooperativeMatrix(right))
6812
firstClass = true;
6813
6814
if (firstClass) {
6815
spv::Id result = builder.createBinOp(op, typeId, left, right);
6816
decorations.addNoContraction(builder, result);
6817
decorations.addNonUniform(builder, result);
6818
return builder.setPrecision(result, decorations.precision);
6819
}
6820
6821
// Handle component-wise +, -, *, %, and / for all combinations of type.
6822
// The result type of all of them is the same type as the (a) matrix operand.
6823
// The algorithm is to:
6824
// - break the matrix(es) into vectors
6825
// - smear any scalar to a vector
6826
// - do vector operations
6827
// - make a matrix out the vector results
6828
switch (op) {
6829
case spv::OpFAdd:
6830
case spv::OpFSub:
6831
case spv::OpFDiv:
6832
case spv::OpFMod:
6833
case spv::OpFMul:
6834
{
6835
// one time set up...
6836
bool leftMat = builder.isMatrix(left);
6837
bool rightMat = builder.isMatrix(right);
6838
unsigned int numCols = leftMat ? builder.getNumColumns(left) : builder.getNumColumns(right);
6839
int numRows = leftMat ? builder.getNumRows(left) : builder.getNumRows(right);
6840
spv::Id scalarType = builder.getScalarTypeId(typeId);
6841
spv::Id vecType = builder.makeVectorType(scalarType, numRows);
6842
std::vector<spv::Id> results;
6843
spv::Id smearVec = spv::NoResult;
6844
if (builder.isScalar(left))
6845
smearVec = builder.smearScalar(decorations.precision, left, vecType);
6846
else if (builder.isScalar(right))
6847
smearVec = builder.smearScalar(decorations.precision, right, vecType);
6848
6849
// do each vector op
6850
for (unsigned int c = 0; c < numCols; ++c) {
6851
std::vector<unsigned int> indexes;
6852
indexes.push_back(c);
6853
spv::Id leftVec = leftMat ? builder.createCompositeExtract( left, vecType, indexes) : smearVec;
6854
spv::Id rightVec = rightMat ? builder.createCompositeExtract(right, vecType, indexes) : smearVec;
6855
spv::Id result = builder.createBinOp(op, vecType, leftVec, rightVec);
6856
decorations.addNoContraction(builder, result);
6857
decorations.addNonUniform(builder, result);
6858
results.push_back(builder.setPrecision(result, decorations.precision));
6859
}
6860
6861
// put the pieces together
6862
spv::Id result = builder.setPrecision(builder.createCompositeConstruct(typeId, results), decorations.precision);
6863
decorations.addNonUniform(builder, result);
6864
return result;
6865
}
6866
default:
6867
assert(0);
6868
return spv::NoResult;
6869
}
6870
}
6871
6872
spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, OpDecorations& decorations, spv::Id typeId,
6873
spv::Id operand, glslang::TBasicType typeProxy, const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags,
6874
const glslang::TType &opType)
6875
{
6876
spv::Op unaryOp = spv::OpNop;
6877
int extBuiltins = -1;
6878
int libCall = -1;
6879
bool isUnsigned = isTypeUnsignedInt(typeProxy);
6880
bool isFloat = isTypeFloat(typeProxy);
6881
6882
switch (op) {
6883
case glslang::EOpNegative:
6884
if (isFloat) {
6885
unaryOp = spv::OpFNegate;
6886
if (builder.isMatrixType(typeId))
6887
return createUnaryMatrixOperation(unaryOp, decorations, typeId, operand, typeProxy);
6888
} else
6889
unaryOp = spv::OpSNegate;
6890
break;
6891
6892
case glslang::EOpLogicalNot:
6893
case glslang::EOpVectorLogicalNot:
6894
unaryOp = spv::OpLogicalNot;
6895
break;
6896
case glslang::EOpBitwiseNot:
6897
unaryOp = spv::OpNot;
6898
break;
6899
6900
case glslang::EOpDeterminant:
6901
libCall = spv::GLSLstd450Determinant;
6902
break;
6903
case glslang::EOpMatrixInverse:
6904
libCall = spv::GLSLstd450MatrixInverse;
6905
break;
6906
case glslang::EOpTranspose:
6907
unaryOp = spv::OpTranspose;
6908
break;
6909
6910
case glslang::EOpRadians:
6911
libCall = spv::GLSLstd450Radians;
6912
break;
6913
case glslang::EOpDegrees:
6914
libCall = spv::GLSLstd450Degrees;
6915
break;
6916
case glslang::EOpSin:
6917
libCall = spv::GLSLstd450Sin;
6918
break;
6919
case glslang::EOpCos:
6920
libCall = spv::GLSLstd450Cos;
6921
break;
6922
case glslang::EOpTan:
6923
libCall = spv::GLSLstd450Tan;
6924
break;
6925
case glslang::EOpAcos:
6926
libCall = spv::GLSLstd450Acos;
6927
break;
6928
case glslang::EOpAsin:
6929
libCall = spv::GLSLstd450Asin;
6930
break;
6931
case glslang::EOpAtan:
6932
libCall = spv::GLSLstd450Atan;
6933
break;
6934
6935
case glslang::EOpAcosh:
6936
libCall = spv::GLSLstd450Acosh;
6937
break;
6938
case glslang::EOpAsinh:
6939
libCall = spv::GLSLstd450Asinh;
6940
break;
6941
case glslang::EOpAtanh:
6942
libCall = spv::GLSLstd450Atanh;
6943
break;
6944
case glslang::EOpTanh:
6945
libCall = spv::GLSLstd450Tanh;
6946
break;
6947
case glslang::EOpCosh:
6948
libCall = spv::GLSLstd450Cosh;
6949
break;
6950
case glslang::EOpSinh:
6951
libCall = spv::GLSLstd450Sinh;
6952
break;
6953
6954
case glslang::EOpLength:
6955
libCall = spv::GLSLstd450Length;
6956
break;
6957
case glslang::EOpNormalize:
6958
libCall = spv::GLSLstd450Normalize;
6959
break;
6960
6961
case glslang::EOpExp:
6962
libCall = spv::GLSLstd450Exp;
6963
break;
6964
case glslang::EOpLog:
6965
libCall = spv::GLSLstd450Log;
6966
break;
6967
case glslang::EOpExp2:
6968
libCall = spv::GLSLstd450Exp2;
6969
break;
6970
case glslang::EOpLog2:
6971
libCall = spv::GLSLstd450Log2;
6972
break;
6973
case glslang::EOpSqrt:
6974
libCall = spv::GLSLstd450Sqrt;
6975
break;
6976
case glslang::EOpInverseSqrt:
6977
libCall = spv::GLSLstd450InverseSqrt;
6978
break;
6979
6980
case glslang::EOpFloor:
6981
libCall = spv::GLSLstd450Floor;
6982
break;
6983
case glslang::EOpTrunc:
6984
libCall = spv::GLSLstd450Trunc;
6985
break;
6986
case glslang::EOpRound:
6987
libCall = spv::GLSLstd450Round;
6988
break;
6989
case glslang::EOpRoundEven:
6990
libCall = spv::GLSLstd450RoundEven;
6991
break;
6992
case glslang::EOpCeil:
6993
libCall = spv::GLSLstd450Ceil;
6994
break;
6995
case glslang::EOpFract:
6996
libCall = spv::GLSLstd450Fract;
6997
break;
6998
6999
case glslang::EOpIsNan:
7000
unaryOp = spv::OpIsNan;
7001
break;
7002
case glslang::EOpIsInf:
7003
unaryOp = spv::OpIsInf;
7004
break;
7005
case glslang::EOpIsFinite:
7006
unaryOp = spv::OpIsFinite;
7007
break;
7008
7009
case glslang::EOpFloatBitsToInt:
7010
case glslang::EOpFloatBitsToUint:
7011
case glslang::EOpIntBitsToFloat:
7012
case glslang::EOpUintBitsToFloat:
7013
case glslang::EOpDoubleBitsToInt64:
7014
case glslang::EOpDoubleBitsToUint64:
7015
case glslang::EOpInt64BitsToDouble:
7016
case glslang::EOpUint64BitsToDouble:
7017
case glslang::EOpFloat16BitsToInt16:
7018
case glslang::EOpFloat16BitsToUint16:
7019
case glslang::EOpInt16BitsToFloat16:
7020
case glslang::EOpUint16BitsToFloat16:
7021
unaryOp = spv::OpBitcast;
7022
break;
7023
7024
case glslang::EOpPackSnorm2x16:
7025
libCall = spv::GLSLstd450PackSnorm2x16;
7026
break;
7027
case glslang::EOpUnpackSnorm2x16:
7028
libCall = spv::GLSLstd450UnpackSnorm2x16;
7029
break;
7030
case glslang::EOpPackUnorm2x16:
7031
libCall = spv::GLSLstd450PackUnorm2x16;
7032
break;
7033
case glslang::EOpUnpackUnorm2x16:
7034
libCall = spv::GLSLstd450UnpackUnorm2x16;
7035
break;
7036
case glslang::EOpPackHalf2x16:
7037
libCall = spv::GLSLstd450PackHalf2x16;
7038
break;
7039
case glslang::EOpUnpackHalf2x16:
7040
libCall = spv::GLSLstd450UnpackHalf2x16;
7041
break;
7042
case glslang::EOpPackSnorm4x8:
7043
libCall = spv::GLSLstd450PackSnorm4x8;
7044
break;
7045
case glslang::EOpUnpackSnorm4x8:
7046
libCall = spv::GLSLstd450UnpackSnorm4x8;
7047
break;
7048
case glslang::EOpPackUnorm4x8:
7049
libCall = spv::GLSLstd450PackUnorm4x8;
7050
break;
7051
case glslang::EOpUnpackUnorm4x8:
7052
libCall = spv::GLSLstd450UnpackUnorm4x8;
7053
break;
7054
case glslang::EOpPackDouble2x32:
7055
libCall = spv::GLSLstd450PackDouble2x32;
7056
break;
7057
case glslang::EOpUnpackDouble2x32:
7058
libCall = spv::GLSLstd450UnpackDouble2x32;
7059
break;
7060
7061
case glslang::EOpPackInt2x32:
7062
case glslang::EOpUnpackInt2x32:
7063
case glslang::EOpPackUint2x32:
7064
case glslang::EOpUnpackUint2x32:
7065
case glslang::EOpPack16:
7066
case glslang::EOpPack32:
7067
case glslang::EOpPack64:
7068
case glslang::EOpUnpack32:
7069
case glslang::EOpUnpack16:
7070
case glslang::EOpUnpack8:
7071
case glslang::EOpPackInt2x16:
7072
case glslang::EOpUnpackInt2x16:
7073
case glslang::EOpPackUint2x16:
7074
case glslang::EOpUnpackUint2x16:
7075
case glslang::EOpPackInt4x16:
7076
case glslang::EOpUnpackInt4x16:
7077
case glslang::EOpPackUint4x16:
7078
case glslang::EOpUnpackUint4x16:
7079
case glslang::EOpPackFloat2x16:
7080
case glslang::EOpUnpackFloat2x16:
7081
unaryOp = spv::OpBitcast;
7082
break;
7083
7084
case glslang::EOpDPdx:
7085
unaryOp = spv::OpDPdx;
7086
break;
7087
case glslang::EOpDPdy:
7088
unaryOp = spv::OpDPdy;
7089
break;
7090
case glslang::EOpFwidth:
7091
unaryOp = spv::OpFwidth;
7092
break;
7093
7094
case glslang::EOpAny:
7095
unaryOp = spv::OpAny;
7096
break;
7097
case glslang::EOpAll:
7098
unaryOp = spv::OpAll;
7099
break;
7100
7101
case glslang::EOpAbs:
7102
if (isFloat)
7103
libCall = spv::GLSLstd450FAbs;
7104
else
7105
libCall = spv::GLSLstd450SAbs;
7106
break;
7107
case glslang::EOpSign:
7108
if (isFloat)
7109
libCall = spv::GLSLstd450FSign;
7110
else
7111
libCall = spv::GLSLstd450SSign;
7112
break;
7113
7114
case glslang::EOpDPdxFine:
7115
unaryOp = spv::OpDPdxFine;
7116
break;
7117
case glslang::EOpDPdyFine:
7118
unaryOp = spv::OpDPdyFine;
7119
break;
7120
case glslang::EOpFwidthFine:
7121
unaryOp = spv::OpFwidthFine;
7122
break;
7123
case glslang::EOpDPdxCoarse:
7124
unaryOp = spv::OpDPdxCoarse;
7125
break;
7126
case glslang::EOpDPdyCoarse:
7127
unaryOp = spv::OpDPdyCoarse;
7128
break;
7129
case glslang::EOpFwidthCoarse:
7130
unaryOp = spv::OpFwidthCoarse;
7131
break;
7132
case glslang::EOpRayQueryProceed:
7133
unaryOp = spv::OpRayQueryProceedKHR;
7134
break;
7135
case glslang::EOpRayQueryGetRayTMin:
7136
unaryOp = spv::OpRayQueryGetRayTMinKHR;
7137
break;
7138
case glslang::EOpRayQueryGetRayFlags:
7139
unaryOp = spv::OpRayQueryGetRayFlagsKHR;
7140
break;
7141
case glslang::EOpRayQueryGetWorldRayOrigin:
7142
unaryOp = spv::OpRayQueryGetWorldRayOriginKHR;
7143
break;
7144
case glslang::EOpRayQueryGetWorldRayDirection:
7145
unaryOp = spv::OpRayQueryGetWorldRayDirectionKHR;
7146
break;
7147
case glslang::EOpRayQueryGetIntersectionCandidateAABBOpaque:
7148
unaryOp = spv::OpRayQueryGetIntersectionCandidateAABBOpaqueKHR;
7149
break;
7150
case glslang::EOpInterpolateAtCentroid:
7151
if (typeProxy == glslang::EbtFloat16)
7152
builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float);
7153
libCall = spv::GLSLstd450InterpolateAtCentroid;
7154
break;
7155
case glslang::EOpAtomicCounterIncrement:
7156
case glslang::EOpAtomicCounterDecrement:
7157
case glslang::EOpAtomicCounter:
7158
{
7159
// Handle all of the atomics in one place, in createAtomicOperation()
7160
std::vector<spv::Id> operands;
7161
operands.push_back(operand);
7162
return createAtomicOperation(op, decorations.precision, typeId, operands, typeProxy, lvalueCoherentFlags, opType);
7163
}
7164
7165
case glslang::EOpBitFieldReverse:
7166
unaryOp = spv::OpBitReverse;
7167
break;
7168
case glslang::EOpBitCount:
7169
unaryOp = spv::OpBitCount;
7170
break;
7171
case glslang::EOpFindLSB:
7172
libCall = spv::GLSLstd450FindILsb;
7173
break;
7174
case glslang::EOpFindMSB:
7175
if (isUnsigned)
7176
libCall = spv::GLSLstd450FindUMsb;
7177
else
7178
libCall = spv::GLSLstd450FindSMsb;
7179
break;
7180
7181
case glslang::EOpCountLeadingZeros:
7182
builder.addCapability(spv::CapabilityIntegerFunctions2INTEL);
7183
builder.addExtension("SPV_INTEL_shader_integer_functions2");
7184
unaryOp = spv::OpUCountLeadingZerosINTEL;
7185
break;
7186
7187
case glslang::EOpCountTrailingZeros:
7188
builder.addCapability(spv::CapabilityIntegerFunctions2INTEL);
7189
builder.addExtension("SPV_INTEL_shader_integer_functions2");
7190
unaryOp = spv::OpUCountTrailingZerosINTEL;
7191
break;
7192
7193
case glslang::EOpBallot:
7194
case glslang::EOpReadFirstInvocation:
7195
case glslang::EOpAnyInvocation:
7196
case glslang::EOpAllInvocations:
7197
case glslang::EOpAllInvocationsEqual:
7198
case glslang::EOpMinInvocations:
7199
case glslang::EOpMaxInvocations:
7200
case glslang::EOpAddInvocations:
7201
case glslang::EOpMinInvocationsNonUniform:
7202
case glslang::EOpMaxInvocationsNonUniform:
7203
case glslang::EOpAddInvocationsNonUniform:
7204
case glslang::EOpMinInvocationsInclusiveScan:
7205
case glslang::EOpMaxInvocationsInclusiveScan:
7206
case glslang::EOpAddInvocationsInclusiveScan:
7207
case glslang::EOpMinInvocationsInclusiveScanNonUniform:
7208
case glslang::EOpMaxInvocationsInclusiveScanNonUniform:
7209
case glslang::EOpAddInvocationsInclusiveScanNonUniform:
7210
case glslang::EOpMinInvocationsExclusiveScan:
7211
case glslang::EOpMaxInvocationsExclusiveScan:
7212
case glslang::EOpAddInvocationsExclusiveScan:
7213
case glslang::EOpMinInvocationsExclusiveScanNonUniform:
7214
case glslang::EOpMaxInvocationsExclusiveScanNonUniform:
7215
case glslang::EOpAddInvocationsExclusiveScanNonUniform:
7216
{
7217
std::vector<spv::Id> operands;
7218
operands.push_back(operand);
7219
return createInvocationsOperation(op, typeId, operands, typeProxy);
7220
}
7221
case glslang::EOpSubgroupAll:
7222
case glslang::EOpSubgroupAny:
7223
case glslang::EOpSubgroupAllEqual:
7224
case glslang::EOpSubgroupBroadcastFirst:
7225
case glslang::EOpSubgroupBallot:
7226
case glslang::EOpSubgroupInverseBallot:
7227
case glslang::EOpSubgroupBallotBitCount:
7228
case glslang::EOpSubgroupBallotInclusiveBitCount:
7229
case glslang::EOpSubgroupBallotExclusiveBitCount:
7230
case glslang::EOpSubgroupBallotFindLSB:
7231
case glslang::EOpSubgroupBallotFindMSB:
7232
case glslang::EOpSubgroupAdd:
7233
case glslang::EOpSubgroupMul:
7234
case glslang::EOpSubgroupMin:
7235
case glslang::EOpSubgroupMax:
7236
case glslang::EOpSubgroupAnd:
7237
case glslang::EOpSubgroupOr:
7238
case glslang::EOpSubgroupXor:
7239
case glslang::EOpSubgroupInclusiveAdd:
7240
case glslang::EOpSubgroupInclusiveMul:
7241
case glslang::EOpSubgroupInclusiveMin:
7242
case glslang::EOpSubgroupInclusiveMax:
7243
case glslang::EOpSubgroupInclusiveAnd:
7244
case glslang::EOpSubgroupInclusiveOr:
7245
case glslang::EOpSubgroupInclusiveXor:
7246
case glslang::EOpSubgroupExclusiveAdd:
7247
case glslang::EOpSubgroupExclusiveMul:
7248
case glslang::EOpSubgroupExclusiveMin:
7249
case glslang::EOpSubgroupExclusiveMax:
7250
case glslang::EOpSubgroupExclusiveAnd:
7251
case glslang::EOpSubgroupExclusiveOr:
7252
case glslang::EOpSubgroupExclusiveXor:
7253
case glslang::EOpSubgroupQuadSwapHorizontal:
7254
case glslang::EOpSubgroupQuadSwapVertical:
7255
case glslang::EOpSubgroupQuadSwapDiagonal:
7256
case glslang::EOpSubgroupQuadAll:
7257
case glslang::EOpSubgroupQuadAny: {
7258
std::vector<spv::Id> operands;
7259
operands.push_back(operand);
7260
return createSubgroupOperation(op, typeId, operands, typeProxy);
7261
}
7262
case glslang::EOpMbcnt:
7263
extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_ballot);
7264
libCall = spv::MbcntAMD;
7265
break;
7266
7267
case glslang::EOpCubeFaceIndex:
7268
extBuiltins = getExtBuiltins(spv::E_SPV_AMD_gcn_shader);
7269
libCall = spv::CubeFaceIndexAMD;
7270
break;
7271
7272
case glslang::EOpCubeFaceCoord:
7273
extBuiltins = getExtBuiltins(spv::E_SPV_AMD_gcn_shader);
7274
libCall = spv::CubeFaceCoordAMD;
7275
break;
7276
case glslang::EOpSubgroupPartition:
7277
unaryOp = spv::OpGroupNonUniformPartitionNV;
7278
break;
7279
case glslang::EOpConstructReference:
7280
unaryOp = spv::OpBitcast;
7281
break;
7282
7283
case glslang::EOpConvUint64ToAccStruct:
7284
case glslang::EOpConvUvec2ToAccStruct:
7285
unaryOp = spv::OpConvertUToAccelerationStructureKHR;
7286
break;
7287
7288
case glslang::EOpHitObjectIsEmptyNV:
7289
unaryOp = spv::OpHitObjectIsEmptyNV;
7290
break;
7291
7292
case glslang::EOpHitObjectIsMissNV:
7293
unaryOp = spv::OpHitObjectIsMissNV;
7294
break;
7295
7296
case glslang::EOpHitObjectIsHitNV:
7297
unaryOp = spv::OpHitObjectIsHitNV;
7298
break;
7299
7300
case glslang::EOpHitObjectGetObjectRayOriginNV:
7301
unaryOp = spv::OpHitObjectGetObjectRayOriginNV;
7302
break;
7303
7304
case glslang::EOpHitObjectGetObjectRayDirectionNV:
7305
unaryOp = spv::OpHitObjectGetObjectRayDirectionNV;
7306
break;
7307
7308
case glslang::EOpHitObjectGetWorldRayOriginNV:
7309
unaryOp = spv::OpHitObjectGetWorldRayOriginNV;
7310
break;
7311
7312
case glslang::EOpHitObjectGetWorldRayDirectionNV:
7313
unaryOp = spv::OpHitObjectGetWorldRayDirectionNV;
7314
break;
7315
7316
case glslang::EOpHitObjectGetObjectToWorldNV:
7317
unaryOp = spv::OpHitObjectGetObjectToWorldNV;
7318
break;
7319
7320
case glslang::EOpHitObjectGetWorldToObjectNV:
7321
unaryOp = spv::OpHitObjectGetWorldToObjectNV;
7322
break;
7323
7324
case glslang::EOpHitObjectGetRayTMinNV:
7325
unaryOp = spv::OpHitObjectGetRayTMinNV;
7326
break;
7327
7328
case glslang::EOpHitObjectGetRayTMaxNV:
7329
unaryOp = spv::OpHitObjectGetRayTMaxNV;
7330
break;
7331
7332
case glslang::EOpHitObjectGetPrimitiveIndexNV:
7333
unaryOp = spv::OpHitObjectGetPrimitiveIndexNV;
7334
break;
7335
7336
case glslang::EOpHitObjectGetInstanceIdNV:
7337
unaryOp = spv::OpHitObjectGetInstanceIdNV;
7338
break;
7339
7340
case glslang::EOpHitObjectGetInstanceCustomIndexNV:
7341
unaryOp = spv::OpHitObjectGetInstanceCustomIndexNV;
7342
break;
7343
7344
case glslang::EOpHitObjectGetGeometryIndexNV:
7345
unaryOp = spv::OpHitObjectGetGeometryIndexNV;
7346
break;
7347
7348
case glslang::EOpHitObjectGetHitKindNV:
7349
unaryOp = spv::OpHitObjectGetHitKindNV;
7350
break;
7351
7352
case glslang::EOpHitObjectGetCurrentTimeNV:
7353
unaryOp = spv::OpHitObjectGetCurrentTimeNV;
7354
break;
7355
7356
case glslang::EOpHitObjectGetShaderBindingTableRecordIndexNV:
7357
unaryOp = spv::OpHitObjectGetShaderBindingTableRecordIndexNV;
7358
break;
7359
7360
case glslang::EOpHitObjectGetShaderRecordBufferHandleNV:
7361
unaryOp = spv::OpHitObjectGetShaderRecordBufferHandleNV;
7362
break;
7363
7364
case glslang::EOpFetchMicroTriangleVertexPositionNV:
7365
unaryOp = spv::OpFetchMicroTriangleVertexPositionNV;
7366
break;
7367
7368
case glslang::EOpFetchMicroTriangleVertexBarycentricNV:
7369
unaryOp = spv::OpFetchMicroTriangleVertexBarycentricNV;
7370
break;
7371
7372
case glslang::EOpCopyObject:
7373
unaryOp = spv::OpCopyObject;
7374
break;
7375
7376
case glslang::EOpDepthAttachmentReadEXT:
7377
builder.addExtension(spv::E_SPV_EXT_shader_tile_image);
7378
builder.addCapability(spv::CapabilityTileImageDepthReadAccessEXT);
7379
unaryOp = spv::OpDepthAttachmentReadEXT;
7380
decorations.precision = spv::NoPrecision;
7381
break;
7382
case glslang::EOpStencilAttachmentReadEXT:
7383
builder.addExtension(spv::E_SPV_EXT_shader_tile_image);
7384
builder.addCapability(spv::CapabilityTileImageStencilReadAccessEXT);
7385
unaryOp = spv::OpStencilAttachmentReadEXT;
7386
decorations.precision = spv::DecorationRelaxedPrecision;
7387
break;
7388
7389
default:
7390
return 0;
7391
}
7392
7393
spv::Id id;
7394
if (libCall >= 0) {
7395
std::vector<spv::Id> args;
7396
args.push_back(operand);
7397
id = builder.createBuiltinCall(typeId, extBuiltins >= 0 ? extBuiltins : stdBuiltins, libCall, args);
7398
} else {
7399
id = builder.createUnaryOp(unaryOp, typeId, operand);
7400
}
7401
7402
decorations.addNoContraction(builder, id);
7403
decorations.addNonUniform(builder, id);
7404
return builder.setPrecision(id, decorations.precision);
7405
}
7406
7407
// Create a unary operation on a matrix
7408
spv::Id TGlslangToSpvTraverser::createUnaryMatrixOperation(spv::Op op, OpDecorations& decorations, spv::Id typeId,
7409
spv::Id operand, glslang::TBasicType /* typeProxy */)
7410
{
7411
// Handle unary operations vector by vector.
7412
// The result type is the same type as the original type.
7413
// The algorithm is to:
7414
// - break the matrix into vectors
7415
// - apply the operation to each vector
7416
// - make a matrix out the vector results
7417
7418
// get the types sorted out
7419
int numCols = builder.getNumColumns(operand);
7420
int numRows = builder.getNumRows(operand);
7421
spv::Id srcVecType = builder.makeVectorType(builder.getScalarTypeId(builder.getTypeId(operand)), numRows);
7422
spv::Id destVecType = builder.makeVectorType(builder.getScalarTypeId(typeId), numRows);
7423
std::vector<spv::Id> results;
7424
7425
// do each vector op
7426
for (int c = 0; c < numCols; ++c) {
7427
std::vector<unsigned int> indexes;
7428
indexes.push_back(c);
7429
spv::Id srcVec = builder.createCompositeExtract(operand, srcVecType, indexes);
7430
spv::Id destVec = builder.createUnaryOp(op, destVecType, srcVec);
7431
decorations.addNoContraction(builder, destVec);
7432
decorations.addNonUniform(builder, destVec);
7433
results.push_back(builder.setPrecision(destVec, decorations.precision));
7434
}
7435
7436
// put the pieces together
7437
spv::Id result = builder.setPrecision(builder.createCompositeConstruct(typeId, results), decorations.precision);
7438
decorations.addNonUniform(builder, result);
7439
return result;
7440
}
7441
7442
// For converting integers where both the bitwidth and the signedness could
7443
// change, but only do the width change here. The caller is still responsible
7444
// for the signedness conversion.
7445
// destType is the final type that will be converted to, but this function
7446
// may only be doing part of that conversion.
7447
spv::Id TGlslangToSpvTraverser::createIntWidthConversion(glslang::TOperator op, spv::Id operand, int vectorSize, spv::Id destType)
7448
{
7449
// Get the result type width, based on the type to convert to.
7450
int width = 32;
7451
switch(op) {
7452
case glslang::EOpConvInt16ToUint8:
7453
case glslang::EOpConvIntToUint8:
7454
case glslang::EOpConvInt64ToUint8:
7455
case glslang::EOpConvUint16ToInt8:
7456
case glslang::EOpConvUintToInt8:
7457
case glslang::EOpConvUint64ToInt8:
7458
width = 8;
7459
break;
7460
case glslang::EOpConvInt8ToUint16:
7461
case glslang::EOpConvIntToUint16:
7462
case glslang::EOpConvInt64ToUint16:
7463
case glslang::EOpConvUint8ToInt16:
7464
case glslang::EOpConvUintToInt16:
7465
case glslang::EOpConvUint64ToInt16:
7466
width = 16;
7467
break;
7468
case glslang::EOpConvInt8ToUint:
7469
case glslang::EOpConvInt16ToUint:
7470
case glslang::EOpConvInt64ToUint:
7471
case glslang::EOpConvUint8ToInt:
7472
case glslang::EOpConvUint16ToInt:
7473
case glslang::EOpConvUint64ToInt:
7474
width = 32;
7475
break;
7476
case glslang::EOpConvInt8ToUint64:
7477
case glslang::EOpConvInt16ToUint64:
7478
case glslang::EOpConvIntToUint64:
7479
case glslang::EOpConvUint8ToInt64:
7480
case glslang::EOpConvUint16ToInt64:
7481
case glslang::EOpConvUintToInt64:
7482
width = 64;
7483
break;
7484
7485
default:
7486
assert(false && "Default missing");
7487
break;
7488
}
7489
7490
// Get the conversion operation and result type,
7491
// based on the target width, but the source type.
7492
spv::Id type = spv::NoType;
7493
spv::Op convOp = spv::OpNop;
7494
switch(op) {
7495
case glslang::EOpConvInt8ToUint16:
7496
case glslang::EOpConvInt8ToUint:
7497
case glslang::EOpConvInt8ToUint64:
7498
case glslang::EOpConvInt16ToUint8:
7499
case glslang::EOpConvInt16ToUint:
7500
case glslang::EOpConvInt16ToUint64:
7501
case glslang::EOpConvIntToUint8:
7502
case glslang::EOpConvIntToUint16:
7503
case glslang::EOpConvIntToUint64:
7504
case glslang::EOpConvInt64ToUint8:
7505
case glslang::EOpConvInt64ToUint16:
7506
case glslang::EOpConvInt64ToUint:
7507
convOp = spv::OpSConvert;
7508
type = builder.makeIntType(width);
7509
break;
7510
default:
7511
convOp = spv::OpUConvert;
7512
type = builder.makeUintType(width);
7513
break;
7514
}
7515
7516
if (vectorSize > 0)
7517
type = builder.makeVectorType(type, vectorSize);
7518
else if (builder.getOpCode(destType) == spv::OpTypeCooperativeMatrixKHR ||
7519
builder.getOpCode(destType) == spv::OpTypeCooperativeMatrixNV) {
7520
7521
type = builder.makeCooperativeMatrixTypeWithSameShape(type, destType);
7522
}
7523
7524
return builder.createUnaryOp(convOp, type, operand);
7525
}
7526
7527
spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, OpDecorations& decorations, spv::Id destType,
7528
spv::Id operand, glslang::TBasicType typeProxy)
7529
{
7530
spv::Op convOp = spv::OpNop;
7531
spv::Id zero = 0;
7532
spv::Id one = 0;
7533
7534
int vectorSize = builder.isVectorType(destType) ? builder.getNumTypeComponents(destType) : 0;
7535
7536
switch (op) {
7537
case glslang::EOpConvIntToBool:
7538
case glslang::EOpConvUintToBool:
7539
zero = builder.makeUintConstant(0);
7540
zero = makeSmearedConstant(zero, vectorSize);
7541
return builder.createBinOp(spv::OpINotEqual, destType, operand, zero);
7542
case glslang::EOpConvFloatToBool:
7543
zero = builder.makeFloatConstant(0.0F);
7544
zero = makeSmearedConstant(zero, vectorSize);
7545
return builder.createBinOp(spv::OpFUnordNotEqual, destType, operand, zero);
7546
case glslang::EOpConvBoolToFloat:
7547
convOp = spv::OpSelect;
7548
zero = builder.makeFloatConstant(0.0F);
7549
one = builder.makeFloatConstant(1.0F);
7550
break;
7551
7552
case glslang::EOpConvBoolToInt:
7553
case glslang::EOpConvBoolToInt64:
7554
if (op == glslang::EOpConvBoolToInt64) {
7555
zero = builder.makeInt64Constant(0);
7556
one = builder.makeInt64Constant(1);
7557
} else {
7558
zero = builder.makeIntConstant(0);
7559
one = builder.makeIntConstant(1);
7560
}
7561
7562
convOp = spv::OpSelect;
7563
break;
7564
7565
case glslang::EOpConvBoolToUint:
7566
case glslang::EOpConvBoolToUint64:
7567
if (op == glslang::EOpConvBoolToUint64) {
7568
zero = builder.makeUint64Constant(0);
7569
one = builder.makeUint64Constant(1);
7570
} else {
7571
zero = builder.makeUintConstant(0);
7572
one = builder.makeUintConstant(1);
7573
}
7574
7575
convOp = spv::OpSelect;
7576
break;
7577
7578
case glslang::EOpConvInt8ToFloat16:
7579
case glslang::EOpConvInt8ToFloat:
7580
case glslang::EOpConvInt8ToDouble:
7581
case glslang::EOpConvInt16ToFloat16:
7582
case glslang::EOpConvInt16ToFloat:
7583
case glslang::EOpConvInt16ToDouble:
7584
case glslang::EOpConvIntToFloat16:
7585
case glslang::EOpConvIntToFloat:
7586
case glslang::EOpConvIntToDouble:
7587
case glslang::EOpConvInt64ToFloat:
7588
case glslang::EOpConvInt64ToDouble:
7589
case glslang::EOpConvInt64ToFloat16:
7590
convOp = spv::OpConvertSToF;
7591
break;
7592
7593
case glslang::EOpConvUint8ToFloat16:
7594
case glslang::EOpConvUint8ToFloat:
7595
case glslang::EOpConvUint8ToDouble:
7596
case glslang::EOpConvUint16ToFloat16:
7597
case glslang::EOpConvUint16ToFloat:
7598
case glslang::EOpConvUint16ToDouble:
7599
case glslang::EOpConvUintToFloat16:
7600
case glslang::EOpConvUintToFloat:
7601
case glslang::EOpConvUintToDouble:
7602
case glslang::EOpConvUint64ToFloat:
7603
case glslang::EOpConvUint64ToDouble:
7604
case glslang::EOpConvUint64ToFloat16:
7605
convOp = spv::OpConvertUToF;
7606
break;
7607
7608
case glslang::EOpConvFloat16ToInt8:
7609
case glslang::EOpConvFloatToInt8:
7610
case glslang::EOpConvDoubleToInt8:
7611
case glslang::EOpConvFloat16ToInt16:
7612
case glslang::EOpConvFloatToInt16:
7613
case glslang::EOpConvDoubleToInt16:
7614
case glslang::EOpConvFloat16ToInt:
7615
case glslang::EOpConvFloatToInt:
7616
case glslang::EOpConvDoubleToInt:
7617
case glslang::EOpConvFloat16ToInt64:
7618
case glslang::EOpConvFloatToInt64:
7619
case glslang::EOpConvDoubleToInt64:
7620
convOp = spv::OpConvertFToS;
7621
break;
7622
7623
case glslang::EOpConvUint8ToInt8:
7624
case glslang::EOpConvInt8ToUint8:
7625
case glslang::EOpConvUint16ToInt16:
7626
case glslang::EOpConvInt16ToUint16:
7627
case glslang::EOpConvUintToInt:
7628
case glslang::EOpConvIntToUint:
7629
case glslang::EOpConvUint64ToInt64:
7630
case glslang::EOpConvInt64ToUint64:
7631
if (builder.isInSpecConstCodeGenMode()) {
7632
// Build zero scalar or vector for OpIAdd.
7633
if(op == glslang::EOpConvUint8ToInt8 || op == glslang::EOpConvInt8ToUint8) {
7634
zero = builder.makeUint8Constant(0);
7635
} else if (op == glslang::EOpConvUint16ToInt16 || op == glslang::EOpConvInt16ToUint16) {
7636
zero = builder.makeUint16Constant(0);
7637
} else if (op == glslang::EOpConvUint64ToInt64 || op == glslang::EOpConvInt64ToUint64) {
7638
zero = builder.makeUint64Constant(0);
7639
} else {
7640
zero = builder.makeUintConstant(0);
7641
}
7642
zero = makeSmearedConstant(zero, vectorSize);
7643
// Use OpIAdd, instead of OpBitcast to do the conversion when
7644
// generating for OpSpecConstantOp instruction.
7645
return builder.createBinOp(spv::OpIAdd, destType, operand, zero);
7646
}
7647
// For normal run-time conversion instruction, use OpBitcast.
7648
convOp = spv::OpBitcast;
7649
break;
7650
7651
case glslang::EOpConvFloat16ToUint8:
7652
case glslang::EOpConvFloatToUint8:
7653
case glslang::EOpConvDoubleToUint8:
7654
case glslang::EOpConvFloat16ToUint16:
7655
case glslang::EOpConvFloatToUint16:
7656
case glslang::EOpConvDoubleToUint16:
7657
case glslang::EOpConvFloat16ToUint:
7658
case glslang::EOpConvFloatToUint:
7659
case glslang::EOpConvDoubleToUint:
7660
case glslang::EOpConvFloatToUint64:
7661
case glslang::EOpConvDoubleToUint64:
7662
case glslang::EOpConvFloat16ToUint64:
7663
convOp = spv::OpConvertFToU;
7664
break;
7665
7666
case glslang::EOpConvInt8ToBool:
7667
case glslang::EOpConvUint8ToBool:
7668
zero = builder.makeUint8Constant(0);
7669
zero = makeSmearedConstant(zero, vectorSize);
7670
return builder.createBinOp(spv::OpINotEqual, destType, operand, zero);
7671
case glslang::EOpConvInt16ToBool:
7672
case glslang::EOpConvUint16ToBool:
7673
zero = builder.makeUint16Constant(0);
7674
zero = makeSmearedConstant(zero, vectorSize);
7675
return builder.createBinOp(spv::OpINotEqual, destType, operand, zero);
7676
case glslang::EOpConvInt64ToBool:
7677
case glslang::EOpConvUint64ToBool:
7678
zero = builder.makeUint64Constant(0);
7679
zero = makeSmearedConstant(zero, vectorSize);
7680
return builder.createBinOp(spv::OpINotEqual, destType, operand, zero);
7681
case glslang::EOpConvDoubleToBool:
7682
zero = builder.makeDoubleConstant(0.0);
7683
zero = makeSmearedConstant(zero, vectorSize);
7684
return builder.createBinOp(spv::OpFUnordNotEqual, destType, operand, zero);
7685
case glslang::EOpConvFloat16ToBool:
7686
zero = builder.makeFloat16Constant(0.0F);
7687
zero = makeSmearedConstant(zero, vectorSize);
7688
return builder.createBinOp(spv::OpFUnordNotEqual, destType, operand, zero);
7689
case glslang::EOpConvBoolToDouble:
7690
convOp = spv::OpSelect;
7691
zero = builder.makeDoubleConstant(0.0);
7692
one = builder.makeDoubleConstant(1.0);
7693
break;
7694
case glslang::EOpConvBoolToFloat16:
7695
convOp = spv::OpSelect;
7696
zero = builder.makeFloat16Constant(0.0F);
7697
one = builder.makeFloat16Constant(1.0F);
7698
break;
7699
case glslang::EOpConvBoolToInt8:
7700
zero = builder.makeInt8Constant(0);
7701
one = builder.makeInt8Constant(1);
7702
convOp = spv::OpSelect;
7703
break;
7704
case glslang::EOpConvBoolToUint8:
7705
zero = builder.makeUint8Constant(0);
7706
one = builder.makeUint8Constant(1);
7707
convOp = spv::OpSelect;
7708
break;
7709
case glslang::EOpConvBoolToInt16:
7710
zero = builder.makeInt16Constant(0);
7711
one = builder.makeInt16Constant(1);
7712
convOp = spv::OpSelect;
7713
break;
7714
case glslang::EOpConvBoolToUint16:
7715
zero = builder.makeUint16Constant(0);
7716
one = builder.makeUint16Constant(1);
7717
convOp = spv::OpSelect;
7718
break;
7719
case glslang::EOpConvDoubleToFloat:
7720
case glslang::EOpConvFloatToDouble:
7721
case glslang::EOpConvDoubleToFloat16:
7722
case glslang::EOpConvFloat16ToDouble:
7723
case glslang::EOpConvFloatToFloat16:
7724
case glslang::EOpConvFloat16ToFloat:
7725
convOp = spv::OpFConvert;
7726
if (builder.isMatrixType(destType))
7727
return createUnaryMatrixOperation(convOp, decorations, destType, operand, typeProxy);
7728
break;
7729
7730
case glslang::EOpConvInt8ToInt16:
7731
case glslang::EOpConvInt8ToInt:
7732
case glslang::EOpConvInt8ToInt64:
7733
case glslang::EOpConvInt16ToInt8:
7734
case glslang::EOpConvInt16ToInt:
7735
case glslang::EOpConvInt16ToInt64:
7736
case glslang::EOpConvIntToInt8:
7737
case glslang::EOpConvIntToInt16:
7738
case glslang::EOpConvIntToInt64:
7739
case glslang::EOpConvInt64ToInt8:
7740
case glslang::EOpConvInt64ToInt16:
7741
case glslang::EOpConvInt64ToInt:
7742
convOp = spv::OpSConvert;
7743
break;
7744
7745
case glslang::EOpConvUint8ToUint16:
7746
case glslang::EOpConvUint8ToUint:
7747
case glslang::EOpConvUint8ToUint64:
7748
case glslang::EOpConvUint16ToUint8:
7749
case glslang::EOpConvUint16ToUint:
7750
case glslang::EOpConvUint16ToUint64:
7751
case glslang::EOpConvUintToUint8:
7752
case glslang::EOpConvUintToUint16:
7753
case glslang::EOpConvUintToUint64:
7754
case glslang::EOpConvUint64ToUint8:
7755
case glslang::EOpConvUint64ToUint16:
7756
case glslang::EOpConvUint64ToUint:
7757
convOp = spv::OpUConvert;
7758
break;
7759
7760
case glslang::EOpConvInt8ToUint16:
7761
case glslang::EOpConvInt8ToUint:
7762
case glslang::EOpConvInt8ToUint64:
7763
case glslang::EOpConvInt16ToUint8:
7764
case glslang::EOpConvInt16ToUint:
7765
case glslang::EOpConvInt16ToUint64:
7766
case glslang::EOpConvIntToUint8:
7767
case glslang::EOpConvIntToUint16:
7768
case glslang::EOpConvIntToUint64:
7769
case glslang::EOpConvInt64ToUint8:
7770
case glslang::EOpConvInt64ToUint16:
7771
case glslang::EOpConvInt64ToUint:
7772
case glslang::EOpConvUint8ToInt16:
7773
case glslang::EOpConvUint8ToInt:
7774
case glslang::EOpConvUint8ToInt64:
7775
case glslang::EOpConvUint16ToInt8:
7776
case glslang::EOpConvUint16ToInt:
7777
case glslang::EOpConvUint16ToInt64:
7778
case glslang::EOpConvUintToInt8:
7779
case glslang::EOpConvUintToInt16:
7780
case glslang::EOpConvUintToInt64:
7781
case glslang::EOpConvUint64ToInt8:
7782
case glslang::EOpConvUint64ToInt16:
7783
case glslang::EOpConvUint64ToInt:
7784
// OpSConvert/OpUConvert + OpBitCast
7785
operand = createIntWidthConversion(op, operand, vectorSize, destType);
7786
7787
if (builder.isInSpecConstCodeGenMode()) {
7788
// Build zero scalar or vector for OpIAdd.
7789
switch(op) {
7790
case glslang::EOpConvInt16ToUint8:
7791
case glslang::EOpConvIntToUint8:
7792
case glslang::EOpConvInt64ToUint8:
7793
case glslang::EOpConvUint16ToInt8:
7794
case glslang::EOpConvUintToInt8:
7795
case glslang::EOpConvUint64ToInt8:
7796
zero = builder.makeUint8Constant(0);
7797
break;
7798
case glslang::EOpConvInt8ToUint16:
7799
case glslang::EOpConvIntToUint16:
7800
case glslang::EOpConvInt64ToUint16:
7801
case glslang::EOpConvUint8ToInt16:
7802
case glslang::EOpConvUintToInt16:
7803
case glslang::EOpConvUint64ToInt16:
7804
zero = builder.makeUint16Constant(0);
7805
break;
7806
case glslang::EOpConvInt8ToUint:
7807
case glslang::EOpConvInt16ToUint:
7808
case glslang::EOpConvInt64ToUint:
7809
case glslang::EOpConvUint8ToInt:
7810
case glslang::EOpConvUint16ToInt:
7811
case glslang::EOpConvUint64ToInt:
7812
zero = builder.makeUintConstant(0);
7813
break;
7814
case glslang::EOpConvInt8ToUint64:
7815
case glslang::EOpConvInt16ToUint64:
7816
case glslang::EOpConvIntToUint64:
7817
case glslang::EOpConvUint8ToInt64:
7818
case glslang::EOpConvUint16ToInt64:
7819
case glslang::EOpConvUintToInt64:
7820
zero = builder.makeUint64Constant(0);
7821
break;
7822
default:
7823
assert(false && "Default missing");
7824
break;
7825
}
7826
zero = makeSmearedConstant(zero, vectorSize);
7827
// Use OpIAdd, instead of OpBitcast to do the conversion when
7828
// generating for OpSpecConstantOp instruction.
7829
return builder.createBinOp(spv::OpIAdd, destType, operand, zero);
7830
}
7831
// For normal run-time conversion instruction, use OpBitcast.
7832
convOp = spv::OpBitcast;
7833
break;
7834
case glslang::EOpConvUint64ToPtr:
7835
convOp = spv::OpConvertUToPtr;
7836
break;
7837
case glslang::EOpConvPtrToUint64:
7838
convOp = spv::OpConvertPtrToU;
7839
break;
7840
case glslang::EOpConvPtrToUvec2:
7841
case glslang::EOpConvUvec2ToPtr:
7842
convOp = spv::OpBitcast;
7843
break;
7844
7845
default:
7846
break;
7847
}
7848
7849
spv::Id result = 0;
7850
if (convOp == spv::OpNop)
7851
return result;
7852
7853
if (convOp == spv::OpSelect) {
7854
zero = makeSmearedConstant(zero, vectorSize);
7855
one = makeSmearedConstant(one, vectorSize);
7856
result = builder.createTriOp(convOp, destType, operand, one, zero);
7857
} else
7858
result = builder.createUnaryOp(convOp, destType, operand);
7859
7860
result = builder.setPrecision(result, decorations.precision);
7861
decorations.addNonUniform(builder, result);
7862
return result;
7863
}
7864
7865
spv::Id TGlslangToSpvTraverser::makeSmearedConstant(spv::Id constant, int vectorSize)
7866
{
7867
if (vectorSize == 0)
7868
return constant;
7869
7870
spv::Id vectorTypeId = builder.makeVectorType(builder.getTypeId(constant), vectorSize);
7871
std::vector<spv::Id> components;
7872
for (int c = 0; c < vectorSize; ++c)
7873
components.push_back(constant);
7874
return builder.makeCompositeConstant(vectorTypeId, components);
7875
}
7876
7877
// For glslang ops that map to SPV atomic opCodes
7878
spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv::Decoration /*precision*/,
7879
spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy,
7880
const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags, const glslang::TType &opType)
7881
{
7882
spv::Op opCode = spv::OpNop;
7883
7884
switch (op) {
7885
case glslang::EOpAtomicAdd:
7886
case glslang::EOpImageAtomicAdd:
7887
case glslang::EOpAtomicCounterAdd:
7888
opCode = spv::OpAtomicIAdd;
7889
if (typeProxy == glslang::EbtFloat16 || typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble) {
7890
opCode = spv::OpAtomicFAddEXT;
7891
if (typeProxy == glslang::EbtFloat16 &&
7892
(opType.getVectorSize() == 2 || opType.getVectorSize() == 4)) {
7893
builder.addExtension(spv::E_SPV_NV_shader_atomic_fp16_vector);
7894
builder.addCapability(spv::CapabilityAtomicFloat16VectorNV);
7895
} else {
7896
builder.addExtension(spv::E_SPV_EXT_shader_atomic_float_add);
7897
if (typeProxy == glslang::EbtFloat16) {
7898
builder.addExtension(spv::E_SPV_EXT_shader_atomic_float16_add);
7899
builder.addCapability(spv::CapabilityAtomicFloat16AddEXT);
7900
} else if (typeProxy == glslang::EbtFloat) {
7901
builder.addCapability(spv::CapabilityAtomicFloat32AddEXT);
7902
} else {
7903
builder.addCapability(spv::CapabilityAtomicFloat64AddEXT);
7904
}
7905
}
7906
}
7907
break;
7908
case glslang::EOpAtomicSubtract:
7909
case glslang::EOpAtomicCounterSubtract:
7910
opCode = spv::OpAtomicISub;
7911
break;
7912
case glslang::EOpAtomicMin:
7913
case glslang::EOpImageAtomicMin:
7914
case glslang::EOpAtomicCounterMin:
7915
if (typeProxy == glslang::EbtFloat16 || typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble) {
7916
opCode = spv::OpAtomicFMinEXT;
7917
if (typeProxy == glslang::EbtFloat16 &&
7918
(opType.getVectorSize() == 2 || opType.getVectorSize() == 4)) {
7919
builder.addExtension(spv::E_SPV_NV_shader_atomic_fp16_vector);
7920
builder.addCapability(spv::CapabilityAtomicFloat16VectorNV);
7921
} else {
7922
builder.addExtension(spv::E_SPV_EXT_shader_atomic_float_min_max);
7923
if (typeProxy == glslang::EbtFloat16)
7924
builder.addCapability(spv::CapabilityAtomicFloat16MinMaxEXT);
7925
else if (typeProxy == glslang::EbtFloat)
7926
builder.addCapability(spv::CapabilityAtomicFloat32MinMaxEXT);
7927
else
7928
builder.addCapability(spv::CapabilityAtomicFloat64MinMaxEXT);
7929
}
7930
} else if (typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64) {
7931
opCode = spv::OpAtomicUMin;
7932
} else {
7933
opCode = spv::OpAtomicSMin;
7934
}
7935
break;
7936
case glslang::EOpAtomicMax:
7937
case glslang::EOpImageAtomicMax:
7938
case glslang::EOpAtomicCounterMax:
7939
if (typeProxy == glslang::EbtFloat16 || typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble) {
7940
opCode = spv::OpAtomicFMaxEXT;
7941
if (typeProxy == glslang::EbtFloat16 &&
7942
(opType.getVectorSize() == 2 || opType.getVectorSize() == 4)) {
7943
builder.addExtension(spv::E_SPV_NV_shader_atomic_fp16_vector);
7944
builder.addCapability(spv::CapabilityAtomicFloat16VectorNV);
7945
} else {
7946
builder.addExtension(spv::E_SPV_EXT_shader_atomic_float_min_max);
7947
if (typeProxy == glslang::EbtFloat16)
7948
builder.addCapability(spv::CapabilityAtomicFloat16MinMaxEXT);
7949
else if (typeProxy == glslang::EbtFloat)
7950
builder.addCapability(spv::CapabilityAtomicFloat32MinMaxEXT);
7951
else
7952
builder.addCapability(spv::CapabilityAtomicFloat64MinMaxEXT);
7953
}
7954
} else if (typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64) {
7955
opCode = spv::OpAtomicUMax;
7956
} else {
7957
opCode = spv::OpAtomicSMax;
7958
}
7959
break;
7960
case glslang::EOpAtomicAnd:
7961
case glslang::EOpImageAtomicAnd:
7962
case glslang::EOpAtomicCounterAnd:
7963
opCode = spv::OpAtomicAnd;
7964
break;
7965
case glslang::EOpAtomicOr:
7966
case glslang::EOpImageAtomicOr:
7967
case glslang::EOpAtomicCounterOr:
7968
opCode = spv::OpAtomicOr;
7969
break;
7970
case glslang::EOpAtomicXor:
7971
case glslang::EOpImageAtomicXor:
7972
case glslang::EOpAtomicCounterXor:
7973
opCode = spv::OpAtomicXor;
7974
break;
7975
case glslang::EOpAtomicExchange:
7976
case glslang::EOpImageAtomicExchange:
7977
case glslang::EOpAtomicCounterExchange:
7978
if ((typeProxy == glslang::EbtFloat16) &&
7979
(opType.getVectorSize() == 2 || opType.getVectorSize() == 4)) {
7980
builder.addExtension(spv::E_SPV_NV_shader_atomic_fp16_vector);
7981
builder.addCapability(spv::CapabilityAtomicFloat16VectorNV);
7982
}
7983
7984
opCode = spv::OpAtomicExchange;
7985
break;
7986
case glslang::EOpAtomicCompSwap:
7987
case glslang::EOpImageAtomicCompSwap:
7988
case glslang::EOpAtomicCounterCompSwap:
7989
opCode = spv::OpAtomicCompareExchange;
7990
break;
7991
case glslang::EOpAtomicCounterIncrement:
7992
opCode = spv::OpAtomicIIncrement;
7993
break;
7994
case glslang::EOpAtomicCounterDecrement:
7995
opCode = spv::OpAtomicIDecrement;
7996
break;
7997
case glslang::EOpAtomicCounter:
7998
case glslang::EOpImageAtomicLoad:
7999
case glslang::EOpAtomicLoad:
8000
opCode = spv::OpAtomicLoad;
8001
break;
8002
case glslang::EOpAtomicStore:
8003
case glslang::EOpImageAtomicStore:
8004
opCode = spv::OpAtomicStore;
8005
break;
8006
default:
8007
assert(0);
8008
break;
8009
}
8010
8011
if (typeProxy == glslang::EbtInt64 || typeProxy == glslang::EbtUint64)
8012
builder.addCapability(spv::CapabilityInt64Atomics);
8013
8014
// Sort out the operands
8015
// - mapping from glslang -> SPV
8016
// - there are extra SPV operands that are optional in glslang
8017
// - compare-exchange swaps the value and comparator
8018
// - compare-exchange has an extra memory semantics
8019
// - EOpAtomicCounterDecrement needs a post decrement
8020
spv::Id pointerId = 0, compareId = 0, valueId = 0;
8021
// scope defaults to Device in the old model, QueueFamilyKHR in the new model
8022
spv::Id scopeId;
8023
if (glslangIntermediate->usingVulkanMemoryModel()) {
8024
scopeId = builder.makeUintConstant(spv::ScopeQueueFamilyKHR);
8025
} else {
8026
scopeId = builder.makeUintConstant(spv::ScopeDevice);
8027
}
8028
// semantics default to relaxed
8029
spv::Id semanticsId = builder.makeUintConstant(lvalueCoherentFlags.isVolatile() &&
8030
glslangIntermediate->usingVulkanMemoryModel() ?
8031
spv::MemorySemanticsVolatileMask :
8032
spv::MemorySemanticsMaskNone);
8033
spv::Id semanticsId2 = semanticsId;
8034
8035
pointerId = operands[0];
8036
if (opCode == spv::OpAtomicIIncrement || opCode == spv::OpAtomicIDecrement) {
8037
// no additional operands
8038
} else if (opCode == spv::OpAtomicCompareExchange) {
8039
compareId = operands[1];
8040
valueId = operands[2];
8041
if (operands.size() > 3) {
8042
scopeId = operands[3];
8043
semanticsId = builder.makeUintConstant(
8044
builder.getConstantScalar(operands[4]) | builder.getConstantScalar(operands[5]));
8045
semanticsId2 = builder.makeUintConstant(
8046
builder.getConstantScalar(operands[6]) | builder.getConstantScalar(operands[7]));
8047
}
8048
} else if (opCode == spv::OpAtomicLoad) {
8049
if (operands.size() > 1) {
8050
scopeId = operands[1];
8051
semanticsId = builder.makeUintConstant(
8052
builder.getConstantScalar(operands[2]) | builder.getConstantScalar(operands[3]));
8053
}
8054
} else {
8055
// atomic store or RMW
8056
valueId = operands[1];
8057
if (operands.size() > 2) {
8058
scopeId = operands[2];
8059
semanticsId = builder.makeUintConstant
8060
(builder.getConstantScalar(operands[3]) | builder.getConstantScalar(operands[4]));
8061
}
8062
}
8063
8064
// Check for capabilities
8065
unsigned semanticsImmediate = builder.getConstantScalar(semanticsId) | builder.getConstantScalar(semanticsId2);
8066
if (semanticsImmediate & (spv::MemorySemanticsMakeAvailableKHRMask |
8067
spv::MemorySemanticsMakeVisibleKHRMask |
8068
spv::MemorySemanticsOutputMemoryKHRMask |
8069
spv::MemorySemanticsVolatileMask)) {
8070
builder.addCapability(spv::CapabilityVulkanMemoryModelKHR);
8071
}
8072
8073
if (builder.getConstantScalar(scopeId) == spv::ScopeQueueFamily) {
8074
builder.addCapability(spv::CapabilityVulkanMemoryModelKHR);
8075
}
8076
8077
if (glslangIntermediate->usingVulkanMemoryModel() && builder.getConstantScalar(scopeId) == spv::ScopeDevice) {
8078
builder.addCapability(spv::CapabilityVulkanMemoryModelDeviceScopeKHR);
8079
}
8080
8081
std::vector<spv::Id> spvAtomicOperands; // hold the spv operands
8082
spvAtomicOperands.reserve(6);
8083
spvAtomicOperands.push_back(pointerId);
8084
spvAtomicOperands.push_back(scopeId);
8085
spvAtomicOperands.push_back(semanticsId);
8086
if (opCode == spv::OpAtomicCompareExchange) {
8087
spvAtomicOperands.push_back(semanticsId2);
8088
spvAtomicOperands.push_back(valueId);
8089
spvAtomicOperands.push_back(compareId);
8090
} else if (opCode != spv::OpAtomicLoad && opCode != spv::OpAtomicIIncrement && opCode != spv::OpAtomicIDecrement) {
8091
spvAtomicOperands.push_back(valueId);
8092
}
8093
8094
if (opCode == spv::OpAtomicStore) {
8095
builder.createNoResultOp(opCode, spvAtomicOperands);
8096
return 0;
8097
} else {
8098
spv::Id resultId = builder.createOp(opCode, typeId, spvAtomicOperands);
8099
8100
// GLSL and HLSL atomic-counter decrement return post-decrement value,
8101
// while SPIR-V returns pre-decrement value. Translate between these semantics.
8102
if (op == glslang::EOpAtomicCounterDecrement)
8103
resultId = builder.createBinOp(spv::OpISub, typeId, resultId, builder.makeIntConstant(1));
8104
8105
return resultId;
8106
}
8107
}
8108
8109
// Create group invocation operations.
8110
spv::Id TGlslangToSpvTraverser::createInvocationsOperation(glslang::TOperator op, spv::Id typeId,
8111
std::vector<spv::Id>& operands, glslang::TBasicType typeProxy)
8112
{
8113
bool isUnsigned = isTypeUnsignedInt(typeProxy);
8114
bool isFloat = isTypeFloat(typeProxy);
8115
8116
spv::Op opCode = spv::OpNop;
8117
std::vector<spv::IdImmediate> spvGroupOperands;
8118
spv::GroupOperation groupOperation = spv::GroupOperationMax;
8119
8120
if (op == glslang::EOpBallot || op == glslang::EOpReadFirstInvocation ||
8121
op == glslang::EOpReadInvocation) {
8122
builder.addExtension(spv::E_SPV_KHR_shader_ballot);
8123
builder.addCapability(spv::CapabilitySubgroupBallotKHR);
8124
} else if (op == glslang::EOpAnyInvocation ||
8125
op == glslang::EOpAllInvocations ||
8126
op == glslang::EOpAllInvocationsEqual) {
8127
builder.addExtension(spv::E_SPV_KHR_subgroup_vote);
8128
builder.addCapability(spv::CapabilitySubgroupVoteKHR);
8129
} else {
8130
builder.addCapability(spv::CapabilityGroups);
8131
if (op == glslang::EOpMinInvocationsNonUniform ||
8132
op == glslang::EOpMaxInvocationsNonUniform ||
8133
op == glslang::EOpAddInvocationsNonUniform ||
8134
op == glslang::EOpMinInvocationsInclusiveScanNonUniform ||
8135
op == glslang::EOpMaxInvocationsInclusiveScanNonUniform ||
8136
op == glslang::EOpAddInvocationsInclusiveScanNonUniform ||
8137
op == glslang::EOpMinInvocationsExclusiveScanNonUniform ||
8138
op == glslang::EOpMaxInvocationsExclusiveScanNonUniform ||
8139
op == glslang::EOpAddInvocationsExclusiveScanNonUniform)
8140
builder.addExtension(spv::E_SPV_AMD_shader_ballot);
8141
8142
switch (op) {
8143
case glslang::EOpMinInvocations:
8144
case glslang::EOpMaxInvocations:
8145
case glslang::EOpAddInvocations:
8146
case glslang::EOpMinInvocationsNonUniform:
8147
case glslang::EOpMaxInvocationsNonUniform:
8148
case glslang::EOpAddInvocationsNonUniform:
8149
groupOperation = spv::GroupOperationReduce;
8150
break;
8151
case glslang::EOpMinInvocationsInclusiveScan:
8152
case glslang::EOpMaxInvocationsInclusiveScan:
8153
case glslang::EOpAddInvocationsInclusiveScan:
8154
case glslang::EOpMinInvocationsInclusiveScanNonUniform:
8155
case glslang::EOpMaxInvocationsInclusiveScanNonUniform:
8156
case glslang::EOpAddInvocationsInclusiveScanNonUniform:
8157
groupOperation = spv::GroupOperationInclusiveScan;
8158
break;
8159
case glslang::EOpMinInvocationsExclusiveScan:
8160
case glslang::EOpMaxInvocationsExclusiveScan:
8161
case glslang::EOpAddInvocationsExclusiveScan:
8162
case glslang::EOpMinInvocationsExclusiveScanNonUniform:
8163
case glslang::EOpMaxInvocationsExclusiveScanNonUniform:
8164
case glslang::EOpAddInvocationsExclusiveScanNonUniform:
8165
groupOperation = spv::GroupOperationExclusiveScan;
8166
break;
8167
default:
8168
break;
8169
}
8170
spv::IdImmediate scope = { true, builder.makeUintConstant(spv::ScopeSubgroup) };
8171
spvGroupOperands.push_back(scope);
8172
if (groupOperation != spv::GroupOperationMax) {
8173
spv::IdImmediate groupOp = { false, (unsigned)groupOperation };
8174
spvGroupOperands.push_back(groupOp);
8175
}
8176
}
8177
8178
for (auto opIt = operands.begin(); opIt != operands.end(); ++opIt) {
8179
spv::IdImmediate op = { true, *opIt };
8180
spvGroupOperands.push_back(op);
8181
}
8182
8183
switch (op) {
8184
case glslang::EOpAnyInvocation:
8185
opCode = spv::OpSubgroupAnyKHR;
8186
break;
8187
case glslang::EOpAllInvocations:
8188
opCode = spv::OpSubgroupAllKHR;
8189
break;
8190
case glslang::EOpAllInvocationsEqual:
8191
opCode = spv::OpSubgroupAllEqualKHR;
8192
break;
8193
case glslang::EOpReadInvocation:
8194
opCode = spv::OpSubgroupReadInvocationKHR;
8195
if (builder.isVectorType(typeId))
8196
return CreateInvocationsVectorOperation(opCode, groupOperation, typeId, operands);
8197
break;
8198
case glslang::EOpReadFirstInvocation:
8199
opCode = spv::OpSubgroupFirstInvocationKHR;
8200
if (builder.isVectorType(typeId))
8201
return CreateInvocationsVectorOperation(opCode, groupOperation, typeId, operands);
8202
break;
8203
case glslang::EOpBallot:
8204
{
8205
// NOTE: According to the spec, the result type of "OpSubgroupBallotKHR" must be a 4 component vector of 32
8206
// bit integer types. The GLSL built-in function "ballotARB()" assumes the maximum number of invocations in
8207
// a subgroup is 64. Thus, we have to convert uvec4.xy to uint64_t as follow:
8208
//
8209
// result = Bitcast(SubgroupBallotKHR(Predicate).xy)
8210
//
8211
spv::Id uintType = builder.makeUintType(32);
8212
spv::Id uvec4Type = builder.makeVectorType(uintType, 4);
8213
spv::Id result = builder.createOp(spv::OpSubgroupBallotKHR, uvec4Type, spvGroupOperands);
8214
8215
std::vector<spv::Id> components;
8216
components.push_back(builder.createCompositeExtract(result, uintType, 0));
8217
components.push_back(builder.createCompositeExtract(result, uintType, 1));
8218
8219
spv::Id uvec2Type = builder.makeVectorType(uintType, 2);
8220
return builder.createUnaryOp(spv::OpBitcast, typeId,
8221
builder.createCompositeConstruct(uvec2Type, components));
8222
}
8223
8224
case glslang::EOpMinInvocations:
8225
case glslang::EOpMaxInvocations:
8226
case glslang::EOpAddInvocations:
8227
case glslang::EOpMinInvocationsInclusiveScan:
8228
case glslang::EOpMaxInvocationsInclusiveScan:
8229
case glslang::EOpAddInvocationsInclusiveScan:
8230
case glslang::EOpMinInvocationsExclusiveScan:
8231
case glslang::EOpMaxInvocationsExclusiveScan:
8232
case glslang::EOpAddInvocationsExclusiveScan:
8233
if (op == glslang::EOpMinInvocations ||
8234
op == glslang::EOpMinInvocationsInclusiveScan ||
8235
op == glslang::EOpMinInvocationsExclusiveScan) {
8236
if (isFloat)
8237
opCode = spv::OpGroupFMin;
8238
else {
8239
if (isUnsigned)
8240
opCode = spv::OpGroupUMin;
8241
else
8242
opCode = spv::OpGroupSMin;
8243
}
8244
} else if (op == glslang::EOpMaxInvocations ||
8245
op == glslang::EOpMaxInvocationsInclusiveScan ||
8246
op == glslang::EOpMaxInvocationsExclusiveScan) {
8247
if (isFloat)
8248
opCode = spv::OpGroupFMax;
8249
else {
8250
if (isUnsigned)
8251
opCode = spv::OpGroupUMax;
8252
else
8253
opCode = spv::OpGroupSMax;
8254
}
8255
} else {
8256
if (isFloat)
8257
opCode = spv::OpGroupFAdd;
8258
else
8259
opCode = spv::OpGroupIAdd;
8260
}
8261
8262
if (builder.isVectorType(typeId))
8263
return CreateInvocationsVectorOperation(opCode, groupOperation, typeId, operands);
8264
8265
break;
8266
case glslang::EOpMinInvocationsNonUniform:
8267
case glslang::EOpMaxInvocationsNonUniform:
8268
case glslang::EOpAddInvocationsNonUniform:
8269
case glslang::EOpMinInvocationsInclusiveScanNonUniform:
8270
case glslang::EOpMaxInvocationsInclusiveScanNonUniform:
8271
case glslang::EOpAddInvocationsInclusiveScanNonUniform:
8272
case glslang::EOpMinInvocationsExclusiveScanNonUniform:
8273
case glslang::EOpMaxInvocationsExclusiveScanNonUniform:
8274
case glslang::EOpAddInvocationsExclusiveScanNonUniform:
8275
if (op == glslang::EOpMinInvocationsNonUniform ||
8276
op == glslang::EOpMinInvocationsInclusiveScanNonUniform ||
8277
op == glslang::EOpMinInvocationsExclusiveScanNonUniform) {
8278
if (isFloat)
8279
opCode = spv::OpGroupFMinNonUniformAMD;
8280
else {
8281
if (isUnsigned)
8282
opCode = spv::OpGroupUMinNonUniformAMD;
8283
else
8284
opCode = spv::OpGroupSMinNonUniformAMD;
8285
}
8286
}
8287
else if (op == glslang::EOpMaxInvocationsNonUniform ||
8288
op == glslang::EOpMaxInvocationsInclusiveScanNonUniform ||
8289
op == glslang::EOpMaxInvocationsExclusiveScanNonUniform) {
8290
if (isFloat)
8291
opCode = spv::OpGroupFMaxNonUniformAMD;
8292
else {
8293
if (isUnsigned)
8294
opCode = spv::OpGroupUMaxNonUniformAMD;
8295
else
8296
opCode = spv::OpGroupSMaxNonUniformAMD;
8297
}
8298
}
8299
else {
8300
if (isFloat)
8301
opCode = spv::OpGroupFAddNonUniformAMD;
8302
else
8303
opCode = spv::OpGroupIAddNonUniformAMD;
8304
}
8305
8306
if (builder.isVectorType(typeId))
8307
return CreateInvocationsVectorOperation(opCode, groupOperation, typeId, operands);
8308
8309
break;
8310
default:
8311
logger->missingFunctionality("invocation operation");
8312
return spv::NoResult;
8313
}
8314
8315
assert(opCode != spv::OpNop);
8316
return builder.createOp(opCode, typeId, spvGroupOperands);
8317
}
8318
8319
// Create group invocation operations on a vector
8320
spv::Id TGlslangToSpvTraverser::CreateInvocationsVectorOperation(spv::Op op, spv::GroupOperation groupOperation,
8321
spv::Id typeId, std::vector<spv::Id>& operands)
8322
{
8323
assert(op == spv::OpGroupFMin || op == spv::OpGroupUMin || op == spv::OpGroupSMin ||
8324
op == spv::OpGroupFMax || op == spv::OpGroupUMax || op == spv::OpGroupSMax ||
8325
op == spv::OpGroupFAdd || op == spv::OpGroupIAdd || op == spv::OpGroupBroadcast ||
8326
op == spv::OpSubgroupReadInvocationKHR || op == spv::OpSubgroupFirstInvocationKHR ||
8327
op == spv::OpGroupFMinNonUniformAMD || op == spv::OpGroupUMinNonUniformAMD ||
8328
op == spv::OpGroupSMinNonUniformAMD ||
8329
op == spv::OpGroupFMaxNonUniformAMD || op == spv::OpGroupUMaxNonUniformAMD ||
8330
op == spv::OpGroupSMaxNonUniformAMD ||
8331
op == spv::OpGroupFAddNonUniformAMD || op == spv::OpGroupIAddNonUniformAMD);
8332
8333
// Handle group invocation operations scalar by scalar.
8334
// The result type is the same type as the original type.
8335
// The algorithm is to:
8336
// - break the vector into scalars
8337
// - apply the operation to each scalar
8338
// - make a vector out the scalar results
8339
8340
// get the types sorted out
8341
int numComponents = builder.getNumComponents(operands[0]);
8342
spv::Id scalarType = builder.getScalarTypeId(builder.getTypeId(operands[0]));
8343
std::vector<spv::Id> results;
8344
8345
// do each scalar op
8346
for (int comp = 0; comp < numComponents; ++comp) {
8347
std::vector<unsigned int> indexes;
8348
indexes.push_back(comp);
8349
spv::IdImmediate scalar = { true, builder.createCompositeExtract(operands[0], scalarType, indexes) };
8350
std::vector<spv::IdImmediate> spvGroupOperands;
8351
if (op == spv::OpSubgroupReadInvocationKHR) {
8352
spvGroupOperands.push_back(scalar);
8353
spv::IdImmediate operand = { true, operands[1] };
8354
spvGroupOperands.push_back(operand);
8355
} else if (op == spv::OpSubgroupFirstInvocationKHR) {
8356
spvGroupOperands.push_back(scalar);
8357
} else if (op == spv::OpGroupBroadcast) {
8358
spv::IdImmediate scope = { true, builder.makeUintConstant(spv::ScopeSubgroup) };
8359
spvGroupOperands.push_back(scope);
8360
spvGroupOperands.push_back(scalar);
8361
spv::IdImmediate operand = { true, operands[1] };
8362
spvGroupOperands.push_back(operand);
8363
} else {
8364
spv::IdImmediate scope = { true, builder.makeUintConstant(spv::ScopeSubgroup) };
8365
spvGroupOperands.push_back(scope);
8366
spv::IdImmediate groupOp = { false, (unsigned)groupOperation };
8367
spvGroupOperands.push_back(groupOp);
8368
spvGroupOperands.push_back(scalar);
8369
}
8370
8371
results.push_back(builder.createOp(op, scalarType, spvGroupOperands));
8372
}
8373
8374
// put the pieces together
8375
return builder.createCompositeConstruct(typeId, results);
8376
}
8377
8378
// Create subgroup invocation operations.
8379
spv::Id TGlslangToSpvTraverser::createSubgroupOperation(glslang::TOperator op, spv::Id typeId,
8380
std::vector<spv::Id>& operands, glslang::TBasicType typeProxy)
8381
{
8382
// Add the required capabilities.
8383
switch (op) {
8384
case glslang::EOpSubgroupElect:
8385
builder.addCapability(spv::CapabilityGroupNonUniform);
8386
break;
8387
case glslang::EOpSubgroupQuadAll:
8388
case glslang::EOpSubgroupQuadAny:
8389
builder.addExtension(spv::E_SPV_KHR_quad_control);
8390
builder.addCapability(spv::CapabilityQuadControlKHR);
8391
[[fallthrough]];
8392
case glslang::EOpSubgroupAll:
8393
case glslang::EOpSubgroupAny:
8394
case glslang::EOpSubgroupAllEqual:
8395
builder.addCapability(spv::CapabilityGroupNonUniform);
8396
builder.addCapability(spv::CapabilityGroupNonUniformVote);
8397
break;
8398
case glslang::EOpSubgroupBroadcast:
8399
case glslang::EOpSubgroupBroadcastFirst:
8400
case glslang::EOpSubgroupBallot:
8401
case glslang::EOpSubgroupInverseBallot:
8402
case glslang::EOpSubgroupBallotBitExtract:
8403
case glslang::EOpSubgroupBallotBitCount:
8404
case glslang::EOpSubgroupBallotInclusiveBitCount:
8405
case glslang::EOpSubgroupBallotExclusiveBitCount:
8406
case glslang::EOpSubgroupBallotFindLSB:
8407
case glslang::EOpSubgroupBallotFindMSB:
8408
builder.addCapability(spv::CapabilityGroupNonUniform);
8409
builder.addCapability(spv::CapabilityGroupNonUniformBallot);
8410
break;
8411
case glslang::EOpSubgroupRotate:
8412
case glslang::EOpSubgroupClusteredRotate:
8413
builder.addExtension(spv::E_SPV_KHR_subgroup_rotate);
8414
builder.addCapability(spv::CapabilityGroupNonUniformRotateKHR);
8415
break;
8416
case glslang::EOpSubgroupShuffle:
8417
case glslang::EOpSubgroupShuffleXor:
8418
builder.addCapability(spv::CapabilityGroupNonUniform);
8419
builder.addCapability(spv::CapabilityGroupNonUniformShuffle);
8420
break;
8421
case glslang::EOpSubgroupShuffleUp:
8422
case glslang::EOpSubgroupShuffleDown:
8423
builder.addCapability(spv::CapabilityGroupNonUniform);
8424
builder.addCapability(spv::CapabilityGroupNonUniformShuffleRelative);
8425
break;
8426
case glslang::EOpSubgroupAdd:
8427
case glslang::EOpSubgroupMul:
8428
case glslang::EOpSubgroupMin:
8429
case glslang::EOpSubgroupMax:
8430
case glslang::EOpSubgroupAnd:
8431
case glslang::EOpSubgroupOr:
8432
case glslang::EOpSubgroupXor:
8433
case glslang::EOpSubgroupInclusiveAdd:
8434
case glslang::EOpSubgroupInclusiveMul:
8435
case glslang::EOpSubgroupInclusiveMin:
8436
case glslang::EOpSubgroupInclusiveMax:
8437
case glslang::EOpSubgroupInclusiveAnd:
8438
case glslang::EOpSubgroupInclusiveOr:
8439
case glslang::EOpSubgroupInclusiveXor:
8440
case glslang::EOpSubgroupExclusiveAdd:
8441
case glslang::EOpSubgroupExclusiveMul:
8442
case glslang::EOpSubgroupExclusiveMin:
8443
case glslang::EOpSubgroupExclusiveMax:
8444
case glslang::EOpSubgroupExclusiveAnd:
8445
case glslang::EOpSubgroupExclusiveOr:
8446
case glslang::EOpSubgroupExclusiveXor:
8447
builder.addCapability(spv::CapabilityGroupNonUniform);
8448
builder.addCapability(spv::CapabilityGroupNonUniformArithmetic);
8449
break;
8450
case glslang::EOpSubgroupClusteredAdd:
8451
case glslang::EOpSubgroupClusteredMul:
8452
case glslang::EOpSubgroupClusteredMin:
8453
case glslang::EOpSubgroupClusteredMax:
8454
case glslang::EOpSubgroupClusteredAnd:
8455
case glslang::EOpSubgroupClusteredOr:
8456
case glslang::EOpSubgroupClusteredXor:
8457
builder.addCapability(spv::CapabilityGroupNonUniform);
8458
builder.addCapability(spv::CapabilityGroupNonUniformClustered);
8459
break;
8460
case glslang::EOpSubgroupQuadBroadcast:
8461
case glslang::EOpSubgroupQuadSwapHorizontal:
8462
case glslang::EOpSubgroupQuadSwapVertical:
8463
case glslang::EOpSubgroupQuadSwapDiagonal:
8464
builder.addCapability(spv::CapabilityGroupNonUniform);
8465
builder.addCapability(spv::CapabilityGroupNonUniformQuad);
8466
break;
8467
case glslang::EOpSubgroupPartitionedAdd:
8468
case glslang::EOpSubgroupPartitionedMul:
8469
case glslang::EOpSubgroupPartitionedMin:
8470
case glslang::EOpSubgroupPartitionedMax:
8471
case glslang::EOpSubgroupPartitionedAnd:
8472
case glslang::EOpSubgroupPartitionedOr:
8473
case glslang::EOpSubgroupPartitionedXor:
8474
case glslang::EOpSubgroupPartitionedInclusiveAdd:
8475
case glslang::EOpSubgroupPartitionedInclusiveMul:
8476
case glslang::EOpSubgroupPartitionedInclusiveMin:
8477
case glslang::EOpSubgroupPartitionedInclusiveMax:
8478
case glslang::EOpSubgroupPartitionedInclusiveAnd:
8479
case glslang::EOpSubgroupPartitionedInclusiveOr:
8480
case glslang::EOpSubgroupPartitionedInclusiveXor:
8481
case glslang::EOpSubgroupPartitionedExclusiveAdd:
8482
case glslang::EOpSubgroupPartitionedExclusiveMul:
8483
case glslang::EOpSubgroupPartitionedExclusiveMin:
8484
case glslang::EOpSubgroupPartitionedExclusiveMax:
8485
case glslang::EOpSubgroupPartitionedExclusiveAnd:
8486
case glslang::EOpSubgroupPartitionedExclusiveOr:
8487
case glslang::EOpSubgroupPartitionedExclusiveXor:
8488
builder.addExtension(spv::E_SPV_NV_shader_subgroup_partitioned);
8489
builder.addCapability(spv::CapabilityGroupNonUniformPartitionedNV);
8490
break;
8491
default: assert(0 && "Unhandled subgroup operation!");
8492
}
8493
8494
8495
const bool isUnsigned = isTypeUnsignedInt(typeProxy);
8496
const bool isFloat = isTypeFloat(typeProxy);
8497
const bool isBool = typeProxy == glslang::EbtBool;
8498
8499
spv::Op opCode = spv::OpNop;
8500
8501
// Figure out which opcode to use.
8502
switch (op) {
8503
case glslang::EOpSubgroupElect: opCode = spv::OpGroupNonUniformElect; break;
8504
case glslang::EOpSubgroupQuadAll: opCode = spv::OpGroupNonUniformQuadAllKHR; break;
8505
case glslang::EOpSubgroupAll: opCode = spv::OpGroupNonUniformAll; break;
8506
case glslang::EOpSubgroupQuadAny: opCode = spv::OpGroupNonUniformQuadAnyKHR; break;
8507
case glslang::EOpSubgroupAny: opCode = spv::OpGroupNonUniformAny; break;
8508
case glslang::EOpSubgroupAllEqual: opCode = spv::OpGroupNonUniformAllEqual; break;
8509
case glslang::EOpSubgroupBroadcast: opCode = spv::OpGroupNonUniformBroadcast; break;
8510
case glslang::EOpSubgroupBroadcastFirst: opCode = spv::OpGroupNonUniformBroadcastFirst; break;
8511
case glslang::EOpSubgroupBallot: opCode = spv::OpGroupNonUniformBallot; break;
8512
case glslang::EOpSubgroupInverseBallot: opCode = spv::OpGroupNonUniformInverseBallot; break;
8513
case glslang::EOpSubgroupBallotBitExtract: opCode = spv::OpGroupNonUniformBallotBitExtract; break;
8514
case glslang::EOpSubgroupBallotBitCount:
8515
case glslang::EOpSubgroupBallotInclusiveBitCount:
8516
case glslang::EOpSubgroupBallotExclusiveBitCount: opCode = spv::OpGroupNonUniformBallotBitCount; break;
8517
case glslang::EOpSubgroupBallotFindLSB: opCode = spv::OpGroupNonUniformBallotFindLSB; break;
8518
case glslang::EOpSubgroupBallotFindMSB: opCode = spv::OpGroupNonUniformBallotFindMSB; break;
8519
case glslang::EOpSubgroupShuffle: opCode = spv::OpGroupNonUniformShuffle; break;
8520
case glslang::EOpSubgroupShuffleXor: opCode = spv::OpGroupNonUniformShuffleXor; break;
8521
case glslang::EOpSubgroupShuffleUp: opCode = spv::OpGroupNonUniformShuffleUp; break;
8522
case glslang::EOpSubgroupShuffleDown: opCode = spv::OpGroupNonUniformShuffleDown; break;
8523
case glslang::EOpSubgroupRotate:
8524
case glslang::EOpSubgroupClusteredRotate: opCode = spv::OpGroupNonUniformRotateKHR; break;
8525
case glslang::EOpSubgroupAdd:
8526
case glslang::EOpSubgroupInclusiveAdd:
8527
case glslang::EOpSubgroupExclusiveAdd:
8528
case glslang::EOpSubgroupClusteredAdd:
8529
case glslang::EOpSubgroupPartitionedAdd:
8530
case glslang::EOpSubgroupPartitionedInclusiveAdd:
8531
case glslang::EOpSubgroupPartitionedExclusiveAdd:
8532
if (isFloat) {
8533
opCode = spv::OpGroupNonUniformFAdd;
8534
} else {
8535
opCode = spv::OpGroupNonUniformIAdd;
8536
}
8537
break;
8538
case glslang::EOpSubgroupMul:
8539
case glslang::EOpSubgroupInclusiveMul:
8540
case glslang::EOpSubgroupExclusiveMul:
8541
case glslang::EOpSubgroupClusteredMul:
8542
case glslang::EOpSubgroupPartitionedMul:
8543
case glslang::EOpSubgroupPartitionedInclusiveMul:
8544
case glslang::EOpSubgroupPartitionedExclusiveMul:
8545
if (isFloat) {
8546
opCode = spv::OpGroupNonUniformFMul;
8547
} else {
8548
opCode = spv::OpGroupNonUniformIMul;
8549
}
8550
break;
8551
case glslang::EOpSubgroupMin:
8552
case glslang::EOpSubgroupInclusiveMin:
8553
case glslang::EOpSubgroupExclusiveMin:
8554
case glslang::EOpSubgroupClusteredMin:
8555
case glslang::EOpSubgroupPartitionedMin:
8556
case glslang::EOpSubgroupPartitionedInclusiveMin:
8557
case glslang::EOpSubgroupPartitionedExclusiveMin:
8558
if (isFloat) {
8559
opCode = spv::OpGroupNonUniformFMin;
8560
} else if (isUnsigned) {
8561
opCode = spv::OpGroupNonUniformUMin;
8562
} else {
8563
opCode = spv::OpGroupNonUniformSMin;
8564
}
8565
break;
8566
case glslang::EOpSubgroupMax:
8567
case glslang::EOpSubgroupInclusiveMax:
8568
case glslang::EOpSubgroupExclusiveMax:
8569
case glslang::EOpSubgroupClusteredMax:
8570
case glslang::EOpSubgroupPartitionedMax:
8571
case glslang::EOpSubgroupPartitionedInclusiveMax:
8572
case glslang::EOpSubgroupPartitionedExclusiveMax:
8573
if (isFloat) {
8574
opCode = spv::OpGroupNonUniformFMax;
8575
} else if (isUnsigned) {
8576
opCode = spv::OpGroupNonUniformUMax;
8577
} else {
8578
opCode = spv::OpGroupNonUniformSMax;
8579
}
8580
break;
8581
case glslang::EOpSubgroupAnd:
8582
case glslang::EOpSubgroupInclusiveAnd:
8583
case glslang::EOpSubgroupExclusiveAnd:
8584
case glslang::EOpSubgroupClusteredAnd:
8585
case glslang::EOpSubgroupPartitionedAnd:
8586
case glslang::EOpSubgroupPartitionedInclusiveAnd:
8587
case glslang::EOpSubgroupPartitionedExclusiveAnd:
8588
if (isBool) {
8589
opCode = spv::OpGroupNonUniformLogicalAnd;
8590
} else {
8591
opCode = spv::OpGroupNonUniformBitwiseAnd;
8592
}
8593
break;
8594
case glslang::EOpSubgroupOr:
8595
case glslang::EOpSubgroupInclusiveOr:
8596
case glslang::EOpSubgroupExclusiveOr:
8597
case glslang::EOpSubgroupClusteredOr:
8598
case glslang::EOpSubgroupPartitionedOr:
8599
case glslang::EOpSubgroupPartitionedInclusiveOr:
8600
case glslang::EOpSubgroupPartitionedExclusiveOr:
8601
if (isBool) {
8602
opCode = spv::OpGroupNonUniformLogicalOr;
8603
} else {
8604
opCode = spv::OpGroupNonUniformBitwiseOr;
8605
}
8606
break;
8607
case glslang::EOpSubgroupXor:
8608
case glslang::EOpSubgroupInclusiveXor:
8609
case glslang::EOpSubgroupExclusiveXor:
8610
case glslang::EOpSubgroupClusteredXor:
8611
case glslang::EOpSubgroupPartitionedXor:
8612
case glslang::EOpSubgroupPartitionedInclusiveXor:
8613
case glslang::EOpSubgroupPartitionedExclusiveXor:
8614
if (isBool) {
8615
opCode = spv::OpGroupNonUniformLogicalXor;
8616
} else {
8617
opCode = spv::OpGroupNonUniformBitwiseXor;
8618
}
8619
break;
8620
case glslang::EOpSubgroupQuadBroadcast: opCode = spv::OpGroupNonUniformQuadBroadcast; break;
8621
case glslang::EOpSubgroupQuadSwapHorizontal:
8622
case glslang::EOpSubgroupQuadSwapVertical:
8623
case glslang::EOpSubgroupQuadSwapDiagonal: opCode = spv::OpGroupNonUniformQuadSwap; break;
8624
default: assert(0 && "Unhandled subgroup operation!");
8625
}
8626
8627
// get the right Group Operation
8628
spv::GroupOperation groupOperation = spv::GroupOperationMax;
8629
switch (op) {
8630
default:
8631
break;
8632
case glslang::EOpSubgroupBallotBitCount:
8633
case glslang::EOpSubgroupAdd:
8634
case glslang::EOpSubgroupMul:
8635
case glslang::EOpSubgroupMin:
8636
case glslang::EOpSubgroupMax:
8637
case glslang::EOpSubgroupAnd:
8638
case glslang::EOpSubgroupOr:
8639
case glslang::EOpSubgroupXor:
8640
groupOperation = spv::GroupOperationReduce;
8641
break;
8642
case glslang::EOpSubgroupBallotInclusiveBitCount:
8643
case glslang::EOpSubgroupInclusiveAdd:
8644
case glslang::EOpSubgroupInclusiveMul:
8645
case glslang::EOpSubgroupInclusiveMin:
8646
case glslang::EOpSubgroupInclusiveMax:
8647
case glslang::EOpSubgroupInclusiveAnd:
8648
case glslang::EOpSubgroupInclusiveOr:
8649
case glslang::EOpSubgroupInclusiveXor:
8650
groupOperation = spv::GroupOperationInclusiveScan;
8651
break;
8652
case glslang::EOpSubgroupBallotExclusiveBitCount:
8653
case glslang::EOpSubgroupExclusiveAdd:
8654
case glslang::EOpSubgroupExclusiveMul:
8655
case glslang::EOpSubgroupExclusiveMin:
8656
case glslang::EOpSubgroupExclusiveMax:
8657
case glslang::EOpSubgroupExclusiveAnd:
8658
case glslang::EOpSubgroupExclusiveOr:
8659
case glslang::EOpSubgroupExclusiveXor:
8660
groupOperation = spv::GroupOperationExclusiveScan;
8661
break;
8662
case glslang::EOpSubgroupClusteredAdd:
8663
case glslang::EOpSubgroupClusteredMul:
8664
case glslang::EOpSubgroupClusteredMin:
8665
case glslang::EOpSubgroupClusteredMax:
8666
case glslang::EOpSubgroupClusteredAnd:
8667
case glslang::EOpSubgroupClusteredOr:
8668
case glslang::EOpSubgroupClusteredXor:
8669
groupOperation = spv::GroupOperationClusteredReduce;
8670
break;
8671
case glslang::EOpSubgroupPartitionedAdd:
8672
case glslang::EOpSubgroupPartitionedMul:
8673
case glslang::EOpSubgroupPartitionedMin:
8674
case glslang::EOpSubgroupPartitionedMax:
8675
case glslang::EOpSubgroupPartitionedAnd:
8676
case glslang::EOpSubgroupPartitionedOr:
8677
case glslang::EOpSubgroupPartitionedXor:
8678
groupOperation = spv::GroupOperationPartitionedReduceNV;
8679
break;
8680
case glslang::EOpSubgroupPartitionedInclusiveAdd:
8681
case glslang::EOpSubgroupPartitionedInclusiveMul:
8682
case glslang::EOpSubgroupPartitionedInclusiveMin:
8683
case glslang::EOpSubgroupPartitionedInclusiveMax:
8684
case glslang::EOpSubgroupPartitionedInclusiveAnd:
8685
case glslang::EOpSubgroupPartitionedInclusiveOr:
8686
case glslang::EOpSubgroupPartitionedInclusiveXor:
8687
groupOperation = spv::GroupOperationPartitionedInclusiveScanNV;
8688
break;
8689
case glslang::EOpSubgroupPartitionedExclusiveAdd:
8690
case glslang::EOpSubgroupPartitionedExclusiveMul:
8691
case glslang::EOpSubgroupPartitionedExclusiveMin:
8692
case glslang::EOpSubgroupPartitionedExclusiveMax:
8693
case glslang::EOpSubgroupPartitionedExclusiveAnd:
8694
case glslang::EOpSubgroupPartitionedExclusiveOr:
8695
case glslang::EOpSubgroupPartitionedExclusiveXor:
8696
groupOperation = spv::GroupOperationPartitionedExclusiveScanNV;
8697
break;
8698
}
8699
8700
// build the instruction
8701
std::vector<spv::IdImmediate> spvGroupOperands;
8702
8703
// Every operation begins with the Execution Scope operand.
8704
spv::IdImmediate executionScope = { true, builder.makeUintConstant(spv::ScopeSubgroup) };
8705
// All other ops need the execution scope. Quad Control Ops don't need scope, it's always Quad.
8706
if (opCode != spv::OpGroupNonUniformQuadAllKHR && opCode != spv::OpGroupNonUniformQuadAnyKHR) {
8707
spvGroupOperands.push_back(executionScope);
8708
}
8709
8710
// Next, for all operations that use a Group Operation, push that as an operand.
8711
if (groupOperation != spv::GroupOperationMax) {
8712
spv::IdImmediate groupOperand = { false, (unsigned)groupOperation };
8713
spvGroupOperands.push_back(groupOperand);
8714
}
8715
8716
// Push back the operands next.
8717
for (auto opIt = operands.cbegin(); opIt != operands.cend(); ++opIt) {
8718
spv::IdImmediate operand = { true, *opIt };
8719
spvGroupOperands.push_back(operand);
8720
}
8721
8722
// Some opcodes have additional operands.
8723
spv::Id directionId = spv::NoResult;
8724
switch (op) {
8725
default: break;
8726
case glslang::EOpSubgroupQuadSwapHorizontal: directionId = builder.makeUintConstant(0); break;
8727
case glslang::EOpSubgroupQuadSwapVertical: directionId = builder.makeUintConstant(1); break;
8728
case glslang::EOpSubgroupQuadSwapDiagonal: directionId = builder.makeUintConstant(2); break;
8729
}
8730
if (directionId != spv::NoResult) {
8731
spv::IdImmediate direction = { true, directionId };
8732
spvGroupOperands.push_back(direction);
8733
}
8734
8735
return builder.createOp(opCode, typeId, spvGroupOperands);
8736
}
8737
8738
spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::Decoration precision,
8739
spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy)
8740
{
8741
bool isUnsigned = isTypeUnsignedInt(typeProxy);
8742
bool isFloat = isTypeFloat(typeProxy);
8743
8744
spv::Op opCode = spv::OpNop;
8745
int extBuiltins = -1;
8746
int libCall = -1;
8747
size_t consumedOperands = operands.size();
8748
spv::Id typeId0 = 0;
8749
if (consumedOperands > 0)
8750
typeId0 = builder.getTypeId(operands[0]);
8751
spv::Id typeId1 = 0;
8752
if (consumedOperands > 1)
8753
typeId1 = builder.getTypeId(operands[1]);
8754
spv::Id frexpIntType = 0;
8755
8756
switch (op) {
8757
case glslang::EOpMin:
8758
if (isFloat)
8759
libCall = nanMinMaxClamp ? spv::GLSLstd450NMin : spv::GLSLstd450FMin;
8760
else if (isUnsigned)
8761
libCall = spv::GLSLstd450UMin;
8762
else
8763
libCall = spv::GLSLstd450SMin;
8764
builder.promoteScalar(precision, operands.front(), operands.back());
8765
break;
8766
case glslang::EOpModf:
8767
libCall = spv::GLSLstd450Modf;
8768
break;
8769
case glslang::EOpMax:
8770
if (isFloat)
8771
libCall = nanMinMaxClamp ? spv::GLSLstd450NMax : spv::GLSLstd450FMax;
8772
else if (isUnsigned)
8773
libCall = spv::GLSLstd450UMax;
8774
else
8775
libCall = spv::GLSLstd450SMax;
8776
builder.promoteScalar(precision, operands.front(), operands.back());
8777
break;
8778
case glslang::EOpPow:
8779
libCall = spv::GLSLstd450Pow;
8780
break;
8781
case glslang::EOpDot:
8782
opCode = spv::OpDot;
8783
break;
8784
case glslang::EOpAtan:
8785
libCall = spv::GLSLstd450Atan2;
8786
break;
8787
8788
case glslang::EOpClamp:
8789
if (isFloat)
8790
libCall = nanMinMaxClamp ? spv::GLSLstd450NClamp : spv::GLSLstd450FClamp;
8791
else if (isUnsigned)
8792
libCall = spv::GLSLstd450UClamp;
8793
else
8794
libCall = spv::GLSLstd450SClamp;
8795
builder.promoteScalar(precision, operands.front(), operands[1]);
8796
builder.promoteScalar(precision, operands.front(), operands[2]);
8797
break;
8798
case glslang::EOpMix:
8799
if (! builder.isBoolType(builder.getScalarTypeId(builder.getTypeId(operands.back())))) {
8800
assert(isFloat);
8801
libCall = spv::GLSLstd450FMix;
8802
} else {
8803
opCode = spv::OpSelect;
8804
std::swap(operands.front(), operands.back());
8805
}
8806
builder.promoteScalar(precision, operands.front(), operands.back());
8807
break;
8808
case glslang::EOpStep:
8809
libCall = spv::GLSLstd450Step;
8810
builder.promoteScalar(precision, operands.front(), operands.back());
8811
break;
8812
case glslang::EOpSmoothStep:
8813
libCall = spv::GLSLstd450SmoothStep;
8814
builder.promoteScalar(precision, operands[0], operands[2]);
8815
builder.promoteScalar(precision, operands[1], operands[2]);
8816
break;
8817
8818
case glslang::EOpDistance:
8819
libCall = spv::GLSLstd450Distance;
8820
break;
8821
case glslang::EOpCross:
8822
libCall = spv::GLSLstd450Cross;
8823
break;
8824
case glslang::EOpFaceForward:
8825
libCall = spv::GLSLstd450FaceForward;
8826
break;
8827
case glslang::EOpReflect:
8828
libCall = spv::GLSLstd450Reflect;
8829
break;
8830
case glslang::EOpRefract:
8831
libCall = spv::GLSLstd450Refract;
8832
break;
8833
case glslang::EOpBarrier:
8834
{
8835
// This is for the extended controlBarrier function, with four operands.
8836
// The unextended barrier() goes through createNoArgOperation.
8837
assert(operands.size() == 4);
8838
unsigned int executionScope = builder.getConstantScalar(operands[0]);
8839
unsigned int memoryScope = builder.getConstantScalar(operands[1]);
8840
unsigned int semantics = builder.getConstantScalar(operands[2]) | builder.getConstantScalar(operands[3]);
8841
builder.createControlBarrier((spv::Scope)executionScope, (spv::Scope)memoryScope,
8842
(spv::MemorySemanticsMask)semantics);
8843
if (semantics & (spv::MemorySemanticsMakeAvailableKHRMask |
8844
spv::MemorySemanticsMakeVisibleKHRMask |
8845
spv::MemorySemanticsOutputMemoryKHRMask |
8846
spv::MemorySemanticsVolatileMask)) {
8847
builder.addCapability(spv::CapabilityVulkanMemoryModelKHR);
8848
}
8849
if (glslangIntermediate->usingVulkanMemoryModel() && (executionScope == spv::ScopeDevice ||
8850
memoryScope == spv::ScopeDevice)) {
8851
builder.addCapability(spv::CapabilityVulkanMemoryModelDeviceScopeKHR);
8852
}
8853
return 0;
8854
}
8855
break;
8856
case glslang::EOpMemoryBarrier:
8857
{
8858
// This is for the extended memoryBarrier function, with three operands.
8859
// The unextended memoryBarrier() goes through createNoArgOperation.
8860
assert(operands.size() == 3);
8861
unsigned int memoryScope = builder.getConstantScalar(operands[0]);
8862
unsigned int semantics = builder.getConstantScalar(operands[1]) | builder.getConstantScalar(operands[2]);
8863
builder.createMemoryBarrier((spv::Scope)memoryScope, (spv::MemorySemanticsMask)semantics);
8864
if (semantics & (spv::MemorySemanticsMakeAvailableKHRMask |
8865
spv::MemorySemanticsMakeVisibleKHRMask |
8866
spv::MemorySemanticsOutputMemoryKHRMask |
8867
spv::MemorySemanticsVolatileMask)) {
8868
builder.addCapability(spv::CapabilityVulkanMemoryModelKHR);
8869
}
8870
if (glslangIntermediate->usingVulkanMemoryModel() && memoryScope == spv::ScopeDevice) {
8871
builder.addCapability(spv::CapabilityVulkanMemoryModelDeviceScopeKHR);
8872
}
8873
return 0;
8874
}
8875
break;
8876
8877
case glslang::EOpInterpolateAtSample:
8878
if (typeProxy == glslang::EbtFloat16)
8879
builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float);
8880
libCall = spv::GLSLstd450InterpolateAtSample;
8881
break;
8882
case glslang::EOpInterpolateAtOffset:
8883
if (typeProxy == glslang::EbtFloat16)
8884
builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float);
8885
libCall = spv::GLSLstd450InterpolateAtOffset;
8886
break;
8887
case glslang::EOpAddCarry:
8888
opCode = spv::OpIAddCarry;
8889
typeId = builder.makeStructResultType(typeId0, typeId0);
8890
consumedOperands = 2;
8891
break;
8892
case glslang::EOpSubBorrow:
8893
opCode = spv::OpISubBorrow;
8894
typeId = builder.makeStructResultType(typeId0, typeId0);
8895
consumedOperands = 2;
8896
break;
8897
case glslang::EOpUMulExtended:
8898
opCode = spv::OpUMulExtended;
8899
typeId = builder.makeStructResultType(typeId0, typeId0);
8900
consumedOperands = 2;
8901
break;
8902
case glslang::EOpIMulExtended:
8903
opCode = spv::OpSMulExtended;
8904
typeId = builder.makeStructResultType(typeId0, typeId0);
8905
consumedOperands = 2;
8906
break;
8907
case glslang::EOpBitfieldExtract:
8908
if (isUnsigned)
8909
opCode = spv::OpBitFieldUExtract;
8910
else
8911
opCode = spv::OpBitFieldSExtract;
8912
break;
8913
case glslang::EOpBitfieldInsert:
8914
opCode = spv::OpBitFieldInsert;
8915
break;
8916
8917
case glslang::EOpFma:
8918
libCall = spv::GLSLstd450Fma;
8919
break;
8920
case glslang::EOpFrexp:
8921
{
8922
libCall = spv::GLSLstd450FrexpStruct;
8923
assert(builder.isPointerType(typeId1));
8924
typeId1 = builder.getContainedTypeId(typeId1);
8925
int width = builder.getScalarTypeWidth(typeId1);
8926
if (width == 16)
8927
// Using 16-bit exp operand, enable extension SPV_AMD_gpu_shader_int16
8928
builder.addExtension(spv::E_SPV_AMD_gpu_shader_int16);
8929
if (builder.getNumComponents(operands[0]) == 1)
8930
frexpIntType = builder.makeIntegerType(width, true);
8931
else
8932
frexpIntType = builder.makeVectorType(builder.makeIntegerType(width, true),
8933
builder.getNumComponents(operands[0]));
8934
typeId = builder.makeStructResultType(typeId0, frexpIntType);
8935
consumedOperands = 1;
8936
}
8937
break;
8938
case glslang::EOpLdexp:
8939
libCall = spv::GLSLstd450Ldexp;
8940
break;
8941
8942
case glslang::EOpReadInvocation:
8943
return createInvocationsOperation(op, typeId, operands, typeProxy);
8944
8945
case glslang::EOpSubgroupBroadcast:
8946
case glslang::EOpSubgroupBallotBitExtract:
8947
case glslang::EOpSubgroupShuffle:
8948
case glslang::EOpSubgroupShuffleXor:
8949
case glslang::EOpSubgroupShuffleUp:
8950
case glslang::EOpSubgroupShuffleDown:
8951
case glslang::EOpSubgroupRotate:
8952
case glslang::EOpSubgroupClusteredRotate:
8953
case glslang::EOpSubgroupClusteredAdd:
8954
case glslang::EOpSubgroupClusteredMul:
8955
case glslang::EOpSubgroupClusteredMin:
8956
case glslang::EOpSubgroupClusteredMax:
8957
case glslang::EOpSubgroupClusteredAnd:
8958
case glslang::EOpSubgroupClusteredOr:
8959
case glslang::EOpSubgroupClusteredXor:
8960
case glslang::EOpSubgroupQuadBroadcast:
8961
case glslang::EOpSubgroupPartitionedAdd:
8962
case glslang::EOpSubgroupPartitionedMul:
8963
case glslang::EOpSubgroupPartitionedMin:
8964
case glslang::EOpSubgroupPartitionedMax:
8965
case glslang::EOpSubgroupPartitionedAnd:
8966
case glslang::EOpSubgroupPartitionedOr:
8967
case glslang::EOpSubgroupPartitionedXor:
8968
case glslang::EOpSubgroupPartitionedInclusiveAdd:
8969
case glslang::EOpSubgroupPartitionedInclusiveMul:
8970
case glslang::EOpSubgroupPartitionedInclusiveMin:
8971
case glslang::EOpSubgroupPartitionedInclusiveMax:
8972
case glslang::EOpSubgroupPartitionedInclusiveAnd:
8973
case glslang::EOpSubgroupPartitionedInclusiveOr:
8974
case glslang::EOpSubgroupPartitionedInclusiveXor:
8975
case glslang::EOpSubgroupPartitionedExclusiveAdd:
8976
case glslang::EOpSubgroupPartitionedExclusiveMul:
8977
case glslang::EOpSubgroupPartitionedExclusiveMin:
8978
case glslang::EOpSubgroupPartitionedExclusiveMax:
8979
case glslang::EOpSubgroupPartitionedExclusiveAnd:
8980
case glslang::EOpSubgroupPartitionedExclusiveOr:
8981
case glslang::EOpSubgroupPartitionedExclusiveXor:
8982
return createSubgroupOperation(op, typeId, operands, typeProxy);
8983
8984
case glslang::EOpSwizzleInvocations:
8985
extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_ballot);
8986
libCall = spv::SwizzleInvocationsAMD;
8987
break;
8988
case glslang::EOpSwizzleInvocationsMasked:
8989
extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_ballot);
8990
libCall = spv::SwizzleInvocationsMaskedAMD;
8991
break;
8992
case glslang::EOpWriteInvocation:
8993
extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_ballot);
8994
libCall = spv::WriteInvocationAMD;
8995
break;
8996
8997
case glslang::EOpMin3:
8998
extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_trinary_minmax);
8999
if (isFloat)
9000
libCall = spv::FMin3AMD;
9001
else {
9002
if (isUnsigned)
9003
libCall = spv::UMin3AMD;
9004
else
9005
libCall = spv::SMin3AMD;
9006
}
9007
break;
9008
case glslang::EOpMax3:
9009
extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_trinary_minmax);
9010
if (isFloat)
9011
libCall = spv::FMax3AMD;
9012
else {
9013
if (isUnsigned)
9014
libCall = spv::UMax3AMD;
9015
else
9016
libCall = spv::SMax3AMD;
9017
}
9018
break;
9019
case glslang::EOpMid3:
9020
extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_trinary_minmax);
9021
if (isFloat)
9022
libCall = spv::FMid3AMD;
9023
else {
9024
if (isUnsigned)
9025
libCall = spv::UMid3AMD;
9026
else
9027
libCall = spv::SMid3AMD;
9028
}
9029
break;
9030
9031
case glslang::EOpInterpolateAtVertex:
9032
if (typeProxy == glslang::EbtFloat16)
9033
builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float);
9034
extBuiltins = getExtBuiltins(spv::E_SPV_AMD_shader_explicit_vertex_parameter);
9035
libCall = spv::InterpolateAtVertexAMD;
9036
break;
9037
9038
case glslang::EOpReportIntersection:
9039
typeId = builder.makeBoolType();
9040
opCode = spv::OpReportIntersectionKHR;
9041
break;
9042
case glslang::EOpTraceNV:
9043
builder.createNoResultOp(spv::OpTraceNV, operands);
9044
return 0;
9045
case glslang::EOpTraceRayMotionNV:
9046
builder.addExtension(spv::E_SPV_NV_ray_tracing_motion_blur);
9047
builder.addCapability(spv::CapabilityRayTracingMotionBlurNV);
9048
builder.createNoResultOp(spv::OpTraceRayMotionNV, operands);
9049
return 0;
9050
case glslang::EOpTraceKHR:
9051
builder.createNoResultOp(spv::OpTraceRayKHR, operands);
9052
return 0;
9053
case glslang::EOpExecuteCallableNV:
9054
builder.createNoResultOp(spv::OpExecuteCallableNV, operands);
9055
return 0;
9056
case glslang::EOpExecuteCallableKHR:
9057
builder.createNoResultOp(spv::OpExecuteCallableKHR, operands);
9058
return 0;
9059
9060
case glslang::EOpRayQueryInitialize:
9061
builder.createNoResultOp(spv::OpRayQueryInitializeKHR, operands);
9062
return 0;
9063
case glslang::EOpRayQueryTerminate:
9064
builder.createNoResultOp(spv::OpRayQueryTerminateKHR, operands);
9065
return 0;
9066
case glslang::EOpRayQueryGenerateIntersection:
9067
builder.createNoResultOp(spv::OpRayQueryGenerateIntersectionKHR, operands);
9068
return 0;
9069
case glslang::EOpRayQueryConfirmIntersection:
9070
builder.createNoResultOp(spv::OpRayQueryConfirmIntersectionKHR, operands);
9071
return 0;
9072
case glslang::EOpRayQueryProceed:
9073
typeId = builder.makeBoolType();
9074
opCode = spv::OpRayQueryProceedKHR;
9075
break;
9076
case glslang::EOpRayQueryGetIntersectionType:
9077
typeId = builder.makeUintType(32);
9078
opCode = spv::OpRayQueryGetIntersectionTypeKHR;
9079
break;
9080
case glslang::EOpRayQueryGetRayTMin:
9081
typeId = builder.makeFloatType(32);
9082
opCode = spv::OpRayQueryGetRayTMinKHR;
9083
break;
9084
case glslang::EOpRayQueryGetRayFlags:
9085
typeId = builder.makeIntType(32);
9086
opCode = spv::OpRayQueryGetRayFlagsKHR;
9087
break;
9088
case glslang::EOpRayQueryGetIntersectionT:
9089
typeId = builder.makeFloatType(32);
9090
opCode = spv::OpRayQueryGetIntersectionTKHR;
9091
break;
9092
case glslang::EOpRayQueryGetIntersectionInstanceCustomIndex:
9093
typeId = builder.makeIntType(32);
9094
opCode = spv::OpRayQueryGetIntersectionInstanceCustomIndexKHR;
9095
break;
9096
case glslang::EOpRayQueryGetIntersectionInstanceId:
9097
typeId = builder.makeIntType(32);
9098
opCode = spv::OpRayQueryGetIntersectionInstanceIdKHR;
9099
break;
9100
case glslang::EOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffset:
9101
typeId = builder.makeUintType(32);
9102
opCode = spv::OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR;
9103
break;
9104
case glslang::EOpRayQueryGetIntersectionGeometryIndex:
9105
typeId = builder.makeIntType(32);
9106
opCode = spv::OpRayQueryGetIntersectionGeometryIndexKHR;
9107
break;
9108
case glslang::EOpRayQueryGetIntersectionPrimitiveIndex:
9109
typeId = builder.makeIntType(32);
9110
opCode = spv::OpRayQueryGetIntersectionPrimitiveIndexKHR;
9111
break;
9112
case glslang::EOpRayQueryGetIntersectionBarycentrics:
9113
typeId = builder.makeVectorType(builder.makeFloatType(32), 2);
9114
opCode = spv::OpRayQueryGetIntersectionBarycentricsKHR;
9115
break;
9116
case glslang::EOpRayQueryGetIntersectionFrontFace:
9117
typeId = builder.makeBoolType();
9118
opCode = spv::OpRayQueryGetIntersectionFrontFaceKHR;
9119
break;
9120
case glslang::EOpRayQueryGetIntersectionCandidateAABBOpaque:
9121
typeId = builder.makeBoolType();
9122
opCode = spv::OpRayQueryGetIntersectionCandidateAABBOpaqueKHR;
9123
break;
9124
case glslang::EOpRayQueryGetIntersectionObjectRayDirection:
9125
typeId = builder.makeVectorType(builder.makeFloatType(32), 3);
9126
opCode = spv::OpRayQueryGetIntersectionObjectRayDirectionKHR;
9127
break;
9128
case glslang::EOpRayQueryGetIntersectionObjectRayOrigin:
9129
typeId = builder.makeVectorType(builder.makeFloatType(32), 3);
9130
opCode = spv::OpRayQueryGetIntersectionObjectRayOriginKHR;
9131
break;
9132
case glslang::EOpRayQueryGetWorldRayDirection:
9133
typeId = builder.makeVectorType(builder.makeFloatType(32), 3);
9134
opCode = spv::OpRayQueryGetWorldRayDirectionKHR;
9135
break;
9136
case glslang::EOpRayQueryGetWorldRayOrigin:
9137
typeId = builder.makeVectorType(builder.makeFloatType(32), 3);
9138
opCode = spv::OpRayQueryGetWorldRayOriginKHR;
9139
break;
9140
case glslang::EOpRayQueryGetIntersectionObjectToWorld:
9141
typeId = builder.makeMatrixType(builder.makeFloatType(32), 4, 3);
9142
opCode = spv::OpRayQueryGetIntersectionObjectToWorldKHR;
9143
break;
9144
case glslang::EOpRayQueryGetIntersectionWorldToObject:
9145
typeId = builder.makeMatrixType(builder.makeFloatType(32), 4, 3);
9146
opCode = spv::OpRayQueryGetIntersectionWorldToObjectKHR;
9147
break;
9148
case glslang::EOpWritePackedPrimitiveIndices4x8NV:
9149
builder.createNoResultOp(spv::OpWritePackedPrimitiveIndices4x8NV, operands);
9150
return 0;
9151
case glslang::EOpEmitMeshTasksEXT:
9152
if (taskPayloadID)
9153
operands.push_back(taskPayloadID);
9154
// As per SPV_EXT_mesh_shader make it a terminating instruction in the current block
9155
builder.makeStatementTerminator(spv::OpEmitMeshTasksEXT, operands, "post-OpEmitMeshTasksEXT");
9156
return 0;
9157
case glslang::EOpSetMeshOutputsEXT:
9158
builder.createNoResultOp(spv::OpSetMeshOutputsEXT, operands);
9159
return 0;
9160
case glslang::EOpCooperativeMatrixMulAddNV:
9161
opCode = spv::OpCooperativeMatrixMulAddNV;
9162
break;
9163
case glslang::EOpHitObjectTraceRayNV:
9164
builder.createNoResultOp(spv::OpHitObjectTraceRayNV, operands);
9165
return 0;
9166
case glslang::EOpHitObjectTraceRayMotionNV:
9167
builder.createNoResultOp(spv::OpHitObjectTraceRayMotionNV, operands);
9168
return 0;
9169
case glslang::EOpHitObjectRecordHitNV:
9170
builder.createNoResultOp(spv::OpHitObjectRecordHitNV, operands);
9171
return 0;
9172
case glslang::EOpHitObjectRecordHitMotionNV:
9173
builder.createNoResultOp(spv::OpHitObjectRecordHitMotionNV, operands);
9174
return 0;
9175
case glslang::EOpHitObjectRecordHitWithIndexNV:
9176
builder.createNoResultOp(spv::OpHitObjectRecordHitWithIndexNV, operands);
9177
return 0;
9178
case glslang::EOpHitObjectRecordHitWithIndexMotionNV:
9179
builder.createNoResultOp(spv::OpHitObjectRecordHitWithIndexMotionNV, operands);
9180
return 0;
9181
case glslang::EOpHitObjectRecordMissNV:
9182
builder.createNoResultOp(spv::OpHitObjectRecordMissNV, operands);
9183
return 0;
9184
case glslang::EOpHitObjectRecordMissMotionNV:
9185
builder.createNoResultOp(spv::OpHitObjectRecordMissMotionNV, operands);
9186
return 0;
9187
case glslang::EOpHitObjectExecuteShaderNV:
9188
builder.createNoResultOp(spv::OpHitObjectExecuteShaderNV, operands);
9189
return 0;
9190
case glslang::EOpHitObjectIsEmptyNV:
9191
typeId = builder.makeBoolType();
9192
opCode = spv::OpHitObjectIsEmptyNV;
9193
break;
9194
case glslang::EOpHitObjectIsMissNV:
9195
typeId = builder.makeBoolType();
9196
opCode = spv::OpHitObjectIsMissNV;
9197
break;
9198
case glslang::EOpHitObjectIsHitNV:
9199
typeId = builder.makeBoolType();
9200
opCode = spv::OpHitObjectIsHitNV;
9201
break;
9202
case glslang::EOpHitObjectGetRayTMinNV:
9203
typeId = builder.makeFloatType(32);
9204
opCode = spv::OpHitObjectGetRayTMinNV;
9205
break;
9206
case glslang::EOpHitObjectGetRayTMaxNV:
9207
typeId = builder.makeFloatType(32);
9208
opCode = spv::OpHitObjectGetRayTMaxNV;
9209
break;
9210
case glslang::EOpHitObjectGetObjectRayOriginNV:
9211
typeId = builder.makeVectorType(builder.makeFloatType(32), 3);
9212
opCode = spv::OpHitObjectGetObjectRayOriginNV;
9213
break;
9214
case glslang::EOpHitObjectGetObjectRayDirectionNV:
9215
typeId = builder.makeVectorType(builder.makeFloatType(32), 3);
9216
opCode = spv::OpHitObjectGetObjectRayDirectionNV;
9217
break;
9218
case glslang::EOpHitObjectGetWorldRayOriginNV:
9219
typeId = builder.makeVectorType(builder.makeFloatType(32), 3);
9220
opCode = spv::OpHitObjectGetWorldRayOriginNV;
9221
break;
9222
case glslang::EOpHitObjectGetWorldRayDirectionNV:
9223
typeId = builder.makeVectorType(builder.makeFloatType(32), 3);
9224
opCode = spv::OpHitObjectGetWorldRayDirectionNV;
9225
break;
9226
case glslang::EOpHitObjectGetWorldToObjectNV:
9227
typeId = builder.makeMatrixType(builder.makeFloatType(32), 4, 3);
9228
opCode = spv::OpHitObjectGetWorldToObjectNV;
9229
break;
9230
case glslang::EOpHitObjectGetObjectToWorldNV:
9231
typeId = builder.makeMatrixType(builder.makeFloatType(32), 4, 3);
9232
opCode = spv::OpHitObjectGetObjectToWorldNV;
9233
break;
9234
case glslang::EOpHitObjectGetInstanceCustomIndexNV:
9235
typeId = builder.makeIntegerType(32, 1);
9236
opCode = spv::OpHitObjectGetInstanceCustomIndexNV;
9237
break;
9238
case glslang::EOpHitObjectGetInstanceIdNV:
9239
typeId = builder.makeIntegerType(32, 1);
9240
opCode = spv::OpHitObjectGetInstanceIdNV;
9241
break;
9242
case glslang::EOpHitObjectGetGeometryIndexNV:
9243
typeId = builder.makeIntegerType(32, 1);
9244
opCode = spv::OpHitObjectGetGeometryIndexNV;
9245
break;
9246
case glslang::EOpHitObjectGetPrimitiveIndexNV:
9247
typeId = builder.makeIntegerType(32, 1);
9248
opCode = spv::OpHitObjectGetPrimitiveIndexNV;
9249
break;
9250
case glslang::EOpHitObjectGetHitKindNV:
9251
typeId = builder.makeIntegerType(32, 0);
9252
opCode = spv::OpHitObjectGetHitKindNV;
9253
break;
9254
case glslang::EOpHitObjectGetCurrentTimeNV:
9255
typeId = builder.makeFloatType(32);
9256
opCode = spv::OpHitObjectGetCurrentTimeNV;
9257
break;
9258
case glslang::EOpHitObjectGetShaderBindingTableRecordIndexNV:
9259
typeId = builder.makeIntegerType(32, 0);
9260
opCode = spv::OpHitObjectGetShaderBindingTableRecordIndexNV;
9261
return 0;
9262
case glslang::EOpHitObjectGetAttributesNV:
9263
builder.createNoResultOp(spv::OpHitObjectGetAttributesNV, operands);
9264
return 0;
9265
case glslang::EOpHitObjectGetShaderRecordBufferHandleNV:
9266
typeId = builder.makeVectorType(builder.makeUintType(32), 2);
9267
opCode = spv::OpHitObjectGetShaderRecordBufferHandleNV;
9268
break;
9269
case glslang::EOpReorderThreadNV: {
9270
if (operands.size() == 2) {
9271
builder.createNoResultOp(spv::OpReorderThreadWithHintNV, operands);
9272
} else {
9273
builder.createNoResultOp(spv::OpReorderThreadWithHitObjectNV, operands);
9274
}
9275
return 0;
9276
9277
}
9278
9279
case glslang::EOpImageSampleWeightedQCOM:
9280
typeId = builder.makeVectorType(builder.makeFloatType(32), 4);
9281
opCode = spv::OpImageSampleWeightedQCOM;
9282
addImageProcessingQCOMDecoration(operands[2], spv::DecorationWeightTextureQCOM);
9283
break;
9284
case glslang::EOpImageBoxFilterQCOM:
9285
typeId = builder.makeVectorType(builder.makeFloatType(32), 4);
9286
opCode = spv::OpImageBoxFilterQCOM;
9287
break;
9288
case glslang::EOpImageBlockMatchSADQCOM:
9289
typeId = builder.makeVectorType(builder.makeFloatType(32), 4);
9290
opCode = spv::OpImageBlockMatchSADQCOM;
9291
addImageProcessingQCOMDecoration(operands[0], spv::DecorationBlockMatchTextureQCOM);
9292
addImageProcessingQCOMDecoration(operands[2], spv::DecorationBlockMatchTextureQCOM);
9293
break;
9294
case glslang::EOpImageBlockMatchSSDQCOM:
9295
typeId = builder.makeVectorType(builder.makeFloatType(32), 4);
9296
opCode = spv::OpImageBlockMatchSSDQCOM;
9297
addImageProcessingQCOMDecoration(operands[0], spv::DecorationBlockMatchTextureQCOM);
9298
addImageProcessingQCOMDecoration(operands[2], spv::DecorationBlockMatchTextureQCOM);
9299
break;
9300
9301
case glslang::EOpFetchMicroTriangleVertexBarycentricNV:
9302
typeId = builder.makeVectorType(builder.makeFloatType(32), 2);
9303
opCode = spv::OpFetchMicroTriangleVertexBarycentricNV;
9304
break;
9305
9306
case glslang::EOpFetchMicroTriangleVertexPositionNV:
9307
typeId = builder.makeVectorType(builder.makeFloatType(32), 3);
9308
opCode = spv::OpFetchMicroTriangleVertexPositionNV;
9309
break;
9310
9311
case glslang::EOpImageBlockMatchWindowSSDQCOM:
9312
typeId = builder.makeVectorType(builder.makeFloatType(32), 4);
9313
opCode = spv::OpImageBlockMatchWindowSSDQCOM;
9314
addImageProcessing2QCOMDecoration(operands[0], false);
9315
addImageProcessing2QCOMDecoration(operands[2], false);
9316
break;
9317
case glslang::EOpImageBlockMatchWindowSADQCOM:
9318
typeId = builder.makeVectorType(builder.makeFloatType(32), 4);
9319
opCode = spv::OpImageBlockMatchWindowSADQCOM;
9320
addImageProcessing2QCOMDecoration(operands[0], false);
9321
addImageProcessing2QCOMDecoration(operands[2], false);
9322
break;
9323
case glslang::EOpImageBlockMatchGatherSSDQCOM:
9324
typeId = builder.makeVectorType(builder.makeFloatType(32), 4);
9325
opCode = spv::OpImageBlockMatchGatherSSDQCOM;
9326
addImageProcessing2QCOMDecoration(operands[0], true);
9327
addImageProcessing2QCOMDecoration(operands[2], true);
9328
break;
9329
case glslang::EOpImageBlockMatchGatherSADQCOM:
9330
typeId = builder.makeVectorType(builder.makeFloatType(32), 4);
9331
opCode = spv::OpImageBlockMatchGatherSADQCOM;
9332
addImageProcessing2QCOMDecoration(operands[0], true);
9333
addImageProcessing2QCOMDecoration(operands[2], true);
9334
break;
9335
default:
9336
return 0;
9337
}
9338
9339
spv::Id id = 0;
9340
if (libCall >= 0) {
9341
// Use an extended instruction from the standard library.
9342
// Construct the call arguments, without modifying the original operands vector.
9343
// We might need the remaining arguments, e.g. in the EOpFrexp case.
9344
std::vector<spv::Id> callArguments(operands.begin(), operands.begin() + consumedOperands);
9345
id = builder.createBuiltinCall(typeId, extBuiltins >= 0 ? extBuiltins : stdBuiltins, libCall, callArguments);
9346
} else if (opCode == spv::OpDot && !isFloat) {
9347
// int dot(int, int)
9348
// NOTE: never called for scalar/vector1, this is turned into simple mul before this can be reached
9349
const int componentCount = builder.getNumComponents(operands[0]);
9350
spv::Id mulOp = builder.createBinOp(spv::OpIMul, builder.getTypeId(operands[0]), operands[0], operands[1]);
9351
builder.setPrecision(mulOp, precision);
9352
id = builder.createCompositeExtract(mulOp, typeId, 0);
9353
for (int i = 1; i < componentCount; ++i) {
9354
builder.setPrecision(id, precision);
9355
id = builder.createBinOp(spv::OpIAdd, typeId, id, builder.createCompositeExtract(mulOp, typeId, i));
9356
}
9357
} else {
9358
switch (consumedOperands) {
9359
case 0:
9360
// should all be handled by visitAggregate and createNoArgOperation
9361
assert(0);
9362
return 0;
9363
case 1:
9364
// should all be handled by createUnaryOperation
9365
assert(0);
9366
return 0;
9367
case 2:
9368
id = builder.createBinOp(opCode, typeId, operands[0], operands[1]);
9369
break;
9370
default:
9371
// anything 3 or over doesn't have l-value operands, so all should be consumed
9372
assert(consumedOperands == operands.size());
9373
id = builder.createOp(opCode, typeId, operands);
9374
break;
9375
}
9376
}
9377
9378
// Decode the return types that were structures
9379
switch (op) {
9380
case glslang::EOpAddCarry:
9381
case glslang::EOpSubBorrow:
9382
builder.createStore(builder.createCompositeExtract(id, typeId0, 1), operands[2]);
9383
id = builder.createCompositeExtract(id, typeId0, 0);
9384
break;
9385
case glslang::EOpUMulExtended:
9386
case glslang::EOpIMulExtended:
9387
builder.createStore(builder.createCompositeExtract(id, typeId0, 0), operands[3]);
9388
builder.createStore(builder.createCompositeExtract(id, typeId0, 1), operands[2]);
9389
break;
9390
case glslang::EOpFrexp:
9391
{
9392
assert(operands.size() == 2);
9393
if (builder.isFloatType(builder.getScalarTypeId(typeId1))) {
9394
// "exp" is floating-point type (from HLSL intrinsic)
9395
spv::Id member1 = builder.createCompositeExtract(id, frexpIntType, 1);
9396
member1 = builder.createUnaryOp(spv::OpConvertSToF, typeId1, member1);
9397
builder.createStore(member1, operands[1]);
9398
} else
9399
// "exp" is integer type (from GLSL built-in function)
9400
builder.createStore(builder.createCompositeExtract(id, frexpIntType, 1), operands[1]);
9401
id = builder.createCompositeExtract(id, typeId0, 0);
9402
}
9403
break;
9404
default:
9405
break;
9406
}
9407
9408
return builder.setPrecision(id, precision);
9409
}
9410
9411
// Intrinsics with no arguments (or no return value, and no precision).
9412
spv::Id TGlslangToSpvTraverser::createNoArgOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId)
9413
{
9414
// GLSL memory barriers use queuefamily scope in new model, device scope in old model
9415
spv::Scope memoryBarrierScope = glslangIntermediate->usingVulkanMemoryModel() ?
9416
spv::ScopeQueueFamilyKHR : spv::ScopeDevice;
9417
9418
switch (op) {
9419
case glslang::EOpBarrier:
9420
if (glslangIntermediate->getStage() == EShLangTessControl) {
9421
if (glslangIntermediate->usingVulkanMemoryModel()) {
9422
builder.createControlBarrier(spv::ScopeWorkgroup, spv::ScopeWorkgroup,
9423
spv::MemorySemanticsOutputMemoryKHRMask |
9424
spv::MemorySemanticsAcquireReleaseMask);
9425
builder.addCapability(spv::CapabilityVulkanMemoryModelKHR);
9426
} else {
9427
builder.createControlBarrier(spv::ScopeWorkgroup, spv::ScopeInvocation, spv::MemorySemanticsMaskNone);
9428
}
9429
} else {
9430
builder.createControlBarrier(spv::ScopeWorkgroup, spv::ScopeWorkgroup,
9431
spv::MemorySemanticsWorkgroupMemoryMask |
9432
spv::MemorySemanticsAcquireReleaseMask);
9433
}
9434
return 0;
9435
case glslang::EOpMemoryBarrier:
9436
builder.createMemoryBarrier(memoryBarrierScope, spv::MemorySemanticsAllMemory |
9437
spv::MemorySemanticsAcquireReleaseMask);
9438
return 0;
9439
case glslang::EOpMemoryBarrierBuffer:
9440
builder.createMemoryBarrier(memoryBarrierScope, spv::MemorySemanticsUniformMemoryMask |
9441
spv::MemorySemanticsAcquireReleaseMask);
9442
return 0;
9443
case glslang::EOpMemoryBarrierShared:
9444
builder.createMemoryBarrier(memoryBarrierScope, spv::MemorySemanticsWorkgroupMemoryMask |
9445
spv::MemorySemanticsAcquireReleaseMask);
9446
return 0;
9447
case glslang::EOpGroupMemoryBarrier:
9448
builder.createMemoryBarrier(spv::ScopeWorkgroup, spv::MemorySemanticsAllMemory |
9449
spv::MemorySemanticsAcquireReleaseMask);
9450
return 0;
9451
case glslang::EOpMemoryBarrierAtomicCounter:
9452
builder.createMemoryBarrier(memoryBarrierScope, spv::MemorySemanticsAtomicCounterMemoryMask |
9453
spv::MemorySemanticsAcquireReleaseMask);
9454
return 0;
9455
case glslang::EOpMemoryBarrierImage:
9456
builder.createMemoryBarrier(memoryBarrierScope, spv::MemorySemanticsImageMemoryMask |
9457
spv::MemorySemanticsAcquireReleaseMask);
9458
return 0;
9459
case glslang::EOpAllMemoryBarrierWithGroupSync:
9460
builder.createControlBarrier(spv::ScopeWorkgroup, spv::ScopeDevice,
9461
spv::MemorySemanticsAllMemory |
9462
spv::MemorySemanticsAcquireReleaseMask);
9463
return 0;
9464
case glslang::EOpDeviceMemoryBarrier:
9465
builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsUniformMemoryMask |
9466
spv::MemorySemanticsImageMemoryMask |
9467
spv::MemorySemanticsAcquireReleaseMask);
9468
return 0;
9469
case glslang::EOpDeviceMemoryBarrierWithGroupSync:
9470
builder.createControlBarrier(spv::ScopeWorkgroup, spv::ScopeDevice, spv::MemorySemanticsUniformMemoryMask |
9471
spv::MemorySemanticsImageMemoryMask |
9472
spv::MemorySemanticsAcquireReleaseMask);
9473
return 0;
9474
case glslang::EOpWorkgroupMemoryBarrier:
9475
builder.createMemoryBarrier(spv::ScopeWorkgroup, spv::MemorySemanticsWorkgroupMemoryMask |
9476
spv::MemorySemanticsAcquireReleaseMask);
9477
return 0;
9478
case glslang::EOpWorkgroupMemoryBarrierWithGroupSync:
9479
builder.createControlBarrier(spv::ScopeWorkgroup, spv::ScopeWorkgroup,
9480
spv::MemorySemanticsWorkgroupMemoryMask |
9481
spv::MemorySemanticsAcquireReleaseMask);
9482
return 0;
9483
case glslang::EOpSubgroupBarrier:
9484
builder.createControlBarrier(spv::ScopeSubgroup, spv::ScopeSubgroup, spv::MemorySemanticsAllMemory |
9485
spv::MemorySemanticsAcquireReleaseMask);
9486
return spv::NoResult;
9487
case glslang::EOpSubgroupMemoryBarrier:
9488
builder.createMemoryBarrier(spv::ScopeSubgroup, spv::MemorySemanticsAllMemory |
9489
spv::MemorySemanticsAcquireReleaseMask);
9490
return spv::NoResult;
9491
case glslang::EOpSubgroupMemoryBarrierBuffer:
9492
builder.createMemoryBarrier(spv::ScopeSubgroup, spv::MemorySemanticsUniformMemoryMask |
9493
spv::MemorySemanticsAcquireReleaseMask);
9494
return spv::NoResult;
9495
case glslang::EOpSubgroupMemoryBarrierImage:
9496
builder.createMemoryBarrier(spv::ScopeSubgroup, spv::MemorySemanticsImageMemoryMask |
9497
spv::MemorySemanticsAcquireReleaseMask);
9498
return spv::NoResult;
9499
case glslang::EOpSubgroupMemoryBarrierShared:
9500
builder.createMemoryBarrier(spv::ScopeSubgroup, spv::MemorySemanticsWorkgroupMemoryMask |
9501
spv::MemorySemanticsAcquireReleaseMask);
9502
return spv::NoResult;
9503
9504
case glslang::EOpEmitVertex:
9505
builder.createNoResultOp(spv::OpEmitVertex);
9506
return 0;
9507
case glslang::EOpEndPrimitive:
9508
builder.createNoResultOp(spv::OpEndPrimitive);
9509
return 0;
9510
9511
case glslang::EOpSubgroupElect: {
9512
std::vector<spv::Id> operands;
9513
return createSubgroupOperation(op, typeId, operands, glslang::EbtVoid);
9514
}
9515
case glslang::EOpTime:
9516
{
9517
std::vector<spv::Id> args; // Dummy arguments
9518
spv::Id id = builder.createBuiltinCall(typeId, getExtBuiltins(spv::E_SPV_AMD_gcn_shader), spv::TimeAMD, args);
9519
return builder.setPrecision(id, precision);
9520
}
9521
case glslang::EOpIgnoreIntersectionNV:
9522
builder.createNoResultOp(spv::OpIgnoreIntersectionNV);
9523
return 0;
9524
case glslang::EOpTerminateRayNV:
9525
builder.createNoResultOp(spv::OpTerminateRayNV);
9526
return 0;
9527
case glslang::EOpRayQueryInitialize:
9528
builder.createNoResultOp(spv::OpRayQueryInitializeKHR);
9529
return 0;
9530
case glslang::EOpRayQueryTerminate:
9531
builder.createNoResultOp(spv::OpRayQueryTerminateKHR);
9532
return 0;
9533
case glslang::EOpRayQueryGenerateIntersection:
9534
builder.createNoResultOp(spv::OpRayQueryGenerateIntersectionKHR);
9535
return 0;
9536
case glslang::EOpRayQueryConfirmIntersection:
9537
builder.createNoResultOp(spv::OpRayQueryConfirmIntersectionKHR);
9538
return 0;
9539
case glslang::EOpBeginInvocationInterlock:
9540
builder.createNoResultOp(spv::OpBeginInvocationInterlockEXT);
9541
return 0;
9542
case glslang::EOpEndInvocationInterlock:
9543
builder.createNoResultOp(spv::OpEndInvocationInterlockEXT);
9544
return 0;
9545
9546
case glslang::EOpIsHelperInvocation:
9547
{
9548
std::vector<spv::Id> args; // Dummy arguments
9549
builder.addExtension(spv::E_SPV_EXT_demote_to_helper_invocation);
9550
builder.addCapability(spv::CapabilityDemoteToHelperInvocationEXT);
9551
return builder.createOp(spv::OpIsHelperInvocationEXT, typeId, args);
9552
}
9553
9554
case glslang::EOpReadClockSubgroupKHR: {
9555
std::vector<spv::Id> args;
9556
args.push_back(builder.makeUintConstant(spv::ScopeSubgroup));
9557
builder.addExtension(spv::E_SPV_KHR_shader_clock);
9558
builder.addCapability(spv::CapabilityShaderClockKHR);
9559
return builder.createOp(spv::OpReadClockKHR, typeId, args);
9560
}
9561
9562
case glslang::EOpReadClockDeviceKHR: {
9563
std::vector<spv::Id> args;
9564
args.push_back(builder.makeUintConstant(spv::ScopeDevice));
9565
builder.addExtension(spv::E_SPV_KHR_shader_clock);
9566
builder.addCapability(spv::CapabilityShaderClockKHR);
9567
return builder.createOp(spv::OpReadClockKHR, typeId, args);
9568
}
9569
case glslang::EOpStencilAttachmentReadEXT:
9570
case glslang::EOpDepthAttachmentReadEXT:
9571
{
9572
builder.addExtension(spv::E_SPV_EXT_shader_tile_image);
9573
9574
spv::Decoration precision;
9575
spv::Op spv_op;
9576
if (op == glslang::EOpStencilAttachmentReadEXT)
9577
{
9578
precision = spv::DecorationRelaxedPrecision;
9579
spv_op = spv::OpStencilAttachmentReadEXT;
9580
builder.addCapability(spv::CapabilityTileImageStencilReadAccessEXT);
9581
}
9582
else
9583
{
9584
precision = spv::NoPrecision;
9585
spv_op = spv::OpDepthAttachmentReadEXT;
9586
builder.addCapability(spv::CapabilityTileImageDepthReadAccessEXT);
9587
}
9588
9589
std::vector<spv::Id> args; // Dummy args
9590
spv::Id result = builder.createOp(spv_op, typeId, args);
9591
return builder.setPrecision(result, precision);
9592
}
9593
default:
9594
break;
9595
}
9596
9597
logger->missingFunctionality("unknown operation with no arguments");
9598
9599
return 0;
9600
}
9601
9602
spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol)
9603
{
9604
auto iter = symbolValues.find(symbol->getId());
9605
spv::Id id;
9606
if (symbolValues.end() != iter) {
9607
id = iter->second;
9608
return id;
9609
}
9610
9611
// it was not found, create it
9612
spv::BuiltIn builtIn = TranslateBuiltInDecoration(symbol->getQualifier().builtIn, false);
9613
auto forcedType = getForcedType(symbol->getQualifier().builtIn, symbol->getType());
9614
9615
// There are pairs of symbols that map to the same SPIR-V built-in:
9616
// gl_ObjectToWorldEXT and gl_ObjectToWorld3x4EXT, and gl_WorldToObjectEXT
9617
// and gl_WorldToObject3x4EXT. SPIR-V forbids having two OpVariables
9618
// with the same BuiltIn in the same storage class, so we must re-use one.
9619
const bool mayNeedToReuseBuiltIn =
9620
builtIn == spv::BuiltInObjectToWorldKHR ||
9621
builtIn == spv::BuiltInWorldToObjectKHR;
9622
9623
if (mayNeedToReuseBuiltIn) {
9624
auto iter = builtInVariableIds.find(uint32_t(builtIn));
9625
if (builtInVariableIds.end() != iter) {
9626
id = iter->second;
9627
symbolValues[symbol->getId()] = id;
9628
if (forcedType.second != spv::NoType)
9629
forceType[id] = forcedType.second;
9630
return id;
9631
}
9632
}
9633
9634
id = createSpvVariable(symbol, forcedType.first);
9635
9636
if (mayNeedToReuseBuiltIn) {
9637
builtInVariableIds.insert({uint32_t(builtIn), id});
9638
}
9639
9640
symbolValues[symbol->getId()] = id;
9641
if (forcedType.second != spv::NoType)
9642
forceType[id] = forcedType.second;
9643
9644
if (symbol->getBasicType() != glslang::EbtBlock) {
9645
builder.addDecoration(id, TranslatePrecisionDecoration(symbol->getType()));
9646
builder.addDecoration(id, TranslateInterpolationDecoration(symbol->getType().getQualifier()));
9647
builder.addDecoration(id, TranslateAuxiliaryStorageDecoration(symbol->getType().getQualifier()));
9648
addMeshNVDecoration(id, /*member*/ -1, symbol->getType().getQualifier());
9649
if (symbol->getQualifier().hasComponent())
9650
builder.addDecoration(id, spv::DecorationComponent, symbol->getQualifier().layoutComponent);
9651
if (symbol->getQualifier().hasIndex())
9652
builder.addDecoration(id, spv::DecorationIndex, symbol->getQualifier().layoutIndex);
9653
if (symbol->getType().getQualifier().hasSpecConstantId())
9654
builder.addDecoration(id, spv::DecorationSpecId, symbol->getType().getQualifier().layoutSpecConstantId);
9655
// atomic counters use this:
9656
if (symbol->getQualifier().hasOffset())
9657
builder.addDecoration(id, spv::DecorationOffset, symbol->getQualifier().layoutOffset);
9658
}
9659
9660
if (symbol->getQualifier().hasLocation()) {
9661
if (!(glslangIntermediate->isRayTracingStage() &&
9662
(glslangIntermediate->IsRequestedExtension(glslang::E_GL_EXT_ray_tracing) ||
9663
glslangIntermediate->IsRequestedExtension(glslang::E_GL_NV_shader_invocation_reorder))
9664
&& (builder.getStorageClass(id) == spv::StorageClassRayPayloadKHR ||
9665
builder.getStorageClass(id) == spv::StorageClassIncomingRayPayloadKHR ||
9666
builder.getStorageClass(id) == spv::StorageClassCallableDataKHR ||
9667
builder.getStorageClass(id) == spv::StorageClassIncomingCallableDataKHR ||
9668
builder.getStorageClass(id) == spv::StorageClassHitObjectAttributeNV))) {
9669
// Location values are used to link TraceRayKHR/ExecuteCallableKHR/HitObjectGetAttributesNV
9670
// to corresponding variables but are not valid in SPIRV since they are supported only
9671
// for Input/Output Storage classes.
9672
builder.addDecoration(id, spv::DecorationLocation, symbol->getQualifier().layoutLocation);
9673
}
9674
}
9675
9676
builder.addDecoration(id, TranslateInvariantDecoration(symbol->getType().getQualifier()));
9677
if (symbol->getQualifier().hasStream() && glslangIntermediate->isMultiStream()) {
9678
builder.addCapability(spv::CapabilityGeometryStreams);
9679
builder.addDecoration(id, spv::DecorationStream, symbol->getQualifier().layoutStream);
9680
}
9681
if (symbol->getQualifier().hasSet())
9682
builder.addDecoration(id, spv::DecorationDescriptorSet, symbol->getQualifier().layoutSet);
9683
else if (IsDescriptorResource(symbol->getType())) {
9684
// default to 0
9685
builder.addDecoration(id, spv::DecorationDescriptorSet, 0);
9686
}
9687
if (symbol->getQualifier().hasBinding())
9688
builder.addDecoration(id, spv::DecorationBinding, symbol->getQualifier().layoutBinding);
9689
else if (IsDescriptorResource(symbol->getType())) {
9690
// default to 0
9691
builder.addDecoration(id, spv::DecorationBinding, 0);
9692
}
9693
if (symbol->getQualifier().hasAttachment())
9694
builder.addDecoration(id, spv::DecorationInputAttachmentIndex, symbol->getQualifier().layoutAttachment);
9695
if (glslangIntermediate->getXfbMode()) {
9696
builder.addCapability(spv::CapabilityTransformFeedback);
9697
if (symbol->getQualifier().hasXfbBuffer()) {
9698
builder.addDecoration(id, spv::DecorationXfbBuffer, symbol->getQualifier().layoutXfbBuffer);
9699
unsigned stride = glslangIntermediate->getXfbStride(symbol->getQualifier().layoutXfbBuffer);
9700
if (stride != glslang::TQualifier::layoutXfbStrideEnd)
9701
builder.addDecoration(id, spv::DecorationXfbStride, stride);
9702
}
9703
if (symbol->getQualifier().hasXfbOffset())
9704
builder.addDecoration(id, spv::DecorationOffset, symbol->getQualifier().layoutXfbOffset);
9705
}
9706
9707
// add built-in variable decoration
9708
if (builtIn != spv::BuiltInMax) {
9709
// WorkgroupSize deprecated in spirv1.6
9710
if (glslangIntermediate->getSpv().spv < glslang::EShTargetSpv_1_6 ||
9711
builtIn != spv::BuiltInWorkgroupSize)
9712
builder.addDecoration(id, spv::DecorationBuiltIn, (int)builtIn);
9713
}
9714
9715
// Add volatile decoration to HelperInvocation for spirv1.6 and beyond
9716
if (builtIn == spv::BuiltInHelperInvocation &&
9717
!glslangIntermediate->usingVulkanMemoryModel() &&
9718
glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_6) {
9719
builder.addDecoration(id, spv::DecorationVolatile);
9720
}
9721
9722
// Subgroup builtins which have input storage class are volatile for ray tracing stages.
9723
if (symbol->getType().isImage() || symbol->getQualifier().isPipeInput()) {
9724
std::vector<spv::Decoration> memory;
9725
TranslateMemoryDecoration(symbol->getType().getQualifier(), memory,
9726
glslangIntermediate->usingVulkanMemoryModel());
9727
for (unsigned int i = 0; i < memory.size(); ++i)
9728
builder.addDecoration(id, memory[i]);
9729
}
9730
9731
if (builtIn == spv::BuiltInSampleMask) {
9732
spv::Decoration decoration;
9733
// GL_NV_sample_mask_override_coverage extension
9734
if (glslangIntermediate->getLayoutOverrideCoverage())
9735
decoration = (spv::Decoration)spv::DecorationOverrideCoverageNV;
9736
else
9737
decoration = (spv::Decoration)spv::DecorationMax;
9738
builder.addDecoration(id, decoration);
9739
if (decoration != spv::DecorationMax) {
9740
builder.addCapability(spv::CapabilitySampleMaskOverrideCoverageNV);
9741
builder.addExtension(spv::E_SPV_NV_sample_mask_override_coverage);
9742
}
9743
}
9744
else if (builtIn == spv::BuiltInLayer) {
9745
// SPV_NV_viewport_array2 extension
9746
if (symbol->getQualifier().layoutViewportRelative) {
9747
builder.addDecoration(id, (spv::Decoration)spv::DecorationViewportRelativeNV);
9748
builder.addCapability(spv::CapabilityShaderViewportMaskNV);
9749
builder.addExtension(spv::E_SPV_NV_viewport_array2);
9750
}
9751
if (symbol->getQualifier().layoutSecondaryViewportRelativeOffset != -2048) {
9752
builder.addDecoration(id, (spv::Decoration)spv::DecorationSecondaryViewportRelativeNV,
9753
symbol->getQualifier().layoutSecondaryViewportRelativeOffset);
9754
builder.addCapability(spv::CapabilityShaderStereoViewNV);
9755
builder.addExtension(spv::E_SPV_NV_stereo_view_rendering);
9756
}
9757
}
9758
9759
if (symbol->getQualifier().layoutPassthrough) {
9760
builder.addDecoration(id, spv::DecorationPassthroughNV);
9761
builder.addCapability(spv::CapabilityGeometryShaderPassthroughNV);
9762
builder.addExtension(spv::E_SPV_NV_geometry_shader_passthrough);
9763
}
9764
if (symbol->getQualifier().pervertexNV) {
9765
builder.addDecoration(id, spv::DecorationPerVertexNV);
9766
builder.addCapability(spv::CapabilityFragmentBarycentricNV);
9767
builder.addExtension(spv::E_SPV_NV_fragment_shader_barycentric);
9768
}
9769
9770
if (symbol->getQualifier().pervertexEXT) {
9771
builder.addDecoration(id, spv::DecorationPerVertexKHR);
9772
builder.addCapability(spv::CapabilityFragmentBarycentricKHR);
9773
builder.addExtension(spv::E_SPV_KHR_fragment_shader_barycentric);
9774
}
9775
9776
if (glslangIntermediate->getHlslFunctionality1() && symbol->getType().getQualifier().semanticName != nullptr) {
9777
builder.addExtension("SPV_GOOGLE_hlsl_functionality1");
9778
builder.addDecoration(id, (spv::Decoration)spv::DecorationHlslSemanticGOOGLE,
9779
symbol->getType().getQualifier().semanticName);
9780
}
9781
9782
if (symbol->isReference()) {
9783
builder.addDecoration(id, symbol->getType().getQualifier().restrict ?
9784
spv::DecorationRestrictPointerEXT : spv::DecorationAliasedPointerEXT);
9785
}
9786
9787
// Add SPIR-V decorations (GL_EXT_spirv_intrinsics)
9788
if (symbol->getType().getQualifier().hasSpirvDecorate())
9789
applySpirvDecorate(symbol->getType(), id, {});
9790
9791
return id;
9792
}
9793
9794
// add per-primitive, per-view. per-task decorations to a struct member (member >= 0) or an object
9795
void TGlslangToSpvTraverser::addMeshNVDecoration(spv::Id id, int member, const glslang::TQualifier& qualifier)
9796
{
9797
bool isMeshShaderExt = (glslangIntermediate->getRequestedExtensions().find(glslang::E_GL_EXT_mesh_shader) !=
9798
glslangIntermediate->getRequestedExtensions().end());
9799
9800
if (member >= 0) {
9801
if (qualifier.perPrimitiveNV) {
9802
// Need to add capability/extension for fragment shader.
9803
// Mesh shader already adds this by default.
9804
if (glslangIntermediate->getStage() == EShLangFragment) {
9805
if(isMeshShaderExt) {
9806
builder.addCapability(spv::CapabilityMeshShadingEXT);
9807
builder.addExtension(spv::E_SPV_EXT_mesh_shader);
9808
} else {
9809
builder.addCapability(spv::CapabilityMeshShadingNV);
9810
builder.addExtension(spv::E_SPV_NV_mesh_shader);
9811
}
9812
}
9813
builder.addMemberDecoration(id, (unsigned)member, spv::DecorationPerPrimitiveNV);
9814
}
9815
if (qualifier.perViewNV)
9816
builder.addMemberDecoration(id, (unsigned)member, spv::DecorationPerViewNV);
9817
if (qualifier.perTaskNV)
9818
builder.addMemberDecoration(id, (unsigned)member, spv::DecorationPerTaskNV);
9819
} else {
9820
if (qualifier.perPrimitiveNV) {
9821
// Need to add capability/extension for fragment shader.
9822
// Mesh shader already adds this by default.
9823
if (glslangIntermediate->getStage() == EShLangFragment) {
9824
if(isMeshShaderExt) {
9825
builder.addCapability(spv::CapabilityMeshShadingEXT);
9826
builder.addExtension(spv::E_SPV_EXT_mesh_shader);
9827
} else {
9828
builder.addCapability(spv::CapabilityMeshShadingNV);
9829
builder.addExtension(spv::E_SPV_NV_mesh_shader);
9830
}
9831
}
9832
builder.addDecoration(id, spv::DecorationPerPrimitiveNV);
9833
}
9834
if (qualifier.perViewNV)
9835
builder.addDecoration(id, spv::DecorationPerViewNV);
9836
if (qualifier.perTaskNV)
9837
builder.addDecoration(id, spv::DecorationPerTaskNV);
9838
}
9839
}
9840
9841
bool TGlslangToSpvTraverser::hasQCOMImageProceessingDecoration(spv::Id id, spv::Decoration decor)
9842
{
9843
std::vector<spv::Decoration> &decoVec = idToQCOMDecorations[id];
9844
for ( auto d : decoVec ) {
9845
if ( d == decor )
9846
return true;
9847
}
9848
return false;
9849
}
9850
9851
void TGlslangToSpvTraverser::addImageProcessingQCOMDecoration(spv::Id id, spv::Decoration decor)
9852
{
9853
spv::Op opc = builder.getOpCode(id);
9854
if (opc == spv::OpSampledImage) {
9855
id = builder.getIdOperand(id, 0);
9856
opc = builder.getOpCode(id);
9857
}
9858
9859
if (opc == spv::OpLoad) {
9860
spv::Id texid = builder.getIdOperand(id, 0);
9861
if (!hasQCOMImageProceessingDecoration(texid, decor)) {//
9862
builder.addDecoration(texid, decor);
9863
idToQCOMDecorations[texid].push_back(decor);
9864
}
9865
}
9866
}
9867
9868
void TGlslangToSpvTraverser::addImageProcessing2QCOMDecoration(spv::Id id, bool isForGather)
9869
{
9870
if (isForGather) {
9871
return addImageProcessingQCOMDecoration(id, spv::DecorationBlockMatchTextureQCOM);
9872
}
9873
9874
auto addDecor =
9875
[this](spv::Id id, spv::Decoration decor) {
9876
spv::Id tsopc = this->builder.getOpCode(id);
9877
if (tsopc == spv::OpLoad) {
9878
spv::Id tsid = this->builder.getIdOperand(id, 0);
9879
if (this->glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_4) {
9880
assert(iOSet.count(tsid) > 0);
9881
}
9882
if (!hasQCOMImageProceessingDecoration(tsid, decor)) {
9883
this->builder.addDecoration(tsid, decor);
9884
idToQCOMDecorations[tsid].push_back(decor);
9885
}
9886
}
9887
};
9888
9889
spv::Id opc = builder.getOpCode(id);
9890
bool isInterfaceObject = (opc != spv::OpSampledImage);
9891
9892
if (!isInterfaceObject) {
9893
addDecor(builder.getIdOperand(id, 0), spv::DecorationBlockMatchTextureQCOM);
9894
addDecor(builder.getIdOperand(id, 1), spv::DecorationBlockMatchSamplerQCOM);
9895
} else {
9896
addDecor(id, spv::DecorationBlockMatchTextureQCOM);
9897
addDecor(id, spv::DecorationBlockMatchSamplerQCOM);
9898
}
9899
}
9900
9901
// Make a full tree of instructions to build a SPIR-V specialization constant,
9902
// or regular constant if possible.
9903
//
9904
// TBD: this is not yet done, nor verified to be the best design, it does do the leaf symbols though
9905
//
9906
// Recursively walk the nodes. The nodes form a tree whose leaves are
9907
// regular constants, which themselves are trees that createSpvConstant()
9908
// recursively walks. So, this function walks the "top" of the tree:
9909
// - emit specialization constant-building instructions for specConstant
9910
// - when running into a non-spec-constant, switch to createSpvConstant()
9911
spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TIntermTyped& node)
9912
{
9913
assert(node.getQualifier().isConstant());
9914
9915
// Handle front-end constants first (non-specialization constants).
9916
if (! node.getQualifier().specConstant) {
9917
// hand off to the non-spec-constant path
9918
assert(node.getAsConstantUnion() != nullptr || node.getAsSymbolNode() != nullptr);
9919
int nextConst = 0;
9920
return createSpvConstantFromConstUnionArray(node.getType(), node.getAsConstantUnion() ?
9921
node.getAsConstantUnion()->getConstArray() : node.getAsSymbolNode()->getConstArray(),
9922
nextConst, false);
9923
}
9924
9925
// We now know we have a specialization constant to build
9926
9927
// Extra capabilities may be needed.
9928
if (node.getType().contains8BitInt())
9929
builder.addCapability(spv::CapabilityInt8);
9930
if (node.getType().contains16BitFloat())
9931
builder.addCapability(spv::CapabilityFloat16);
9932
if (node.getType().contains16BitInt())
9933
builder.addCapability(spv::CapabilityInt16);
9934
if (node.getType().contains64BitInt())
9935
builder.addCapability(spv::CapabilityInt64);
9936
if (node.getType().containsDouble())
9937
builder.addCapability(spv::CapabilityFloat64);
9938
9939
// gl_WorkGroupSize is a special case until the front-end handles hierarchical specialization constants,
9940
// even then, it's specialization ids are handled by special case syntax in GLSL: layout(local_size_x = ...
9941
if (node.getType().getQualifier().builtIn == glslang::EbvWorkGroupSize) {
9942
std::vector<spv::Id> dimConstId;
9943
for (int dim = 0; dim < 3; ++dim) {
9944
bool specConst = (glslangIntermediate->getLocalSizeSpecId(dim) != glslang::TQualifier::layoutNotSet);
9945
dimConstId.push_back(builder.makeUintConstant(glslangIntermediate->getLocalSize(dim), specConst));
9946
if (specConst) {
9947
builder.addDecoration(dimConstId.back(), spv::DecorationSpecId,
9948
glslangIntermediate->getLocalSizeSpecId(dim));
9949
}
9950
}
9951
return builder.makeCompositeConstant(builder.makeVectorType(builder.makeUintType(32), 3), dimConstId, true);
9952
}
9953
9954
// An AST node labelled as specialization constant should be a symbol node.
9955
// Its initializer should either be a sub tree with constant nodes, or a constant union array.
9956
if (auto* sn = node.getAsSymbolNode()) {
9957
spv::Id result;
9958
if (auto* sub_tree = sn->getConstSubtree()) {
9959
// Traverse the constant constructor sub tree like generating normal run-time instructions.
9960
// During the AST traversal, if the node is marked as 'specConstant', SpecConstantOpModeGuard
9961
// will set the builder into spec constant op instruction generating mode.
9962
sub_tree->traverse(this);
9963
result = accessChainLoad(sub_tree->getType());
9964
} else if (auto* const_union_array = &sn->getConstArray()) {
9965
int nextConst = 0;
9966
result = createSpvConstantFromConstUnionArray(sn->getType(), *const_union_array, nextConst, true);
9967
} else {
9968
logger->missingFunctionality("Invalid initializer for spec onstant.");
9969
return spv::NoResult;
9970
}
9971
builder.addName(result, sn->getName().c_str());
9972
return result;
9973
}
9974
9975
// Neither a front-end constant node, nor a specialization constant node with constant union array or
9976
// constant sub tree as initializer.
9977
logger->missingFunctionality("Neither a front-end constant nor a spec constant.");
9978
return spv::NoResult;
9979
}
9980
9981
// Use 'consts' as the flattened glslang source of scalar constants to recursively
9982
// build the aggregate SPIR-V constant.
9983
//
9984
// If there are not enough elements present in 'consts', 0 will be substituted;
9985
// an empty 'consts' can be used to create a fully zeroed SPIR-V constant.
9986
//
9987
spv::Id TGlslangToSpvTraverser::createSpvConstantFromConstUnionArray(const glslang::TType& glslangType,
9988
const glslang::TConstUnionArray& consts, int& nextConst, bool specConstant)
9989
{
9990
// vector of constants for SPIR-V
9991
std::vector<spv::Id> spvConsts;
9992
9993
// Type is used for struct and array constants
9994
spv::Id typeId = convertGlslangToSpvType(glslangType);
9995
9996
if (glslangType.isArray()) {
9997
glslang::TType elementType(glslangType, 0);
9998
for (int i = 0; i < glslangType.getOuterArraySize(); ++i)
9999
spvConsts.push_back(createSpvConstantFromConstUnionArray(elementType, consts, nextConst, false));
10000
} else if (glslangType.isMatrix()) {
10001
glslang::TType vectorType(glslangType, 0);
10002
for (int col = 0; col < glslangType.getMatrixCols(); ++col)
10003
spvConsts.push_back(createSpvConstantFromConstUnionArray(vectorType, consts, nextConst, false));
10004
} else if (glslangType.isCoopMat()) {
10005
glslang::TType componentType(glslangType.getBasicType());
10006
spvConsts.push_back(createSpvConstantFromConstUnionArray(componentType, consts, nextConst, false));
10007
} else if (glslangType.isStruct()) {
10008
glslang::TVector<glslang::TTypeLoc>::const_iterator iter;
10009
for (iter = glslangType.getStruct()->begin(); iter != glslangType.getStruct()->end(); ++iter)
10010
spvConsts.push_back(createSpvConstantFromConstUnionArray(*iter->type, consts, nextConst, false));
10011
} else if (glslangType.getVectorSize() > 1) {
10012
for (unsigned int i = 0; i < (unsigned int)glslangType.getVectorSize(); ++i) {
10013
bool zero = nextConst >= consts.size();
10014
switch (glslangType.getBasicType()) {
10015
case glslang::EbtInt:
10016
spvConsts.push_back(builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst()));
10017
break;
10018
case glslang::EbtUint:
10019
spvConsts.push_back(builder.makeUintConstant(zero ? 0 : consts[nextConst].getUConst()));
10020
break;
10021
case glslang::EbtFloat:
10022
spvConsts.push_back(builder.makeFloatConstant(zero ? 0.0F : (float)consts[nextConst].getDConst()));
10023
break;
10024
case glslang::EbtBool:
10025
spvConsts.push_back(builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst()));
10026
break;
10027
case glslang::EbtInt8:
10028
builder.addCapability(spv::CapabilityInt8);
10029
spvConsts.push_back(builder.makeInt8Constant(zero ? 0 : consts[nextConst].getI8Const()));
10030
break;
10031
case glslang::EbtUint8:
10032
builder.addCapability(spv::CapabilityInt8);
10033
spvConsts.push_back(builder.makeUint8Constant(zero ? 0 : consts[nextConst].getU8Const()));
10034
break;
10035
case glslang::EbtInt16:
10036
builder.addCapability(spv::CapabilityInt16);
10037
spvConsts.push_back(builder.makeInt16Constant(zero ? 0 : consts[nextConst].getI16Const()));
10038
break;
10039
case glslang::EbtUint16:
10040
builder.addCapability(spv::CapabilityInt16);
10041
spvConsts.push_back(builder.makeUint16Constant(zero ? 0 : consts[nextConst].getU16Const()));
10042
break;
10043
case glslang::EbtInt64:
10044
spvConsts.push_back(builder.makeInt64Constant(zero ? 0 : consts[nextConst].getI64Const()));
10045
break;
10046
case glslang::EbtUint64:
10047
spvConsts.push_back(builder.makeUint64Constant(zero ? 0 : consts[nextConst].getU64Const()));
10048
break;
10049
case glslang::EbtDouble:
10050
spvConsts.push_back(builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst()));
10051
break;
10052
case glslang::EbtFloat16:
10053
builder.addCapability(spv::CapabilityFloat16);
10054
spvConsts.push_back(builder.makeFloat16Constant(zero ? 0.0F : (float)consts[nextConst].getDConst()));
10055
break;
10056
default:
10057
assert(0);
10058
break;
10059
}
10060
++nextConst;
10061
}
10062
} else {
10063
// we have a non-aggregate (scalar) constant
10064
bool zero = nextConst >= consts.size();
10065
spv::Id scalar = 0;
10066
switch (glslangType.getBasicType()) {
10067
case glslang::EbtInt:
10068
scalar = builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst(), specConstant);
10069
break;
10070
case glslang::EbtUint:
10071
scalar = builder.makeUintConstant(zero ? 0 : consts[nextConst].getUConst(), specConstant);
10072
break;
10073
case glslang::EbtFloat:
10074
scalar = builder.makeFloatConstant(zero ? 0.0F : (float)consts[nextConst].getDConst(), specConstant);
10075
break;
10076
case glslang::EbtBool:
10077
scalar = builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst(), specConstant);
10078
break;
10079
case glslang::EbtInt8:
10080
builder.addCapability(spv::CapabilityInt8);
10081
scalar = builder.makeInt8Constant(zero ? 0 : consts[nextConst].getI8Const(), specConstant);
10082
break;
10083
case glslang::EbtUint8:
10084
builder.addCapability(spv::CapabilityInt8);
10085
scalar = builder.makeUint8Constant(zero ? 0 : consts[nextConst].getU8Const(), specConstant);
10086
break;
10087
case glslang::EbtInt16:
10088
builder.addCapability(spv::CapabilityInt16);
10089
scalar = builder.makeInt16Constant(zero ? 0 : consts[nextConst].getI16Const(), specConstant);
10090
break;
10091
case glslang::EbtUint16:
10092
builder.addCapability(spv::CapabilityInt16);
10093
scalar = builder.makeUint16Constant(zero ? 0 : consts[nextConst].getU16Const(), specConstant);
10094
break;
10095
case glslang::EbtInt64:
10096
scalar = builder.makeInt64Constant(zero ? 0 : consts[nextConst].getI64Const(), specConstant);
10097
break;
10098
case glslang::EbtUint64:
10099
scalar = builder.makeUint64Constant(zero ? 0 : consts[nextConst].getU64Const(), specConstant);
10100
break;
10101
case glslang::EbtDouble:
10102
scalar = builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst(), specConstant);
10103
break;
10104
case glslang::EbtFloat16:
10105
builder.addCapability(spv::CapabilityFloat16);
10106
scalar = builder.makeFloat16Constant(zero ? 0.0F : (float)consts[nextConst].getDConst(), specConstant);
10107
break;
10108
case glslang::EbtReference:
10109
scalar = builder.makeUint64Constant(zero ? 0 : consts[nextConst].getU64Const(), specConstant);
10110
scalar = builder.createUnaryOp(spv::OpBitcast, typeId, scalar);
10111
break;
10112
case glslang::EbtString:
10113
scalar = builder.getStringId(consts[nextConst].getSConst()->c_str());
10114
break;
10115
default:
10116
assert(0);
10117
break;
10118
}
10119
++nextConst;
10120
return scalar;
10121
}
10122
10123
return builder.makeCompositeConstant(typeId, spvConsts);
10124
}
10125
10126
// Return true if the node is a constant or symbol whose reading has no
10127
// non-trivial observable cost or effect.
10128
bool TGlslangToSpvTraverser::isTrivialLeaf(const glslang::TIntermTyped* node)
10129
{
10130
// don't know what this is
10131
if (node == nullptr)
10132
return false;
10133
10134
// a constant is safe
10135
if (node->getAsConstantUnion() != nullptr)
10136
return true;
10137
10138
// not a symbol means non-trivial
10139
if (node->getAsSymbolNode() == nullptr)
10140
return false;
10141
10142
// a symbol, depends on what's being read
10143
switch (node->getType().getQualifier().storage) {
10144
case glslang::EvqTemporary:
10145
case glslang::EvqGlobal:
10146
case glslang::EvqIn:
10147
case glslang::EvqInOut:
10148
case glslang::EvqConst:
10149
case glslang::EvqConstReadOnly:
10150
case glslang::EvqUniform:
10151
return true;
10152
default:
10153
return false;
10154
}
10155
}
10156
10157
// A node is trivial if it is a single operation with no side effects.
10158
// HLSL (and/or vectors) are always trivial, as it does not short circuit.
10159
// Otherwise, error on the side of saying non-trivial.
10160
// Return true if trivial.
10161
bool TGlslangToSpvTraverser::isTrivial(const glslang::TIntermTyped* node)
10162
{
10163
if (node == nullptr)
10164
return false;
10165
10166
// count non scalars as trivial, as well as anything coming from HLSL
10167
if (! node->getType().isScalarOrVec1() || glslangIntermediate->getSource() == glslang::EShSourceHlsl)
10168
return true;
10169
10170
// symbols and constants are trivial
10171
if (isTrivialLeaf(node))
10172
return true;
10173
10174
// otherwise, it needs to be a simple operation or one or two leaf nodes
10175
10176
// not a simple operation
10177
const glslang::TIntermBinary* binaryNode = node->getAsBinaryNode();
10178
const glslang::TIntermUnary* unaryNode = node->getAsUnaryNode();
10179
if (binaryNode == nullptr && unaryNode == nullptr)
10180
return false;
10181
10182
// not on leaf nodes
10183
if (binaryNode && (! isTrivialLeaf(binaryNode->getLeft()) || ! isTrivialLeaf(binaryNode->getRight())))
10184
return false;
10185
10186
if (unaryNode && ! isTrivialLeaf(unaryNode->getOperand())) {
10187
return false;
10188
}
10189
10190
switch (node->getAsOperator()->getOp()) {
10191
case glslang::EOpLogicalNot:
10192
case glslang::EOpConvIntToBool:
10193
case glslang::EOpConvUintToBool:
10194
case glslang::EOpConvFloatToBool:
10195
case glslang::EOpConvDoubleToBool:
10196
case glslang::EOpEqual:
10197
case glslang::EOpNotEqual:
10198
case glslang::EOpLessThan:
10199
case glslang::EOpGreaterThan:
10200
case glslang::EOpLessThanEqual:
10201
case glslang::EOpGreaterThanEqual:
10202
case glslang::EOpIndexDirect:
10203
case glslang::EOpIndexDirectStruct:
10204
case glslang::EOpLogicalXor:
10205
case glslang::EOpAny:
10206
case glslang::EOpAll:
10207
return true;
10208
default:
10209
return false;
10210
}
10211
}
10212
10213
// Emit short-circuiting code, where 'right' is never evaluated unless
10214
// the left side is true (for &&) or false (for ||).
10215
spv::Id TGlslangToSpvTraverser::createShortCircuit(glslang::TOperator op, glslang::TIntermTyped& left,
10216
glslang::TIntermTyped& right)
10217
{
10218
spv::Id boolTypeId = builder.makeBoolType();
10219
10220
// emit left operand
10221
builder.clearAccessChain();
10222
left.traverse(this);
10223
spv::Id leftId = accessChainLoad(left.getType());
10224
10225
// Operands to accumulate OpPhi operands
10226
std::vector<spv::Id> phiOperands;
10227
phiOperands.reserve(4);
10228
// accumulate left operand's phi information
10229
phiOperands.push_back(leftId);
10230
phiOperands.push_back(builder.getBuildPoint()->getId());
10231
10232
// Make the two kinds of operation symmetric with a "!"
10233
// || => emit "if (! left) result = right"
10234
// && => emit "if ( left) result = right"
10235
//
10236
// TODO: this runtime "not" for || could be avoided by adding functionality
10237
// to 'builder' to have an "else" without an "then"
10238
if (op == glslang::EOpLogicalOr)
10239
leftId = builder.createUnaryOp(spv::OpLogicalNot, boolTypeId, leftId);
10240
10241
// make an "if" based on the left value
10242
spv::Builder::If ifBuilder(leftId, spv::SelectionControlMaskNone, builder);
10243
10244
// emit right operand as the "then" part of the "if"
10245
builder.clearAccessChain();
10246
right.traverse(this);
10247
spv::Id rightId = accessChainLoad(right.getType());
10248
10249
// accumulate left operand's phi information
10250
phiOperands.push_back(rightId);
10251
phiOperands.push_back(builder.getBuildPoint()->getId());
10252
10253
// finish the "if"
10254
ifBuilder.makeEndIf();
10255
10256
// phi together the two results
10257
return builder.createOp(spv::OpPhi, boolTypeId, phiOperands);
10258
}
10259
10260
// Return type Id of the imported set of extended instructions corresponds to the name.
10261
// Import this set if it has not been imported yet.
10262
spv::Id TGlslangToSpvTraverser::getExtBuiltins(const char* name)
10263
{
10264
if (extBuiltinMap.find(name) != extBuiltinMap.end())
10265
return extBuiltinMap[name];
10266
else {
10267
spv::Id extBuiltins = builder.import(name);
10268
extBuiltinMap[name] = extBuiltins;
10269
return extBuiltins;
10270
}
10271
}
10272
10273
}; // end anonymous namespace
10274
10275
namespace glslang {
10276
10277
void GetSpirvVersion(std::string& version)
10278
{
10279
const int bufSize = 100;
10280
char buf[bufSize];
10281
snprintf(buf, bufSize, "0x%08x, Revision %d", spv::Version, spv::Revision);
10282
version = buf;
10283
}
10284
10285
// For low-order part of the generator's magic number. Bump up
10286
// when there is a change in the style (e.g., if SSA form changes,
10287
// or a different instruction sequence to do something gets used).
10288
int GetSpirvGeneratorVersion()
10289
{
10290
// return 1; // start
10291
// return 2; // EOpAtomicCounterDecrement gets a post decrement, to map between GLSL -> SPIR-V
10292
// return 3; // change/correct barrier-instruction operands, to match memory model group decisions
10293
// return 4; // some deeper access chains: for dynamic vector component, and local Boolean component
10294
// return 5; // make OpArrayLength result type be an int with signedness of 0
10295
// return 6; // revert version 5 change, which makes a different (new) kind of incorrect code,
10296
// versions 4 and 6 each generate OpArrayLength as it has long been done
10297
// return 7; // GLSL volatile keyword maps to both SPIR-V decorations Volatile and Coherent
10298
// return 8; // switch to new dead block eliminator; use OpUnreachable
10299
// return 9; // don't include opaque function parameters in OpEntryPoint global's operand list
10300
// return 10; // Generate OpFUnordNotEqual for != comparisons
10301
return 11; // Make OpEmitMeshTasksEXT a terminal instruction
10302
}
10303
10304
// Write SPIR-V out to a binary file
10305
bool OutputSpvBin(const std::vector<unsigned int>& spirv, const char* baseName)
10306
{
10307
std::ofstream out;
10308
out.open(baseName, std::ios::binary | std::ios::out);
10309
if (out.fail()) {
10310
printf("ERROR: Failed to open file: %s\n", baseName);
10311
return false;
10312
}
10313
for (int i = 0; i < (int)spirv.size(); ++i) {
10314
unsigned int word = spirv[i];
10315
out.write((const char*)&word, 4);
10316
}
10317
out.close();
10318
return true;
10319
}
10320
10321
// Write SPIR-V out to a text file with 32-bit hexadecimal words
10322
bool OutputSpvHex(const std::vector<unsigned int>& spirv, const char* baseName, const char* varName)
10323
{
10324
std::ofstream out;
10325
out.open(baseName, std::ios::binary | std::ios::out);
10326
if (out.fail()) {
10327
printf("ERROR: Failed to open file: %s\n", baseName);
10328
return false;
10329
}
10330
out << "\t// " <<
10331
GetSpirvGeneratorVersion() <<
10332
GLSLANG_VERSION_MAJOR << "." << GLSLANG_VERSION_MINOR << "." << GLSLANG_VERSION_PATCH <<
10333
GLSLANG_VERSION_FLAVOR << std::endl;
10334
if (varName != nullptr) {
10335
out << "\t #pragma once" << std::endl;
10336
out << "const uint32_t " << varName << "[] = {" << std::endl;
10337
}
10338
const int WORDS_PER_LINE = 8;
10339
for (int i = 0; i < (int)spirv.size(); i += WORDS_PER_LINE) {
10340
out << "\t";
10341
for (int j = 0; j < WORDS_PER_LINE && i + j < (int)spirv.size(); ++j) {
10342
const unsigned int word = spirv[i + j];
10343
out << "0x" << std::hex << std::setw(8) << std::setfill('0') << word;
10344
if (i + j + 1 < (int)spirv.size()) {
10345
out << ",";
10346
}
10347
}
10348
out << std::endl;
10349
}
10350
if (varName != nullptr) {
10351
out << "};";
10352
out << std::endl;
10353
}
10354
out.close();
10355
return true;
10356
}
10357
10358
//
10359
// Set up the glslang traversal
10360
//
10361
void GlslangToSpv(const TIntermediate& intermediate, std::vector<unsigned int>& spirv, SpvOptions* options)
10362
{
10363
spv::SpvBuildLogger logger;
10364
GlslangToSpv(intermediate, spirv, &logger, options);
10365
}
10366
10367
void GlslangToSpv(const TIntermediate& intermediate, std::vector<unsigned int>& spirv,
10368
spv::SpvBuildLogger* logger, SpvOptions* options)
10369
{
10370
TIntermNode* root = intermediate.getTreeRoot();
10371
10372
if (root == nullptr)
10373
return;
10374
10375
SpvOptions defaultOptions;
10376
if (options == nullptr)
10377
options = &defaultOptions;
10378
10379
GetThreadPoolAllocator().push();
10380
10381
TGlslangToSpvTraverser it(intermediate.getSpv().spv, &intermediate, logger, *options);
10382
root->traverse(&it);
10383
it.finishSpv(options->compileOnly);
10384
it.dumpSpv(spirv);
10385
10386
#if ENABLE_OPT
10387
// If from HLSL, run spirv-opt to "legalize" the SPIR-V for Vulkan
10388
// eg. forward and remove memory writes of opaque types.
10389
bool prelegalization = intermediate.getSource() == EShSourceHlsl;
10390
if ((prelegalization || options->optimizeSize) && !options->disableOptimizer) {
10391
SpirvToolsTransform(intermediate, spirv, logger, options);
10392
prelegalization = false;
10393
}
10394
else if (options->stripDebugInfo) {
10395
// Strip debug info even if optimization is disabled.
10396
SpirvToolsStripDebugInfo(intermediate, spirv, logger);
10397
}
10398
10399
if (options->validate)
10400
SpirvToolsValidate(intermediate, spirv, logger, prelegalization);
10401
10402
if (options->disassemble)
10403
SpirvToolsDisassemble(std::cout, spirv);
10404
10405
#endif
10406
10407
GetThreadPoolAllocator().pop();
10408
}
10409
10410
}; // end namespace glslang
10411
10412