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 {
|
||||
// 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;
|
||||
for (int i = 0; i < (int)fProgram.size(); i++) {
|
||||
Builder::Instruction inst = fProgram[i];
|
||||
Instruction inst = fProgram[i];
|
||||
|
||||
#if defined(SK_CPU_X86)
|
||||
switch (Op imm_op; inst.op) {
|
||||
@ -478,8 +478,7 @@ namespace skvm {
|
||||
}
|
||||
return specialized.fProgram;
|
||||
};
|
||||
const std::vector<Builder::Instruction>& program = for_jit ? specialize_for_jit()
|
||||
: fProgram;
|
||||
const std::vector<Instruction>& program = for_jit ? specialize_for_jit() : fProgram;
|
||||
|
||||
std::vector<bool> live_instructions;
|
||||
std::vector<Val> frontier;
|
||||
@ -496,7 +495,7 @@ namespace skvm {
|
||||
|
||||
auto pressure_change = [&](Val id) -> int {
|
||||
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 (inst.op > Op::store32) { pressure += 1; }
|
||||
@ -550,7 +549,7 @@ namespace skvm {
|
||||
Val id = frontier.back();
|
||||
frontier.pop_back();
|
||||
new_index[id] = i;
|
||||
Builder::Instruction inst = program[id];
|
||||
Instruction inst = program[id];
|
||||
SkASSERT(remaining_uses[id] == 0);
|
||||
|
||||
// Use the old indices, and fix them up later.
|
||||
@ -648,7 +647,7 @@ namespace skvm {
|
||||
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
|
||||
&& a.x == b.x
|
||||
&& a.y == b.y
|
||||
@ -657,7 +656,7 @@ namespace skvm {
|
||||
&& 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);
|
||||
}
|
||||
|
||||
@ -1426,7 +1425,7 @@ namespace skvm {
|
||||
// - (*live)[id]: notes whether each input instruction is live
|
||||
// - *sinks: an unsorted set of live instructions with side effects (stores, assert_true)
|
||||
// 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<Val>* sinks) {
|
||||
int instruction_count = instructions.size();
|
||||
@ -1436,7 +1435,7 @@ namespace skvm {
|
||||
if (!(*live)[id]) {
|
||||
(*live)[id] = true;
|
||||
liveInstructionCount++;
|
||||
Builder::Instruction inst = instructions[id];
|
||||
Instruction inst = instructions[id];
|
||||
if (inst.x != NA) { recurse(inst.x, recurse); }
|
||||
if (inst.y != NA) { recurse(inst.y, recurse); }
|
||||
if (inst.z != NA) { recurse(inst.z, recurse); }
|
||||
@ -1483,7 +1482,7 @@ namespace skvm {
|
||||
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) {
|
||||
int instruction_count = instructions.size();
|
||||
|
||||
@ -1492,7 +1491,7 @@ namespace skvm {
|
||||
out_edge_count.resize(instruction_count);
|
||||
for (Val id = 0; id < instruction_count; id++) {
|
||||
if (liveness[id]) {
|
||||
Builder::Instruction inst = instructions[id];
|
||||
Instruction inst = instructions[id];
|
||||
if (inst.x != NA) {
|
||||
out_edge_count[inst.x] += 1;
|
||||
}
|
||||
@ -1522,7 +1521,7 @@ namespace skvm {
|
||||
std::vector<int> edge_cursor{fIndex};
|
||||
for (Val id = 0; id < instruction_count; id++) {
|
||||
if (liveness[id]) {
|
||||
Builder::Instruction inst = instructions[id];
|
||||
Instruction inst = instructions[id];
|
||||
if (inst.x != NA) {
|
||||
fTable[edge_cursor[inst.x]] = id;
|
||||
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; }
|
||||
};
|
||||
|
||||
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 {
|
||||
Op op;
|
||||
Val x,y,z;
|
||||
@ -412,13 +457,6 @@ namespace skvm {
|
||||
|
||||
class Builder {
|
||||
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;
|
||||
|
||||
@ -477,11 +515,7 @@ namespace skvm {
|
||||
return bit_cast(gather32(ptr, offset, index));
|
||||
}
|
||||
|
||||
// Convenience methods for working with skvm::Uniforms.
|
||||
struct Uniform {
|
||||
Arg ptr;
|
||||
int offset;
|
||||
};
|
||||
// Convenience methods for working with skvm::Uniform(s).
|
||||
I32 uniform8 (Uniform u) { return this->uniform8 (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); }
|
||||
@ -655,10 +689,6 @@ namespace skvm {
|
||||
uint64_t hash() const;
|
||||
|
||||
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);
|
||||
|
||||
I32 _(I32a x) {
|
||||
@ -697,13 +727,13 @@ namespace skvm {
|
||||
// - (*live)[id]: notes whether each input instruction is live
|
||||
// - *sinks: an unsorted set of live instructions with side effects (stores, assert_true)
|
||||
// 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<Val>* sinks);
|
||||
|
||||
class Uses {
|
||||
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.
|
||||
SkSpan<const Val> users(Val id) const;
|
||||
@ -714,35 +744,6 @@ namespace skvm {
|
||||
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;
|
||||
|
||||
// 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 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 gather16(Builder::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 F32 gatherF (Builder::Uniform u, I32 ix) { return ix->gatherF (u, ix); }
|
||||
static inline I32 gather8 (Uniform u, I32 ix) { return ix->gather8 (u, ix); }
|
||||
static inline I32 gather16(Uniform u, I32 ix) { return ix->gather16(u, ix); }
|
||||
static inline I32 gather32(Uniform u, I32 ix) { return ix->gather32(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 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));
|
||||
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);
|
||||
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());
|
||||
|
||||
// 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),
|
||||
p->mul(p->trunc(clamped_y),
|
||||
p->uniform32(uniforms->push(pm.rowBytesAsPixels()))));
|
||||
|
@ -536,7 +536,7 @@ skvm::Color SkGradientShaderBase::onProgram(skvm::Builder* p,
|
||||
fb[stops.size()] = { 0.0f, color_lo };
|
||||
|
||||
// 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.
|
||||
skvm::I32 ix;
|
||||
|
Loading…
Reference in New Issue
Block a user