| 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 | |
| 17 | namespace SkSL { |
| 18 | |
| 19 | class ExternalValue; |
| 20 | struct 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 | |
| 34 | enum 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 | |
| 174 | class ByteCodeFunction { |
| 175 | public: |
| 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 | |
| 188 | private: |
| 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 | |
| 218 | enum class TypeCategory { |
| 219 | kBool, |
| 220 | kSigned, |
| 221 | kUnsigned, |
| 222 | kFloat, |
| 223 | }; |
| 224 | |
| 225 | class SK_API ByteCode { |
| 226 | public: |
| 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 | |
| 291 | private: |
| 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 | |