Ethan Nicholas | 0e9401d | 2019-03-21 11:05:37 -0400 | [diff] [blame] | 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 | |
Mike Klein | c0bd9f9 | 2019-04-23 12:05:21 -0500 | [diff] [blame] | 11 | #include "src/sksl/ir/SkSLFunctionDeclaration.h" |
Ethan Nicholas | 0e9401d | 2019-03-21 11:05:37 -0400 | [diff] [blame] | 12 | |
Ethan Nicholas | 91164d1 | 2019-05-15 15:29:54 -0400 | [diff] [blame] | 13 | #include <memory> |
| 14 | #include <vector> |
| 15 | |
Ethan Nicholas | 0e9401d | 2019-03-21 11:05:37 -0400 | [diff] [blame] | 16 | namespace SkSL { |
| 17 | |
Ethan Nicholas | 91164d1 | 2019-05-15 15:29:54 -0400 | [diff] [blame] | 18 | struct ByteCode; |
| 19 | class ExternalValue; |
| 20 | struct FunctionDeclaration; |
| 21 | |
Ethan Nicholas | 48a75aa | 2019-05-16 17:15:56 -0400 | [diff] [blame] | 22 | #define VECTOR(name) name, name ## 2, name ## 3, name ## 4 |
Brian Osman | 1e855b2 | 2019-05-29 15:21:52 -0400 | [diff] [blame] | 23 | #define VECTOR_MATRIX(name) name, name ## 2, name ## 3, name ## 4, name ## N |
| 24 | |
Mike Klein | 108e935 | 2019-05-21 11:05:17 -0500 | [diff] [blame] | 25 | enum class ByteCodeInstruction : uint16_t { |
Ethan Nicholas | 0e9401d | 2019-03-21 11:05:37 -0400 | [diff] [blame] | 26 | // B = bool, F = float, I = int, S = signed, U = unsigned |
Brian Osman | 1e855b2 | 2019-05-29 15:21:52 -0400 | [diff] [blame] | 27 | VECTOR_MATRIX(kAddF), |
Ethan Nicholas | 48a75aa | 2019-05-16 17:15:56 -0400 | [diff] [blame] | 28 | VECTOR(kAddI), |
| 29 | VECTOR(kAndB), |
| 30 | VECTOR(kAndI), |
Ethan Nicholas | 0e9401d | 2019-03-21 11:05:37 -0400 | [diff] [blame] | 31 | kBranch, |
Brian Osman | 226668a | 2019-05-14 16:47:30 -0400 | [diff] [blame] | 32 | // Followed by a byte indicating the index of the function to call |
| 33 | kCall, |
Ethan Nicholas | 9e6a393 | 2019-05-17 16:31:21 -0400 | [diff] [blame] | 34 | // Followed by three bytes indicating: the number of argument slots, the number of return slots, |
| 35 | // and the index of the external value to call |
| 36 | kCallExternal, |
Ethan Nicholas | 48a75aa | 2019-05-16 17:15:56 -0400 | [diff] [blame] | 37 | VECTOR(kCompareIEQ), |
| 38 | VECTOR(kCompareINEQ), |
Brian Osman | 1e855b2 | 2019-05-29 15:21:52 -0400 | [diff] [blame] | 39 | VECTOR_MATRIX(kCompareFEQ), |
Ethan Nicholas | 48a75aa | 2019-05-16 17:15:56 -0400 | [diff] [blame] | 40 | VECTOR(kCompareFGT), |
| 41 | VECTOR(kCompareFGTEQ), |
| 42 | VECTOR(kCompareFLT), |
| 43 | VECTOR(kCompareFLTEQ), |
Brian Osman | 1e855b2 | 2019-05-29 15:21:52 -0400 | [diff] [blame] | 44 | VECTOR_MATRIX(kCompareFNEQ), |
Ethan Nicholas | 48a75aa | 2019-05-16 17:15:56 -0400 | [diff] [blame] | 45 | VECTOR(kCompareSGT), |
| 46 | VECTOR(kCompareSGTEQ), |
| 47 | VECTOR(kCompareSLT), |
| 48 | VECTOR(kCompareSLTEQ), |
| 49 | VECTOR(kCompareUGT), |
| 50 | VECTOR(kCompareUGTEQ), |
| 51 | VECTOR(kCompareULT), |
| 52 | VECTOR(kCompareULTEQ), |
Ethan Nicholas | 0e9401d | 2019-03-21 11:05:37 -0400 | [diff] [blame] | 53 | // Followed by a 16 bit address |
| 54 | kConditionalBranch, |
Ethan Nicholas | 82162ee | 2019-05-21 16:05:08 -0400 | [diff] [blame] | 55 | VECTOR(kConvertFtoI), |
| 56 | VECTOR(kConvertStoF), |
| 57 | VECTOR(kConvertUtoF), |
| 58 | VECTOR(kCos), |
Ethan Nicholas | ae9633b | 2019-05-24 12:46:34 -0400 | [diff] [blame] | 59 | kCross, |
Ethan Nicholas | 0e9401d | 2019-03-21 11:05:37 -0400 | [diff] [blame] | 60 | // Pops and prints the top value from the stack |
| 61 | kDebugPrint, |
Brian Osman | 1e855b2 | 2019-05-29 15:21:52 -0400 | [diff] [blame] | 62 | VECTOR_MATRIX(kDivideF), |
Ethan Nicholas | 48a75aa | 2019-05-16 17:15:56 -0400 | [diff] [blame] | 63 | VECTOR(kDivideS), |
| 64 | VECTOR(kDivideU), |
Ethan Nicholas | 0e9401d | 2019-03-21 11:05:37 -0400 | [diff] [blame] | 65 | // Duplicates the top stack value |
Brian Osman | 1e855b2 | 2019-05-29 15:21:52 -0400 | [diff] [blame] | 66 | VECTOR_MATRIX(kDup), |
Brian Osman | 07c117b | 2019-05-23 12:51:06 -0700 | [diff] [blame] | 67 | // kLoad/kLoadGlobal are followed by a byte indicating the local/global slot to load |
Ethan Nicholas | 48a75aa | 2019-05-16 17:15:56 -0400 | [diff] [blame] | 68 | VECTOR(kLoad), |
| 69 | VECTOR(kLoadGlobal), |
Brian Osman | 07c117b | 2019-05-23 12:51:06 -0700 | [diff] [blame] | 70 | // As kLoad/kLoadGlobal, then a count byte (1-4), and then one byte per swizzle component (0-3). |
Ethan Nicholas | 0e9401d | 2019-03-21 11:05:37 -0400 | [diff] [blame] | 71 | kLoadSwizzle, |
Brian Osman | b745129 | 2019-05-15 13:02:13 -0400 | [diff] [blame] | 72 | kLoadSwizzleGlobal, |
Brian Osman | 07c117b | 2019-05-23 12:51:06 -0700 | [diff] [blame] | 73 | // kLoadExtended* are fallback load ops when we lack a specialization. They are followed by a |
| 74 | // count byte, and get the slot to load from the top of the stack. |
| 75 | kLoadExtended, |
| 76 | kLoadExtendedGlobal, |
Brian Osman | 29e013d | 2019-05-28 17:16:03 -0400 | [diff] [blame] | 77 | // Followed by four bytes: srcCols, srcRows, dstCols, dstRows. Consumes the src matrix from the |
| 78 | // stack, and replaces it with the dst matrix. Per GLSL rules, there are no restrictions on |
| 79 | // dimensions. Any overlapping values are copied, and any other values are filled in with the |
| 80 | // identity matrix. |
| 81 | kMatrixToMatrix, |
Brian Osman | 909231c | 2019-05-29 15:34:36 -0400 | [diff] [blame^] | 82 | // Followed by three bytes: leftCols (== rightRows), leftRows, rightCols |
| 83 | kMatrixMultiply, |
Brian Osman | 1e855b2 | 2019-05-29 15:21:52 -0400 | [diff] [blame] | 84 | VECTOR_MATRIX(kNegateF), |
Mike Klein | 1271091 | 2019-05-21 11:04:59 -0500 | [diff] [blame] | 85 | VECTOR(kNegateI), |
Ethan Nicholas | ae9633b | 2019-05-24 12:46:34 -0400 | [diff] [blame] | 86 | VECTOR(kMix), |
Brian Osman | 1e855b2 | 2019-05-29 15:21:52 -0400 | [diff] [blame] | 87 | VECTOR_MATRIX(kMultiplyF), |
Ethan Nicholas | 48a75aa | 2019-05-16 17:15:56 -0400 | [diff] [blame] | 88 | VECTOR(kMultiplyI), |
| 89 | VECTOR(kNot), |
| 90 | VECTOR(kOrB), |
| 91 | VECTOR(kOrI), |
Brian Osman | 1e855b2 | 2019-05-29 15:21:52 -0400 | [diff] [blame] | 92 | VECTOR_MATRIX(kPop), |
Ethan Nicholas | 0e9401d | 2019-03-21 11:05:37 -0400 | [diff] [blame] | 93 | // Followed by a 32 bit value containing the value to push |
| 94 | kPushImmediate, |
Ethan Nicholas | 91164d1 | 2019-05-15 15:29:54 -0400 | [diff] [blame] | 95 | // Followed by a byte indicating external value to read |
Ethan Nicholas | 48a75aa | 2019-05-16 17:15:56 -0400 | [diff] [blame] | 96 | VECTOR(kReadExternal), |
| 97 | VECTOR(kRemainderF), |
| 98 | VECTOR(kRemainderS), |
| 99 | VECTOR(kRemainderU), |
Ethan Nicholas | 746035a | 2019-04-23 13:31:09 -0400 | [diff] [blame] | 100 | // Followed by a byte indicating the number of slots being returned |
| 101 | kReturn, |
Brian Osman | 29e013d | 2019-05-28 17:16:03 -0400 | [diff] [blame] | 102 | // Followed by two bytes indicating columns and rows of matrix (2, 3, or 4 each). |
| 103 | // Takes a single value from the top of the stack, and converts to a CxR matrix with that value |
| 104 | // replicated along the diagonal (and zero elsewhere), per the GLSL matrix construction rules. |
| 105 | kScalarToMatrix, |
Ethan Nicholas | 82162ee | 2019-05-21 16:05:08 -0400 | [diff] [blame] | 106 | VECTOR(kSin), |
| 107 | VECTOR(kSqrt), |
Brian Osman | 07c117b | 2019-05-23 12:51:06 -0700 | [diff] [blame] | 108 | // kStore/kStoreGlobal are followed by a byte indicating the local/global slot to store |
Ethan Nicholas | 48a75aa | 2019-05-16 17:15:56 -0400 | [diff] [blame] | 109 | VECTOR(kStore), |
| 110 | VECTOR(kStoreGlobal), |
Brian Osman | 07c117b | 2019-05-23 12:51:06 -0700 | [diff] [blame] | 111 | // Fallback stores. Followed by count byte, and get the slot to store from the top of the stack |
| 112 | kStoreExtended, |
| 113 | kStoreExtendedGlobal, |
| 114 | // As kStore/kStoreGlobal, then a count byte (1-4), then one byte per swizzle component (0-3). |
Brian Osman | 1091f02 | 2019-05-16 09:42:16 -0400 | [diff] [blame] | 115 | // Expects the stack to look like: ... v1 v2 v3 v4, where the number of 'v's is equal to the |
| 116 | // number of swizzle components. After the store, all v's are popped from the stack. |
Ethan Nicholas | 0e9401d | 2019-03-21 11:05:37 -0400 | [diff] [blame] | 117 | kStoreSwizzle, |
Brian Osman | 1091f02 | 2019-05-16 09:42:16 -0400 | [diff] [blame] | 118 | kStoreSwizzleGlobal, |
Brian Osman | 07c117b | 2019-05-23 12:51:06 -0700 | [diff] [blame] | 119 | // As above, but gets the store slot from the top of the stack (before values to be stored) |
| 120 | kStoreSwizzleIndirect, |
| 121 | kStoreSwizzleIndirectGlobal, |
Ethan Nicholas | 0e9401d | 2019-03-21 11:05:37 -0400 | [diff] [blame] | 122 | // Followed by two count bytes (1-4), and then one byte per swizzle component (0-3). The first |
| 123 | // count byte provides the current vector size (the vector is the top n stack elements), and the |
| 124 | // second count byte provides the swizzle component count. |
| 125 | kSwizzle, |
Brian Osman | 1e855b2 | 2019-05-29 15:21:52 -0400 | [diff] [blame] | 126 | VECTOR_MATRIX(kSubtractF), |
Ethan Nicholas | 48a75aa | 2019-05-16 17:15:56 -0400 | [diff] [blame] | 127 | VECTOR(kSubtractI), |
Ethan Nicholas | 82162ee | 2019-05-21 16:05:08 -0400 | [diff] [blame] | 128 | VECTOR(kTan), |
Ethan Nicholas | 48a75aa | 2019-05-16 17:15:56 -0400 | [diff] [blame] | 129 | VECTOR(kXorB), |
| 130 | VECTOR(kXorI), |
Ethan Nicholas | 91164d1 | 2019-05-15 15:29:54 -0400 | [diff] [blame] | 131 | // Followed by a byte indicating external value to write |
Ethan Nicholas | 48a75aa | 2019-05-16 17:15:56 -0400 | [diff] [blame] | 132 | VECTOR(kWriteExternal), |
Ethan Nicholas | 0e9401d | 2019-03-21 11:05:37 -0400 | [diff] [blame] | 133 | }; |
Ethan Nicholas | 48a75aa | 2019-05-16 17:15:56 -0400 | [diff] [blame] | 134 | #undef VECTOR |
Ethan Nicholas | 0e9401d | 2019-03-21 11:05:37 -0400 | [diff] [blame] | 135 | |
Ethan Nicholas | 0e9401d | 2019-03-21 11:05:37 -0400 | [diff] [blame] | 136 | struct ByteCodeFunction { |
Brian Osman | 226668a | 2019-05-14 16:47:30 -0400 | [diff] [blame] | 137 | ByteCodeFunction(const FunctionDeclaration* declaration) |
| 138 | : fDeclaration(*declaration) {} |
Ethan Nicholas | 0e9401d | 2019-03-21 11:05:37 -0400 | [diff] [blame] | 139 | |
Ethan Nicholas | 0e9401d | 2019-03-21 11:05:37 -0400 | [diff] [blame] | 140 | const FunctionDeclaration& fDeclaration; |
| 141 | int fParameterCount = 0; |
| 142 | int fLocalCount = 0; |
Ethan Nicholas | dfcad06 | 2019-05-07 12:53:34 -0400 | [diff] [blame] | 143 | // TODO: Compute this value analytically. For now, just pick an arbitrary value that we probably |
| 144 | // won't overflow. |
| 145 | int fStackCount = 128; |
| 146 | int fReturnCount = 0; |
Ethan Nicholas | 0e9401d | 2019-03-21 11:05:37 -0400 | [diff] [blame] | 147 | std::vector<uint8_t> fCode; |
| 148 | }; |
| 149 | |
| 150 | struct ByteCode { |
| 151 | int fGlobalCount = 0; |
Ethan Nicholas | 0e9401d | 2019-03-21 11:05:37 -0400 | [diff] [blame] | 152 | // one entry per input slot, contains the global slot to which the input slot maps |
| 153 | std::vector<uint8_t> fInputSlots; |
| 154 | std::vector<std::unique_ptr<ByteCodeFunction>> fFunctions; |
Brian Osman | 226668a | 2019-05-14 16:47:30 -0400 | [diff] [blame] | 155 | |
| 156 | const ByteCodeFunction* getFunction(const char* name) const { |
| 157 | for (const auto& f : fFunctions) { |
| 158 | if (f->fDeclaration.fName == name) { |
| 159 | return f.get(); |
| 160 | } |
| 161 | } |
| 162 | return nullptr; |
| 163 | } |
Ethan Nicholas | 91164d1 | 2019-05-15 15:29:54 -0400 | [diff] [blame] | 164 | |
| 165 | std::vector<ExternalValue*> fExternalValues; |
Ethan Nicholas | 0e9401d | 2019-03-21 11:05:37 -0400 | [diff] [blame] | 166 | }; |
| 167 | |
| 168 | } |
| 169 | |
| 170 | #endif |