Interpreter: Support component-wise ops for matrices
The linear algebra cases are more complex, coming in separate CL. Change-Id: I5bbc25a126b61eee6f5b9775ab142e103c00f837 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/216612 Reviewed-by: Ethan Nicholas <ethannicholas@google.com> Commit-Queue: Brian Osman <brianosman@google.com>
This commit is contained in:
parent
21399d0407
commit
1e855b22b7
@ -20,9 +20,11 @@ class ExternalValue;
|
||||
struct FunctionDeclaration;
|
||||
|
||||
#define VECTOR(name) name, name ## 2, name ## 3, name ## 4
|
||||
#define VECTOR_MATRIX(name) name, name ## 2, name ## 3, name ## 4, name ## N
|
||||
|
||||
enum class ByteCodeInstruction : uint16_t {
|
||||
// B = bool, F = float, I = int, S = signed, U = unsigned
|
||||
VECTOR(kAddF),
|
||||
VECTOR_MATRIX(kAddF),
|
||||
VECTOR(kAddI),
|
||||
VECTOR(kAndB),
|
||||
VECTOR(kAndI),
|
||||
@ -34,12 +36,12 @@ enum class ByteCodeInstruction : uint16_t {
|
||||
kCallExternal,
|
||||
VECTOR(kCompareIEQ),
|
||||
VECTOR(kCompareINEQ),
|
||||
VECTOR(kCompareFEQ),
|
||||
VECTOR_MATRIX(kCompareFEQ),
|
||||
VECTOR(kCompareFGT),
|
||||
VECTOR(kCompareFGTEQ),
|
||||
VECTOR(kCompareFLT),
|
||||
VECTOR(kCompareFLTEQ),
|
||||
VECTOR(kCompareFNEQ),
|
||||
VECTOR_MATRIX(kCompareFNEQ),
|
||||
VECTOR(kCompareSGT),
|
||||
VECTOR(kCompareSGTEQ),
|
||||
VECTOR(kCompareSLT),
|
||||
@ -57,13 +59,11 @@ enum class ByteCodeInstruction : uint16_t {
|
||||
kCross,
|
||||
// Pops and prints the top value from the stack
|
||||
kDebugPrint,
|
||||
VECTOR(kDivideF),
|
||||
VECTOR_MATRIX(kDivideF),
|
||||
VECTOR(kDivideS),
|
||||
VECTOR(kDivideU),
|
||||
// Duplicates the top stack value
|
||||
VECTOR(kDup),
|
||||
// Followed by count byte. Duplicates that many values
|
||||
kDupN,
|
||||
VECTOR_MATRIX(kDup),
|
||||
// kLoad/kLoadGlobal are followed by a byte indicating the local/global slot to load
|
||||
VECTOR(kLoad),
|
||||
VECTOR(kLoadGlobal),
|
||||
@ -79,17 +79,15 @@ enum class ByteCodeInstruction : uint16_t {
|
||||
// dimensions. Any overlapping values are copied, and any other values are filled in with the
|
||||
// identity matrix.
|
||||
kMatrixToMatrix,
|
||||
VECTOR(kNegateF),
|
||||
VECTOR_MATRIX(kNegateF),
|
||||
VECTOR(kNegateI),
|
||||
VECTOR(kMix),
|
||||
VECTOR(kMultiplyF),
|
||||
VECTOR_MATRIX(kMultiplyF),
|
||||
VECTOR(kMultiplyI),
|
||||
VECTOR(kNot),
|
||||
VECTOR(kOrB),
|
||||
VECTOR(kOrI),
|
||||
VECTOR(kPop),
|
||||
// Followed by count byte
|
||||
kPopN,
|
||||
VECTOR_MATRIX(kPop),
|
||||
// Followed by a 32 bit value containing the value to push
|
||||
kPushImmediate,
|
||||
// Followed by a byte indicating external value to read
|
||||
@ -123,7 +121,7 @@ enum class ByteCodeInstruction : uint16_t {
|
||||
// count byte provides the current vector size (the vector is the top n stack elements), and the
|
||||
// second count byte provides the swizzle component count.
|
||||
kSwizzle,
|
||||
VECTOR(kSubtractF),
|
||||
VECTOR_MATRIX(kSubtractF),
|
||||
VECTOR(kSubtractI),
|
||||
VECTOR(kTan),
|
||||
VECTOR(kXorB),
|
||||
|
@ -319,9 +319,15 @@ void ByteCodeGenerator::writeTypedInstruction(const Type& type, ByteCodeInstruct
|
||||
case TypeCategory::kUnsigned:
|
||||
this->write(vector_instruction(u, count));
|
||||
break;
|
||||
case TypeCategory::kFloat:
|
||||
this->write(vector_instruction(f, count));
|
||||
case TypeCategory::kFloat: {
|
||||
if (count > 4) {
|
||||
this->write((ByteCodeInstruction)((int)f + 4));
|
||||
this->write8(count);
|
||||
} else {
|
||||
this->write(vector_instruction(f, count));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
SkASSERT(false);
|
||||
}
|
||||
|
@ -92,9 +92,16 @@ static T unaligned_load(const void* ptr) {
|
||||
case ByteCodeInstruction::op##3: printf(text "3"); break; \
|
||||
case ByteCodeInstruction::op##4: printf(text "4"); break;
|
||||
|
||||
#define VECTOR_MATRIX_DISASSEMBLE(op, text) \
|
||||
case ByteCodeInstruction::op: printf(text); break; \
|
||||
case ByteCodeInstruction::op##2: printf(text "2"); break; \
|
||||
case ByteCodeInstruction::op##3: printf(text "3"); break; \
|
||||
case ByteCodeInstruction::op##4: printf(text "4"); break; \
|
||||
case ByteCodeInstruction::op##N: printf(text "N %d", READ8()); break;
|
||||
|
||||
static const uint8_t* disassemble_instruction(const uint8_t* ip) {
|
||||
switch ((ByteCodeInstruction) READ16()) {
|
||||
VECTOR_DISASSEMBLE(kAddF, "addf")
|
||||
VECTOR_MATRIX_DISASSEMBLE(kAddF, "addf")
|
||||
VECTOR_DISASSEMBLE(kAddI, "addi")
|
||||
VECTOR_DISASSEMBLE(kAndB, "andb")
|
||||
VECTOR_DISASSEMBLE(kAndI, "andb")
|
||||
@ -109,8 +116,8 @@ static const uint8_t* disassemble_instruction(const uint8_t* ip) {
|
||||
}
|
||||
VECTOR_DISASSEMBLE(kCompareIEQ, "compareieq")
|
||||
VECTOR_DISASSEMBLE(kCompareINEQ, "compareineq")
|
||||
VECTOR_DISASSEMBLE(kCompareFEQ, "comparefeq")
|
||||
VECTOR_DISASSEMBLE(kCompareFNEQ, "comparefneq")
|
||||
VECTOR_MATRIX_DISASSEMBLE(kCompareFEQ, "comparefeq")
|
||||
VECTOR_MATRIX_DISASSEMBLE(kCompareFNEQ, "comparefneq")
|
||||
VECTOR_DISASSEMBLE(kCompareFGT, "comparefgt")
|
||||
VECTOR_DISASSEMBLE(kCompareFGTEQ, "comparefgteq")
|
||||
VECTOR_DISASSEMBLE(kCompareFLT, "compareflt")
|
||||
@ -131,11 +138,10 @@ static const uint8_t* disassemble_instruction(const uint8_t* ip) {
|
||||
VECTOR_DISASSEMBLE(kConvertUtoF, "convertutof")
|
||||
VECTOR_DISASSEMBLE(kCos, "cos")
|
||||
case ByteCodeInstruction::kDebugPrint: printf("debugprint"); break;
|
||||
VECTOR_DISASSEMBLE(kDivideF, "dividef")
|
||||
VECTOR_MATRIX_DISASSEMBLE(kDivideF, "dividef")
|
||||
VECTOR_DISASSEMBLE(kDivideS, "divideS")
|
||||
VECTOR_DISASSEMBLE(kDivideU, "divideu")
|
||||
VECTOR_DISASSEMBLE(kDup, "dup")
|
||||
case ByteCodeInstruction::kDupN: printf("dupN %d", READ8()); break;
|
||||
VECTOR_MATRIX_DISASSEMBLE(kDup, "dup")
|
||||
case ByteCodeInstruction::kLoad: printf("load %d", READ8()); break;
|
||||
case ByteCodeInstruction::kLoad2: printf("load2 %d", READ8()); break;
|
||||
case ByteCodeInstruction::kLoad3: printf("load3 %d", READ8()); break;
|
||||
@ -174,15 +180,14 @@ static const uint8_t* disassemble_instruction(const uint8_t* ip) {
|
||||
break;
|
||||
}
|
||||
VECTOR_DISASSEMBLE(kMix, "mix")
|
||||
VECTOR_DISASSEMBLE(kMultiplyF, "multiplyf")
|
||||
VECTOR_MATRIX_DISASSEMBLE(kMultiplyF, "multiplyf")
|
||||
VECTOR_DISASSEMBLE(kMultiplyI, "multiplyi")
|
||||
VECTOR_DISASSEMBLE(kNegateF, "negatef")
|
||||
VECTOR_MATRIX_DISASSEMBLE(kNegateF, "negatef")
|
||||
VECTOR_DISASSEMBLE(kNegateI, "negatei")
|
||||
VECTOR_DISASSEMBLE(kNot, "not")
|
||||
VECTOR_DISASSEMBLE(kOrB, "orb")
|
||||
VECTOR_DISASSEMBLE(kOrI, "ori")
|
||||
VECTOR_DISASSEMBLE(kPop, "pop")
|
||||
case ByteCodeInstruction::kPopN: printf("popN %d", READ8()); break;
|
||||
VECTOR_MATRIX_DISASSEMBLE(kPop, "pop")
|
||||
case ByteCodeInstruction::kPushImmediate: {
|
||||
uint32_t v = READ32();
|
||||
union { uint32_t u; float f; } pun = { v };
|
||||
@ -250,7 +255,7 @@ static const uint8_t* disassemble_instruction(const uint8_t* ip) {
|
||||
case ByteCodeInstruction::kStoreExtended: printf("storeextended %d", READ8()); break;
|
||||
case ByteCodeInstruction::kStoreExtendedGlobal: printf("storeextendedglobal %d", READ8());
|
||||
break;
|
||||
VECTOR_DISASSEMBLE(kSubtractF, "subtractf")
|
||||
VECTOR_MATRIX_DISASSEMBLE(kSubtractF, "subtractf")
|
||||
VECTOR_DISASSEMBLE(kSubtractI, "subtracti")
|
||||
case ByteCodeInstruction::kSwizzle: {
|
||||
printf("swizzle %d, ", READ8());
|
||||
@ -302,6 +307,17 @@ void Interpreter::disassemble(const ByteCodeFunction& f) {
|
||||
break; \
|
||||
}
|
||||
|
||||
#define VECTOR_MATRIX_BINARY_OP(base, field, op) \
|
||||
VECTOR_BINARY_OP(base, field, op) \
|
||||
case ByteCodeInstruction::base ## N: { \
|
||||
int count = READ8(); \
|
||||
for (int i = count; i > 0; --i) { \
|
||||
sp[-count] = sp[-count].field op sp[0].field; \
|
||||
POP(); \
|
||||
} \
|
||||
break; \
|
||||
}
|
||||
|
||||
#define VECTOR_BINARY_FN(base, field, fn) \
|
||||
case ByteCodeInstruction::base ## 4: \
|
||||
sp[-4] = fn(sp[-4].field, sp[0].field); \
|
||||
@ -360,7 +376,7 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe
|
||||
ByteCodeInstruction inst = (ByteCodeInstruction) READ16();
|
||||
switch (inst) {
|
||||
VECTOR_BINARY_OP(kAddI, fSigned, +)
|
||||
VECTOR_BINARY_OP(kAddF, fFloat, +)
|
||||
VECTOR_MATRIX_BINARY_OP(kAddF, fFloat, +)
|
||||
VECTOR_BINARY_OP(kAndB, fBool, &&)
|
||||
|
||||
case ByteCodeInstruction::kBranch:
|
||||
@ -396,9 +412,9 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe
|
||||
}
|
||||
|
||||
VECTOR_BINARY_OP(kCompareIEQ, fSigned, ==)
|
||||
VECTOR_BINARY_OP(kCompareFEQ, fFloat, ==)
|
||||
VECTOR_MATRIX_BINARY_OP(kCompareFEQ, fFloat, ==)
|
||||
VECTOR_BINARY_OP(kCompareINEQ, fSigned, !=)
|
||||
VECTOR_BINARY_OP(kCompareFNEQ, fFloat, !=)
|
||||
VECTOR_MATRIX_BINARY_OP(kCompareFNEQ, fFloat, !=)
|
||||
VECTOR_BINARY_OP(kCompareSGT, fSigned, >)
|
||||
VECTOR_BINARY_OP(kCompareUGT, fUnsigned, >)
|
||||
VECTOR_BINARY_OP(kCompareFGT, fFloat, >)
|
||||
@ -462,7 +478,7 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe
|
||||
|
||||
VECTOR_BINARY_OP(kDivideS, fSigned, /)
|
||||
VECTOR_BINARY_OP(kDivideU, fUnsigned, /)
|
||||
VECTOR_BINARY_OP(kDivideF, fFloat, /)
|
||||
VECTOR_MATRIX_BINARY_OP(kDivideF, fFloat, /)
|
||||
|
||||
case ByteCodeInstruction::kDup4: PUSH(sp[(int)ByteCodeInstruction::kDup - (int)inst]);
|
||||
case ByteCodeInstruction::kDup3: PUSH(sp[(int)ByteCodeInstruction::kDup - (int)inst]);
|
||||
@ -580,7 +596,7 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe
|
||||
}
|
||||
|
||||
VECTOR_BINARY_OP(kMultiplyI, fSigned, *)
|
||||
VECTOR_BINARY_OP(kMultiplyF, fFloat, *)
|
||||
VECTOR_MATRIX_BINARY_OP(kMultiplyF, fFloat, *)
|
||||
|
||||
case ByteCodeInstruction::kNot:
|
||||
sp[0].fBool = !sp[0].fBool;
|
||||
@ -592,6 +608,14 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe
|
||||
case ByteCodeInstruction::kNegateF : sp[ 0] = -sp[ 0].fFloat;
|
||||
break;
|
||||
|
||||
case ByteCodeInstruction::kNegateFN: {
|
||||
int count = READ8();
|
||||
for (int i = count - 1; i >= 0; --i) {
|
||||
sp[-i] = -sp[-i].fFloat;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ByteCodeInstruction::kNegateI4: sp[-3] = -sp[-3].fSigned;
|
||||
case ByteCodeInstruction::kNegateI3: sp[-2] = -sp[-2].fSigned;
|
||||
case ByteCodeInstruction::kNegateI2: sp[-1] = -sp[-1].fSigned;
|
||||
@ -736,7 +760,7 @@ void Interpreter::innerRun(const ByteCodeFunction& f, Value* stack, Value* outRe
|
||||
}
|
||||
|
||||
VECTOR_BINARY_OP(kSubtractI, fSigned, -)
|
||||
VECTOR_BINARY_OP(kSubtractF, fFloat, -)
|
||||
VECTOR_MATRIX_BINARY_OP(kSubtractF, fFloat, -)
|
||||
|
||||
case ByteCodeInstruction::kSwizzle: {
|
||||
Value tmp[4];
|
||||
|
@ -151,8 +151,8 @@ DEF_TEST(SkSLInterpreterRemainder, r) {
|
||||
}
|
||||
|
||||
DEF_TEST(SkSLInterpreterMatrix, r) {
|
||||
SkSL::Interpreter::Value in[4];
|
||||
SkSL::Interpreter::Value expected[1];
|
||||
SkSL::Interpreter::Value in[16];
|
||||
SkSL::Interpreter::Value expected[16];
|
||||
|
||||
// Constructing matrix from scalar produces a diagonal matrix
|
||||
in[0] = 1.0f;
|
||||
@ -186,13 +186,40 @@ DEF_TEST(SkSLInterpreterMatrix, r) {
|
||||
"return m[0][1] + m[1][0]; }",
|
||||
in, 1, expected);
|
||||
|
||||
#if 0
|
||||
// Addition of matrices
|
||||
test(r, "void main(inout half4 color) {"
|
||||
"half4x4 m = half4x4(color, color, color, color);"
|
||||
"m += m; color = m[0]; }",
|
||||
1, 2, 3, 4, 2, 4, 6, 8);
|
||||
// Initialize 16 values to be used as inputs to matrix tests
|
||||
for (int i = 0; i < 16; ++i) { in[i] = (float)i; }
|
||||
|
||||
// M+M, M-S, S-M
|
||||
for (int i = 0; i < 16; ++i) { expected[i] = (float)(2 * i); }
|
||||
test(r, "float4x4 main(float4x4 m) { return m + m; }", in, 16, expected);
|
||||
for (int i = 0; i < 16; ++i) { expected[i] = (float)(i + 3); }
|
||||
test(r, "float4x4 main(float4x4 m) { return m + 3.0; }", in, 16, expected);
|
||||
test(r, "float4x4 main(float4x4 m) { return 3.0 + m; }", in, 16, expected);
|
||||
|
||||
// M-M, M-S, S-M
|
||||
for (int i = 0; i < 8; ++i) { expected[i] = 8.0f; }
|
||||
test(r, "float4x2 main(float4x2 m1, float4x2 m2) { return m2 - m1; }", in, 8, expected);
|
||||
for (int i = 0; i < 16; ++i) { expected[i] = (float)(i - 3); }
|
||||
test(r, "float4x4 main(float4x4 m) { return m - 3.0; }", in, 16, expected);
|
||||
for (int i = 0; i < 16; ++i) { expected[i] = (float)(3 - i); }
|
||||
test(r, "float4x4 main(float4x4 m) { return 3.0 - m; }", in, 16, expected);
|
||||
|
||||
// M*S, S*M, M/S, S/M
|
||||
for (int i = 0; i < 16; ++i) { expected[i] = (float)(i * 3); }
|
||||
test(r, "float4x4 main(float4x4 m) { return m * 3.0; }", in, 16, expected);
|
||||
test(r, "float4x4 main(float4x4 m) { return 3.0 * m; }", in, 16, expected);
|
||||
for (int i = 0; i < 16; ++i) { expected[i] = (float)(i) / 2.0f; }
|
||||
test(r, "float4x4 main(float4x4 m) { return m / 2.0; }", in, 16, expected);
|
||||
for (int i = 0; i < 16; ++i) { expected[i] = 1.0f / (float)(i); }
|
||||
test(r, "float4x4 main(float4x4 m) { return 1.0 / m; }", in, 16, expected);
|
||||
|
||||
#if 0
|
||||
// Matrix negation - legal in GLSL, not in SkSL?
|
||||
for (int i = 0; i < 16; ++i) { expected[i] = (float)(-i); }
|
||||
test(r, "float4x4 main(float4x4 m) { return -m; }", in, 16, expected);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
// Matrix * Vector multiplication
|
||||
test(r, "void main(inout half4 color) {"
|
||||
"half4x4 m = half4x4(color, color, color, color);"
|
||||
|
Loading…
Reference in New Issue
Block a user