1/*
2 * Copyright 2019 Google LLC
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_BYTECODE
9#define SKSL_BYTECODE
10
11#include "include/private/SkOnce.h"
12#include "src/sksl/SkSLString.h"
13
14#include <memory>
15#include <vector>
16
17namespace SkSL {
18
19class ExternalValue;
20struct FunctionDeclaration;
21
22// GCC and Clang support the "labels as values" extension which we need to implement the interpreter
23// using threaded code. Otherwise, we fall back to using a switch statement in a for loop.
24#if defined(__GNUC__) || defined(__clang__)
25 #define SKSLC_THREADED_CODE
26 using instruction = void*;
27#else
28 using instruction = uint16_t;
29#endif
30
31#define VECTOR(name) name ## 4, name ## 3, name ## 2, name
32#define VECTOR_MATRIX(name) name ## 4, name ## 3, name ## 2, name, name ## N
33
34enum class ByteCodeInstruction : uint16_t {
35 // B = bool, F = float, I = int, S = signed, U = unsigned
36 // All binary VECTOR instructions (kAddF, KSubtractI, kCompareIEQ, etc.) are followed by a byte
37 // indicating the count, even though it is redundant due to the count appearing in the opcode.
38 // This is because the original opcodes are lost after we preprocess it into threaded code, and
39 // we need to still be able to access the count so as to permit the implementation to use opcode
40 // fallthrough.
41 VECTOR_MATRIX(kAddF),
42 VECTOR(kAddI),
43 kAndB,
44 kBranch,
45 // Followed by a byte indicating the index of the function to call
46 kCall,
47 // Followed by three bytes indicating: the number of argument slots, the number of return slots,
48 // and the index of the external value to call
49 kCallExternal,
50 // For dynamic array access: Followed by byte indicating length of array
51 kClampIndex,
52 VECTOR(kCompareIEQ),
53 VECTOR(kCompareINEQ),
54 VECTOR_MATRIX(kCompareFEQ),
55 VECTOR_MATRIX(kCompareFNEQ),
56 VECTOR(kCompareFGT),
57 VECTOR(kCompareFGTEQ),
58 VECTOR(kCompareFLT),
59 VECTOR(kCompareFLTEQ),
60 VECTOR(kCompareSGT),
61 VECTOR(kCompareSGTEQ),
62 VECTOR(kCompareSLT),
63 VECTOR(kCompareSLTEQ),
64 VECTOR(kCompareUGT),
65 VECTOR(kCompareUGTEQ),
66 VECTOR(kCompareULT),
67 VECTOR(kCompareULTEQ),
68 VECTOR(kConvertFtoI),
69 VECTOR(kConvertStoF),
70 VECTOR(kConvertUtoF),
71 // Followed by a (redundant) byte indicating the count
72 VECTOR(kCos),
73 VECTOR_MATRIX(kDivideF),
74 VECTOR(kDivideS),
75 VECTOR(kDivideU),
76 // Duplicates the top stack value. Followed by a (redundant) byte indicating the count.
77 VECTOR_MATRIX(kDup),
78 kInverse2x2,
79 kInverse3x3,
80 kInverse4x4,
81 // kLoad/kLoadGlobal are followed by a byte indicating the count, and a byte indicating the
82 // local/global slot to load
83 VECTOR(kLoad),
84 VECTOR(kLoadGlobal),
85 VECTOR(kLoadUniform),
86 // As kLoad/kLoadGlobal, then a count byte (1-4), and then one byte per swizzle component (0-3).
87 kLoadSwizzle,
88 kLoadSwizzleGlobal,
89 kLoadSwizzleUniform,
90 // kLoadExtended* are fallback load ops when we lack a specialization. They are followed by a
91 // count byte, and get the slot to load from the top of the stack.
92 kLoadExtended,
93 kLoadExtendedGlobal,
94 kLoadExtendedUniform,
95 // Followed by four bytes: srcCols, srcRows, dstCols, dstRows. Consumes the src matrix from the
96 // stack, and replaces it with the dst matrix. Per GLSL rules, there are no restrictions on
97 // dimensions. Any overlapping values are copied, and any other values are filled in with the
98 // identity matrix.
99 kMatrixToMatrix,
100 // Followed by three bytes: leftCols (== rightRows), leftRows, rightCols
101 kMatrixMultiply,
102 VECTOR_MATRIX(kNegateF),
103 VECTOR(kNegateI),
104 VECTOR_MATRIX(kMultiplyF),
105 VECTOR(kMultiplyI),
106 kNotB,
107 kOrB,
108 VECTOR_MATRIX(kPop),
109 // Followed by a 32 bit value containing the value to push
110 kPushImmediate,
111 // Followed by a byte indicating external value to read
112 VECTOR(kReadExternal),
113 VECTOR(kRemainderF),
114 VECTOR(kRemainderS),
115 VECTOR(kRemainderU),
116 // Followed by a byte indicating the number of slots to reserve on the stack (for later return)
117 kReserve,
118 // Followed by a byte indicating the number of slots being returned
119 kReturn,
120 // Followed by two bytes indicating columns and rows of matrix (2, 3, or 4 each).
121 // Takes a single value from the top of the stack, and converts to a CxR matrix with that value
122 // replicated along the diagonal (and zero elsewhere), per the GLSL matrix construction rules.
123 kScalarToMatrix,
124 // Followed by a byte indicating the number of bits to shift
125 kShiftLeft,
126 kShiftRightS,
127 kShiftRightU,
128 // Followed by a (redundant) byte indicating the count
129 VECTOR(kSin),
130 VECTOR(kSqrt),
131 // kStore/kStoreGlobal are followed by a byte indicating the local/global slot to store
132 VECTOR(kStore),
133 VECTOR(kStoreGlobal),
134 // Fallback stores. Followed by count byte, and get the slot to store from the top of the stack
135 kStoreExtended,
136 kStoreExtendedGlobal,
137 // As kStore/kStoreGlobal, then a count byte (1-4), then one byte per swizzle component (0-3).
138 // Expects the stack to look like: ... v1 v2 v3 v4, where the number of 'v's is equal to the
139 // number of swizzle components. After the store, all v's are popped from the stack.
140 kStoreSwizzle,
141 kStoreSwizzleGlobal,
142 // As above, but gets the store slot from the top of the stack (before values to be stored)
143 kStoreSwizzleIndirect,
144 kStoreSwizzleIndirectGlobal,
145 // Followed by two count bytes (1-4), and then one byte per swizzle component (0-3). The first
146 // count byte provides the current vector size (the vector is the top n stack elements), and the
147 // second count byte provides the swizzle component count.
148 kSwizzle,
149 VECTOR_MATRIX(kSubtractF),
150 VECTOR(kSubtractI),
151 // Followed by a (redundant) byte indicating the count
152 VECTOR(kTan),
153 // Followed by a byte indicating external value to write
154 VECTOR(kWriteExternal),
155 kXorB,
156
157 kMaskPush,
158 kMaskPop,
159 kMaskNegate,
160 // Followed by count byte
161 kMaskBlend,
162 // Followed by address
163 kBranchIfAllFalse,
164
165 kLoopBegin,
166 kLoopNext,
167 kLoopMask,
168 kLoopEnd,
169 kLoopBreak,
170 kLoopContinue,
171};
172#undef VECTOR
173
174class ByteCodeFunction {
175public:
176 int getParameterCount() const { return fParameterCount; }
177 int getReturnCount() const { return fReturnCount; }
178 int getLocalCount() const { return fLocalCount; }
179
180 const uint8_t* code() const { return fCode.data(); }
181 size_t size() const { return fCode.size(); }
182
183 /**
184 * Print bytecode disassembly to stdout.
185 */
186 void disassemble() const;
187
188private:
189 ByteCodeFunction(const FunctionDeclaration* declaration);
190
191 friend class ByteCode;
192 friend class ByteCodeGenerator;
193 friend struct Interpreter;
194
195 struct Parameter {
196 int fSlotCount;
197 bool fIsOutParameter;
198 };
199
200 SkSL::String fName;
201 std::vector<Parameter> fParameters;
202 int fParameterCount;
203 int fReturnCount = 0;
204
205 int fLocalCount = 0;
206 int fStackCount = 0;
207 int fConditionCount = 0;
208 int fLoopCount = 0;
209 mutable SkOnce fPreprocessOnce;
210 std::vector<uint8_t> fCode;
211
212 /**
213 * Replace each opcode with the corresponding entry from the labels array.
214 */
215 void preprocess(const void* labels[]);
216};
217
218enum class TypeCategory {
219 kBool,
220 kSigned,
221 kUnsigned,
222 kFloat,
223};
224
225class SK_API ByteCode {
226public:
227 static constexpr int kVecWidth = 8;
228
229 ByteCode() = default;
230
231 const ByteCodeFunction* getFunction(const char* name) const {
232 for (const auto& f : fFunctions) {
233 if (f->fName == name) {
234 return f.get();
235 }
236 }
237 return nullptr;
238 }
239
240 /**
241 * Invokes the specified function once, with the given arguments.
242 * 'args', 'outReturn', and 'uniforms' are collections of 32-bit values (typically floats,
243 * but possibly int32_t or uint32_t, depending on the types used in the SkSL).
244 * Any 'out' or 'inout' parameters will result in the 'args' array being modified.
245 * The return value is stored in 'outReturn' (may be null, to discard the return value).
246 * 'uniforms' are mapped to 'uniform' globals, in order.
247 */
248 bool SKSL_WARN_UNUSED_RESULT run(const ByteCodeFunction*,
249 float* args, int argCount,
250 float* outReturn, int returnCount,
251 const float* uniforms, int uniformCount) const;
252
253 /**
254 * Invokes the specified function with the given arguments, 'N' times. 'args' and 'outReturn'
255 * are accepted and returned in structure-of-arrays form:
256 * args[0] points to an array of N values, the first argument for each invocation
257 * ...
258 * args[argCount - 1] points to an array of N values, the last argument for each invocation
259 *
260 * All values in 'args', 'outReturn', and 'uniforms' are 32-bit values (typically floats,
261 * but possibly int32_t or uint32_t, depending on the types used in the SkSL).
262 * Any 'out' or 'inout' parameters will result in the 'args' array being modified.
263 * The return value is stored in 'outReturn' (may be null, to discard the return value).
264 * 'uniforms' are mapped to 'uniform' globals, in order.
265 */
266 bool SKSL_WARN_UNUSED_RESULT runStriped(const ByteCodeFunction*, int N,
267 float* args[], int argCount,
268 float* outReturn[], int returnCount,
269 const float* uniforms, int uniformCount) const;
270
271 struct Uniform {
272 SkSL::String fName;
273 TypeCategory fType;
274 int fColumns;
275 int fRows;
276 int fSlot;
277 };
278
279 int getUniformSlotCount() const { return fUniformSlotCount; }
280 int getUniformCount() const { return fUniforms.size(); }
281 int getUniformLocation(const char* name) const {
282 for (int i = 0; i < (int)fUniforms.size(); ++i) {
283 if (fUniforms[i].fName == name) {
284 return fUniforms[i].fSlot;
285 }
286 }
287 return -1;
288 }
289 const Uniform& getUniform(int i) const { return fUniforms[i]; }
290
291private:
292 ByteCode(const ByteCode&) = delete;
293 ByteCode& operator=(const ByteCode&) = delete;
294
295 friend class ByteCodeGenerator;
296 friend struct Interpreter;
297
298 int fGlobalSlotCount = 0;
299 int fUniformSlotCount = 0;
300 std::vector<Uniform> fUniforms;
301
302 std::vector<std::unique_ptr<ByteCodeFunction>> fFunctions;
303 std::vector<ExternalValue*> fExternalValues;
304};
305
306}
307
308#endif
309