Coverage Report

Created: 2021-08-22 09:07

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