• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef SKSL_SPIRVCODEGENERATOR
9 #define SKSL_SPIRVCODEGENERATOR
10 
11 #include <stack>
12 #include <tuple>
13 #include <unordered_map>
14 #include <unordered_set>
15 
16 #include "src/core/SkOpts.h"
17 #include "src/sksl/SkSLMemoryLayout.h"
18 #include "src/sksl/SkSLStringStream.h"
19 #include "src/sksl/codegen/SkSLCodeGenerator.h"
20 
21 namespace SkSL {
22 
23 class BinaryExpression;
24 class Block;
25 class ConstructorCompound;
26 class ConstructorCompoundCast;
27 class ConstructorDiagonalMatrix;
28 class ConstructorMatrixResize;
29 class ConstructorScalarCast;
30 class ConstructorSplat;
31 class DoStatement;
32 class FieldAccess;
33 class ForStatement;
34 class FunctionCall;
35 class FunctionDeclaration;
36 class FunctionDefinition;
37 class FunctionPrototype;
38 class IfStatement;
39 struct IndexExpression;
40 class InterfaceBlock;
41 enum IntrinsicKind : int8_t;
42 class Literal;
43 class Operator;
44 class PostfixExpression;
45 class PrefixExpression;
46 class ReturnStatement;
47 class Setting;
48 class StructDefinition;
49 class SwitchStatement;
50 struct Swizzle;
51 class TernaryExpression;
52 class VarDeclaration;
53 class VariableReference;
54 
55 struct SPIRVNumberConstant {
56     bool operator==(const SPIRVNumberConstant& that) const {
57         return fValueBits == that.fValueBits &&
58                fKind      == that.fKind;
59     }
60     int32_t                fValueBits;
61     SkSL::Type::NumberKind fKind;
62 };
63 
64 struct SPIRVVectorConstant {
65     bool operator==(const SPIRVVectorConstant& that) const {
66         return fTypeId     == that.fTypeId &&
67                fValueId[0] == that.fValueId[0] &&
68                fValueId[1] == that.fValueId[1] &&
69                fValueId[2] == that.fValueId[2] &&
70                fValueId[3] == that.fValueId[3];
71     }
72     SpvId fTypeId;
73     SpvId fValueId[4];
74 };
75 
76 }  // namespace SkSL
77 
78 namespace std {
79 
80 template <>
81 struct hash<SkSL::SPIRVNumberConstant> {
82     size_t operator()(const SkSL::SPIRVNumberConstant& key) const {
83         return key.fValueBits ^ (int)key.fKind;
84     }
85 };
86 
87 template <>
88 struct hash<SkSL::SPIRVVectorConstant> {
89     size_t operator()(const SkSL::SPIRVVectorConstant& key) const {
90         return SkOpts::hash(&key, sizeof(key));
91     }
92 };
93 
94 }  // namespace std
95 
96 namespace SkSL {
97 
98 /**
99  * Converts a Program into a SPIR-V binary.
100  */
101 class SPIRVCodeGenerator : public CodeGenerator {
102 public:
103     class LValue {
104     public:
105         virtual ~LValue() {}
106 
107         // returns a pointer to the lvalue, if possible. If the lvalue cannot be directly referenced
108         // by a pointer (e.g. vector swizzles), returns -1.
109         virtual SpvId getPointer() { return -1; }
110 
111         // Returns true if a valid pointer returned by getPointer represents a memory object
112         // (see https://github.com/KhronosGroup/SPIRV-Tools/issues/2892). Has no meaning if
113         // getPointer() returns -1.
114         virtual bool isMemoryObjectPointer() const { return true; }
115 
116         // Applies a swizzle to the components of the LValue, if possible. This is used to create
117         // LValues that are swizzes-of-swizzles. Non-swizzle LValues can just return false.
118         virtual bool applySwizzle(const ComponentArray& components, const Type& newType) {
119             return false;
120         }
121 
122         virtual SpvId load(OutputStream& out) = 0;
123 
124         virtual void store(SpvId value, OutputStream& out) = 0;
125     };
126 
127     SPIRVCodeGenerator(const Context* context,
128                        const Program* program,
129                        OutputStream* out)
130             : INHERITED(context, program, out)
131 #ifdef SKSL_EXT
132             , fDefaultLayout(MemoryLayout::k430_Standard)
133 #else
134             , fDefaultLayout(MemoryLayout::k140_Standard)
135 #endif
136             , fCapabilities(0)
137             , fIdCount(1)
138             , fSetupFragPosition(false)
139             , fCurrentBlock(0)
140             , fSynthetics(fContext, /*builtin=*/true) {
141         this->setupIntrinsics();
142     }
143 
144     bool generateCode() override;
145 
146 private:
147     enum IntrinsicOpcodeKind {
148         kGLSL_STD_450_IntrinsicOpcodeKind,
149         kSPIRV_IntrinsicOpcodeKind,
150         kSpecial_IntrinsicOpcodeKind
151     };
152 
153     enum SpecialIntrinsic {
154         kAtan_SpecialIntrinsic,
155         kClamp_SpecialIntrinsic,
156         kMatrixCompMult_SpecialIntrinsic,
157         kMax_SpecialIntrinsic,
158         kMin_SpecialIntrinsic,
159         kMix_SpecialIntrinsic,
160         kMod_SpecialIntrinsic,
161         kDFdy_SpecialIntrinsic,
162         kSaturate_SpecialIntrinsic,
163         kSampledImage_SpecialIntrinsic,
164         kSmoothStep_SpecialIntrinsic,
165         kStep_SpecialIntrinsic,
166         kSubpassLoad_SpecialIntrinsic,
167         kTexture_SpecialIntrinsic,
168 #ifdef SKSL_EXT
169         kTextureSize_SpecialIntrinsic,
170         kNonuniformEXT_SpecialIntrinsic,
171 #endif
172     };
173 
174     enum class Precision {
175         kDefault,
176         kRelaxed,
177     };
178 
179     struct TempVar {
180         SpvId spvId;
181         const Type* type;
182         std::unique_ptr<SPIRVCodeGenerator::LValue> lvalue;
183     };
184 
185     void setupIntrinsics();
186 
187     /**
188      * Pass in the type to automatically add a RelaxedPrecision decoration for the id when
189      * appropriate, or null to never add one.
190      */
191     SpvId nextId(const Type* type);
192 
193     SpvId nextId(Precision precision);
194 
195     const Type& getActualType(const Type& type);
196 
197     SpvId getType(const Type& type);
198 
199     SpvId getType(const Type& type, const MemoryLayout& layout);
200 
201     SpvId getImageType(const Type& type);
202 
203     SpvId getFunctionType(const FunctionDeclaration& function);
204 
205     SpvId getPointerType(const Type& type, SpvStorageClass_ storageClass);
206 
207     SpvId getPointerType(const Type& type, const MemoryLayout& layout,
208                          SpvStorageClass_ storageClass);
209 
210     std::vector<SpvId> getAccessChain(const Expression& expr, OutputStream& out);
211 
212     void writeLayout(const Layout& layout, SpvId target);
213 
214     void writeLayout(const Layout& layout, SpvId target, int member);
215 
216     void writeStruct(const Type& type, const MemoryLayout& layout, SpvId resultId);
217 
218     void writeProgramElement(const ProgramElement& pe, OutputStream& out);
219 
220     SpvId writeInterfaceBlock(const InterfaceBlock& intf, bool appendRTFlip = true);
221 
222     SpvId writeFunctionStart(const FunctionDeclaration& f, OutputStream& out);
223 
224     SpvId writeFunctionDeclaration(const FunctionDeclaration& f, OutputStream& out);
225 
226     SpvId writeFunction(const FunctionDefinition& f, OutputStream& out);
227 
228     void writeGlobalVar(ProgramKind kind, const VarDeclaration& v);
229 
230     void writeVarDeclaration(const VarDeclaration& var, OutputStream& out);
231 
232     SpvId writeVariableReference(const VariableReference& ref, OutputStream& out);
233 
234     int findUniformFieldIndex(const Variable& var) const;
235 
236     std::unique_ptr<LValue> getLValue(const Expression& value, OutputStream& out);
237 
238     SpvId writeExpression(const Expression& expr, OutputStream& out);
239 
240     SpvId writeIntrinsicCall(const FunctionCall& c, OutputStream& out);
241 
242     SpvId writeFunctionCallArgument(const Expression& arg,
243                                     const Modifiers& paramModifiers,
244                                     std::vector<TempVar>* tempVars,
245                                     OutputStream& out);
246 
247     void copyBackTempVars(const std::vector<TempVar>& tempVars, OutputStream& out);
248 
249     SpvId writeFunctionCall(const FunctionCall& c, OutputStream& out);
250 
251 
252     void writeGLSLExtendedInstruction(const Type& type, SpvId id, SpvId floatInst,
253                                       SpvId signedInst, SpvId unsignedInst,
254                                       const std::vector<SpvId>& args, OutputStream& out);
255 
256     /**
257      * Promotes an expression to a vector. If the expression is already a vector with vectorSize
258      * columns, returns it unmodified. If the expression is a scalar, either promotes it to a
259      * vector (if vectorSize > 1) or returns it unmodified (if vectorSize == 1). Asserts if the
260      * expression is already a vector and it does not have vectorSize columns.
261      */
262     SpvId vectorize(const Expression& expr, int vectorSize, OutputStream& out);
263 
264     /**
265      * Given a list of potentially mixed scalars and vectors, promotes the scalars to match the
266      * size of the vectors and returns the ids of the written expressions. e.g. given (float, vec2),
267      * returns (vec2(float), vec2). It is an error to use mismatched vector sizes, e.g. (float,
268      * vec2, vec3).
269      */
270     std::vector<SpvId> vectorize(const ExpressionArray& args, OutputStream& out);
271 
272     SpvId writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind, OutputStream& out);
273 
274     SpvId writeConstantVector(const AnyConstructor& c);
275 
276     SpvId writeScalarToMatrixSplat(const Type& matrixType, SpvId scalarId, OutputStream& out);
277 
278     SpvId writeFloatConstructor(const AnyConstructor& c, OutputStream& out);
279 
280     SpvId castScalarToFloat(SpvId inputId, const Type& inputType, const Type& outputType,
281                             OutputStream& out);
282 
283     SpvId writeIntConstructor(const AnyConstructor& c, OutputStream& out);
284 
285     SpvId castScalarToSignedInt(SpvId inputId, const Type& inputType, const Type& outputType,
286                                 OutputStream& out);
287 
288     SpvId writeUIntConstructor(const AnyConstructor& c, OutputStream& out);
289 
290     SpvId castScalarToUnsignedInt(SpvId inputId, const Type& inputType, const Type& outputType,
291                                   OutputStream& out);
292 
293     SpvId writeBooleanConstructor(const AnyConstructor& c, OutputStream& out);
294 
295     SpvId castScalarToBoolean(SpvId inputId, const Type& inputType, const Type& outputType,
296                               OutputStream& out);
297 
298     SpvId castScalarToType(SpvId inputExprId, const Type& inputType, const Type& outputType,
299                            OutputStream& out);
300 
301     /**
302      * Writes a matrix with the diagonal entries all equal to the provided expression, and all other
303      * entries equal to zero.
304      */
305     void writeUniformScaleMatrix(SpvId id, SpvId diagonal, const Type& type, OutputStream& out);
306 
307     /**
308      * Writes a potentially-different-sized copy of a matrix. Entries which do not exist in the
309      * source matrix are filled with zero; entries which do not exist in the destination matrix are
310      * ignored.
311      */
312     SpvId writeMatrixCopy(SpvId src, const Type& srcType, const Type& dstType, OutputStream& out);
313 
314     void addColumnEntry(const Type& columnType, std::vector<SpvId>* currentColumn,
315                         std::vector<SpvId>* columnIds, int rows, SpvId entry, OutputStream& out);
316 
317     SpvId writeConstructorCompound(const ConstructorCompound& c, OutputStream& out);
318 
319     SpvId writeMatrixConstructor(const ConstructorCompound& c, OutputStream& out);
320 
321     SpvId writeVectorConstructor(const ConstructorCompound& c, OutputStream& out);
322 
323     SpvId writeCompositeConstructor(const AnyConstructor& c, OutputStream& out);
324 
325     SpvId writeConstructorDiagonalMatrix(const ConstructorDiagonalMatrix& c, OutputStream& out);
326 
327     SpvId writeConstructorMatrixResize(const ConstructorMatrixResize& c, OutputStream& out);
328 
329     SpvId writeConstructorScalarCast(const ConstructorScalarCast& c, OutputStream& out);
330 
331     SpvId writeConstructorSplat(const ConstructorSplat& c, OutputStream& out);
332 
333     SpvId writeConstructorCompoundCast(const ConstructorCompoundCast& c, OutputStream& out);
334 
335     SpvId writeComposite(const std::vector<SpvId>& arguments, const Type& type, OutputStream& out);
336 
337     SpvId writeFieldAccess(const FieldAccess& f, OutputStream& out);
338 
339     SpvId writeSwizzle(const Swizzle& swizzle, OutputStream& out);
340 
341     /**
342      * Folds the potentially-vector result of a logical operation down to a single bool. If
343      * operandType is a vector type, assumes that the intermediate result in id is a bvec of the
344      * same dimensions, and applys all() to it to fold it down to a single bool value. Otherwise,
345      * returns the original id value.
346      */
347     SpvId foldToBool(SpvId id, const Type& operandType, SpvOp op, OutputStream& out);
348 
349     SpvId writeMatrixComparison(const Type& operandType, SpvId lhs, SpvId rhs, SpvOp_ floatOperator,
350                                 SpvOp_ intOperator, SpvOp_ vectorMergeOperator,
351                                 SpvOp_ mergeOperator, OutputStream& out);
352 
353     SpvId writeStructComparison(const Type& structType, SpvId lhs, Operator op, SpvId rhs,
354                                 OutputStream& out);
355 
356     SpvId writeArrayComparison(const Type& structType, SpvId lhs, Operator op, SpvId rhs,
357                                OutputStream& out);
358 
359     // Used by writeStructComparison and writeArrayComparison to logically combine field-by-field
360     // comparisons into an overall comparison result.
361     // - `a.x == b.x` merged with `a.y == b.y` generates `(a.x == b.x) && (a.y == b.y)`
362     // - `a.x != b.x` merged with `a.y != b.y` generates `(a.x != b.x) || (a.y != b.y)`
363     SpvId mergeComparisons(SpvId comparison, SpvId allComparisons, Operator op, OutputStream& out);
364 
365     SpvId writeComponentwiseMatrixBinary(const Type& operandType, SpvId lhs, SpvId rhs,
366                                          SpvOp_ op, OutputStream& out);
367 
368     SpvId writeBinaryOperation(const Type& resultType, const Type& operandType, SpvId lhs,
369                                SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt, SpvOp_ ifUInt,
370                                SpvOp_ ifBool, OutputStream& out);
371 
372     SpvId writeBinaryOperation(const BinaryExpression& expr, SpvOp_ ifFloat, SpvOp_ ifInt,
373                                SpvOp_ ifUInt, OutputStream& out);
374 
375     SpvId writeReciprocal(const Type& type, SpvId value, OutputStream& out);
376 
377     SpvId writeBinaryExpression(const Type& leftType, SpvId lhs, Operator op,
378                                 const Type& rightType, SpvId rhs, const Type& resultType,
379                                 OutputStream& out);
380 
381     SpvId writeBinaryExpression(const BinaryExpression& b, OutputStream& out);
382 
383     SpvId writeTernaryExpression(const TernaryExpression& t, OutputStream& out);
384 
385     SpvId writeIndexExpression(const IndexExpression& expr, OutputStream& out);
386 
387     SpvId writeLogicalAnd(const Expression& left, const Expression& right, OutputStream& out);
388 
389     SpvId writeLogicalOr(const Expression& left, const Expression& right, OutputStream& out);
390 
391     SpvId writePrefixExpression(const PrefixExpression& p, OutputStream& out);
392 
393     SpvId writePostfixExpression(const PostfixExpression& p, OutputStream& out);
394 
395     SpvId writeLiteral(const Literal& f);
396 
397     SpvId writeLiteral(double value, const Type& type);
398 
399     void writeStatement(const Statement& s, OutputStream& out);
400 
401     void writeBlock(const Block& b, OutputStream& out);
402 
403     void writeIfStatement(const IfStatement& stmt, OutputStream& out);
404 
405     void writeForStatement(const ForStatement& f, OutputStream& out);
406 
407     void writeDoStatement(const DoStatement& d, OutputStream& out);
408 
409     void writeSwitchStatement(const SwitchStatement& s, OutputStream& out);
410 
411     void writeReturnStatement(const ReturnStatement& r, OutputStream& out);
412 
413     void writeCapabilities(OutputStream& out);
414 
415     void writeInstructions(const Program& program, OutputStream& out);
416 
417     void writeOpCode(SpvOp_ opCode, int length, OutputStream& out);
418 
419     void writeWord(int32_t word, OutputStream& out);
420 
421     void writeString(skstd::string_view s, OutputStream& out);
422 
423     void writeLabel(SpvId id, OutputStream& out);
424 
425     void writeInstruction(SpvOp_ opCode, OutputStream& out);
426 
427     void writeInstruction(SpvOp_ opCode, skstd::string_view string, OutputStream& out);
428 
429     void writeInstruction(SpvOp_ opCode, int32_t word1, OutputStream& out);
430 
431     void writeInstruction(SpvOp_ opCode, int32_t word1, skstd::string_view string,
432                           OutputStream& out);
433 
434     void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, skstd::string_view string,
435                           OutputStream& out);
436 
437     void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, OutputStream& out);
438 
439     void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3,
440                           OutputStream& out);
441 
442     void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4,
443                           OutputStream& out);
444 
445     void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4,
446                           int32_t word5, OutputStream& out);
447 
448     void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4,
449                           int32_t word5, int32_t word6, OutputStream& out);
450 
451     void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4,
452                           int32_t word5, int32_t word6, int32_t word7, OutputStream& out);
453 
454     void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4,
455                           int32_t word5, int32_t word6, int32_t word7, int32_t word8,
456                           OutputStream& out);
457 
458     bool isDead(const Variable& var) const;
459 
460     MemoryLayout memoryLayoutForVariable(const Variable&) const;
461 
462     struct EntrypointAdapter {
463         std::unique_ptr<FunctionDefinition> entrypointDef;
464         std::unique_ptr<FunctionDeclaration> entrypointDecl;
465         Layout fLayout;
466         Modifiers fModifiers;
467     };
468 
469     EntrypointAdapter writeEntrypointAdapter(const FunctionDeclaration& main);
470 
471     struct UniformBuffer {
472         std::unique_ptr<InterfaceBlock> fInterfaceBlock;
473         std::unique_ptr<Variable> fInnerVariable;
474         std::unique_ptr<Type> fStruct;
475     };
476 
477     void writeUniformBuffer(std::shared_ptr<SymbolTable> topLevelSymbolTable);
478 
479     void addRTFlipUniform(int line);
480 
481 #ifdef SKSL_EXT
482     SpvId writeOpLoad(SpvId type, Precision precision, SpvId pointer, OutputStream& out);
483     SpvId writeSpecConstBinaryExpression(const BinaryExpression& b, const Operator& op,
484                                          SpvId lhs, SpvId rhs);
485     void writeExtensions(OutputStream& out);
486     void writePrecisionDecoration(SpvId var, const Type& type);
487 
488     std::unordered_set<std::string> fExtensions;
489     std::unordered_set<uint32_t> fCapabilitiesExt;
490     std::unordered_set<SpvId> fNonUniformSpvId;
491     std::unordered_map<const Variable*, SpvId> fGlobalConstVariableValueMap;
492     bool fEmittingGlobalConstConstructor = false;
493 #endif
494 
495     const MemoryLayout fDefaultLayout;
496 
497     uint64_t fCapabilities;
498     SpvId fIdCount;
499     SpvId fGLSLExtendedInstructions;
500     typedef std::tuple<IntrinsicOpcodeKind, int32_t, int32_t, int32_t, int32_t> Intrinsic;
501     std::unordered_map<IntrinsicKind, Intrinsic> fIntrinsicMap;
502     std::unordered_map<const FunctionDeclaration*, SpvId> fFunctionMap;
503     std::unordered_map<const Variable*, SpvId> fVariableMap;
504     std::unordered_map<const Variable*, int32_t> fInterfaceBlockMap;
505     std::unordered_map<String, SpvId> fImageTypeMap;
506     std::unordered_map<String, SpvId> fTypeMap;
507     StringStream fCapabilitiesBuffer;
508     StringStream fGlobalInitializersBuffer;
509     StringStream fConstantBuffer;
510     StringStream fExtraGlobalsBuffer;
511     StringStream fVariableBuffer;
512     StringStream fNameBuffer;
513     StringStream fDecorationBuffer;
514 
515     std::unordered_map<SPIRVNumberConstant, SpvId> fNumberConstants;
516     std::unordered_map<SPIRVVectorConstant, SpvId> fVectorConstants;
517     bool fSetupFragPosition;
518     // label of the current block, or 0 if we are not in a block
519     SpvId fCurrentBlock;
520     std::stack<SpvId> fBreakTarget;
521     std::stack<SpvId> fContinueTarget;
522     bool fWroteRTFlip = false;
523     // holds variables synthesized during output, for lifetime purposes
524     SymbolTable fSynthetics;
525     int fSkInCount = 1;
526     // Holds a list of uniforms that were declared as globals at the top-level instead of in an
527     // interface block.
528     UniformBuffer fUniformBuffer;
529     std::vector<const VarDeclaration*> fTopLevelUniforms;
530     std::unordered_map<const Variable*, int> fTopLevelUniformMap; //<var, UniformBuffer field index>
531     std::unordered_set<const Variable*> fSPIRVBonusVariables;
532     SpvId fUniformBufferId = -1;
533 
534     friend class PointerLValue;
535     friend class SwizzleLValue;
536 
537     using INHERITED = CodeGenerator;
538 };
539 
540 }  // namespace SkSL
541 
542 #endif
543