Support sample(matrix) in SkRuntimeEffect's CPU backend

Also support the "N" variant of several instructions (for doing
component-wise math on matrices). With these changes, all cases
in sksl_sample_chaining work on the CPU backend, too.

Change-Id: Ie439153da452c80127e314e48fa0fa751d9f8d33
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/299378
Reviewed-by: Mike Klein <mtklein@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
This commit is contained in:
Brian Osman 2020-06-26 11:31:59 -04:00 committed by Skia Commit-Bot
parent 1caf3789f8
commit 56079c4c3e
3 changed files with 54 additions and 20 deletions

View File

@ -441,7 +441,7 @@ static std::vector<skvm::F32> program_fn(skvm::Builder* p,
std::vector<skvm::F32> stack,
/*these parameters are used to call program() on children*/
const std::vector<sk_sp<SkShader>>& children,
skvm::Coord device, skvm::Color paint,
skvm::Coord device, skvm::Coord local, skvm::Color paint,
SkFilterQuality quality, const SkColorInfo& dst,
skvm::Uniforms* uniforms, SkArenaAlloc* alloc) {
auto push = [&](skvm::F32 x) { stack.push_back(x); };
@ -461,10 +461,11 @@ static std::vector<skvm::F32> program_fn(skvm::Builder* p,
//auto u16 = [&]{ auto x = sk_unaligned_load<uint16_t>(ip); ip += sizeof(x); return x; };
auto u32 = [&]{ auto x = sk_unaligned_load<uint32_t>(ip); ip += sizeof(x); return x; };
auto unary = [&](Inst base, auto&& fn) {
const int N = (int)base - (int)inst + 1;
SkASSERT(0 < N && N <= 4);
skvm::F32 args[4];
auto unary = [&](Inst base, auto&& fn, bool allow_big = false) {
int N = (int)base - (int)inst + 1;
SkASSERT(0 < N && N <= (allow_big ? 5 : 4));
if (N == 5) { N = u8(); }
std::vector<skvm::F32> args(N);
for (int i = 0; i < N; ++i) {
args[i] = pop();
}
@ -473,14 +474,15 @@ static std::vector<skvm::F32> program_fn(skvm::Builder* p,
}
};
auto binary = [&](Inst base, auto&& fn) {
const int N = (int)base - (int)inst + 1;
SkASSERT(0 < N && N <= 4);
skvm::F32 right[4];
auto binary = [&](Inst base, auto&& fn, bool allow_big = false) {
int N = (int)base - (int)inst + 1;
SkASSERT(0 < N && N <= (allow_big ? 5 : 4));
if (N == 5) { N = u8(); }
std::vector<skvm::F32> right(N);
for (int i = 0; i < N; ++i) {
right[i] = pop();
}
skvm::F32 left[4];
std::vector<skvm::F32> left(N);
for (int i = 0; i < N; ++i) {
left[i] = pop();
}
@ -498,7 +500,34 @@ static std::vector<skvm::F32> program_fn(skvm::Builder* p,
#endif
return {};
// TODO: Inst::kSampleMatrix, should look much like kSampleExplicit.
case Inst::kSampleMatrix: {
// Child shader to run.
int ix = u8();
// Stack contains matrix to apply to sample coordinates.
skvm::F32 m[9];
for (int i = 9; i --> 0; ) { m[i] = pop(); }
// TODO: Optimize this for simpler matrices
skvm::F32 x = m[0]*local.x + m[3]*local.y + m[6],
y = m[1]*local.x + m[4]*local.y + m[7],
w = m[2]*local.x + m[5]*local.y + m[8];
x = x / w;
y = y / w;
SkOverrideDeviceMatrixProvider mats{matrices, SkMatrix::I()};
skvm::Color c = as_SB(children[ix])->program(p, device, {x,y},paint,
mats, nullptr,
quality, dst,
uniforms, alloc);
if (!c) {
return {};
}
push(c.r);
push(c.g);
push(c.b);
push(c.a);
} break;
case Inst::kSampleExplicit: {
// Child shader to run.
@ -648,22 +677,26 @@ static std::vector<skvm::F32> program_fn(skvm::Builder* p,
case Inst::kAddF:
case Inst::kAddF2:
case Inst::kAddF3:
case Inst::kAddF4: binary(Inst::kAddF, std::plus<>{}); break;
case Inst::kAddF4:
case Inst::kAddFN: binary(Inst::kAddF, std::plus<>{}, true); break;
case Inst::kSubtractF:
case Inst::kSubtractF2:
case Inst::kSubtractF3:
case Inst::kSubtractF4: binary(Inst::kSubtractF, std::minus<>{}); break;
case Inst::kSubtractF4:
case Inst::kSubtractFN: binary(Inst::kSubtractF, std::minus<>{}, true); break;
case Inst::kMultiplyF:
case Inst::kMultiplyF2:
case Inst::kMultiplyF3:
case Inst::kMultiplyF4: binary(Inst::kMultiplyF, std::multiplies<>{}); break;
case Inst::kMultiplyF4:
case Inst::kMultiplyFN: binary(Inst::kMultiplyF, std::multiplies<>{}, true); break;
case Inst::kDivideF:
case Inst::kDivideF2:
case Inst::kDivideF3:
case Inst::kDivideF4: binary(Inst::kDivideF, std::divides<>{}); break;
case Inst::kDivideF4:
case Inst::kDivideFN: binary(Inst::kDivideF, std::divides<>{}, true); break;
case Inst::kMinF:
case Inst::kMinF2:
@ -682,7 +715,8 @@ static std::vector<skvm::F32> program_fn(skvm::Builder* p,
case Inst::kNegateF:
case Inst::kNegateF2:
case Inst::kNegateF3:
case Inst::kNegateF4: unary(Inst::kNegateF, std::negate<>{}); break;
case Inst::kNegateF4:
case Inst::kNegateFN: unary(Inst::kNegateF, std::negate<>{}, true); break;
case Inst::kPow:
case Inst::kPow2:
@ -862,7 +896,7 @@ public:
std::vector<skvm::F32> stack =
program_fn(p, *fn, uniform, SkSimpleMatrixProvider{SkMatrix::I()}, {c.r, c.g, c.b, c.a},
/* the remaining parameters are for shaders only and won't be used here */
{},{},{},{},{},{},{});
{},{},{},{},{},{},{},{});
if (stack.size() == 4) {
return {stack[0], stack[1], stack[2], stack[3]};
@ -1088,7 +1122,7 @@ public:
program_fn(p, *fn, uniform, matrices,
{local.x,local.y, paint.r, paint.g, paint.b, paint.a},
/*parameters for calling program() on children*/
fChildren, device,paint, quality,dst, uniforms,alloc);
fChildren, device,local,paint, quality,dst, uniforms,alloc);
if (stack.size() == 6) {
return {stack[2], stack[3], stack[4], stack[5]};

View File

@ -20,7 +20,7 @@ class ExternalValue;
struct FunctionDeclaration;
#define VECTOR(name) name ## 4, name ## 3, name ## 2, name
#define VECTOR_MATRIX(name) name ## 4, name ## 3, name ## 2, name, name ## N
#define VECTOR_MATRIX(name) name ## N, name ## 4, name ## 3, name ## 2, name
enum class ByteCodeInstruction : uint16_t {
// B = bool, F = float, I = int, S = signed, U = unsigned

View File

@ -721,7 +721,7 @@ void ByteCodeGenerator::writeTypedInstruction(const Type& type, ByteCodeInstruct
break;
case TypeCategory::kFloat: {
if (count > 4) {
this->write((ByteCodeInstruction)((int)f + 1), count);
this->write((ByteCodeInstruction)((int)f + 1 - 5), count);
this->write8(count);
} else {
this->write(vector_instruction(f, count));