Interpreter: Add radians and normalize builtins

Change-Id: I2c76d8cbcfc3f36448127de5a3e1a22f76eda863
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/229489
Reviewed-by: Mike Klein <mtklein@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
This commit is contained in:
Brian Osman 2019-07-24 17:02:39 -04:00 committed by Skia Commit-Bot
parent efc7205c14
commit b380e71cfe
6 changed files with 91 additions and 38 deletions

View File

@ -137,6 +137,7 @@ static const uint8_t* disassemble_instruction(const uint8_t* ip) {
VECTOR_DISASSEMBLE(kMultiplyI, "multiplyi")
VECTOR_MATRIX_DISASSEMBLE(kNegateF, "negatef")
VECTOR_DISASSEMBLE(kNegateI, "negatei")
VECTOR_DISASSEMBLE(kNormalize, "normalize")
case ByteCodeInstruction::kNotB: printf("notb"); break;
case ByteCodeInstruction::kOrB: printf("orb"); break;
VECTOR_MATRIX_DISASSEMBLE(kPop, "pop")
@ -786,6 +787,22 @@ static bool innerRun(const ByteCode* byteCode, const ByteCodeFunction* f, VValue
case ByteCodeInstruction::kNegateI : sp[ 0] = -sp[ 0].fSigned;
break;
case ByteCodeInstruction::kNormalize:
case ByteCodeInstruction::kNormalize2:
case ByteCodeInstruction::kNormalize3:
case ByteCodeInstruction::kNormalize4: {
int count = (int)inst - (int)ByteCodeInstruction::kNormalize + 1;
F32 len = sp[0].fFloat * sp[0].fFloat;
for (int i = 1; i < count; ++i) {
len = skvx::mad(sp[-i].fFloat, sp[-i].fFloat, len);
}
F32 invLen = 1.0f / skvx::sqrt(len);
for (int i = 0; i < count; ++i) {
sp[-i].fFloat *= invLen;
}
break;
}
case ByteCodeInstruction::kPop4: POP();
case ByteCodeInstruction::kPop3: POP();
case ByteCodeInstruction::kPop2: POP();

View File

@ -83,6 +83,7 @@ enum class ByteCodeInstruction : uint16_t {
VECTOR(kMix),
VECTOR_MATRIX(kMultiplyF),
VECTOR(kMultiplyI),
VECTOR(kNormalize),
kNotB,
kOrB,
VECTOR_MATRIX(kPop),

View File

@ -1,4 +1,4 @@
/*
/*
* Copyright 2019 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
@ -17,14 +17,16 @@ ByteCodeGenerator::ByteCodeGenerator(const Context* context, const Program* prog
, fContext(*context)
, fOutput(output)
, fIntrinsics {
{ "cos", ByteCodeInstruction::kCos },
{ "cross", ByteCodeInstruction::kCross },
{ "dot", SpecialIntrinsic::kDot },
{ "inverse", ByteCodeInstruction::kInverse2x2 },
{ "sin", ByteCodeInstruction::kSin },
{ "sqrt", ByteCodeInstruction::kSqrt },
{ "tan", ByteCodeInstruction::kTan },
{ "mix", ByteCodeInstruction::kMix },
{ "cos", ByteCodeInstruction::kCos },
{ "cross", ByteCodeInstruction::kCross },
{ "dot", SpecialIntrinsic::kDot },
{ "inverse", ByteCodeInstruction::kInverse2x2 },
{ "normalize", ByteCodeInstruction::kNormalize },
{ "radians", SpecialIntrinsic::kRadians },
{ "sin", ByteCodeInstruction::kSin },
{ "sqrt", ByteCodeInstruction::kSqrt },
{ "tan", ByteCodeInstruction::kTan },
{ "mix", ByteCodeInstruction::kMix },
} {}
@ -197,6 +199,7 @@ int ByteCodeGenerator::StackUsage(ByteCodeInstruction inst, int count_) {
VECTOR_UNARY_OP(kConvertUtoF)
VECTOR_UNARY_OP(kCos)
VECTOR_UNARY_OP(kNormalize)
VECTOR_UNARY_OP(kSin)
VECTOR_UNARY_OP(kSqrt)
VECTOR_UNARY_OP(kTan)
@ -879,17 +882,34 @@ void ByteCodeGenerator::writeIntrinsicCall(const FunctionCall& c) {
}
int count = SlotCount(c.fArguments[0]->fType);
if (found->second.fIsSpecial) {
SkASSERT(found->second.fValue.fSpecial == SpecialIntrinsic::kDot);
SkASSERT(c.fArguments.size() == 2);
SkASSERT(count == SlotCount(c.fArguments[1]->fType));
this->write((ByteCodeInstruction)((int)ByteCodeInstruction::kMultiplyF + count - 1));
for (int i = count; i > 1; --i) {
this->write(ByteCodeInstruction::kAddF);
SpecialIntrinsic special = found->second.fValue.fSpecial;
switch (special) {
case SpecialIntrinsic::kDot: {
SkASSERT(c.fArguments.size() == 2);
SkASSERT(count == SlotCount(c.fArguments[1]->fType));
this->write((ByteCodeInstruction)((int)ByteCodeInstruction::kMultiplyF + count-1));
for (int i = count; i > 1; --i) {
this->write(ByteCodeInstruction::kAddF);
}
break;
}
case SpecialIntrinsic::kRadians: {
this->write(ByteCodeInstruction::kPushImmediate);
this->write32(float_to_bits(0.0174532925f)); // π/180
for (int i = count; i > 1; --i) {
this->write(ByteCodeInstruction::kDup);
}
this->write((ByteCodeInstruction)((int)ByteCodeInstruction::kMultiplyF + count-1));
break;
}
default:
SkASSERT(false);
}
} else {
switch (found->second.fValue.fInstruction) {
case ByteCodeInstruction::kCos:
case ByteCodeInstruction::kMix:
case ByteCodeInstruction::kNormalize:
case ByteCodeInstruction::kSin:
case ByteCodeInstruction::kSqrt:
case ByteCodeInstruction::kTan:
@ -910,7 +930,8 @@ void ByteCodeGenerator::writeIntrinsicCall(const FunctionCall& c) {
default: SkASSERT(false);
}
this->write(op);
} break;
break;
}
default:
SkASSERT(false);
}

View File

@ -139,6 +139,7 @@ private:
// Intrinsics which do not simply map to a single opcode
enum class SpecialIntrinsic {
kDot,
kRadians,
};
struct Intrinsic {

View File

@ -1,16 +1,22 @@
STRINGIFY(
$genType cos($genType y);
$genHType cos($genHType y);
float3 cross(float3 x, float3 y);
float dot($genType x, $genType y);
$genType mix($genType x, $genType y, float t);
float2x2 inverse(float2x2 m);
float3x3 inverse(float3x3 m);
float4x4 inverse(float4x4 m);
$genType sin($genType x);
$genHType sin($genHType x);
$genType sqrt($genType x);
$genHType sqrt($genHType x);
$genType tan($genType x);
$genHType tan($genHType x);
$genType cos($genType y);
$genHType cos($genHType y);
float3 cross(float3 x, float3 y);
float dot($genType x, $genType y);
$genType mix($genType x, $genType y, float t);
float2x2 inverse(float2x2 m);
float3x3 inverse(float3x3 m);
float4x4 inverse(float4x4 m);
$genType normalize($genType x);
$genHType normalize($genHType x);
$genType radians($genType degrees);
$genHType radians($genHType degrees);
$genType sin($genType x);
$genHType sin($genHType x);
$genType sqrt($genType x);
$genHType sqrt($genHType x);
$genType tan($genType x);
$genHType tan($genHType x);
)

View File

@ -730,17 +730,24 @@ DEF_TEST(SkSLInterpreterOutParams, r) {
}
DEF_TEST(SkSLInterpreterMathFunctions, r) {
float value, expected;
float value[4], expected[4];
value = 0.0f; expected = 0.0f;
test(r, "float main(float x) { return sin(x); }", &value, 1, &expected);
test(r, "float main(float x) { return tan(x); }", &value, 1, &expected);
value[0] = 0.0f; expected[0] = 0.0f;
test(r, "float main(float x) { return sin(x); }", value, 1, expected);
test(r, "float main(float x) { return tan(x); }", value, 1, expected);
value = 0.0f; expected = 1.0f;
test(r, "float main(float x) { return cos(x); }", &value, 1, &expected);
value[0] = 0.0f; expected[0] = 1.0f;
test(r, "float main(float x) { return cos(x); }", value, 1, expected);
value = 25.0f; expected = 5.0f;
test(r, "float main(float x) { return sqrt(x); }", &value, 1, &expected);
value[0] = 25.0f; expected[0] = 5.0f;
test(r, "float main(float x) { return sqrt(x); }", value, 1, expected);
value[0] = 90.0f; expected[0] = sk_float_degrees_to_radians(value[0]);
test(r, "float main(float x) { return radians(x); }", value, 1, expected);
value[0] = 1.0f; value[1] = -1.0f;
expected[0] = 1.0f / SK_FloatSqrt2; expected[1] = -1.0f / SK_FloatSqrt2;
test(r, "float2 main(float2 x) { return normalize(x); }", value, 2, expected);
}
DEF_TEST(SkSLInterpreterVoidFunction, r) {