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:
Brian Osman 2019-05-29 15:21:52 -04:00 committed by Skia Commit-Bot
parent 21399d0407
commit 1e855b22b7
4 changed files with 95 additions and 40 deletions

View File

@ -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),

View File

@ -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);
}

View File

@ -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];

View File

@ -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);"