flatten skvm type nesting
I don't think nesting types in Builder does anything but make us type Builder:: a lot. Change-Id: Iaa66a7b5d71cb337f2774688f316e8aa196da55c Reviewed-on: https://skia-review.googlesource.com/c/skia/+/280572 Reviewed-by: Mike Reed <reed@google.com> Commit-Queue: Mike Klein <mtklein@google.com>
This commit is contained in:
parent
adf9d21704
commit
8b99b9e1d1
@ -425,10 +425,10 @@ namespace skvm {
|
|||||||
|
|
||||||
std::vector<OptimizedInstruction> Builder::optimize(bool for_jit) const {
|
std::vector<OptimizedInstruction> Builder::optimize(bool for_jit) const {
|
||||||
// If requested, first specialize for our JIT backend.
|
// If requested, first specialize for our JIT backend.
|
||||||
auto specialize_for_jit = [&]() -> std::vector<Builder::Instruction> {
|
auto specialize_for_jit = [&]() -> std::vector<Instruction> {
|
||||||
Builder specialized;
|
Builder specialized;
|
||||||
for (int i = 0; i < (int)fProgram.size(); i++) {
|
for (int i = 0; i < (int)fProgram.size(); i++) {
|
||||||
Builder::Instruction inst = fProgram[i];
|
Instruction inst = fProgram[i];
|
||||||
|
|
||||||
#if defined(SK_CPU_X86)
|
#if defined(SK_CPU_X86)
|
||||||
switch (Op imm_op; inst.op) {
|
switch (Op imm_op; inst.op) {
|
||||||
@ -478,8 +478,7 @@ namespace skvm {
|
|||||||
}
|
}
|
||||||
return specialized.fProgram;
|
return specialized.fProgram;
|
||||||
};
|
};
|
||||||
const std::vector<Builder::Instruction>& program = for_jit ? specialize_for_jit()
|
const std::vector<Instruction>& program = for_jit ? specialize_for_jit() : fProgram;
|
||||||
: fProgram;
|
|
||||||
|
|
||||||
std::vector<bool> live_instructions;
|
std::vector<bool> live_instructions;
|
||||||
std::vector<Val> frontier;
|
std::vector<Val> frontier;
|
||||||
@ -496,7 +495,7 @@ namespace skvm {
|
|||||||
|
|
||||||
auto pressure_change = [&](Val id) -> int {
|
auto pressure_change = [&](Val id) -> int {
|
||||||
int pressure = 0;
|
int pressure = 0;
|
||||||
Builder::Instruction inst = program[id];
|
Instruction inst = program[id];
|
||||||
|
|
||||||
// If this is not a sink, then it takes up a register
|
// If this is not a sink, then it takes up a register
|
||||||
if (inst.op > Op::store32) { pressure += 1; }
|
if (inst.op > Op::store32) { pressure += 1; }
|
||||||
@ -550,7 +549,7 @@ namespace skvm {
|
|||||||
Val id = frontier.back();
|
Val id = frontier.back();
|
||||||
frontier.pop_back();
|
frontier.pop_back();
|
||||||
new_index[id] = i;
|
new_index[id] = i;
|
||||||
Builder::Instruction inst = program[id];
|
Instruction inst = program[id];
|
||||||
SkASSERT(remaining_uses[id] == 0);
|
SkASSERT(remaining_uses[id] == 0);
|
||||||
|
|
||||||
// Use the old indices, and fix them up later.
|
// Use the old indices, and fix them up later.
|
||||||
@ -648,7 +647,7 @@ namespace skvm {
|
|||||||
return (uint64_t)lo | (uint64_t)hi << 32;
|
return (uint64_t)lo | (uint64_t)hi << 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool operator==(const Builder::Instruction& a, const Builder::Instruction& b) {
|
bool operator==(const Instruction& a, const Instruction& b) {
|
||||||
return a.op == b.op
|
return a.op == b.op
|
||||||
&& a.x == b.x
|
&& a.x == b.x
|
||||||
&& a.y == b.y
|
&& a.y == b.y
|
||||||
@ -657,7 +656,7 @@ namespace skvm {
|
|||||||
&& a.immz == b.immz;
|
&& a.immz == b.immz;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Builder::InstructionHash::operator()(const Instruction& inst, uint32_t seed) const {
|
uint32_t InstructionHash::operator()(const Instruction& inst, uint32_t seed) const {
|
||||||
return SkOpts::hash(&inst, sizeof(inst), seed);
|
return SkOpts::hash(&inst, sizeof(inst), seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1426,7 +1425,7 @@ namespace skvm {
|
|||||||
// - (*live)[id]: notes whether each input instruction is live
|
// - (*live)[id]: notes whether each input instruction is live
|
||||||
// - *sinks: an unsorted set of live instructions with side effects (stores, assert_true)
|
// - *sinks: an unsorted set of live instructions with side effects (stores, assert_true)
|
||||||
// Returns the number of live instructions.
|
// Returns the number of live instructions.
|
||||||
int liveness_analysis(const std::vector<Builder::Instruction>& instructions,
|
int liveness_analysis(const std::vector<Instruction>& instructions,
|
||||||
std::vector<bool>* live,
|
std::vector<bool>* live,
|
||||||
std::vector<Val>* sinks) {
|
std::vector<Val>* sinks) {
|
||||||
int instruction_count = instructions.size();
|
int instruction_count = instructions.size();
|
||||||
@ -1436,7 +1435,7 @@ namespace skvm {
|
|||||||
if (!(*live)[id]) {
|
if (!(*live)[id]) {
|
||||||
(*live)[id] = true;
|
(*live)[id] = true;
|
||||||
liveInstructionCount++;
|
liveInstructionCount++;
|
||||||
Builder::Instruction inst = instructions[id];
|
Instruction inst = instructions[id];
|
||||||
if (inst.x != NA) { recurse(inst.x, recurse); }
|
if (inst.x != NA) { recurse(inst.x, recurse); }
|
||||||
if (inst.y != NA) { recurse(inst.y, recurse); }
|
if (inst.y != NA) { recurse(inst.y, recurse); }
|
||||||
if (inst.z != NA) { recurse(inst.z, recurse); }
|
if (inst.z != NA) { recurse(inst.z, recurse); }
|
||||||
@ -1483,7 +1482,7 @@ namespace skvm {
|
|||||||
return SkMakeSpan(fTable.data() + begin, end - begin);
|
return SkMakeSpan(fTable.data() + begin, end - begin);
|
||||||
}
|
}
|
||||||
|
|
||||||
Uses::Uses(const std::vector<Builder::Instruction>& instructions,
|
Uses::Uses(const std::vector<Instruction>& instructions,
|
||||||
const std::vector<bool>& liveness) {
|
const std::vector<bool>& liveness) {
|
||||||
int instruction_count = instructions.size();
|
int instruction_count = instructions.size();
|
||||||
|
|
||||||
@ -1492,7 +1491,7 @@ namespace skvm {
|
|||||||
out_edge_count.resize(instruction_count);
|
out_edge_count.resize(instruction_count);
|
||||||
for (Val id = 0; id < instruction_count; id++) {
|
for (Val id = 0; id < instruction_count; id++) {
|
||||||
if (liveness[id]) {
|
if (liveness[id]) {
|
||||||
Builder::Instruction inst = instructions[id];
|
Instruction inst = instructions[id];
|
||||||
if (inst.x != NA) {
|
if (inst.x != NA) {
|
||||||
out_edge_count[inst.x] += 1;
|
out_edge_count[inst.x] += 1;
|
||||||
}
|
}
|
||||||
@ -1522,7 +1521,7 @@ namespace skvm {
|
|||||||
std::vector<int> edge_cursor{fIndex};
|
std::vector<int> edge_cursor{fIndex};
|
||||||
for (Val id = 0; id < instruction_count; id++) {
|
for (Val id = 0; id < instruction_count; id++) {
|
||||||
if (liveness[id]) {
|
if (liveness[id]) {
|
||||||
Builder::Instruction inst = instructions[id];
|
Instruction inst = instructions[id];
|
||||||
if (inst.x != NA) {
|
if (inst.x != NA) {
|
||||||
fTable[edge_cursor[inst.x]] = id;
|
fTable[edge_cursor[inst.x]] = id;
|
||||||
edge_cursor[inst.x] += 1;
|
edge_cursor[inst.x] += 1;
|
||||||
|
103
src/core/SkVM.h
103
src/core/SkVM.h
@ -400,6 +400,51 @@ namespace skvm {
|
|||||||
explicit operator bool() const { return h && s && l && a; }
|
explicit operator bool() const { return h && s && l && a; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Uniform {
|
||||||
|
Arg ptr;
|
||||||
|
int offset;
|
||||||
|
};
|
||||||
|
struct Uniforms {
|
||||||
|
Arg base;
|
||||||
|
std::vector<int> buf;
|
||||||
|
|
||||||
|
explicit Uniforms(int init) : base(Arg{0}), buf(init) {}
|
||||||
|
|
||||||
|
Uniform push(int val) {
|
||||||
|
buf.push_back(val);
|
||||||
|
return {base, (int)( sizeof(int)*(buf.size() - 1) )};
|
||||||
|
}
|
||||||
|
|
||||||
|
Uniform pushF(float val) {
|
||||||
|
int bits;
|
||||||
|
memcpy(&bits, &val, sizeof(int));
|
||||||
|
return this->push(bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
Uniform pushPtr(const void* ptr) {
|
||||||
|
// Jam the pointer into 1 or 2 ints.
|
||||||
|
int ints[sizeof(ptr) / sizeof(int)];
|
||||||
|
memcpy(ints, &ptr, sizeof(ptr));
|
||||||
|
for (int bits : ints) {
|
||||||
|
buf.push_back(bits);
|
||||||
|
}
|
||||||
|
return {base, (int)( sizeof(int)*(buf.size() - SK_ARRAY_COUNT(ints)) )};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SK_BEGIN_REQUIRE_DENSE
|
||||||
|
struct Instruction {
|
||||||
|
Op op; // v* = op(x,y,z,imm), where * == index of this Instruction.
|
||||||
|
Val x,y,z; // Enough arguments for mad().
|
||||||
|
int immy,immz; // Immediate bit pattern, shift count, argument index, etc.
|
||||||
|
};
|
||||||
|
SK_END_REQUIRE_DENSE
|
||||||
|
|
||||||
|
bool operator==(const Instruction&, const Instruction&);
|
||||||
|
struct InstructionHash {
|
||||||
|
uint32_t operator()(const Instruction&, uint32_t seed=0) const;
|
||||||
|
};
|
||||||
|
|
||||||
struct OptimizedInstruction {
|
struct OptimizedInstruction {
|
||||||
Op op;
|
Op op;
|
||||||
Val x,y,z;
|
Val x,y,z;
|
||||||
@ -412,13 +457,6 @@ namespace skvm {
|
|||||||
|
|
||||||
class Builder {
|
class Builder {
|
||||||
public:
|
public:
|
||||||
SK_BEGIN_REQUIRE_DENSE
|
|
||||||
struct Instruction {
|
|
||||||
Op op; // v* = op(x,y,z,imm), where * == index of this Instruction.
|
|
||||||
Val x,y,z; // Enough arguments for mad().
|
|
||||||
int immy,immz; // Immediate bit pattern, shift count, argument index, etc.
|
|
||||||
};
|
|
||||||
SK_END_REQUIRE_DENSE
|
|
||||||
|
|
||||||
Program done(const char* debug_name = nullptr) const;
|
Program done(const char* debug_name = nullptr) const;
|
||||||
|
|
||||||
@ -477,11 +515,7 @@ namespace skvm {
|
|||||||
return bit_cast(gather32(ptr, offset, index));
|
return bit_cast(gather32(ptr, offset, index));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convenience methods for working with skvm::Uniforms.
|
// Convenience methods for working with skvm::Uniform(s).
|
||||||
struct Uniform {
|
|
||||||
Arg ptr;
|
|
||||||
int offset;
|
|
||||||
};
|
|
||||||
I32 uniform8 (Uniform u) { return this->uniform8 (u.ptr, u.offset); }
|
I32 uniform8 (Uniform u) { return this->uniform8 (u.ptr, u.offset); }
|
||||||
I32 uniform16(Uniform u) { return this->uniform16(u.ptr, u.offset); }
|
I32 uniform16(Uniform u) { return this->uniform16(u.ptr, u.offset); }
|
||||||
I32 uniform32(Uniform u) { return this->uniform32(u.ptr, u.offset); }
|
I32 uniform32(Uniform u) { return this->uniform32(u.ptr, u.offset); }
|
||||||
@ -655,10 +689,6 @@ namespace skvm {
|
|||||||
uint64_t hash() const;
|
uint64_t hash() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct InstructionHash {
|
|
||||||
uint32_t operator()(const Instruction& inst, uint32_t seed=0) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
Val push(Op, Val x, Val y=NA, Val z=NA, int immy=0, int immz=0);
|
Val push(Op, Val x, Val y=NA, Val z=NA, int immy=0, int immz=0);
|
||||||
|
|
||||||
I32 _(I32a x) {
|
I32 _(I32a x) {
|
||||||
@ -697,13 +727,13 @@ namespace skvm {
|
|||||||
// - (*live)[id]: notes whether each input instruction is live
|
// - (*live)[id]: notes whether each input instruction is live
|
||||||
// - *sinks: an unsorted set of live instructions with side effects (stores, assert_true)
|
// - *sinks: an unsorted set of live instructions with side effects (stores, assert_true)
|
||||||
// Returns the number of live instructions.
|
// Returns the number of live instructions.
|
||||||
int liveness_analysis(const std::vector<Builder::Instruction>&,
|
int liveness_analysis(const std::vector<Instruction>&,
|
||||||
std::vector<bool>* live,
|
std::vector<bool>* live,
|
||||||
std::vector<Val>* sinks);
|
std::vector<Val>* sinks);
|
||||||
|
|
||||||
class Uses {
|
class Uses {
|
||||||
public:
|
public:
|
||||||
Uses(const std::vector<Builder::Instruction>&, const std::vector<bool>&);
|
Uses(const std::vector<Instruction>&, const std::vector<bool>&);
|
||||||
|
|
||||||
// Return an unordered span of Vals which use result of Instruction id.
|
// Return an unordered span of Vals which use result of Instruction id.
|
||||||
SkSpan<const Val> users(Val id) const;
|
SkSpan<const Val> users(Val id) const;
|
||||||
@ -714,35 +744,6 @@ namespace skvm {
|
|||||||
std::vector<Val> fTable;
|
std::vector<Val> fTable;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Helper to streamline allocating and working with uniforms.
|
|
||||||
struct Uniforms {
|
|
||||||
Arg base;
|
|
||||||
std::vector<int> buf;
|
|
||||||
|
|
||||||
explicit Uniforms(int init) : base(Arg{0}), buf(init) {}
|
|
||||||
|
|
||||||
Builder::Uniform push(int val) {
|
|
||||||
buf.push_back(val);
|
|
||||||
return {base, (int)( sizeof(int)*(buf.size() - 1) )};
|
|
||||||
}
|
|
||||||
|
|
||||||
Builder::Uniform pushF(float val) {
|
|
||||||
int bits;
|
|
||||||
memcpy(&bits, &val, sizeof(int));
|
|
||||||
return this->push(bits);
|
|
||||||
}
|
|
||||||
|
|
||||||
Builder::Uniform pushPtr(const void* ptr) {
|
|
||||||
// Jam the pointer into 1 or 2 ints.
|
|
||||||
int ints[sizeof(ptr) / sizeof(int)];
|
|
||||||
memcpy(ints, &ptr, sizeof(ptr));
|
|
||||||
for (int bits : ints) {
|
|
||||||
buf.push_back(bits);
|
|
||||||
}
|
|
||||||
return {base, (int)( sizeof(int)*(buf.size() - SK_ARRAY_COUNT(ints)) )};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
using Reg = int;
|
using Reg = int;
|
||||||
|
|
||||||
// d = op(x, y/imm, z/imm)
|
// d = op(x, y/imm, z/imm)
|
||||||
@ -907,10 +908,10 @@ namespace skvm {
|
|||||||
static inline I32 gather32(Arg ptr, int off, I32 ix) { return ix->gather32(ptr, off, ix); }
|
static inline I32 gather32(Arg ptr, int off, I32 ix) { return ix->gather32(ptr, off, ix); }
|
||||||
static inline F32 gatherF (Arg ptr, int off, I32 ix) { return ix->gatherF (ptr, off, ix); }
|
static inline F32 gatherF (Arg ptr, int off, I32 ix) { return ix->gatherF (ptr, off, ix); }
|
||||||
|
|
||||||
static inline I32 gather8 (Builder::Uniform u, I32 ix) { return ix->gather8 (u, ix); }
|
static inline I32 gather8 (Uniform u, I32 ix) { return ix->gather8 (u, ix); }
|
||||||
static inline I32 gather16(Builder::Uniform u, I32 ix) { return ix->gather16(u, ix); }
|
static inline I32 gather16(Uniform u, I32 ix) { return ix->gather16(u, ix); }
|
||||||
static inline I32 gather32(Builder::Uniform u, I32 ix) { return ix->gather32(u, ix); }
|
static inline I32 gather32(Uniform u, I32 ix) { return ix->gather32(u, ix); }
|
||||||
static inline F32 gatherF (Builder::Uniform u, I32 ix) { return ix->gatherF (u, ix); }
|
static inline F32 gatherF (Uniform u, I32 ix) { return ix->gatherF (u, ix); }
|
||||||
|
|
||||||
static inline F32 sqrt(F32 x) { return x-> sqrt(x); }
|
static inline F32 sqrt(F32 x) { return x-> sqrt(x); }
|
||||||
static inline F32 approx_log2(F32 x) { return x->approx_log2(x); }
|
static inline F32 approx_log2(F32 x) { return x->approx_log2(x); }
|
||||||
|
@ -131,7 +131,7 @@ public:
|
|||||||
c = p->clamp(c, p->splat(0.f), p->splat(1.0f));
|
c = p->clamp(c, p->splat(0.f), p->splat(1.0f));
|
||||||
skvm::I32 index = p->to_unorm(8, c);
|
skvm::I32 index = p->to_unorm(8, c);
|
||||||
|
|
||||||
skvm::Builder::Uniform table = uniforms->pushPtr(bytePtr);
|
skvm::Uniform table = uniforms->pushPtr(bytePtr);
|
||||||
skvm::I32 byte = p->gather8(table, index);
|
skvm::I32 byte = p->gather8(table, index);
|
||||||
return p->from_unorm(8, byte);
|
return p->from_unorm(8, byte);
|
||||||
};
|
};
|
||||||
|
@ -730,7 +730,7 @@ skvm::Color SkImageShader::onProgram(skvm::Builder* p, skvm::F32 x, skvm::F32 y,
|
|||||||
clamped_y = clamp(sy, pm.height());
|
clamped_y = clamp(sy, pm.height());
|
||||||
|
|
||||||
// Load pixels from pm.addr()[(int)sx + (int)sy*stride].
|
// Load pixels from pm.addr()[(int)sx + (int)sy*stride].
|
||||||
skvm::Builder::Uniform img = uniforms->pushPtr(pm.addr());
|
skvm::Uniform img = uniforms->pushPtr(pm.addr());
|
||||||
skvm::I32 index = p->add(p->trunc(clamped_x),
|
skvm::I32 index = p->add(p->trunc(clamped_x),
|
||||||
p->mul(p->trunc(clamped_y),
|
p->mul(p->trunc(clamped_y),
|
||||||
p->uniform32(uniforms->push(pm.rowBytesAsPixels()))));
|
p->uniform32(uniforms->push(pm.rowBytesAsPixels()))));
|
||||||
|
@ -536,7 +536,7 @@ skvm::Color SkGradientShaderBase::onProgram(skvm::Builder* p,
|
|||||||
fb[stops.size()] = { 0.0f, color_lo };
|
fb[stops.size()] = { 0.0f, color_lo };
|
||||||
|
|
||||||
// We'll gather FBs from that array we just created.
|
// We'll gather FBs from that array we just created.
|
||||||
skvm::Builder::Uniform fbs = uniforms->pushPtr(fb);
|
skvm::Uniform fbs = uniforms->pushPtr(fb);
|
||||||
|
|
||||||
// Find the two stops we need to interpolate.
|
// Find the two stops we need to interpolate.
|
||||||
skvm::I32 ix;
|
skvm::I32 ix;
|
||||||
|
Loading…
Reference in New Issue
Block a user