2 //Copyright (C) 2014 LunarG, Inc.
\r
4 //All rights reserved.
\r
6 //Redistribution and use in source and binary forms, with or without
\r
7 //modification, are permitted provided that the following conditions
\r
10 // Redistributions of source code must retain the above copyright
\r
11 // notice, this list of conditions and the following disclaimer.
\r
13 // Redistributions in binary form must reproduce the above
\r
14 // copyright notice, this list of conditions and the following
\r
15 // disclaimer in the documentation and/or other materials provided
\r
16 // with the distribution.
\r
18 // Neither the name of 3Dlabs Inc. Ltd. nor the names of its
\r
19 // contributors may be used to endorse or promote products derived
\r
20 // from this software without specific prior written permission.
\r
22 //THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
\r
23 //"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
\r
24 //LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
\r
25 //FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
\r
26 //COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
\r
27 //INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
\r
28 //BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
\r
29 //LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
\r
30 //CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
\r
31 //LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
\r
32 //ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
\r
33 //POSSIBILITY OF SUCH DAMAGE.
\r
36 // Author: John Kessenich, LunarG
\r
38 // Visit the nodes in the glslang intermediate tree representation to
\r
39 // translate them to SPIR-V.
\r
43 #include "GlslangToSpv.h"
\r
44 #include "SpvBuilder.h"
\r
45 #include "GLSL450Lib.h"
\r
48 #include "glslang/MachineIndependent/localintermediate.h"
\r
49 #include "glslang/MachineIndependent/SymbolTable.h"
\r
60 const int GlslangMagic = 0x51a;
\r
63 // The main holder of information for translating glslang to SPIR-V.
\r
65 // Derives from the AST walking base class.
\r
67 class TGlslangToSpvTraverser : public glslang::TIntermTraverser {
\r
69 TGlslangToSpvTraverser(const glslang::TIntermediate*);
\r
70 virtual ~TGlslangToSpvTraverser();
\r
72 bool visitAggregate(glslang::TVisit, glslang::TIntermAggregate*);
\r
73 bool visitBinary(glslang::TVisit, glslang::TIntermBinary*);
\r
74 void visitConstantUnion(glslang::TIntermConstantUnion*);
\r
75 bool visitSelection(glslang::TVisit, glslang::TIntermSelection*);
\r
76 bool visitSwitch(glslang::TVisit, glslang::TIntermSwitch*);
\r
77 void visitSymbol(glslang::TIntermSymbol* symbol);
\r
78 bool visitUnary(glslang::TVisit, glslang::TIntermUnary*);
\r
79 bool visitLoop(glslang::TVisit, glslang::TIntermLoop*);
\r
80 bool visitBranch(glslang::TVisit visit, glslang::TIntermBranch*);
\r
82 void dumpSpv(std::vector<unsigned int>& out) { builder.dump(out); }
\r
85 spv::Id createSpvVariable(const glslang::TIntermSymbol*);
\r
86 spv::Id getSampledType(const glslang::TSampler&);
\r
87 spv::Id convertGlslangToSpvType(const glslang::TType& type);
\r
89 bool isShaderEntrypoint(const glslang::TIntermAggregate* node);
\r
90 void makeFunctions(const glslang::TIntermSequence&);
\r
91 void makeGlobalInitializers(const glslang::TIntermSequence&);
\r
92 void visitFunctions(const glslang::TIntermSequence&);
\r
93 void handleFunctionEntry(const glslang::TIntermAggregate* node);
\r
94 void translateArguments(const glslang::TIntermSequence& glslangArguments, std::vector<spv::Id>& arguments);
\r
95 spv::Id handleBuiltInFunctionCall(const glslang::TIntermAggregate*);
\r
96 spv::Id handleUserFunctionCall(const glslang::TIntermAggregate*);
\r
98 spv::Id createBinaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, spv::Id left, spv::Id right, glslang::TBasicType typeProxy, bool reduceComparison = true);
\r
99 spv::Id createUnaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, spv::Id operand, bool isFloat);
\r
100 spv::Id createConversion(glslang::TOperator op, spv::Decoration precision, spv::Id destTypeId, spv::Id operand);
\r
101 spv::Id makeSmearedConstant(spv::Id constant, int vectorSize);
\r
102 spv::Id createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands);
\r
103 spv::Id createNoArgOperation(glslang::TOperator op);
\r
104 spv::Id getSymbolId(const glslang::TIntermSymbol* node);
\r
105 void addDecoration(spv::Id id, spv::Decoration dec);
\r
106 void addMemberDecoration(spv::Id id, int member, spv::Decoration dec);
\r
107 spv::Id createSpvConstant(const glslang::TType& type, const glslang::TConstUnionArray&, int& nextConst);
\r
109 spv::Function* shaderEntry;
\r
112 // There is a 1:1 mapping between a spv builder and a module; this is thread safe
\r
113 spv::Builder builder;
\r
115 bool mainTerminated;
\r
117 const glslang::TIntermediate* glslangIntermediate;
\r
118 spv::Id stdBuiltins;
\r
120 std::map<int, spv::Id> symbolValues;
\r
121 std::set<int> constReadOnlyParameters; // set of formal function parameters that have glslang qualifier constReadOnly, so we know they are not local function "const" that are write-once
\r
122 std::map<std::string, spv::Function*> functionMap;
\r
123 std::map<const glslang::TTypeList*, spv::Id> structMap;
\r
124 std::map<const glslang::TTypeList*, std::vector<int> > memberRemapper; // for mapping glslang block indices to spv indices (e.g., due to hidden members)
\r
125 std::stack<bool> breakForLoop; // false means break for switch
\r
126 std::stack<glslang::TIntermTyped*> loopTerminal; // code from the last part of a for loop: for(...; ...; terminal), needed for e.g., continue };
\r
130 // Helper functions for translating glslang representations to SPIR-V enumerants.
\r
133 // Translate glslang language (stage) to SPIR-V execution model.
\r
134 spv::ExecutionModel TranslateExecutionModel(EShLanguage stage)
\r
137 case EShLangVertex: return spv::ExecutionModelVertex;
\r
138 case EShLangTessControl: return spv::ExecutionModelTessellationControl;
\r
139 case EShLangTessEvaluation: return spv::ExecutionModelTessellationEvaluation;
\r
140 case EShLangGeometry: return spv::ExecutionModelGeometry;
\r
141 case EShLangFragment: return spv::ExecutionModelFragment;
\r
142 case EShLangCompute: return spv::ExecutionModelGLCompute;
\r
144 spv::MissingFunctionality("GLSL stage");
\r
145 return spv::ExecutionModelFragment;
\r
149 // Translate glslang type to SPIR-V storage class.
\r
150 spv::StorageClass TranslateStorageClass(const glslang::TType& type)
\r
152 if (type.getQualifier().isPipeInput())
\r
153 return spv::StorageClassInput;
\r
154 else if (type.getQualifier().isPipeOutput())
\r
155 return spv::StorageClassOutput;
\r
156 else if (type.getQualifier().isUniformOrBuffer()) {
\r
157 if (type.getBasicType() == glslang::EbtBlock)
\r
158 return spv::StorageClassUniform;
\r
160 return spv::StorageClassUniformConstant;
\r
161 // TODO: how are we distuingishing between default and non-default non-writable uniforms? Do default uniforms even exist?
\r
163 switch (type.getQualifier().storage) {
\r
164 case glslang::EvqShared: return spv::StorageClassWorkgroupLocal; break;
\r
165 case glslang::EvqGlobal: return spv::StorageClassPrivateGlobal;
\r
166 case glslang::EvqConstReadOnly: return spv::StorageClassFunction;
\r
167 case glslang::EvqTemporary: return spv::StorageClassFunction;
\r
169 spv::MissingFunctionality("unknown glslang storage class");
\r
170 return spv::StorageClassFunction;
\r
175 // Translate glslang sampler type to SPIR-V dimensionality.
\r
176 spv::Dim TranslateDimensionality(const glslang::TSampler& sampler)
\r
178 switch (sampler.dim) {
\r
179 case glslang::Esd1D: return spv::Dim1D;
\r
180 case glslang::Esd2D: return spv::Dim2D;
\r
181 case glslang::Esd3D: return spv::Dim3D;
\r
182 case glslang::EsdCube: return spv::DimCube;
\r
183 case glslang::EsdRect: return spv::DimRect;
\r
184 case glslang::EsdBuffer: return spv::DimBuffer;
\r
186 spv::MissingFunctionality("unknown sampler dimension");
\r
191 // Translate glslang type to SPIR-V precision decorations.
\r
192 spv::Decoration TranslatePrecisionDecoration(const glslang::TType& type)
\r
194 switch (type.getQualifier().precision) {
\r
195 case glslang::EpqLow: return spv::DecorationPrecisionLow;
\r
196 case glslang::EpqMedium: return spv::DecorationPrecisionMedium;
\r
197 case glslang::EpqHigh: return spv::DecorationPrecisionHigh;
\r
199 return spv::NoPrecision;
\r
203 // Translate glslang type to SPIR-V block decorations.
\r
204 spv::Decoration TranslateBlockDecoration(const glslang::TType& type)
\r
206 if (type.getBasicType() == glslang::EbtBlock) {
\r
207 switch (type.getQualifier().storage) {
\r
208 case glslang::EvqUniform: return spv::DecorationBlock;
\r
209 case glslang::EvqBuffer: return spv::DecorationBufferBlock;
\r
210 case glslang::EvqVaryingIn: return spv::DecorationBlock;
\r
211 case glslang::EvqVaryingOut: return spv::DecorationBlock;
\r
213 spv::MissingFunctionality("kind of block");
\r
218 return (spv::Decoration)spv::BadValue;
\r
221 // Translate glslang type to SPIR-V layout decorations.
\r
222 spv::Decoration TranslateLayoutDecoration(const glslang::TType& type)
\r
224 if (type.isMatrix()) {
\r
225 switch (type.getQualifier().layoutMatrix) {
\r
226 case glslang::ElmRowMajor:
\r
227 return spv::DecorationRowMajor;
\r
229 return spv::DecorationColMajor;
\r
232 switch (type.getBasicType()) {
\r
234 return (spv::Decoration)spv::BadValue;
\r
236 case glslang::EbtBlock:
\r
237 switch (type.getQualifier().storage) {
\r
238 case glslang::EvqUniform:
\r
239 case glslang::EvqBuffer:
\r
240 switch (type.getQualifier().layoutPacking) {
\r
241 case glslang::ElpShared: return spv::DecorationGLSLShared;
\r
242 case glslang::ElpStd140: return spv::DecorationGLSLStd140;
\r
243 case glslang::ElpStd430: return spv::DecorationGLSLStd430;
\r
244 case glslang::ElpPacked: return spv::DecorationGLSLPacked;
\r
246 spv::MissingFunctionality("uniform block layout");
\r
247 return spv::DecorationGLSLShared;
\r
249 case glslang::EvqVaryingIn:
\r
250 case glslang::EvqVaryingOut:
\r
251 if (type.getQualifier().layoutPacking != glslang::ElpNone)
\r
252 spv::MissingFunctionality("in/out block layout");
\r
253 return (spv::Decoration)spv::BadValue;
\r
255 spv::MissingFunctionality("block storage qualification");
\r
256 return (spv::Decoration)spv::BadValue;
\r
262 // Translate glslang type to SPIR-V interpolation decorations.
\r
263 spv::Decoration TranslateInterpolationDecoration(const glslang::TType& type)
\r
265 if (type.getQualifier().smooth)
\r
266 return spv::DecorationSmooth;
\r
267 if (type.getQualifier().nopersp)
\r
268 return spv::DecorationNoperspective;
\r
269 else if (type.getQualifier().patch)
\r
270 return spv::DecorationPatch;
\r
271 else if (type.getQualifier().flat)
\r
272 return spv::DecorationFlat;
\r
273 else if (type.getQualifier().centroid)
\r
274 return spv::DecorationCentroid;
\r
275 else if (type.getQualifier().sample)
\r
276 return spv::DecorationSample;
\r
278 return (spv::Decoration)spv::BadValue;
\r
281 // If glslang type is invaraiant, return SPIR-V invariant decoration.
\r
282 spv::Decoration TranslateInvariantDecoration(const glslang::TType& type)
\r
284 if (type.getQualifier().invariant)
\r
285 return spv::DecorationInvariant;
\r
287 return (spv::Decoration)spv::BadValue;
\r
290 // Translate glslang built-in variable to SPIR-V built in decoration.
\r
291 spv::BuiltIn TranslateBuiltInDecoration(const glslang::TIntermSymbol& node)
\r
293 const glslang::TString& name = node.getName();
\r
294 if (name.compare(0, 3, "gl_") != 0)
\r
295 return (spv::BuiltIn)spv::BadValue;
\r
297 switch (node.getQualifier().storage) {
\r
298 case glslang::EvqPosition: return spv::BuiltInPosition;
\r
299 case glslang::EvqPointSize: return spv::BuiltInPointSize;
\r
300 case glslang::EvqClipVertex: return spv::BuiltInClipVertex;
\r
301 case glslang::EvqVertexId: return spv::BuiltInVertexId;
\r
302 case glslang::EvqInstanceId: return spv::BuiltInInstanceId;
\r
303 case glslang::EvqFragCoord: return spv::BuiltInFragCoord;
\r
304 case glslang::EvqPointCoord: return spv::BuiltInPointCoord;
\r
305 case glslang::EvqFace: return spv::BuiltInFrontFacing;
\r
306 case glslang::EvqFragColor: return spv::BuiltInFragColor;
\r
307 case glslang::EvqFragDepth: return spv::BuiltInFragDepth;
\r
309 if (name == "gl_ClipDistance")
\r
310 return spv::BuiltInClipDistance;
\r
311 else if (name == "gl_PrimitiveID" || name == "gl_PrimitiveIDIn")
\r
312 return spv::BuiltInPrimitiveId;
\r
313 else if (name == "gl_InvocationID")
\r
314 return spv::BuiltInInvocationId;
\r
315 else if (name == "gl_Layer")
\r
316 return spv::BuiltInLayer;
\r
317 else if (name == "gl_ViewportIndex")
\r
318 return spv::BuiltInViewportIndex;
\r
319 else if (name == "gl_TessLevelOuter")
\r
320 return spv::BuiltInTessLevelOuter;
\r
321 else if (name == "gl_TessLevelInner")
\r
322 return spv::BuiltInTessLevelInner;
\r
323 else if (name == "gl_TessCoord")
\r
324 return spv::BuiltInTessCoord;
\r
325 else if (name == "gl_PatchVerticesIn")
\r
326 return spv::BuiltInPatchVertices;
\r
327 else if (name == "gl_SampleID")
\r
328 return spv::BuiltInSampleId;
\r
329 else if (name == "gl_SamplePosition")
\r
330 return spv::BuiltInSamplePosition;
\r
331 else if (name == "gl_SampleMask" || name == "gl_SampleMaskIn")
\r
332 return spv::BuiltInSampleMask;
\r
335 else if (name == "gl_NumWorkGroups")
\r
336 return spv::BuiltInNumWorkgroups;
\r
337 else if (name == "gl_WorkGroupSize")
\r
338 return spv::BuiltInWorkgroupSize;
\r
339 else if (name == "gl_WorkGroupID")
\r
340 return spv::BuiltInWorkgroupId;
\r
341 else if (name == "gl_LocalInvocationID")
\r
342 return spv::BuiltInLocalInvocationId;
\r
343 else if (name == "gl_GlobalInvocationID")
\r
344 return spv::BuiltInGlobalInvocationId;
\r
345 else if (name == "gl_LocalInvocationIndexID")
\r
346 return spv::BuiltInLocalInvocationIndex;
\r
350 return (spv::BuiltIn)spv::BadValue;
\r
354 // Implement the TGlslangToSpvTraverser class.
\r
357 TGlslangToSpvTraverser::TGlslangToSpvTraverser(const glslang::TIntermediate* glslangIntermediate)
\r
358 : TIntermTraverser(true, false, true), shaderEntry(0), sequenceDepth(0),
\r
359 builder(GlslangMagic),
\r
360 inMain(false), mainTerminated(false), linkageOnly(false),
\r
361 glslangIntermediate(glslangIntermediate)
\r
363 spv::ExecutionModel executionModel = TranslateExecutionModel(glslangIntermediate->getStage());
\r
365 builder.clearAccessChain();
\r
366 builder.setSource(spv::SourceLanguageGLSL, glslangIntermediate->getVersion());
\r
367 stdBuiltins = builder.import("GLSL.std.450");
\r
368 builder.setMemoryModel(spv::AddressingModelLogical, spv::MemoryModelGLSL450);
\r
369 shaderEntry = builder.makeMain();
\r
370 builder.addEntryPoint(executionModel, shaderEntry);
\r
372 // Add the source extensions
\r
373 const std::set<std::string>& sourceExtensions = glslangIntermediate->getRequestedExtensions();
\r
374 for (std::set<std::string>::const_iterator it = sourceExtensions.begin(); it != sourceExtensions.end(); ++it)
\r
375 builder.addSourceExtension(it->c_str());
\r
377 // Add the top-level modes for this shader.
\r
379 if (glslangIntermediate->getXfbMode())
\r
380 builder.addExecutionMode(shaderEntry, spv::ExecutionModeXfb);
\r
382 spv::ExecutionMode mode;
\r
383 switch (glslangIntermediate->getStage()) {
\r
384 case EShLangVertex:
\r
387 case EShLangTessControl:
\r
388 builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices());
\r
391 case EShLangTessEvaluation:
\r
392 switch (glslangIntermediate->getInputPrimitive()) {
\r
393 case glslang::ElgTriangles: mode = spv::ExecutionModeInputTriangles; break;
\r
394 case glslang::ElgQuads: mode = spv::ExecutionModeInputQuads; break;
\r
395 case glslang::ElgIsolines: mode = spv::ExecutionModeInputIsolines; break;
\r
396 default: mode = (spv::ExecutionMode)spv::BadValue; break;
\r
398 if (mode != spv::BadValue)
\r
399 builder.addExecutionMode(shaderEntry, mode);
\r
402 //builder.addExecutionMode(spv::VertexSpacingMdName, glslangIntermediate->getVertexSpacing());
\r
403 //builder.addExecutionMode(spv::VertexOrderMdName, glslangIntermediate->getVertexOrder());
\r
404 //builder.addExecutionMode(spv::PointModeMdName, glslangIntermediate->getPointMode());
\r
407 case EShLangGeometry:
\r
408 switch (glslangIntermediate->getInputPrimitive()) {
\r
409 case glslang::ElgPoints: mode = spv::ExecutionModeInputPoints; break;
\r
410 case glslang::ElgLines: mode = spv::ExecutionModeInputLines; break;
\r
411 case glslang::ElgLinesAdjacency: mode = spv::ExecutionModeInputLinesAdjacency; break;
\r
412 case glslang::ElgTriangles: mode = spv::ExecutionModeInputTriangles; break;
\r
413 case glslang::ElgTrianglesAdjacency: mode = spv::ExecutionModeInputTrianglesAdjacency; break;
\r
414 default: mode = (spv::ExecutionMode)spv::BadValue; break;
\r
416 if (mode != spv::BadValue)
\r
417 builder.addExecutionMode(shaderEntry, mode);
\r
418 builder.addExecutionMode(shaderEntry, spv::ExecutionModeInvocations, glslangIntermediate->getInvocations());
\r
420 switch (glslangIntermediate->getOutputPrimitive()) {
\r
421 case glslang::ElgPoints: mode = spv::ExecutionModeOutputPoints; break;
\r
422 case glslang::ElgLineStrip: mode = spv::ExecutionModeOutputLineStrip; break;
\r
423 case glslang::ElgTriangleStrip: mode = spv::ExecutionModeOutputTriangleStrip; break;
\r
424 default: mode = (spv::ExecutionMode)spv::BadValue; break;
\r
426 if (mode != spv::BadValue)
\r
427 builder.addExecutionMode(shaderEntry, mode);
\r
428 builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices());
\r
431 case EShLangFragment:
\r
432 if (glslangIntermediate->getPixelCenterInteger())
\r
433 builder.addExecutionMode(shaderEntry, spv::ExecutionModePixelCenterInteger);
\r
434 if (glslangIntermediate->getOriginUpperLeft())
\r
435 builder.addExecutionMode(shaderEntry, spv::ExecutionModeOriginUpperLeft);
\r
438 case EShLangCompute:
\r
447 TGlslangToSpvTraverser::~TGlslangToSpvTraverser()
\r
449 if (! mainTerminated) {
\r
450 spv::Block* lastMainBlock = shaderEntry->getLastBlock();
\r
451 builder.setBuildPoint(lastMainBlock);
\r
452 builder.leaveFunction(true);
\r
457 // Implement the traversal functions.
\r
459 // Return true from interior nodes to have the external traversal
\r
460 // continue on to children. Return false if children were
\r
461 // already processed.
\r
465 // Symbols can turn into
\r
466 // - uniform/input reads
\r
468 // - complex lvalue base setups: foo.bar[3].... , where we see foo and start up an access chain
\r
469 // - something simple that degenerates into the last bullet
\r
471 void TGlslangToSpvTraverser::visitSymbol(glslang::TIntermSymbol* symbol)
\r
473 // getSymbolId() will set up all the IO decorations on the first call.
\r
474 // Formal function parameters were mapped during makeFunctions().
\r
475 spv::Id id = getSymbolId(symbol);
\r
477 if (! linkageOnly) {
\r
478 // Prepare to generate code for the access
\r
480 // L-value chains will be computed left to right. We're on the symbol now,
\r
481 // which is the left-most part of the access chain, so now is "clear" time,
\r
482 // followed by setting the base.
\r
483 builder.clearAccessChain();
\r
485 // For now, we consider all user variables as being in memory, so they are pointers,
\r
486 // except for "const in" arguments to a function, which are an intermediate object.
\r
487 // See comments in handleUserFunctionCall().
\r
488 glslang::TStorageQualifier qualifier = symbol->getQualifier().storage;
\r
489 if (qualifier == glslang::EvqConstReadOnly && constReadOnlyParameters.find(symbol->getId()) != constReadOnlyParameters.end())
\r
490 builder.setAccessChainRValue(id);
\r
492 builder.setAccessChainLValue(id);
\r
496 bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::TIntermBinary* node)
\r
498 // First, handle special cases
\r
499 switch (node->getOp()) {
\r
500 case glslang::EOpAssign:
\r
501 case glslang::EOpAddAssign:
\r
502 case glslang::EOpSubAssign:
\r
503 case glslang::EOpMulAssign:
\r
504 case glslang::EOpVectorTimesMatrixAssign:
\r
505 case glslang::EOpVectorTimesScalarAssign:
\r
506 case glslang::EOpMatrixTimesScalarAssign:
\r
507 case glslang::EOpMatrixTimesMatrixAssign:
\r
508 case glslang::EOpDivAssign:
\r
509 case glslang::EOpModAssign:
\r
510 case glslang::EOpAndAssign:
\r
511 case glslang::EOpInclusiveOrAssign:
\r
512 case glslang::EOpExclusiveOrAssign:
\r
513 case glslang::EOpLeftShiftAssign:
\r
514 case glslang::EOpRightShiftAssign:
\r
515 // A bin-op assign "a += b" means the same thing as "a = a + b"
\r
516 // where a is evaluated before b. For a simple assignment, GLSL
\r
517 // says to evaluate the left before the right. So, always, left
\r
518 // node then right node.
\r
520 // get the left l-value, save it away
\r
521 builder.clearAccessChain();
\r
522 node->getLeft()->traverse(this);
\r
523 spv::Builder::AccessChain lValue = builder.getAccessChain();
\r
525 // evaluate the right
\r
526 builder.clearAccessChain();
\r
527 node->getRight()->traverse(this);
\r
528 spv::Id rValue = builder.accessChainLoad(TranslatePrecisionDecoration(node->getRight()->getType()));
\r
530 if (node->getOp() != glslang::EOpAssign) {
\r
531 // the left is also an r-value
\r
532 builder.setAccessChain(lValue);
\r
533 spv::Id leftRValue = builder.accessChainLoad(TranslatePrecisionDecoration(node->getLeft()->getType()));
\r
535 // do the operation
\r
536 rValue = createBinaryOperation(node->getOp(), TranslatePrecisionDecoration(node->getType()),
\r
537 convertGlslangToSpvType(node->getType()), leftRValue, rValue,
\r
538 node->getType().getBasicType());
\r
540 // these all need their counterparts in createBinaryOperation()
\r
542 spv::MissingFunctionality("createBinaryOperation");
\r
545 // store the result
\r
546 builder.setAccessChain(lValue);
\r
547 builder.accessChainStore(rValue);
\r
549 // assignments are expressions having an rValue after they are evaluated...
\r
550 builder.clearAccessChain();
\r
551 builder.setAccessChainRValue(rValue);
\r
554 case glslang::EOpIndexDirect:
\r
555 case glslang::EOpIndexDirectStruct:
\r
557 // Get the left part of the access chain.
\r
558 node->getLeft()->traverse(this);
\r
560 // Add the next element in the chain
\r
563 if (node->getRight()->getAsConstantUnion() == 0)
\r
564 spv::MissingFunctionality("direct index without a constant node");
\r
566 index = node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
\r
568 if (node->getLeft()->getBasicType() == glslang::EbtBlock && node->getOp() == glslang::EOpIndexDirectStruct) {
\r
569 // This may be, e.g., an anonymous block-member selection, which generally need
\r
570 // index remapping due to hidden members in anonymous blocks.
\r
571 std::vector<int>& remapper = memberRemapper[node->getLeft()->getType().getStruct()];
\r
572 if (remapper.size() == 0)
\r
573 spv::MissingFunctionality("block without member remapping");
\r
575 index = remapper[index];
\r
578 if (! node->getLeft()->getType().isArray() &&
\r
579 node->getLeft()->getType().isVector() &&
\r
580 node->getOp() == glslang::EOpIndexDirect) {
\r
581 // This is essentially a hard-coded vector swizzle of size 1,
\r
582 // so short circuit the access-chain stuff with a swizzle.
\r
583 std::vector<unsigned> swizzle;
\r
584 swizzle.push_back(node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst());
\r
585 builder.accessChainPushSwizzle(swizzle, node->getLeft()->getVectorSize(), convertGlslangToSpvType(node->getType()));
\r
587 // normal case for indexing array or structure or block
\r
588 builder.accessChainPush(builder.makeIntConstant(index), convertGlslangToSpvType(node->getType()));
\r
592 case glslang::EOpIndexIndirect:
\r
594 // Structure or array or vector indirection.
\r
595 // Will use native SPIR-V access-chain for struct and array indirection;
\r
596 // matrices are arrays of vectors, so will also work for a matrix.
\r
597 // Will use the access chain's 'component' for variable index into a vector.
\r
599 // This adapter is building access chains left to right.
\r
600 // Set up the access chain to the left.
\r
601 node->getLeft()->traverse(this);
\r
603 // save it so that computing the right side doesn't trash it
\r
604 spv::Builder::AccessChain partial = builder.getAccessChain();
\r
606 // compute the next index in the chain
\r
607 builder.clearAccessChain();
\r
608 node->getRight()->traverse(this);
\r
609 spv::Id index = builder.accessChainLoad(TranslatePrecisionDecoration(node->getRight()->getType()));
\r
611 // restore the saved access chain
\r
612 builder.setAccessChain(partial);
\r
614 if (! node->getLeft()->getType().isArray() && node->getLeft()->getType().isVector())
\r
615 builder.accessChainPushComponent(index);
\r
617 builder.accessChainPush(index, convertGlslangToSpvType(node->getType()));
\r
620 case glslang::EOpVectorSwizzle:
\r
622 node->getLeft()->traverse(this);
\r
623 glslang::TIntermSequence& swizzleSequence = node->getRight()->getAsAggregate()->getSequence();
\r
624 std::vector<unsigned> swizzle;
\r
625 for (int i = 0; i < (int)swizzleSequence.size(); ++i)
\r
626 swizzle.push_back(swizzleSequence[i]->getAsConstantUnion()->getConstArray()[0].getIConst());
\r
627 builder.accessChainPushSwizzle(swizzle, node->getLeft()->getVectorSize(), convertGlslangToSpvType(node->getType()));
\r
634 // Assume generic binary op...
\r
636 // Get the operands
\r
637 builder.clearAccessChain();
\r
638 node->getLeft()->traverse(this);
\r
639 spv::Id left = builder.accessChainLoad(TranslatePrecisionDecoration(node->getLeft()->getType()));
\r
641 builder.clearAccessChain();
\r
642 node->getRight()->traverse(this);
\r
643 spv::Id right = builder.accessChainLoad(TranslatePrecisionDecoration(node->getRight()->getType()));
\r
646 spv::Decoration precision = TranslatePrecisionDecoration(node->getType());
\r
648 result = createBinaryOperation(node->getOp(), precision,
\r
649 convertGlslangToSpvType(node->getType()), left, right,
\r
650 node->getLeft()->getType().getBasicType());
\r
653 spv::MissingFunctionality("glslang binary operation");
\r
655 builder.clearAccessChain();
\r
656 builder.setAccessChainRValue(result);
\r
664 bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TIntermUnary* node)
\r
666 builder.clearAccessChain();
\r
667 node->getOperand()->traverse(this);
\r
668 spv::Id operand = builder.accessChainLoad(TranslatePrecisionDecoration(node->getOperand()->getType()));
\r
670 spv::Decoration precision = TranslatePrecisionDecoration(node->getType());
\r
672 // it could be a conversion
\r
673 spv::Id result = createConversion(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operand);
\r
675 // if not, then possibly an operation
\r
677 result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operand, node->getBasicType() == glslang::EbtFloat || node->getBasicType() == glslang::EbtDouble);
\r
680 builder.clearAccessChain();
\r
681 builder.setAccessChainRValue(result);
\r
683 return false; // done with this node
\r
686 // it must be a special case, check...
\r
687 switch (node->getOp()) {
\r
688 case glslang::EOpPostIncrement:
\r
689 case glslang::EOpPostDecrement:
\r
690 case glslang::EOpPreIncrement:
\r
691 case glslang::EOpPreDecrement:
\r
693 // we need the integer value "1" or the floating point "1.0" to add/subtract
\r
694 spv::Id one = node->getBasicType() == glslang::EbtFloat ?
\r
695 builder.makeFloatConstant(1.0F) :
\r
696 builder.makeIntConstant(1);
\r
697 glslang::TOperator op;
\r
698 if (node->getOp() == glslang::EOpPreIncrement ||
\r
699 node->getOp() == glslang::EOpPostIncrement)
\r
700 op = glslang::EOpAdd;
\r
702 op = glslang::EOpSub;
\r
704 spv::Id result = createBinaryOperation(op, TranslatePrecisionDecoration(node->getType()),
\r
705 convertGlslangToSpvType(node->getType()), operand, one,
\r
706 node->getType().getBasicType());
\r
708 spv::MissingFunctionality("createBinaryOperation for unary");
\r
710 // The result of operation is always stored, but conditionally the
\r
711 // consumed result. The consumed result is always an r-value.
\r
712 builder.accessChainStore(result);
\r
713 builder.clearAccessChain();
\r
714 if (node->getOp() == glslang::EOpPreIncrement ||
\r
715 node->getOp() == glslang::EOpPreDecrement)
\r
716 builder.setAccessChainRValue(result);
\r
718 builder.setAccessChainRValue(operand);
\r
723 case glslang::EOpEmitStreamVertex:
\r
724 builder.createNoResultOp(spv::OpEmitStreamVertex, operand);
\r
726 case glslang::EOpEndStreamPrimitive:
\r
727 builder.createNoResultOp(spv::OpEndStreamPrimitive, operand);
\r
731 spv::MissingFunctionality("glslang unary");
\r
738 bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TIntermAggregate* node)
\r
741 glslang::TOperator binOp = glslang::EOpNull;
\r
742 bool reduceComparison = true;
\r
743 bool isMatrix = false;
\r
744 bool noReturnValue = false;
\r
746 assert(node->getOp());
\r
748 spv::Decoration precision = TranslatePrecisionDecoration(node->getType());
\r
750 switch (node->getOp()) {
\r
751 case glslang::EOpSequence:
\r
758 if (sequenceDepth == 1) {
\r
759 // If this is the parent node of all the functions, we want to see them
\r
760 // early, so all call points have actual SPIR-V functions to reference.
\r
761 // In all cases, still let the traverser visit the children for us.
\r
762 makeFunctions(node->getAsAggregate()->getSequence());
\r
764 // Also, we want all globals initializers to go into the entry of main(), before
\r
765 // anything else gets there, so visit out of order, doing them all now.
\r
766 makeGlobalInitializers(node->getAsAggregate()->getSequence());
\r
768 // Initializers are done, don't want to visit again, but functions link objects need to be processed,
\r
769 // so do them manually.
\r
770 visitFunctions(node->getAsAggregate()->getSequence());
\r
777 case glslang::EOpLinkerObjects:
\r
779 if (visit == glslang::EvPreVisit)
\r
780 linkageOnly = true;
\r
782 linkageOnly = false;
\r
786 case glslang::EOpComma:
\r
788 // processing from left to right naturally leaves the right-most
\r
789 // lying around in the access chain
\r
790 glslang::TIntermSequence& glslangOperands = node->getSequence();
\r
791 for (int i = 0; i < (int)glslangOperands.size(); ++i)
\r
792 glslangOperands[i]->traverse(this);
\r
796 case glslang::EOpFunction:
\r
797 if (visit == glslang::EvPreVisit) {
\r
798 if (isShaderEntrypoint(node)) {
\r
800 builder.setBuildPoint(shaderEntry->getLastBlock());
\r
802 handleFunctionEntry(node);
\r
806 mainTerminated = true;
\r
807 builder.leaveFunction(inMain);
\r
812 case glslang::EOpParameters:
\r
813 // Parameters will have been consumed by EOpFunction processing, but not
\r
814 // the body, so we still visited the function node's children, making this
\r
815 // child redundant.
\r
817 case glslang::EOpFunctionCall:
\r
819 if (node->isUserDefined())
\r
820 result = handleUserFunctionCall(node);
\r
822 result = handleBuiltInFunctionCall(node);
\r
825 spv::MissingFunctionality("glslang function call");
\r
826 glslang::TConstUnionArray emptyConsts;
\r
828 result = createSpvConstant(node->getType(), emptyConsts, nextConst);
\r
830 builder.clearAccessChain();
\r
831 builder.setAccessChainRValue(result);
\r
835 case glslang::EOpConstructMat2x2:
\r
836 case glslang::EOpConstructMat2x3:
\r
837 case glslang::EOpConstructMat2x4:
\r
838 case glslang::EOpConstructMat3x2:
\r
839 case glslang::EOpConstructMat3x3:
\r
840 case glslang::EOpConstructMat3x4:
\r
841 case glslang::EOpConstructMat4x2:
\r
842 case glslang::EOpConstructMat4x3:
\r
843 case glslang::EOpConstructMat4x4:
\r
844 case glslang::EOpConstructDMat2x2:
\r
845 case glslang::EOpConstructDMat2x3:
\r
846 case glslang::EOpConstructDMat2x4:
\r
847 case glslang::EOpConstructDMat3x2:
\r
848 case glslang::EOpConstructDMat3x3:
\r
849 case glslang::EOpConstructDMat3x4:
\r
850 case glslang::EOpConstructDMat4x2:
\r
851 case glslang::EOpConstructDMat4x3:
\r
852 case glslang::EOpConstructDMat4x4:
\r
855 case glslang::EOpConstructFloat:
\r
856 case glslang::EOpConstructVec2:
\r
857 case glslang::EOpConstructVec3:
\r
858 case glslang::EOpConstructVec4:
\r
859 case glslang::EOpConstructDouble:
\r
860 case glslang::EOpConstructDVec2:
\r
861 case glslang::EOpConstructDVec3:
\r
862 case glslang::EOpConstructDVec4:
\r
863 case glslang::EOpConstructBool:
\r
864 case glslang::EOpConstructBVec2:
\r
865 case glslang::EOpConstructBVec3:
\r
866 case glslang::EOpConstructBVec4:
\r
867 case glslang::EOpConstructInt:
\r
868 case glslang::EOpConstructIVec2:
\r
869 case glslang::EOpConstructIVec3:
\r
870 case glslang::EOpConstructIVec4:
\r
871 case glslang::EOpConstructUint:
\r
872 case glslang::EOpConstructUVec2:
\r
873 case glslang::EOpConstructUVec3:
\r
874 case glslang::EOpConstructUVec4:
\r
875 case glslang::EOpConstructStruct:
\r
877 std::vector<spv::Id> arguments;
\r
878 translateArguments(node->getSequence(), arguments);
\r
879 spv::Id resultTypeId = convertGlslangToSpvType(node->getType());
\r
880 spv::Id constructed;
\r
881 if (node->getOp() == glslang::EOpConstructStruct || node->getType().isArray()) {
\r
882 std::vector<spv::Id> constituents;
\r
883 for (int c = 0; c < (int)arguments.size(); ++c)
\r
884 constituents.push_back(arguments[c]);
\r
885 constructed = builder.createCompositeConstruct(resultTypeId, constituents);
\r
888 constructed = builder.createMatrixConstructor(precision, arguments, resultTypeId);
\r
890 constructed = builder.createConstructor(precision, arguments, resultTypeId);
\r
893 builder.clearAccessChain();
\r
894 builder.setAccessChainRValue(constructed);
\r
899 // These six are component-wise compares with component-wise results.
\r
900 // Forward on to createBinaryOperation(), requesting a vector result.
\r
901 case glslang::EOpLessThan:
\r
902 case glslang::EOpGreaterThan:
\r
903 case glslang::EOpLessThanEqual:
\r
904 case glslang::EOpGreaterThanEqual:
\r
905 case glslang::EOpVectorEqual:
\r
906 case glslang::EOpVectorNotEqual:
\r
908 // Map the operation to a binary
\r
909 binOp = node->getOp();
\r
910 reduceComparison = false;
\r
911 switch (node->getOp()) {
\r
912 case glslang::EOpVectorEqual: binOp = glslang::EOpVectorEqual; break;
\r
913 case glslang::EOpVectorNotEqual: binOp = glslang::EOpVectorNotEqual; break;
\r
914 default: binOp = node->getOp(); break;
\r
919 case glslang::EOpMul:
\r
920 // compontent-wise matrix multiply
\r
921 binOp = glslang::EOpMul;
\r
923 case glslang::EOpOuterProduct:
\r
924 // two vectors multiplied to make a matrix
\r
925 binOp = glslang::EOpOuterProduct;
\r
927 case glslang::EOpDot:
\r
929 // for scalar dot product, use multiply
\r
930 glslang::TIntermSequence& glslangOperands = node->getSequence();
\r
931 if (! glslangOperands[0]->getAsTyped()->isVector())
\r
932 binOp = glslang::EOpMul;
\r
935 case glslang::EOpMod:
\r
936 // when an aggregate, this is the floating-point mod built-in function,
\r
937 // which can be emitted by the one in createBinaryOperation()
\r
938 binOp = glslang::EOpMod;
\r
940 case glslang::EOpArrayLength:
\r
942 glslang::TIntermTyped* typedNode = node->getSequence()[0]->getAsTyped();
\r
944 spv::Id length = builder.makeIntConstant(typedNode->getType().getArraySize());
\r
946 builder.clearAccessChain();
\r
947 builder.setAccessChainRValue(length);
\r
951 case glslang::EOpEmitVertex:
\r
952 case glslang::EOpEndPrimitive:
\r
953 case glslang::EOpBarrier:
\r
954 case glslang::EOpMemoryBarrier:
\r
955 case glslang::EOpMemoryBarrierAtomicCounter:
\r
956 case glslang::EOpMemoryBarrierBuffer:
\r
957 case glslang::EOpMemoryBarrierImage:
\r
958 case glslang::EOpMemoryBarrierShared:
\r
959 case glslang::EOpGroupMemoryBarrier:
\r
960 noReturnValue = true;
\r
961 // These all have 0 operands and will naturally finish up in the code below for 0 operands
\r
969 // See if it maps to a regular operation.
\r
972 if (binOp != glslang::EOpNull) {
\r
973 glslang::TIntermTyped* left = node->getSequence()[0]->getAsTyped();
\r
974 glslang::TIntermTyped* right = node->getSequence()[1]->getAsTyped();
\r
975 assert(left && right);
\r
977 builder.clearAccessChain();
\r
978 left->traverse(this);
\r
979 spv::Id leftId = builder.accessChainLoad(TranslatePrecisionDecoration(left->getType()));
\r
981 builder.clearAccessChain();
\r
982 right->traverse(this);
\r
983 spv::Id rightId = builder.accessChainLoad(TranslatePrecisionDecoration(right->getType()));
\r
985 result = createBinaryOperation(binOp, precision,
\r
986 convertGlslangToSpvType(node->getType()), leftId, rightId,
\r
987 left->getType().getBasicType(), reduceComparison);
\r
989 // code above should only make binOp that exists in createBinaryOperation
\r
991 spv::MissingFunctionality("createBinaryOperation for aggregate");
\r
993 builder.clearAccessChain();
\r
994 builder.setAccessChainRValue(result);
\r
999 glslang::TIntermSequence& glslangOperands = node->getSequence();
\r
1000 std::vector<spv::Id> operands;
\r
1001 for (int arg = 0; arg < (int)glslangOperands.size(); ++arg) {
\r
1002 builder.clearAccessChain();
\r
1003 glslangOperands[arg]->traverse(this);
\r
1005 // special case l-value operands; there are just a few
\r
1006 bool lvalue = false;
\r
1007 switch (node->getOp()) {
\r
1008 //case glslang::EOpFrexp:
\r
1009 case glslang::EOpModf:
\r
1013 //case glslang::EOpUAddCarry:
\r
1014 //case glslang::EOpUSubBorrow:
\r
1015 //case glslang::EOpUMulExtended:
\r
1020 operands.push_back(builder.accessChainGetLValue());
\r
1022 operands.push_back(builder.accessChainLoad(TranslatePrecisionDecoration(glslangOperands[arg]->getAsTyped()->getType())));
\r
1024 switch (glslangOperands.size()) {
\r
1026 result = createNoArgOperation(node->getOp());
\r
1029 result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands.front(), node->getType().getBasicType() == glslang::EbtFloat || node->getType().getBasicType() == glslang::EbtDouble);
\r
1032 result = createMiscOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands);
\r
1036 if (noReturnValue)
\r
1040 spv::MissingFunctionality("glslang aggregate");
\r
1043 builder.clearAccessChain();
\r
1044 builder.setAccessChainRValue(result);
\r
1049 bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang::TIntermSelection* node)
\r
1051 // This path handles both if-then-else and ?:
\r
1052 // The if-then-else has a node type of void, while
\r
1053 // ?: has a non-void node type
\r
1054 spv::Id result = 0;
\r
1055 if (node->getBasicType() != glslang::EbtVoid) {
\r
1056 // don't handle this as just on-the-fly temporaries, because there will be two names
\r
1057 // and better to leave SSA to later passes
\r
1058 result = builder.createVariable(spv::StorageClassFunction, convertGlslangToSpvType(node->getType()));
\r
1061 // emit the condition before doing anything with selection
\r
1062 node->getCondition()->traverse(this);
\r
1064 // make an "if" based on the value created by the condition
\r
1065 spv::Builder::If ifBuilder(builder.accessChainLoad(spv::NoPrecision), builder);
\r
1067 if (node->getTrueBlock()) {
\r
1068 // emit the "then" statement
\r
1069 node->getTrueBlock()->traverse(this);
\r
1071 builder.createStore(builder.accessChainLoad(TranslatePrecisionDecoration(node->getTrueBlock()->getAsTyped()->getType())), result);
\r
1074 if (node->getFalseBlock()) {
\r
1075 ifBuilder.makeBeginElse();
\r
1076 // emit the "else" statement
\r
1077 node->getFalseBlock()->traverse(this);
\r
1079 builder.createStore(builder.accessChainLoad(TranslatePrecisionDecoration(node->getFalseBlock()->getAsTyped()->getType())), result);
\r
1082 ifBuilder.makeEndIf();
\r
1085 // GLSL only has r-values as the result of a :?, but
\r
1086 // if we have an l-value, that can be more efficient if it will
\r
1087 // become the base of a complex r-value expression, because the
\r
1088 // next layer copies r-values into memory to use the access-chain mechanism
\r
1089 builder.clearAccessChain();
\r
1090 builder.setAccessChainLValue(result);
\r
1096 bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::TIntermSwitch* node)
\r
1098 // emit and get the condition before doing anything with switch
\r
1099 node->getCondition()->traverse(this);
\r
1100 spv::Id selector = builder.accessChainLoad(TranslatePrecisionDecoration(node->getCondition()->getAsTyped()->getType()));
\r
1102 // browse the children to sort out code segments
\r
1103 int defaultSegment = -1;
\r
1104 std::vector<TIntermNode*> codeSegments;
\r
1105 glslang::TIntermSequence& sequence = node->getBody()->getSequence();
\r
1106 std::vector<int> caseValues;
\r
1107 std::vector<int> valueIndexToSegment(sequence.size()); // note: probably not all are used, it is an overestimate
\r
1108 for (glslang::TIntermSequence::iterator c = sequence.begin(); c != sequence.end(); ++c) {
\r
1109 TIntermNode* child = *c;
\r
1110 if (child->getAsBranchNode() && child->getAsBranchNode()->getFlowOp() == glslang::EOpDefault)
\r
1111 defaultSegment = codeSegments.size();
\r
1112 else if (child->getAsBranchNode() && child->getAsBranchNode()->getFlowOp() == glslang::EOpCase) {
\r
1113 valueIndexToSegment[caseValues.size()] = codeSegments.size();
\r
1114 caseValues.push_back(child->getAsBranchNode()->getExpression()->getAsConstantUnion()->getConstArray()[0].getIConst());
\r
1116 codeSegments.push_back(child);
\r
1119 // handle the case where the last code segment is missing, due to no code
\r
1120 // statements between the last case and the end of the switch statement
\r
1121 if ((int)codeSegments.size() == valueIndexToSegment[caseValues.size() - 1])
\r
1122 codeSegments.push_back(0);
\r
1124 // make the switch statement
\r
1125 std::vector<spv::Block*> segmentBlocks; // returned, as the blocks allocated in the call
\r
1126 builder.makeSwitch(selector, codeSegments.size(), caseValues, valueIndexToSegment, defaultSegment, segmentBlocks);
\r
1128 // emit all the code in the segments
\r
1129 breakForLoop.push(false);
\r
1130 for (unsigned int s = 0; s < codeSegments.size(); ++s) {
\r
1131 builder.nextSwitchSegment(segmentBlocks, s);
\r
1132 if (codeSegments[s])
\r
1133 codeSegments[s]->traverse(this);
\r
1135 builder.addSwitchBreak();
\r
1137 breakForLoop.pop();
\r
1139 builder.endSwitch(segmentBlocks);
\r
1144 void TGlslangToSpvTraverser::visitConstantUnion(glslang::TIntermConstantUnion* node)
\r
1146 int nextConst = 0;
\r
1147 spv::Id constant = createSpvConstant(node->getType(), node->getConstArray(), nextConst);
\r
1149 builder.clearAccessChain();
\r
1150 builder.setAccessChainRValue(constant);
\r
1153 bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIntermLoop* node)
\r
1155 // body emission needs to know what the for-loop terminal is when it sees a "continue"
\r
1156 loopTerminal.push(node->getTerminal());
\r
1158 builder.makeNewLoop();
\r
1160 bool bodyOut = false;
\r
1161 if (! node->testFirst()) {
\r
1162 if (node->getBody()) {
\r
1163 breakForLoop.push(true);
\r
1164 node->getBody()->traverse(this);
\r
1165 breakForLoop.pop();
\r
1170 if (node->getTest()) {
\r
1171 node->getTest()->traverse(this);
\r
1172 // the AST only contained the test computation, not the branch, we have to add it
\r
1173 spv::Id condition = builder.accessChainLoad(TranslatePrecisionDecoration(node->getTest()->getType()));
\r
1174 builder.createLoopHeaderBranch(condition);
\r
1177 if (! bodyOut && node->getBody()) {
\r
1178 breakForLoop.push(true);
\r
1179 node->getBody()->traverse(this);
\r
1180 breakForLoop.pop();
\r
1183 if (loopTerminal.top())
\r
1184 loopTerminal.top()->traverse(this);
\r
1186 builder.closeLoop();
\r
1188 loopTerminal.pop();
\r
1193 bool TGlslangToSpvTraverser::visitBranch(glslang::TVisit /* visit */, glslang::TIntermBranch* node)
\r
1195 if (node->getExpression())
\r
1196 node->getExpression()->traverse(this);
\r
1198 switch (node->getFlowOp()) {
\r
1199 case glslang::EOpKill:
\r
1200 builder.makeDiscard();
\r
1202 case glslang::EOpBreak:
\r
1203 if (breakForLoop.top())
\r
1204 builder.createLoopExit();
\r
1206 builder.addSwitchBreak();
\r
1208 case glslang::EOpContinue:
\r
1209 if (loopTerminal.top())
\r
1210 loopTerminal.top()->traverse(this);
\r
1211 builder.createLoopBackEdge();
\r
1213 case glslang::EOpReturn:
\r
1215 builder.makeMainReturn();
\r
1216 else if (node->getExpression())
\r
1217 builder.makeReturn(false, builder.accessChainLoad(TranslatePrecisionDecoration(node->getExpression()->getType())));
\r
1219 builder.makeReturn();
\r
1221 builder.clearAccessChain();
\r
1225 spv::MissingFunctionality("branch type");
\r
1232 spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol* node)
\r
1234 // First, steer off constants, which are not SPIR-V variables, but
\r
1235 // can still have a mapping to a SPIR-V Id.
\r
1236 if (node->getQualifier().storage == glslang::EvqConst) {
\r
1237 int nextConst = 0;
\r
1238 return createSpvConstant(node->getType(), node->getConstArray(), nextConst);
\r
1241 // Now, handle actual variables
\r
1242 spv::StorageClass storageClass = TranslateStorageClass(node->getType());
\r
1243 spv::Id spvType = convertGlslangToSpvType(node->getType());
\r
1245 const char* name = node->getName().c_str();
\r
1246 if (glslang::IsAnonymous(name))
\r
1249 if (storageClass == spv::BadValue)
\r
1250 return builder.createVariable(spv::StorageClassFunction, spvType, name);
\r
1252 return builder.createVariable(storageClass, spvType, name);
\r
1255 // Return type Id of the sampled type.
\r
1256 spv::Id TGlslangToSpvTraverser::getSampledType(const glslang::TSampler& sampler)
\r
1258 switch (sampler.type) {
\r
1259 case glslang::EbtFloat: return builder.makeFloatType(32);
\r
1260 case glslang::EbtInt: return builder.makeIntType(32);
\r
1261 case glslang::EbtUint: return builder.makeUintType(32);
\r
1263 spv::MissingFunctionality("sampled type");
\r
1264 return builder.makeFloatType(32);
\r
1268 // Do full recursive conversion of an arbitrary glslang type to a SPIR-V Id.
\r
1269 spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type)
\r
1271 spv::Id spvType = 0;
\r
1273 switch (type.getBasicType()) {
\r
1274 case glslang::EbtVoid:
\r
1275 spvType = builder.makeVoidType();
\r
1276 if (type.isArray())
\r
1277 spv::MissingFunctionality("array of void");
\r
1279 case glslang::EbtFloat:
\r
1280 spvType = builder.makeFloatType(32);
\r
1282 case glslang::EbtDouble:
\r
1283 spvType = builder.makeFloatType(64);
\r
1285 case glslang::EbtBool:
\r
1286 spvType = builder.makeBoolType();
\r
1288 case glslang::EbtInt:
\r
1289 spvType = builder.makeIntType(32);
\r
1291 case glslang::EbtUint:
\r
1292 spvType = builder.makeUintType(32);
\r
1294 case glslang::EbtSampler:
\r
1296 const glslang::TSampler& sampler = type.getSampler();
\r
1297 spvType = builder.makeSampler(getSampledType(sampler), TranslateDimensionality(sampler),
\r
1298 sampler.image ? spv::Builder::samplerContentImage : spv::Builder::samplerContentTextureFilter,
\r
1299 sampler.arrayed, sampler.shadow, sampler.ms);
\r
1302 case glslang::EbtStruct:
\r
1303 case glslang::EbtBlock:
\r
1305 // If we've seen this struct type, return it
\r
1306 const glslang::TTypeList* glslangStruct = type.getStruct();
\r
1307 std::vector<spv::Id> structFields;
\r
1308 spvType = structMap[glslangStruct];
\r
1312 // else, we haven't seen it...
\r
1314 // Create a vector of struct types for SPIR-V to consume
\r
1315 int memberDelta = 0; // how much the member's index changes from glslang to SPIR-V, normally 0, except sometimes for blocks
\r
1316 if (type.getBasicType() == glslang::EbtBlock)
\r
1317 memberRemapper[glslangStruct].resize(glslangStruct->size());
\r
1318 for (int i = 0; i < (int)glslangStruct->size(); i++) {
\r
1319 glslang::TType& glslangType = *(*glslangStruct)[i].type;
\r
1320 if (glslangType.hiddenMember()) {
\r
1322 if (type.getBasicType() == glslang::EbtBlock)
\r
1323 memberRemapper[glslangStruct][i] = -1;
\r
1325 if (type.getBasicType() == glslang::EbtBlock)
\r
1326 memberRemapper[glslangStruct][i] = i - memberDelta;
\r
1327 structFields.push_back(convertGlslangToSpvType(glslangType));
\r
1331 // Make the SPIR-V type
\r
1332 spvType = builder.makeStructType(structFields, type.getTypeName().c_str());
\r
1333 structMap[glslangStruct] = spvType;
\r
1335 // Name and decorate the non-hidden members
\r
1336 for (int i = 0; i < (int)glslangStruct->size(); i++) {
\r
1337 glslang::TType& glslangType = *(*glslangStruct)[i].type;
\r
1339 if (type.getBasicType() == glslang::EbtBlock)
\r
1340 member = memberRemapper[glslangStruct][i];
\r
1341 // using -1 above to indicate a hidden member
\r
1342 if (member >= 0) {
\r
1343 builder.addMemberName(spvType, member, glslangType.getFieldName().c_str());
\r
1344 addMemberDecoration(spvType, member, TranslateLayoutDecoration(glslangType));
\r
1345 addMemberDecoration(spvType, member, TranslatePrecisionDecoration(glslangType));
\r
1346 addMemberDecoration(spvType, member, TranslateInterpolationDecoration(glslangType));
\r
1347 addMemberDecoration(spvType, member, TranslateInvariantDecoration(glslangType));
\r
1348 if (glslangType.getQualifier().hasLocation())
\r
1349 builder.addMemberDecoration(spvType, member, spv::DecorationLocation, glslangType.getQualifier().layoutLocation);
\r
1350 if (glslangType.getQualifier().hasComponent())
\r
1351 builder.addMemberDecoration(spvType, member, spv::DecorationComponent, glslangType.getQualifier().layoutComponent);
\r
1352 if (glslangType.getQualifier().hasXfbOffset())
\r
1353 builder.addMemberDecoration(spvType, member, spv::DecorationOffset, glslangType.getQualifier().layoutXfbOffset);
\r
1357 // Decorate the structure
\r
1358 addDecoration(spvType, TranslateLayoutDecoration(type));
\r
1359 addDecoration(spvType, TranslateBlockDecoration(type));
\r
1360 if (type.getQualifier().hasStream())
\r
1361 builder.addDecoration(spvType, spv::DecorationStream, type.getQualifier().layoutStream);
\r
1362 if (glslangIntermediate->getXfbMode()) {
\r
1363 if (type.getQualifier().hasXfbStride())
\r
1364 builder.addDecoration(spvType, spv::DecorationStride, type.getQualifier().layoutXfbStride);
\r
1365 if (type.getQualifier().hasXfbBuffer())
\r
1366 builder.addDecoration(spvType, spv::DecorationXfbBuffer, type.getQualifier().layoutXfbBuffer);
\r
1371 spv::MissingFunctionality("basic type");
\r
1375 if (type.isMatrix())
\r
1376 spvType = builder.makeMatrixType(spvType, type.getMatrixCols(), type.getMatrixRows());
\r
1378 // If this variable has a vector element count greater than 1, create a SPIR-V vector
\r
1379 if (type.getVectorSize() > 1)
\r
1380 spvType = builder.makeVectorType(spvType, type.getVectorSize());
\r
1383 if (type.isArray()) {
\r
1384 unsigned arraySize;
\r
1385 if (! type.isExplicitlySizedArray()) {
\r
1386 spv::MissingFunctionality("Unsized array");
\r
1389 arraySize = type.getArraySize();
\r
1390 spvType = builder.makeArrayType(spvType, arraySize);
\r
1396 bool TGlslangToSpvTraverser::isShaderEntrypoint(const glslang::TIntermAggregate* node)
\r
1398 return node->getName() == "main(";
\r
1401 // Make all the functions, skeletally, without actually visiting their bodies.
\r
1402 void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslFunctions)
\r
1404 for (int f = 0; f < (int)glslFunctions.size(); ++f) {
\r
1405 glslang::TIntermAggregate* glslFunction = glslFunctions[f]->getAsAggregate();
\r
1406 if (! glslFunction || glslFunction->getOp() != glslang::EOpFunction || isShaderEntrypoint(glslFunction))
\r
1409 // We're on a user function. Set up the basic interface for the function now,
\r
1410 // so that it's available to call.
\r
1411 // Translating the body will happen later.
\r
1413 // Typically (except for a "const in" parameter), an address will be passed to the
\r
1414 // function. What it is an address of varies:
\r
1416 // - "in" parameters not marked as "const" can be written to without modifying the argument,
\r
1417 // so that write needs to be to a copy, hence the address of a copy works.
\r
1419 // - "const in" parameters can just be the r-value, as no writes need occur.
\r
1421 // - "out" and "inout" arguments can't be done as direct pointers, because GLSL has
\r
1422 // copy-in/copy-out semantics. They can be handled though with a pointer to a copy.
\r
1424 std::vector<spv::Id> paramTypes;
\r
1425 glslang::TIntermSequence& parameters = glslFunction->getSequence()[0]->getAsAggregate()->getSequence();
\r
1427 for (int p = 0; p < (int)parameters.size(); ++p) {
\r
1428 const glslang::TType& paramType = parameters[p]->getAsTyped()->getType();
\r
1429 spv::Id typeId = convertGlslangToSpvType(paramType);
\r
1430 if (paramType.getQualifier().storage != glslang::EvqConstReadOnly)
\r
1431 typeId = builder.makePointer(spv::StorageClassFunction, typeId);
\r
1433 constReadOnlyParameters.insert(parameters[p]->getAsSymbolNode()->getId());
\r
1434 paramTypes.push_back(typeId);
\r
1437 spv::Block* functionBlock;
\r
1438 spv::Function *function = builder.makeFunctionEntry(convertGlslangToSpvType(glslFunction->getType()), glslFunction->getName().c_str(),
\r
1439 paramTypes, &functionBlock);
\r
1441 // Track function to emit/call later
\r
1442 functionMap[glslFunction->getName().c_str()] = function;
\r
1444 // Set the parameter id's
\r
1445 for (int p = 0; p < (int)parameters.size(); ++p) {
\r
1446 symbolValues[parameters[p]->getAsSymbolNode()->getId()] = function->getParamId(p);
\r
1447 // give a name too
\r
1448 builder.addName(function->getParamId(p), parameters[p]->getAsSymbolNode()->getName().c_str());
\r
1453 // Process all the initializers, while skipping the functions and link objects
\r
1454 void TGlslangToSpvTraverser::makeGlobalInitializers(const glslang::TIntermSequence& initializers)
\r
1456 builder.setBuildPoint(shaderEntry->getLastBlock());
\r
1457 for (int i = 0; i < (int)initializers.size(); ++i) {
\r
1458 glslang::TIntermAggregate* initializer = initializers[i]->getAsAggregate();
\r
1459 if (initializer && initializer->getOp() != glslang::EOpFunction && initializer->getOp() != glslang::EOpLinkerObjects) {
\r
1461 // We're on a top-level node that's not a function. Treat as an initializer, whose
\r
1462 // code goes into the beginning of main.
\r
1463 initializer->traverse(this);
\r
1468 // Process all the functions, while skipping initializers.
\r
1469 void TGlslangToSpvTraverser::visitFunctions(const glslang::TIntermSequence& glslFunctions)
\r
1471 for (int f = 0; f < (int)glslFunctions.size(); ++f) {
\r
1472 glslang::TIntermAggregate* node = glslFunctions[f]->getAsAggregate();
\r
1473 if (node && (node->getOp() == glslang::EOpFunction || node->getOp() == glslang ::EOpLinkerObjects))
\r
1474 node->traverse(this);
\r
1478 void TGlslangToSpvTraverser::handleFunctionEntry(const glslang::TIntermAggregate* node)
\r
1480 // SPIR-V functions should already be in the functionMap from the prepass
\r
1481 // that called makeFunctions().
\r
1482 spv::Function* function = functionMap[node->getName().c_str()];
\r
1483 spv::Block* functionBlock = function->getEntryBlock();
\r
1484 builder.setBuildPoint(functionBlock);
\r
1487 void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermSequence& glslangArguments, std::vector<spv::Id>& arguments)
\r
1489 for (int i = 0; i < (int)glslangArguments.size(); ++i) {
\r
1490 builder.clearAccessChain();
\r
1491 glslangArguments[i]->traverse(this);
\r
1492 arguments.push_back(builder.accessChainLoad(TranslatePrecisionDecoration(glslangArguments[i]->getAsTyped()->getType())));
\r
1496 spv::Id TGlslangToSpvTraverser::handleBuiltInFunctionCall(const glslang::TIntermAggregate* node)
\r
1498 std::vector<spv::Id> arguments;
\r
1499 translateArguments(node->getSequence(), arguments);
\r
1501 std::vector<spv::Id> argTypes;
\r
1502 for (int a = 0; a < (int)arguments.size(); ++a)
\r
1503 argTypes.push_back(builder.getTypeId(arguments[a]));
\r
1505 spv::Decoration precision = TranslatePrecisionDecoration(node->getType());
\r
1507 if (node->getName() == "ftransform(") {
\r
1508 spv::MissingFunctionality("ftransform()");
\r
1509 //spv::Id vertex = builder.createVariable(spv::StorageShaderGlobal, spv::VectorType::get(spv::makeFloatType(), 4),
\r
1510 // "gl_Vertex_sim");
\r
1511 //spv::Id matrix = builder.createVariable(spv::StorageShaderGlobal, spv::VectorType::get(spv::makeFloatType(), 4),
\r
1512 // "gl_ModelViewProjectionMatrix_sim");
\r
1516 if (node->getName().substr(0, 7) == "texture" || node->getName().substr(0, 5) == "texel" || node->getName().substr(0, 6) == "shadow") {
\r
1517 const glslang::TSampler sampler = node->getSequence()[0]->getAsTyped()->getType().getSampler();
\r
1518 spv::Builder::TextureParameters params = { };
\r
1519 params.sampler = arguments[0];
\r
1521 // special case size query
\r
1522 if (node->getName().find("textureSize", 0) != std::string::npos) {
\r
1523 if (arguments.size() > 1) {
\r
1524 params.lod = arguments[1];
\r
1525 return builder.createTextureQueryCall(spv::OpTextureQuerySizeLod, params);
\r
1527 return builder.createTextureQueryCall(spv::OpTextureQuerySize, params);
\r
1530 // special case the number of samples query
\r
1531 if (node->getName().find("textureSamples", 0) != std::string::npos)
\r
1532 return builder.createTextureQueryCall(spv::OpTextureQuerySamples, params);
\r
1534 // special case the other queries
\r
1535 if (node->getName().find("Query", 0) != std::string::npos) {
\r
1536 if (node->getName().find("Levels", 0) != std::string::npos)
\r
1537 return builder.createTextureQueryCall(spv::OpTextureQueryLevels, params);
\r
1538 else if (node->getName().find("Lod", 0) != std::string::npos) {
\r
1539 params.coords = arguments[1];
\r
1540 return builder.createTextureQueryCall(spv::OpTextureQueryLod, params);
\r
1542 spv::MissingFunctionality("glslang texture query");
\r
1545 // This is no longer a query....
\r
1547 bool lod = node->getName().find("Lod", 0) != std::string::npos;
\r
1548 bool proj = node->getName().find("Proj", 0) != std::string::npos;
\r
1549 bool offsets = node->getName().find("Offsets", 0) != std::string::npos;
\r
1550 bool offset = ! offsets && node->getName().find("Offset", 0) != std::string::npos;
\r
1551 bool fetch = node->getName().find("Fetch", 0) != std::string::npos;
\r
1552 bool gather = node->getName().find("Gather", 0) != std::string::npos;
\r
1553 bool grad = node->getName().find("Grad", 0) != std::string::npos;
\r
1556 spv::MissingFunctionality("texel fetch");
\r
1558 spv::MissingFunctionality("texture gather");
\r
1560 // check for bias argument
\r
1561 bool bias = false;
\r
1562 if (! lod && ! gather && ! grad && ! fetch) {
\r
1563 int nonBiasArgCount = 2;
\r
1565 ++nonBiasArgCount;
\r
1567 nonBiasArgCount += 2;
\r
1569 if ((int)arguments.size() > nonBiasArgCount)
\r
1573 bool cubeCompare = sampler.dim == glslang::EsdCube && sampler.arrayed && sampler.shadow;
\r
1575 // set the rest of the arguments
\r
1576 params.coords = arguments[1];
\r
1577 int extraArgs = 0;
\r
1579 params.Dref = arguments[2];
\r
1581 params.lod = arguments[2];
\r
1585 params.gradX = arguments[2 + extraArgs];
\r
1586 params.gradY = arguments[3 + extraArgs];
\r
1589 //if (gather && compare) {
\r
1590 // params.compare = arguments[2 + extraArgs];
\r
1593 if (offset | offsets) {
\r
1594 params.offset = arguments[2 + extraArgs];
\r
1598 params.bias = arguments[2 + extraArgs];
\r
1602 return builder.createTextureCall(precision, convertGlslangToSpvType(node->getType()), proj, params);
\r
1605 spv::MissingFunctionality("built-in function call");
\r
1610 spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAggregate* node)
\r
1612 // Grab the function's pointer from the previously created function
\r
1613 spv::Function* function = functionMap[node->getName().c_str()];
\r
1617 const glslang::TIntermSequence& glslangArgs = node->getSequence();
\r
1618 const glslang::TQualifierList& qualifiers = node->getQualifierList();
\r
1620 // See comments in makeFunctions() for details about the semantics for parameter passing.
\r
1622 // These imply we need a four step process:
\r
1623 // 1. Evaluate the arguments
\r
1624 // 2. Allocate and make copies of in, out, and inout arguments
\r
1625 // 3. Make the call
\r
1626 // 4. Copy back the results
\r
1628 // 1. Evaluate the arguments
\r
1629 std::vector<spv::Builder::AccessChain> lValues;
\r
1630 std::vector<spv::Id> rValues;
\r
1631 for (int a = 0; a < (int)glslangArgs.size(); ++a) {
\r
1633 builder.clearAccessChain();
\r
1634 glslangArgs[a]->traverse(this);
\r
1635 // keep outputs as l-values, evaluate input-only as r-values
\r
1636 if (qualifiers[a] != glslang::EvqConstReadOnly) {
\r
1638 lValues.push_back(builder.getAccessChain());
\r
1640 // process r-value
\r
1641 rValues.push_back(builder.accessChainLoad(TranslatePrecisionDecoration(glslangArgs[a]->getAsTyped()->getType())));
\r
1645 // 2. Allocate space for anything needing a copy, and if it's "in" or "inout"
\r
1646 // copy the original into that space.
\r
1648 // Also, build up the list of actual arguments to pass in for the call
\r
1649 int lValueCount = 0;
\r
1650 int rValueCount = 0;
\r
1651 std::vector<spv::Id> spvArgs;
\r
1652 for (int a = 0; a < (int)glslangArgs.size(); ++a) {
\r
1654 if (qualifiers[a] != glslang::EvqConstReadOnly) {
\r
1655 // need space to hold the copy
\r
1656 const glslang::TType& paramType = glslangArgs[a]->getAsTyped()->getType();
\r
1657 arg = builder.createVariable(spv::StorageClassFunction, convertGlslangToSpvType(paramType), "param");
\r
1658 if (qualifiers[a] == glslang::EvqIn || qualifiers[a] == glslang::EvqInOut) {
\r
1659 // need to copy the input into output space
\r
1660 builder.setAccessChain(lValues[lValueCount]);
\r
1661 spv::Id copy = builder.accessChainLoad(spv::NoPrecision); // TODO: get precision
\r
1662 builder.createStore(copy, arg);
\r
1666 arg = rValues[rValueCount];
\r
1669 spvArgs.push_back(arg);
\r
1672 // 3. Make the call.
\r
1673 spv::Id result = builder.createFunctionCall(function, spvArgs);
\r
1675 // 4. Copy back out an "out" arguments.
\r
1677 for (int a = 0; a < (int)glslangArgs.size(); ++a) {
\r
1678 if (qualifiers[a] != glslang::EvqConstReadOnly) {
\r
1679 if (qualifiers[a] == glslang::EvqOut || qualifiers[a] == glslang::EvqInOut) {
\r
1680 spv::Id copy = builder.createLoad(spvArgs[a]);
\r
1681 builder.setAccessChain(lValues[lValueCount]);
\r
1682 builder.accessChainStore(copy);
\r
1691 spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, spv::Decoration precision,
\r
1692 spv::Id typeId, spv::Id left, spv::Id right,
\r
1693 glslang::TBasicType typeProxy, bool reduceComparison)
\r
1695 bool isUnsigned = typeProxy == glslang::EbtUint;
\r
1696 bool isFloat = typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble;
\r
1698 spv::Op binOp = spv::OpNop;
\r
1699 bool needsPromotion = true;
\r
1700 bool comparison = false;
\r
1703 case glslang::EOpAdd:
\r
1704 case glslang::EOpAddAssign:
\r
1706 binOp = spv::OpFAdd;
\r
1708 binOp = spv::OpIAdd;
\r
1710 case glslang::EOpSub:
\r
1711 case glslang::EOpSubAssign:
\r
1713 binOp = spv::OpFSub;
\r
1715 binOp = spv::OpISub;
\r
1717 case glslang::EOpMul:
\r
1718 case glslang::EOpMulAssign:
\r
1720 binOp = spv::OpFMul;
\r
1722 binOp = spv::OpIMul;
\r
1724 case glslang::EOpVectorTimesScalar:
\r
1725 case glslang::EOpVectorTimesScalarAssign:
\r
1726 binOp = spv::OpVectorTimesScalar;
\r
1727 needsPromotion = false;
\r
1729 case glslang::EOpVectorTimesMatrix:
\r
1730 case glslang::EOpVectorTimesMatrixAssign:
\r
1731 binOp = spv::OpVectorTimesMatrix;
\r
1733 case glslang::EOpMatrixTimesVector:
\r
1734 binOp = spv::OpMatrixTimesVector;
\r
1736 case glslang::EOpMatrixTimesScalar:
\r
1737 case glslang::EOpMatrixTimesScalarAssign:
\r
1738 binOp = spv::OpMatrixTimesScalar;
\r
1740 case glslang::EOpMatrixTimesMatrix:
\r
1741 case glslang::EOpMatrixTimesMatrixAssign:
\r
1742 binOp = spv::OpMatrixTimesMatrix;
\r
1744 case glslang::EOpOuterProduct:
\r
1745 binOp = spv::OpOuterProduct;
\r
1746 needsPromotion = false;
\r
1749 case glslang::EOpDiv:
\r
1750 case glslang::EOpDivAssign:
\r
1752 binOp = spv::OpFDiv;
\r
1753 else if (isUnsigned)
\r
1754 binOp = spv::OpUDiv;
\r
1756 binOp = spv::OpSDiv;
\r
1758 case glslang::EOpMod:
\r
1759 case glslang::EOpModAssign:
\r
1761 binOp = spv::OpFMod;
\r
1762 else if (isUnsigned)
\r
1763 binOp = spv::OpUMod;
\r
1765 binOp = spv::OpSMod;
\r
1767 case glslang::EOpRightShift:
\r
1768 case glslang::EOpRightShiftAssign:
\r
1770 binOp = spv::OpShiftRightLogical;
\r
1772 binOp = spv::OpShiftRightArithmetic;
\r
1774 case glslang::EOpLeftShift:
\r
1775 case glslang::EOpLeftShiftAssign:
\r
1776 binOp = spv::OpShiftLeftLogical;
\r
1778 case glslang::EOpAnd:
\r
1779 case glslang::EOpAndAssign:
\r
1780 binOp = spv::OpBitwiseAnd;
\r
1782 case glslang::EOpLogicalAnd:
\r
1783 needsPromotion = false;
\r
1784 binOp = spv::OpLogicalAnd;
\r
1786 case glslang::EOpInclusiveOr:
\r
1787 case glslang::EOpInclusiveOrAssign:
\r
1788 binOp = spv::OpBitwiseOr;
\r
1790 case glslang::EOpLogicalOr:
\r
1791 needsPromotion = false;
\r
1792 binOp = spv::OpLogicalOr;
\r
1794 case glslang::EOpExclusiveOr:
\r
1795 case glslang::EOpExclusiveOrAssign:
\r
1796 binOp = spv::OpBitwiseXor;
\r
1798 case glslang::EOpLogicalXor:
\r
1799 needsPromotion = false;
\r
1800 binOp = spv::OpLogicalXor;
\r
1803 case glslang::EOpLessThan:
\r
1804 case glslang::EOpGreaterThan:
\r
1805 case glslang::EOpLessThanEqual:
\r
1806 case glslang::EOpGreaterThanEqual:
\r
1807 case glslang::EOpEqual:
\r
1808 case glslang::EOpNotEqual:
\r
1809 case glslang::EOpVectorEqual:
\r
1810 case glslang::EOpVectorNotEqual:
\r
1811 comparison = true;
\r
1817 if (binOp != spv::OpNop) {
\r
1818 if (builder.isMatrix(left) || builder.isMatrix(right)) {
\r
1820 case spv::OpMatrixTimesScalar:
\r
1821 case spv::OpVectorTimesMatrix:
\r
1822 case spv::OpMatrixTimesVector:
\r
1823 case spv::OpMatrixTimesMatrix:
\r
1826 // turn it into a multiply...
\r
1827 assert(builder.isMatrix(left) && builder.isScalar(right));
\r
1828 right = builder.createBinOp(spv::OpFDiv, builder.getTypeId(right), builder.makeFloatConstant(1.0F), right);
\r
1829 binOp = spv::OpFMul;
\r
1832 spv::MissingFunctionality("binary operation on matrix");
\r
1836 spv::Id id = builder.createBinOp(binOp, typeId, left, right);
\r
1837 builder.setPrecision(id, precision);
\r
1842 // No matrix involved; make both operands be the same number of components, if needed
\r
1843 if (needsPromotion)
\r
1844 builder.promoteScalar(precision, left, right);
\r
1846 spv::Id id = builder.createBinOp(binOp, typeId, left, right);
\r
1847 builder.setPrecision(id, precision);
\r
1855 // Comparison instructions
\r
1857 if (reduceComparison && (builder.isVector(left) || builder.isMatrix(left) || builder.isAggregate(left))) {
\r
1858 assert(op == glslang::EOpEqual || op == glslang::EOpNotEqual);
\r
1860 return builder.createCompare(precision, left, right, op == glslang::EOpEqual);
\r
1864 case glslang::EOpLessThan:
\r
1866 binOp = spv::OpFOrdLessThan;
\r
1867 else if (isUnsigned)
\r
1868 binOp = spv::OpULessThan;
\r
1870 binOp = spv::OpSLessThan;
\r
1872 case glslang::EOpGreaterThan:
\r
1874 binOp = spv::OpFOrdGreaterThan;
\r
1875 else if (isUnsigned)
\r
1876 binOp = spv::OpUGreaterThan;
\r
1878 binOp = spv::OpSGreaterThan;
\r
1880 case glslang::EOpLessThanEqual:
\r
1882 binOp = spv::OpFOrdLessThanEqual;
\r
1883 else if (isUnsigned)
\r
1884 binOp = spv::OpULessThanEqual;
\r
1886 binOp = spv::OpSLessThanEqual;
\r
1888 case glslang::EOpGreaterThanEqual:
\r
1890 binOp = spv::OpFOrdGreaterThanEqual;
\r
1891 else if (isUnsigned)
\r
1892 binOp = spv::OpUGreaterThanEqual;
\r
1894 binOp = spv::OpSGreaterThanEqual;
\r
1896 case glslang::EOpEqual:
\r
1897 case glslang::EOpVectorEqual:
\r
1899 binOp = spv::OpFOrdEqual;
\r
1901 binOp = spv::OpIEqual;
\r
1903 case glslang::EOpNotEqual:
\r
1904 case glslang::EOpVectorNotEqual:
\r
1906 binOp = spv::OpFOrdNotEqual;
\r
1908 binOp = spv::OpINotEqual;
\r
1914 if (binOp != spv::OpNop) {
\r
1915 spv::Id id = builder.createBinOp(binOp, typeId, left, right);
\r
1916 builder.setPrecision(id, precision);
\r
1924 spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, spv::Id operand, bool isFloat)
\r
1926 spv::Op unaryOp = spv::OpNop;
\r
1930 case glslang::EOpNegative:
\r
1932 unaryOp = spv::OpFNegate;
\r
1934 unaryOp = spv::OpSNegate;
\r
1937 case glslang::EOpLogicalNot:
\r
1938 case glslang::EOpVectorLogicalNot:
\r
1939 case glslang::EOpBitwiseNot:
\r
1940 unaryOp = spv::OpNot;
\r
1943 case glslang::EOpDeterminant:
\r
1944 libCall = GLSL_STD_450::Determinant;
\r
1946 case glslang::EOpMatrixInverse:
\r
1947 libCall = GLSL_STD_450::MatrixInverse;
\r
1949 case glslang::EOpTranspose:
\r
1950 unaryOp = spv::OpTranspose;
\r
1953 case glslang::EOpRadians:
\r
1954 libCall = GLSL_STD_450::Radians;
\r
1956 case glslang::EOpDegrees:
\r
1957 libCall = GLSL_STD_450::Degrees;
\r
1959 case glslang::EOpSin:
\r
1960 libCall = GLSL_STD_450::Sin;
\r
1962 case glslang::EOpCos:
\r
1963 libCall = GLSL_STD_450::Cos;
\r
1965 case glslang::EOpTan:
\r
1966 libCall = GLSL_STD_450::Tan;
\r
1968 case glslang::EOpAcos:
\r
1969 libCall = GLSL_STD_450::Acos;
\r
1971 case glslang::EOpAsin:
\r
1972 libCall = GLSL_STD_450::Asin;
\r
1974 case glslang::EOpAtan:
\r
1975 libCall = GLSL_STD_450::Atan;
\r
1978 case glslang::EOpAcosh:
\r
1979 libCall = GLSL_STD_450::Acosh;
\r
1981 case glslang::EOpAsinh:
\r
1982 libCall = GLSL_STD_450::Asinh;
\r
1984 case glslang::EOpAtanh:
\r
1985 libCall = GLSL_STD_450::Atanh;
\r
1987 case glslang::EOpTanh:
\r
1988 libCall = GLSL_STD_450::Tanh;
\r
1990 case glslang::EOpCosh:
\r
1991 libCall = GLSL_STD_450::Cosh;
\r
1993 case glslang::EOpSinh:
\r
1994 libCall = GLSL_STD_450::Sinh;
\r
1997 case glslang::EOpLength:
\r
1998 libCall = GLSL_STD_450::Length;
\r
2000 case glslang::EOpNormalize:
\r
2001 libCall = GLSL_STD_450::Normalize;
\r
2004 case glslang::EOpExp:
\r
2005 libCall = GLSL_STD_450::Exp;
\r
2007 case glslang::EOpLog:
\r
2008 libCall = GLSL_STD_450::Log;
\r
2010 case glslang::EOpExp2:
\r
2011 libCall = GLSL_STD_450::Exp2;
\r
2013 case glslang::EOpLog2:
\r
2014 libCall = GLSL_STD_450::Log2;
\r
2016 case glslang::EOpSqrt:
\r
2017 libCall = GLSL_STD_450::Sqrt;
\r
2019 case glslang::EOpInverseSqrt:
\r
2020 libCall = GLSL_STD_450::InverseSqrt;
\r
2023 case glslang::EOpFloor:
\r
2024 libCall = GLSL_STD_450::Floor;
\r
2026 case glslang::EOpTrunc:
\r
2027 libCall = GLSL_STD_450::Trunc;
\r
2029 case glslang::EOpRound:
\r
2030 libCall = GLSL_STD_450::Round;
\r
2032 case glslang::EOpRoundEven:
\r
2033 libCall = GLSL_STD_450::RoundEven;
\r
2035 case glslang::EOpCeil:
\r
2036 libCall = GLSL_STD_450::Ceil;
\r
2038 case glslang::EOpFract:
\r
2039 libCall = GLSL_STD_450::Fract;
\r
2042 case glslang::EOpIsNan:
\r
2043 unaryOp = spv::OpIsNan;
\r
2045 case glslang::EOpIsInf:
\r
2046 unaryOp = spv::OpIsInf;
\r
2049 case glslang::EOpFloatBitsToInt:
\r
2050 libCall = GLSL_STD_450::FloatBitsToInt;
\r
2052 case glslang::EOpFloatBitsToUint:
\r
2053 libCall = GLSL_STD_450::FloatBitsToUint;
\r
2055 case glslang::EOpIntBitsToFloat:
\r
2056 libCall = GLSL_STD_450::IntBitsToFloat;
\r
2058 case glslang::EOpUintBitsToFloat:
\r
2059 libCall = GLSL_STD_450::UintBitsToFloat;
\r
2061 case glslang::EOpPackSnorm2x16:
\r
2062 libCall = GLSL_STD_450::PackSnorm2x16;
\r
2064 case glslang::EOpUnpackSnorm2x16:
\r
2065 libCall = GLSL_STD_450::UnpackSnorm2x16;
\r
2067 case glslang::EOpPackUnorm2x16:
\r
2068 libCall = GLSL_STD_450::PackUnorm2x16;
\r
2070 case glslang::EOpUnpackUnorm2x16:
\r
2071 libCall = GLSL_STD_450::UnpackUnorm2x16;
\r
2073 case glslang::EOpPackHalf2x16:
\r
2074 libCall = GLSL_STD_450::PackHalf2x16;
\r
2076 case glslang::EOpUnpackHalf2x16:
\r
2077 libCall = GLSL_STD_450::UnpackHalf2x16;
\r
2080 case glslang::EOpDPdx:
\r
2081 unaryOp = spv::OpDPdx;
\r
2083 case glslang::EOpDPdy:
\r
2084 unaryOp = spv::OpDPdy;
\r
2086 case glslang::EOpFwidth:
\r
2087 unaryOp = spv::OpFwidth;
\r
2089 case glslang::EOpDPdxFine:
\r
2090 unaryOp = spv::OpDPdxFine;
\r
2092 case glslang::EOpDPdyFine:
\r
2093 unaryOp = spv::OpDPdyFine;
\r
2095 case glslang::EOpFwidthFine:
\r
2096 unaryOp = spv::OpFwidthFine;
\r
2098 case glslang::EOpDPdxCoarse:
\r
2099 unaryOp = spv::OpDPdxCoarse;
\r
2101 case glslang::EOpDPdyCoarse:
\r
2102 unaryOp = spv::OpDPdyCoarse;
\r
2104 case glslang::EOpFwidthCoarse:
\r
2105 unaryOp = spv::OpFwidthCoarse;
\r
2108 case glslang::EOpAny:
\r
2109 unaryOp = spv::OpAny;
\r
2111 case glslang::EOpAll:
\r
2112 unaryOp = spv::OpAll;
\r
2115 case glslang::EOpAbs:
\r
2116 libCall = GLSL_STD_450::Abs;
\r
2118 case glslang::EOpSign:
\r
2119 libCall = GLSL_STD_450::Sign;
\r
2127 if (libCall >= 0) {
\r
2128 std::vector<spv::Id> args;
\r
2129 args.push_back(operand);
\r
2130 id = builder.createBuiltinCall(precision, typeId, stdBuiltins, libCall, args);
\r
2132 id = builder.createUnaryOp(unaryOp, typeId, operand);
\r
2134 builder.setPrecision(id, precision);
\r
2139 spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, spv::Decoration precision, spv::Id destType, spv::Id operand)
\r
2141 spv::Op convOp = spv::OpNop;
\r
2145 int vectorSize = builder.isVectorType(destType) ? builder.getNumTypeComponents(destType) : 0;
\r
2148 case glslang::EOpConvIntToBool:
\r
2149 case glslang::EOpConvUintToBool:
\r
2150 zero = builder.makeUintConstant(0);
\r
2151 zero = makeSmearedConstant(zero, vectorSize);
\r
2152 return builder.createBinOp(spv::OpINotEqual, destType, operand, zero);
\r
2154 case glslang::EOpConvFloatToBool:
\r
2155 zero = builder.makeFloatConstant(0.0F);
\r
2156 zero = makeSmearedConstant(zero, vectorSize);
\r
2157 return builder.createBinOp(spv::OpFOrdNotEqual, destType, operand, zero);
\r
2159 case glslang::EOpConvDoubleToBool:
\r
2160 zero = builder.makeDoubleConstant(0.0);
\r
2161 zero = makeSmearedConstant(zero, vectorSize);
\r
2162 return builder.createBinOp(spv::OpFOrdNotEqual, destType, operand, zero);
\r
2164 case glslang::EOpConvBoolToFloat:
\r
2165 convOp = spv::OpSelect;
\r
2166 zero = builder.makeFloatConstant(0.0);
\r
2167 one = builder.makeFloatConstant(1.0);
\r
2169 case glslang::EOpConvBoolToDouble:
\r
2170 convOp = spv::OpSelect;
\r
2171 zero = builder.makeDoubleConstant(0.0);
\r
2172 one = builder.makeDoubleConstant(1.0);
\r
2174 case glslang::EOpConvBoolToInt:
\r
2175 zero = builder.makeIntConstant(0);
\r
2176 one = builder.makeIntConstant(1);
\r
2177 convOp = spv::OpSelect;
\r
2179 case glslang::EOpConvBoolToUint:
\r
2180 zero = builder.makeUintConstant(0);
\r
2181 one = builder.makeUintConstant(1);
\r
2182 convOp = spv::OpSelect;
\r
2185 case glslang::EOpConvIntToFloat:
\r
2186 case glslang::EOpConvIntToDouble:
\r
2187 convOp = spv::OpConvertSToF;
\r
2190 case glslang::EOpConvUintToFloat:
\r
2191 case glslang::EOpConvUintToDouble:
\r
2192 convOp = spv::OpConvertUToF;
\r
2195 case glslang::EOpConvDoubleToFloat:
\r
2196 case glslang::EOpConvFloatToDouble:
\r
2197 convOp = spv::OpFConvert;
\r
2200 case glslang::EOpConvFloatToInt:
\r
2201 case glslang::EOpConvDoubleToInt:
\r
2202 convOp = spv::OpConvertFToS;
\r
2205 case glslang::EOpConvUintToInt:
\r
2206 case glslang::EOpConvIntToUint:
\r
2207 convOp = spv::OpBitcast;
\r
2210 case glslang::EOpConvFloatToUint:
\r
2211 case glslang::EOpConvDoubleToUint:
\r
2212 convOp = spv::OpConvertFToU;
\r
2218 spv::Id result = 0;
\r
2219 if (convOp == spv::OpNop)
\r
2222 if (convOp == spv::OpSelect) {
\r
2223 zero = makeSmearedConstant(zero, vectorSize);
\r
2224 one = makeSmearedConstant(one, vectorSize);
\r
2225 result = builder.createTriOp(convOp, destType, operand, one, zero);
\r
2227 result = builder.createUnaryOp(convOp, destType, operand);
\r
2229 builder.setPrecision(result, precision);
\r
2234 spv::Id TGlslangToSpvTraverser::makeSmearedConstant(spv::Id constant, int vectorSize)
\r
2236 if (vectorSize == 0)
\r
2239 spv::Id vectorTypeId = builder.makeVectorType(builder.getTypeId(constant), vectorSize);
\r
2240 std::vector<spv::Id> components;
\r
2241 for (int c = 0; c < vectorSize; ++c)
\r
2242 components.push_back(constant);
\r
2243 return builder.makeCompositeConstant(vectorTypeId, components);
\r
2246 spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands)
\r
2248 spv::Op opCode = spv::OpNop;
\r
2252 case glslang::EOpMin:
\r
2253 libCall = GLSL_STD_450::Min;
\r
2255 case glslang::EOpModf:
\r
2256 libCall = GLSL_STD_450::Modf;
\r
2258 case glslang::EOpMax:
\r
2259 libCall = GLSL_STD_450::Max;
\r
2261 case glslang::EOpPow:
\r
2262 libCall = GLSL_STD_450::Pow;
\r
2264 case glslang::EOpDot:
\r
2265 opCode = spv::OpDot;
\r
2267 case glslang::EOpAtan:
\r
2268 libCall = GLSL_STD_450::Atan2;
\r
2271 case glslang::EOpClamp:
\r
2272 libCall = GLSL_STD_450::Clamp;
\r
2274 case glslang::EOpMix:
\r
2275 libCall = GLSL_STD_450::Mix;
\r
2277 case glslang::EOpStep:
\r
2278 libCall = GLSL_STD_450::Step;
\r
2280 case glslang::EOpSmoothStep:
\r
2281 libCall = GLSL_STD_450::SmoothStep;
\r
2284 case glslang::EOpDistance:
\r
2285 libCall = GLSL_STD_450::Distance;
\r
2287 case glslang::EOpCross:
\r
2288 libCall = GLSL_STD_450::Cross;
\r
2290 case glslang::EOpFaceForward:
\r
2291 libCall = GLSL_STD_450::FaceForward;
\r
2293 case glslang::EOpReflect:
\r
2294 libCall = GLSL_STD_450::Reflect;
\r
2296 case glslang::EOpRefract:
\r
2297 libCall = GLSL_STD_450::Refract;
\r
2305 id = builder.createBuiltinCall(precision, typeId, stdBuiltins, libCall, operands);
\r
2307 switch (operands.size()) {
\r
2309 // should all be handled by visitAggregate and createNoArgOperation
\r
2313 // should all be handled by createUnaryOperation
\r
2317 id = builder.createBinOp(opCode, typeId, operands[0], operands[1]);
\r
2320 id = builder.createTernaryOp(opCode, typeId, operands[0], operands[1], operands[2]);
\r
2323 // These do not exist yet
\r
2324 assert(0 && "operation with more than 3 operands");
\r
2329 builder.setPrecision(id, precision);
\r
2334 // Intrinsics with no arguments, no return value, and no precision.
\r
2335 spv::Id TGlslangToSpvTraverser::createNoArgOperation(glslang::TOperator op)
\r
2337 // TODO: get the barrier operands correct
\r
2340 case glslang::EOpEmitVertex:
\r
2341 builder.createNoResultOp(spv::OpEmitVertex);
\r
2343 case glslang::EOpEndPrimitive:
\r
2344 builder.createNoResultOp(spv::OpEndPrimitive);
\r
2346 case glslang::EOpBarrier:
\r
2347 builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsAllMemory);
\r
2348 builder.createControlBarrier(spv::ExecutionScopeDevice);
\r
2350 case glslang::EOpMemoryBarrier:
\r
2351 builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsAllMemory);
\r
2353 case glslang::EOpMemoryBarrierAtomicCounter:
\r
2354 builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsAtomicCounterMemoryMask);
\r
2356 case glslang::EOpMemoryBarrierBuffer:
\r
2357 builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsUniformMemoryMask);
\r
2359 case glslang::EOpMemoryBarrierImage:
\r
2360 builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsImageMemoryMask);
\r
2362 case glslang::EOpMemoryBarrierShared:
\r
2363 builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsWorkgroupLocalMemoryMask);
\r
2365 case glslang::EOpGroupMemoryBarrier:
\r
2366 builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsWorkgroupGlobalMemoryMask);
\r
2369 spv::MissingFunctionality("operation with no arguments");
\r
2374 spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol)
\r
2376 std::map<int, spv::Id>::iterator iter;
\r
2377 iter = symbolValues.find(symbol->getId());
\r
2379 if (symbolValues.end() != iter) {
\r
2380 id = iter->second;
\r
2384 // it was not found, create it
\r
2385 id = createSpvVariable(symbol);
\r
2386 symbolValues[symbol->getId()] = id;
\r
2388 if (! symbol->getType().isStruct()) {
\r
2389 addDecoration(id, TranslatePrecisionDecoration(symbol->getType()));
\r
2390 addDecoration(id, TranslateInterpolationDecoration(symbol->getType()));
\r
2391 if (symbol->getQualifier().hasLocation())
\r
2392 builder.addDecoration(id, spv::DecorationLocation, symbol->getQualifier().layoutLocation);
\r
2393 if (symbol->getQualifier().hasIndex())
\r
2394 builder.addDecoration(id, spv::DecorationIndex, symbol->getQualifier().layoutIndex);
\r
2395 if (symbol->getQualifier().hasComponent())
\r
2396 builder.addDecoration(id, spv::DecorationComponent, symbol->getQualifier().layoutComponent);
\r
2397 if (glslangIntermediate->getXfbMode()) {
\r
2398 if (symbol->getQualifier().hasXfbStride())
\r
2399 builder.addDecoration(id, spv::DecorationStride, symbol->getQualifier().layoutXfbStride);
\r
2400 if (symbol->getQualifier().hasXfbBuffer())
\r
2401 builder.addDecoration(id, spv::DecorationXfbBuffer, symbol->getQualifier().layoutXfbBuffer);
\r
2402 if (symbol->getQualifier().hasXfbOffset())
\r
2403 builder.addDecoration(id, spv::DecorationOffset, symbol->getQualifier().layoutXfbOffset);
\r
2407 addDecoration(id, TranslateInvariantDecoration(symbol->getType()));
\r
2408 if (symbol->getQualifier().hasStream())
\r
2409 builder.addDecoration(id, spv::DecorationStream, symbol->getQualifier().layoutStream);
\r
2410 if (symbol->getQualifier().hasSet())
\r
2411 builder.addDecoration(id, spv::DecorationDescriptorSet, symbol->getQualifier().layoutSet);
\r
2412 if (symbol->getQualifier().hasBinding())
\r
2413 builder.addDecoration(id, spv::DecorationBinding, symbol->getQualifier().layoutBinding);
\r
2414 if (glslangIntermediate->getXfbMode()) {
\r
2415 if (symbol->getQualifier().hasXfbStride())
\r
2416 builder.addDecoration(id, spv::DecorationStride, symbol->getQualifier().layoutXfbStride);
\r
2417 if (symbol->getQualifier().hasXfbBuffer())
\r
2418 builder.addDecoration(id, spv::DecorationXfbBuffer, symbol->getQualifier().layoutXfbBuffer);
\r
2421 // built-in variable decorations
\r
2422 int num = TranslateBuiltInDecoration(*symbol);
\r
2423 if (num != spv::BadValue)
\r
2424 builder.addDecoration(id, spv::DecorationBuiltIn, num);
\r
2427 builder.addDecoration(id, spv::DecorationNoStaticUse);
\r
2432 void TGlslangToSpvTraverser::addDecoration(spv::Id id, spv::Decoration dec)
\r
2434 if (dec != spv::BadValue)
\r
2435 builder.addDecoration(id, dec);
\r
2438 void TGlslangToSpvTraverser::addMemberDecoration(spv::Id id, int member, spv::Decoration dec)
\r
2440 if (dec != spv::BadValue)
\r
2441 builder.addMemberDecoration(id, (unsigned)member, dec);
\r
2444 // Use 'consts' as the flattened glslang source of scalar constants to recursively
\r
2445 // build the aggregate SPIR-V constant.
\r
2447 // If there are not enough elements present in 'consts', 0 will be substituted;
\r
2448 // an empty 'consts' can be used to create a fully zeroed SPIR-V constant.
\r
2450 spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TType& glslangType, const glslang::TConstUnionArray& consts, int& nextConst)
\r
2452 // vector of constants for SPIR-V
\r
2453 std::vector<spv::Id> spvConsts;
\r
2455 // Type is used for struct and array constants
\r
2456 spv::Id typeId = convertGlslangToSpvType(glslangType);
\r
2458 if (glslangType.isArray()) {
\r
2459 glslang::TType elementType;
\r
2460 elementType.shallowCopy(glslangType); // TODO: desktop arrays of arrays functionality will need a deeper copy to avoid modifying the original
\r
2461 elementType.dereference();
\r
2462 for (int i = 0; i < glslangType.getArraySize(); ++i)
\r
2463 spvConsts.push_back(createSpvConstant(elementType, consts, nextConst));
\r
2464 } else if (glslangType.isMatrix()) {
\r
2465 glslang::TType vectorType;
\r
2466 vectorType.shallowCopy(glslangType);
\r
2467 vectorType.dereference();
\r
2468 for (int col = 0; col < glslangType.getMatrixCols(); ++col)
\r
2469 spvConsts.push_back(createSpvConstant(vectorType, consts, nextConst));
\r
2470 } else if (glslangType.getStruct()) {
\r
2471 glslang::TVector<glslang::TTypeLoc>::const_iterator iter;
\r
2472 for (iter = glslangType.getStruct()->begin(); iter != glslangType.getStruct()->end(); ++iter)
\r
2473 spvConsts.push_back(createSpvConstant(*iter->type, consts, nextConst));
\r
2474 } else if (glslangType.isVector()) {
\r
2475 for (unsigned int i = 0; i < (unsigned int)glslangType.getVectorSize(); ++i) {
\r
2476 bool zero = nextConst >= consts.size();
\r
2477 switch (glslangType.getBasicType()) {
\r
2478 case glslang::EbtInt:
\r
2479 spvConsts.push_back(builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst()));
\r
2481 case glslang::EbtUint:
\r
2482 spvConsts.push_back(builder.makeUintConstant(zero ? 0 : consts[nextConst].getUConst()));
\r
2484 case glslang::EbtFloat:
\r
2485 spvConsts.push_back(builder.makeFloatConstant(zero ? 0.0F : (float)consts[nextConst].getDConst()));
\r
2487 case glslang::EbtDouble:
\r
2488 spvConsts.push_back(builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst()));
\r
2490 case glslang::EbtBool:
\r
2491 spvConsts.push_back(builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst()));
\r
2494 spv::MissingFunctionality("constant vector type");
\r
2500 // we have a non-aggregate (scalar) constant
\r
2501 bool zero = nextConst >= consts.size();
\r
2502 spv::Id scalar = 0;
\r
2503 switch (glslangType.getBasicType()) {
\r
2504 case glslang::EbtInt:
\r
2505 scalar = builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst());
\r
2507 case glslang::EbtUint:
\r
2508 scalar = builder.makeUintConstant(zero ? 0 : consts[nextConst].getUConst());
\r
2510 case glslang::EbtFloat:
\r
2511 scalar = builder.makeFloatConstant(zero ? 0.0F : (float)consts[nextConst].getDConst());
\r
2513 case glslang::EbtDouble:
\r
2514 scalar = builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst());
\r
2516 case glslang::EbtBool:
\r
2517 scalar = builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst());
\r
2520 spv::MissingFunctionality("constant scalar type");
\r
2527 return builder.makeCompositeConstant(typeId, spvConsts);
\r
2530 }; // end anonymous namespace
\r
2532 namespace glslang {
\r
2534 // Write SPIR-V out to a binary file
\r
2535 void OutputSpv(const std::vector<unsigned int>& spirv, const char* baseName)
\r
2537 std::ofstream out;
\r
2538 std::string fileName(baseName);
\r
2539 fileName.append(".spv");
\r
2540 out.open(fileName.c_str(), std::ios::binary | std::ios::out);
\r
2541 for (int i = 0; i < (int)spirv.size(); ++i) {
\r
2542 unsigned int word = spirv[i];
\r
2543 out.write((const char*)&word, 4);
\r
2549 // Set up the glslang traversal
\r
2551 void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv)
\r
2553 TIntermNode* root = intermediate.getTreeRoot();
\r
2558 glslang::GetThreadPoolAllocator().push();
\r
2560 TGlslangToSpvTraverser it(&intermediate);
\r
2562 root->traverse(&it);
\r
2564 it.dumpSpv(spirv);
\r
2566 glslang::GetThreadPoolAllocator().pop();
\r
2569 }; // end namespace glslang
\r