Optimize SkVM approx_powf for simple cases.
Our SkVM code generator will always convert `pow(x, y)` into an `approx_powf` call. However, in many cases, `x` or `y` might boil down to an immediate value, and for some immediates, we can reduce the operation into something much simpler: - `pow(1, y)` is always 1 - `pow(2, y)` can be converted to `approx_pow2(y)` - `pow(x, 0.5)` can be converted into `sqrt(x)`. - `pow(x, 1)` can be converted to `x` - `pow(x, 2)` can be converted to `x * x` We could go further if there is a need, e.g. `pow(x, 4)` can become `a = x * x; return a * a`, but these seemed like the best places to start. Change-Id: I02b9d4d3f5067581ebad5e53b2d1d7befa308300 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/502308 Auto-Submit: John Stiles <johnstiles@google.com> Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: John Stiles <johnstiles@google.com>
This commit is contained in:
parent
1d0d1e9f16
commit
260d925cb3
@ -863,6 +863,12 @@ namespace skvm {
|
||||
// TODO: assert this instead? Sometimes x is very slightly negative. See skia:10210.
|
||||
x = max(0.0f, x);
|
||||
|
||||
if (this->isImm(x.id, 1.0f)) { return x; } // 1^y is one
|
||||
if (this->isImm(x.id, 2.0f)) { return this->approx_pow2(y); } // 2^y is pow2(y)
|
||||
if (this->isImm(y.id, 0.5f)) { return this->sqrt(x); } // x^0.5 is sqrt(x)
|
||||
if (this->isImm(y.id, 1.0f)) { return x; } // x^1 is x
|
||||
if (this->isImm(y.id, 2.0f)) { return x * x; } // x^2 is x*x
|
||||
|
||||
auto is_x = bit_or(eq(x, 0.0f),
|
||||
eq(x, 1.0f));
|
||||
return select(is_x, x, approx_pow2(mul(approx_log2(x), y)));
|
||||
|
@ -2161,16 +2161,25 @@ DEF_TEST(SkVM_approx_math, r) {
|
||||
const float expected[] = {0, 0.03125f, 0.25f, 0.5f, 1, 2, 4, 8, 32, INFINITY};
|
||||
compare(N, values, expected);
|
||||
}
|
||||
|
||||
// powf -- x^0.5
|
||||
// powf -- 1^x
|
||||
{
|
||||
float bases[] = {0, 1, 4, 9, 16};
|
||||
constexpr int N = SK_ARRAY_COUNT(bases);
|
||||
eval(N, bases, [](skvm::Builder* b, skvm::F32 base) {
|
||||
return b->approx_powf(base, b->splat(0.5f));
|
||||
float exps[] = {-2, -1, 0, 1, 2};
|
||||
constexpr int N = SK_ARRAY_COUNT(exps);
|
||||
eval(N, exps, [](skvm::Builder* b, skvm::F32 exp) {
|
||||
return b->approx_powf(b->splat(1.0f), exp);
|
||||
});
|
||||
const float expected[] = {0, 1, 2, 3, 4};
|
||||
compare(N, bases, expected);
|
||||
const float expected[] = {1, 1, 1, 1, 1};
|
||||
compare(N, exps, expected);
|
||||
}
|
||||
// powf -- 2^x
|
||||
{
|
||||
float exps[] = {-80, -5, -2, -1, 0, 1, 2, 3, 5, 160};
|
||||
constexpr int N = SK_ARRAY_COUNT(exps);
|
||||
eval(N, exps, [](skvm::Builder* b, skvm::F32 exp) {
|
||||
return b->approx_powf(2.0, exp);
|
||||
});
|
||||
const float expected[] = {0, 0.03125f, 0.25f, 0.5f, 1, 2, 4, 8, 32, INFINITY};
|
||||
compare(N, exps, expected);
|
||||
}
|
||||
// powf -- 3^x
|
||||
{
|
||||
@ -2182,6 +2191,36 @@ DEF_TEST(SkVM_approx_math, r) {
|
||||
const float expected[] = {1/9.0f, 1/3.0f, 1, 3, 9};
|
||||
compare(N, exps, expected);
|
||||
}
|
||||
// powf -- x^0.5
|
||||
{
|
||||
float bases[] = {0, 1, 4, 9, 16};
|
||||
constexpr int N = SK_ARRAY_COUNT(bases);
|
||||
eval(N, bases, [](skvm::Builder* b, skvm::F32 base) {
|
||||
return b->approx_powf(base, b->splat(0.5f));
|
||||
});
|
||||
const float expected[] = {0, 1, 2, 3, 4};
|
||||
compare(N, bases, expected);
|
||||
}
|
||||
// powf -- x^1
|
||||
{
|
||||
float bases[] = {0, 1, 2, 3, 4};
|
||||
constexpr int N = SK_ARRAY_COUNT(bases);
|
||||
eval(N, bases, [](skvm::Builder* b, skvm::F32 base) {
|
||||
return b->approx_powf(base, b->splat(1.0f));
|
||||
});
|
||||
const float expected[] = {0, 1, 2, 3, 4};
|
||||
compare(N, bases, expected);
|
||||
}
|
||||
// powf -- x^2
|
||||
{
|
||||
float bases[] = {0, 1, 2, 3, 4};
|
||||
constexpr int N = SK_ARRAY_COUNT(bases);
|
||||
eval(N, bases, [](skvm::Builder* b, skvm::F32 base) {
|
||||
return b->approx_powf(base, b->splat(2.0f));
|
||||
});
|
||||
const float expected[] = {0, 1, 4, 9, 16};
|
||||
compare(N, bases, expected);
|
||||
}
|
||||
|
||||
auto test = [r](float arg, float expected, float tolerance, auto prog) {
|
||||
skvm::Builder b;
|
||||
|
Loading…
Reference in New Issue
Block a user