• 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 
15 #include "SkSLCodeGenerator.h"
16 #include "SkSLMemoryLayout.h"
17 #include "ir/SkSLBinaryExpression.h"
18 #include "ir/SkSLBoolLiteral.h"
19 #include "ir/SkSLConstructor.h"
20 #include "ir/SkSLDoStatement.h"
21 #include "ir/SkSLFloatLiteral.h"
22 #include "ir/SkSLIfStatement.h"
23 #include "ir/SkSLIndexExpression.h"
24 #include "ir/SkSLInterfaceBlock.h"
25 #include "ir/SkSLIntLiteral.h"
26 #include "ir/SkSLFieldAccess.h"
27 #include "ir/SkSLForStatement.h"
28 #include "ir/SkSLFunctionCall.h"
29 #include "ir/SkSLFunctionDeclaration.h"
30 #include "ir/SkSLFunctionDefinition.h"
31 #include "ir/SkSLPrefixExpression.h"
32 #include "ir/SkSLPostfixExpression.h"
33 #include "ir/SkSLProgramElement.h"
34 #include "ir/SkSLReturnStatement.h"
35 #include "ir/SkSLStatement.h"
36 #include "ir/SkSLSwitchStatement.h"
37 #include "ir/SkSLSwizzle.h"
38 #include "ir/SkSLTernaryExpression.h"
39 #include "ir/SkSLVarDeclarations.h"
40 #include "ir/SkSLVarDeclarationsStatement.h"
41 #include "ir/SkSLVariableReference.h"
42 #include "ir/SkSLWhileStatement.h"
43 #include "spirv.h"
44 
45 namespace SkSL {
46 
47 #define kLast_Capability SpvCapabilityMultiViewport
48 
49 /**
50  * Converts a Program into a SPIR-V binary.
51  */
52 class SPIRVCodeGenerator : public CodeGenerator {
53 public:
54     class LValue {
55     public:
~LValue()56         virtual ~LValue() {}
57 
58         // returns a pointer to the lvalue, if possible. If the lvalue cannot be directly referenced
59         // by a pointer (e.g. vector swizzles), returns 0.
60         virtual SpvId getPointer() = 0;
61 
62         virtual SpvId load(OutputStream& out) = 0;
63 
64         virtual void store(SpvId value, OutputStream& out) = 0;
65     };
66 
SPIRVCodeGenerator(const Context * context,const Program * program,ErrorReporter * errors,OutputStream * out)67     SPIRVCodeGenerator(const Context* context, const Program* program, ErrorReporter* errors,
68                        OutputStream* out)
69     : INHERITED(program, errors, out)
70     , fContext(*context)
71     , fDefaultLayout(MemoryLayout::k140_Standard)
72     , fCapabilities(0)
73     , fIdCount(1)
74     , fBoolTrue(0)
75     , fBoolFalse(0)
76     , fSetupFragPosition(false)
77     , fCurrentBlock(0)
78     , fSynthetics(nullptr, errors) {
79         this->setupIntrinsics();
80     }
81 
82     bool generateCode() override;
83 
84 private:
85     enum IntrinsicKind {
86         kGLSL_STD_450_IntrinsicKind,
87         kSPIRV_IntrinsicKind,
88         kSpecial_IntrinsicKind
89     };
90 
91     enum SpecialIntrinsic {
92         kAtan_SpecialIntrinsic,
93         kClamp_SpecialIntrinsic,
94         kMax_SpecialIntrinsic,
95         kMin_SpecialIntrinsic,
96         kMix_SpecialIntrinsic,
97         kMod_SpecialIntrinsic,
98         kSaturate_SpecialIntrinsic,
99         kSubpassLoad_SpecialIntrinsic,
100         kTexture_SpecialIntrinsic,
101     };
102 
103     void setupIntrinsics();
104 
105     SpvId nextId();
106 
107     Type getActualType(const Type& type);
108 
109     SpvId getType(const Type& type);
110 
111     SpvId getType(const Type& type, const MemoryLayout& layout);
112 
113     SpvId getImageType(const Type& type);
114 
115     SpvId getFunctionType(const FunctionDeclaration& function);
116 
117     SpvId getPointerType(const Type& type, SpvStorageClass_ storageClass);
118 
119     SpvId getPointerType(const Type& type, const MemoryLayout& layout,
120                          SpvStorageClass_ storageClass);
121 
122     void writePrecisionModifier(const Modifiers& modifiers, SpvId id);
123 
124     std::vector<SpvId> getAccessChain(const Expression& expr, OutputStream& out);
125 
126     void writeLayout(const Layout& layout, SpvId target);
127 
128     void writeLayout(const Layout& layout, SpvId target, int member);
129 
130     void writeStruct(const Type& type, const MemoryLayout& layout, SpvId resultId);
131 
132     void writeProgramElement(const ProgramElement& pe, OutputStream& out);
133 
134     SpvId writeInterfaceBlock(const InterfaceBlock& intf);
135 
136     SpvId writeFunctionStart(const FunctionDeclaration& f, OutputStream& out);
137 
138     SpvId writeFunctionDeclaration(const FunctionDeclaration& f, OutputStream& out);
139 
140     SpvId writeFunction(const FunctionDefinition& f, OutputStream& out);
141 
142     void writeGlobalVars(Program::Kind kind, const VarDeclarations& v, OutputStream& out);
143 
144     void writeVarDeclarations(const VarDeclarations& decl, OutputStream& out);
145 
146     SpvId writeVariableReference(const VariableReference& ref, OutputStream& out);
147 
148     std::unique_ptr<LValue> getLValue(const Expression& value, OutputStream& out);
149 
150     SpvId writeExpression(const Expression& expr, OutputStream& out);
151 
152     SpvId writeIntrinsicCall(const FunctionCall& c, OutputStream& out);
153 
154     SpvId writeFunctionCall(const FunctionCall& c, OutputStream& out);
155 
156 
157     void writeGLSLExtendedInstruction(const Type& type, SpvId id, SpvId floatInst,
158                                       SpvId signedInst, SpvId unsignedInst,
159                                       const std::vector<SpvId>& args, OutputStream& out);
160 
161     /**
162      * Given a list of potentially mixed scalars and vectors, promotes the scalars to match the
163      * size of the vectors and returns the ids of the written expressions. e.g. given (float, vec2),
164      * returns (vec2(float), vec2). It is an error to use mismatched vector sizes, e.g. (float,
165      * vec2, vec3).
166      */
167     std::vector<SpvId> vectorize(const std::vector<std::unique_ptr<Expression>>& args,
168                                  OutputStream& out);
169 
170     SpvId writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind, OutputStream& out);
171 
172     SpvId writeConstantVector(const Constructor& c);
173 
174     SpvId writeFloatConstructor(const Constructor& c, OutputStream& out);
175 
176     SpvId writeIntConstructor(const Constructor& c, OutputStream& out);
177 
178     SpvId writeUIntConstructor(const Constructor& c, OutputStream& out);
179 
180     /**
181      * Writes a matrix with the diagonal entries all equal to the provided expression, and all other
182      * entries equal to zero.
183      */
184     void writeUniformScaleMatrix(SpvId id, SpvId diagonal, const Type& type, OutputStream& out);
185 
186     /**
187      * Writes a potentially-different-sized copy of a matrix. Entries which do not exist in the
188      * source matrix are filled with zero; entries which do not exist in the destination matrix are
189      * ignored.
190      */
191     void writeMatrixCopy(SpvId id, SpvId src, const Type& srcType, const Type& dstType,
192                          OutputStream& out);
193 
194     SpvId writeMatrixConstructor(const Constructor& c, OutputStream& out);
195 
196     SpvId writeVectorConstructor(const Constructor& c, OutputStream& out);
197 
198     SpvId writeArrayConstructor(const Constructor& c, OutputStream& out);
199 
200     SpvId writeConstructor(const Constructor& c, OutputStream& out);
201 
202     SpvId writeFieldAccess(const FieldAccess& f, OutputStream& out);
203 
204     SpvId writeSwizzle(const Swizzle& swizzle, OutputStream& out);
205 
206     /**
207      * Folds the potentially-vector result of a logical operation down to a single bool. If
208      * operandType is a vector type, assumes that the intermediate result in id is a bvec of the
209      * same dimensions, and applys all() to it to fold it down to a single bool value. Otherwise,
210      * returns the original id value.
211      */
212     SpvId foldToBool(SpvId id, const Type& operandType, SpvOp op, OutputStream& out);
213 
214     SpvId writeMatrixComparison(const Type& operandType, SpvId lhs, SpvId rhs, SpvOp_ floatOperator,
215                                 SpvOp_ intOperator, SpvOp_ vectorMergeOperator,
216                                 SpvOp_ mergeOperator, OutputStream& out);
217 
218     SpvId writeComponentwiseMatrixBinary(const Type& operandType, SpvId lhs, SpvId rhs,
219                                          SpvOp_ floatOperator, SpvOp_ intOperator,
220                                          OutputStream& out);
221 
222     SpvId writeBinaryOperation(const Type& resultType, const Type& operandType, SpvId lhs,
223                                SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt, SpvOp_ ifUInt,
224                                SpvOp_ ifBool, OutputStream& out);
225 
226     SpvId writeBinaryOperation(const BinaryExpression& expr, SpvOp_ ifFloat, SpvOp_ ifInt,
227                                SpvOp_ ifUInt, OutputStream& out);
228 
229     SpvId writeBinaryExpression(const BinaryExpression& b, OutputStream& out);
230 
231     SpvId writeTernaryExpression(const TernaryExpression& t, OutputStream& out);
232 
233     SpvId writeIndexExpression(const IndexExpression& expr, OutputStream& out);
234 
235     SpvId writeLogicalAnd(const BinaryExpression& b, OutputStream& out);
236 
237     SpvId writeLogicalOr(const BinaryExpression& o, OutputStream& out);
238 
239     SpvId writePrefixExpression(const PrefixExpression& p, OutputStream& out);
240 
241     SpvId writePostfixExpression(const PostfixExpression& p, OutputStream& out);
242 
243     SpvId writeBoolLiteral(const BoolLiteral& b);
244 
245     SpvId writeIntLiteral(const IntLiteral& i);
246 
247     SpvId writeFloatLiteral(const FloatLiteral& f);
248 
249     void writeStatement(const Statement& s, OutputStream& out);
250 
251     void writeBlock(const Block& b, OutputStream& out);
252 
253     void writeIfStatement(const IfStatement& stmt, OutputStream& out);
254 
255     void writeForStatement(const ForStatement& f, OutputStream& out);
256 
257     void writeWhileStatement(const WhileStatement& w, OutputStream& out);
258 
259     void writeDoStatement(const DoStatement& d, OutputStream& out);
260 
261     void writeSwitchStatement(const SwitchStatement& s, OutputStream& out);
262 
263     void writeReturnStatement(const ReturnStatement& r, OutputStream& out);
264 
265     void writeCapabilities(OutputStream& out);
266 
267     void writeInstructions(const Program& program, OutputStream& out);
268 
269     void writeOpCode(SpvOp_ opCode, int length, OutputStream& out);
270 
271     void writeWord(int32_t word, OutputStream& out);
272 
273     void writeString(const char* string, size_t length, OutputStream& out);
274 
275     void writeLabel(SpvId id, OutputStream& out);
276 
277     void writeInstruction(SpvOp_ opCode, OutputStream& out);
278 
279     void writeInstruction(SpvOp_ opCode, StringFragment string, OutputStream& out);
280 
281     void writeInstruction(SpvOp_ opCode, int32_t word1, OutputStream& out);
282 
283     void writeInstruction(SpvOp_ opCode, int32_t word1, StringFragment string, OutputStream& out);
284 
285     void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, StringFragment string,
286                           OutputStream& out);
287 
288     void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, OutputStream& out);
289 
290     void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3,
291                           OutputStream& out);
292 
293     void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4,
294                           OutputStream& out);
295 
296     void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4,
297                           int32_t word5, OutputStream& out);
298 
299     void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4,
300                           int32_t word5, int32_t word6, OutputStream& out);
301 
302     void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4,
303                           int32_t word5, int32_t word6, int32_t word7, OutputStream& out);
304 
305     void writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4,
306                           int32_t word5, int32_t word6, int32_t word7, int32_t word8,
307                           OutputStream& out);
308 
309     void writeGeometryShaderExecutionMode(SpvId entryPoint, OutputStream& out);
310 
311     const Context& fContext;
312     const MemoryLayout fDefaultLayout;
313 
314     uint64_t fCapabilities;
315     SpvId fIdCount;
316     SpvId fGLSLExtendedInstructions;
317     typedef std::tuple<IntrinsicKind, int32_t, int32_t, int32_t, int32_t> Intrinsic;
318     std::unordered_map<String, Intrinsic> fIntrinsicMap;
319     std::unordered_map<const FunctionDeclaration*, SpvId> fFunctionMap;
320     std::unordered_map<const Variable*, SpvId> fVariableMap;
321     std::unordered_map<const Variable*, int32_t> fInterfaceBlockMap;
322     std::unordered_map<String, SpvId> fImageTypeMap;
323     std::unordered_map<String, SpvId> fTypeMap;
324     StringStream fCapabilitiesBuffer;
325     StringStream fGlobalInitializersBuffer;
326     StringStream fConstantBuffer;
327     StringStream fExtraGlobalsBuffer;
328     StringStream fExternalFunctionsBuffer;
329     StringStream fVariableBuffer;
330     StringStream fNameBuffer;
331     StringStream fDecorationBuffer;
332 
333     SpvId fBoolTrue;
334     SpvId fBoolFalse;
335     std::unordered_map<int64_t, SpvId> fIntConstants;
336     std::unordered_map<uint64_t, SpvId> fUIntConstants;
337     std::unordered_map<float, SpvId> fFloatConstants;
338     std::unordered_map<double, SpvId> fDoubleConstants;
339     bool fSetupFragPosition;
340     // label of the current block, or 0 if we are not in a block
341     SpvId fCurrentBlock;
342     std::stack<SpvId> fBreakTarget;
343     std::stack<SpvId> fContinueTarget;
344     SpvId fRTHeightStructId = (SpvId) -1;
345     SpvId fRTHeightFieldIndex = (SpvId) -1;
346     // holds variables synthesized during output, for lifetime purposes
347     SymbolTable fSynthetics;
348     int fSkInCount = 1;
349 
350     friend class PointerLValue;
351     friend class SwizzleLValue;
352 
353     typedef CodeGenerator INHERITED;
354 };
355 
356 }
357 
358 #endif
359