Simplify more: remove SkRasterPipeline::compile().

It's easier to work on SkJumper if everything funnels through run().

I don't anticipate huge benefit from compile() without JITing,
but it's something we can always put back if we find a need.

Change-Id: Id5256fd21495e8195cad1924dbad81856416d913
Reviewed-on: https://skia-review.googlesource.com/8468
Commit-Queue: Mike Klein <mtklein@chromium.org>
Reviewed-by: Mike Klein <mtklein@chromium.org>
This commit is contained in:
Mike Klein 2017-02-16 06:51:48 -05:00 committed by Skia Commit-Bot
parent 394d414452
commit 8729e5bbf7
10 changed files with 60 additions and 111 deletions

View File

@ -22,16 +22,14 @@ static uint8_t mask[N]; // 8-bit linear
// - src = srcover(dst, src)
// - store src back as srgb/f16
template <bool kF16, bool kCompiled>
template <bool kF16>
class SkRasterPipelineBench : public Benchmark {
public:
bool isSuitableFor(Backend backend) override { return backend == kNonRendering_Backend; }
const char* onGetName() override {
switch ((int)kCompiled << 1 | (int)kF16) {
case 0: return "SkRasterPipeline_srgb_run";
case 1: return "SkRasterPipeline_f16_run";
case 2: return "SkRasterPipeline_srgb_compile";
case 3: return "SkRasterPipeline_f16_compile";
switch ((int)kF16) {
case 0: return "SkRasterPipeline_srgb";
case 1: return "SkRasterPipeline_f16";
}
return "whoops";
}
@ -60,30 +58,19 @@ public:
p.append(SkRasterPipeline::store_8888, &dst_ctx);
}
if (kCompiled) {
auto compiled = p.compile();
while (loops --> 0) {
compiled(0,N);
}
} else {
while (loops --> 0) {
p.run(0,N);
}
while (loops --> 0) {
p.run(0,N);
}
}
};
DEF_BENCH( return (new SkRasterPipelineBench< true, true>); )
DEF_BENCH( return (new SkRasterPipelineBench<false, true>); )
DEF_BENCH( return (new SkRasterPipelineBench< true, false>); )
DEF_BENCH( return (new SkRasterPipelineBench<false, false>); )
DEF_BENCH( return (new SkRasterPipelineBench< true>); )
DEF_BENCH( return (new SkRasterPipelineBench<false>); )
template <bool kCompiled>
class SkRasterPipelineLegacyBench : public Benchmark {
public:
bool isSuitableFor(Backend backend) override { return backend == kNonRendering_Backend; }
const char* onGetName() override {
return kCompiled ? "SkRasterPipeline_legacy_compile"
: "SkRasterPipeline_legacy_run";
return "SkRasterPipeline_legacy";
}
void onDraw(int loops, SkCanvas*) override {
@ -97,17 +84,9 @@ public:
p.append(SkRasterPipeline::srcover);
p.append(SkRasterPipeline::store_8888, &dst_ctx);
if (kCompiled) {
auto compiled = p.compile();
while (loops --> 0) {
compiled(0,N);
}
} else {
while (loops --> 0) {
p.run(0,N);
}
while (loops --> 0) {
p.run(0,N);
}
}
};
DEF_BENCH( return (new SkRasterPipelineLegacyBench< true>); )
DEF_BENCH( return (new SkRasterPipelineLegacyBench<false>); )
DEF_BENCH( return (new SkRasterPipelineLegacyBench); )

View File

@ -275,10 +275,8 @@ static void convert_with_pipeline(const SkImageInfo& dstInfo, void* dstRow, size
break;
}
auto p = pipeline.compile();
for (int y = 0; y < srcInfo.height(); ++y) {
p(0,srcInfo.width());
pipeline.run(0,srcInfo.width());
// The pipeline has pointers to srcRow and dstRow, so we just need to update them in the
// loop to move between rows of src/dst.
dstRow = SkTAddOffset<void>(dstRow, dstRB);

View File

@ -85,7 +85,6 @@ namespace SkOpts {
DEFINE_DEFAULT(hash_fn);
DEFINE_DEFAULT(run_pipeline);
DEFINE_DEFAULT(compile_pipeline);
DEFINE_DEFAULT(convolve_vertically);
DEFINE_DEFAULT(convolve_horizontally);

View File

@ -12,7 +12,6 @@
#include "SkRasterPipeline.h"
#include "SkTypes.h"
#include "SkXfermodePriv.h"
#include <functional>
struct ProcCoeff;
@ -61,8 +60,6 @@ namespace SkOpts {
}
extern void (*run_pipeline)(size_t, size_t, const SkRasterPipeline::Stage*, int);
extern std::function<void(size_t, size_t)>
(*compile_pipeline)(const SkRasterPipeline::Stage*, int);
extern void (*convolve_vertically)(const SkConvolutionFilter1D::ConvolutionFixed* filter_values,
int filter_length, unsigned char* const* source_data_rows,

View File

@ -31,10 +31,6 @@ void SkRasterPipeline::run(size_t x, size_t n) const {
}
}
std::function<void(size_t, size_t)> SkRasterPipeline::compile() const {
return SkOpts::compile_pipeline(fStages.data(), SkToInt(fStages.size()));
}
void SkRasterPipeline::dump() const {
SkDebugf("SkRasterPipeline, %d stages\n", SkToInt(fStages.size()));
for (auto&& st : fStages) {

View File

@ -12,7 +12,6 @@
#include "SkNx.h"
#include "SkTArray.h"
#include "SkTypes.h"
#include <functional>
#include <vector>
/**
@ -120,9 +119,6 @@ public:
// Runs the pipeline walking x through [x,x+n).
void run(size_t x, size_t n) const;
// If you're going to run() the pipeline more than once, it's best to compile it.
std::function<void(size_t x, size_t n)> compile() const;
void dump() const;
struct Stage {
@ -134,6 +130,8 @@ public:
// Use these helpers to keep things sane.
void append_from_srgb(SkAlphaType);
bool empty() const { return fStages.empty(); }
private:
bool run_with_jumper(size_t x, size_t n) const;

View File

@ -50,14 +50,18 @@ private:
SkRasterPipeline fShader;
bool fBlendCorrectly;
// These functions are compiled lazily when first used.
std::function<void(size_t, size_t)> fBlitH = nullptr,
fBlitAntiH = nullptr,
fBlitMaskA8 = nullptr,
fBlitMaskLCD16 = nullptr;
// We may be able to specialize blitH() into a memset.
bool fCanMemsetInBlitH = false;
uint64_t fMemsetColor = 0; // Big enough for largest dst format, F16.
// These values are pointed to by the compiled blit functions
// above, which allows us to adjust them from call to call.
// Built lazily on first use.
SkRasterPipeline fBlitH,
fBlitAntiH,
fBlitMaskA8,
fBlitMaskLCD16;
// These values are pointed to by the blit pipelines above,
// which allows us to adjust them from call to call.
void* fDstPtr = nullptr;
const void* fMaskPtr = nullptr;
float fCurrentCoverage = 0.0f;
@ -152,31 +156,13 @@ SkBlitter* SkRasterPipelineBlitter::Create(const SkPixmap& dst,
}
if (is_constant && *blend == SkBlendMode::kSrc) {
uint64_t color; // Big enough for largest dst format, F16.
SkRasterPipeline p;
p.extend(*pipeline);
blitter->fDstPtr = &color;
blitter->fDstPtr = &blitter->fMemsetColor;
blitter->append_store(&p);
p.run(0,1);
switch (dst.shiftPerPixel()) {
case 1:
blitter->fBlitH = [blitter,color](size_t x, size_t n) {
sk_memset16((uint16_t*)blitter->fDstPtr + x, color, n);
};
break;
case 2:
blitter->fBlitH = [blitter,color](size_t x, size_t n) {
sk_memset32((uint32_t*)blitter->fDstPtr + x, color, n);
};
break;
case 3:
blitter->fBlitH = [blitter,color](size_t x, size_t n) {
sk_memset64((uint64_t*)blitter->fDstPtr + x, color, n);
};
break;
default: break;
}
blitter->fCanMemsetInBlitH = true;
}
return blitter;
@ -233,8 +219,27 @@ void SkRasterPipelineBlitter::maybe_clamp(SkRasterPipeline* p) const {
}
void SkRasterPipelineBlitter::blitH(int x, int y, int w) {
if (!fBlitH) {
SkRasterPipeline p;
fDstPtr = fDst.writable_addr(0,y);
fCurrentY = y;
if (fCanMemsetInBlitH) {
switch (fDst.shiftPerPixel()) {
// TODO: case 0: memset (for A8)
case 1:
sk_memset16((uint16_t*)fDstPtr + x, fMemsetColor, w);
return;
case 2:
sk_memset32((uint32_t*)fDstPtr + x, fMemsetColor, w);
return;
case 3:
sk_memset64((uint64_t*)fDstPtr + x, fMemsetColor, w);
return;
default: break;
}
}
auto& p = fBlitH;
if (p.empty()) {
p.extend(fShader);
if (fBlend != SkBlendMode::kSrc) {
this->append_load_d(&p);
@ -242,16 +247,13 @@ void SkRasterPipelineBlitter::blitH(int x, int y, int w) {
this->maybe_clamp(&p);
}
this->append_store(&p);
fBlitH = p.compile();
}
fDstPtr = fDst.writable_addr(0,y);
fCurrentY = y;
fBlitH(x,w);
p.run(x,w);
}
void SkRasterPipelineBlitter::blitAntiH(int x, int y, const SkAlpha aa[], const int16_t runs[]) {
if (!fBlitAntiH) {
SkRasterPipeline p;
auto& p = fBlitAntiH;
if (p.empty()) {
p.extend(fShader);
if (fBlend == SkBlendMode::kSrcOver) {
p.append(SkRasterPipeline::scale_1_float, &fCurrentCoverage);
@ -264,7 +266,6 @@ void SkRasterPipelineBlitter::blitAntiH(int x, int y, const SkAlpha aa[], const
}
this->maybe_clamp(&p);
this->append_store(&p);
fBlitAntiH = p.compile();
}
fDstPtr = fDst.writable_addr(0,y);
@ -275,7 +276,7 @@ void SkRasterPipelineBlitter::blitAntiH(int x, int y, const SkAlpha aa[], const
case 0xff: this->blitH(x,y,run); break;
default:
fCurrentCoverage = *aa * (1/255.0f);
fBlitAntiH(x,run);
p.run(x,run);
}
x += run;
runs += run;
@ -289,8 +290,8 @@ void SkRasterPipelineBlitter::blitMask(const SkMask& mask, const SkIRect& clip)
return INHERITED::blitMask(mask, clip);
}
if (mask.fFormat == SkMask::kA8_Format && !fBlitMaskA8) {
SkRasterPipeline p;
if (mask.fFormat == SkMask::kA8_Format && fBlitMaskA8.empty()) {
auto& p = fBlitMaskA8;
p.extend(fShader);
if (fBlend == SkBlendMode::kSrcOver) {
p.append(SkRasterPipeline::scale_u8, &fMaskPtr);
@ -303,18 +304,16 @@ void SkRasterPipelineBlitter::blitMask(const SkMask& mask, const SkIRect& clip)
}
this->maybe_clamp(&p);
this->append_store(&p);
fBlitMaskA8 = p.compile();
}
if (mask.fFormat == SkMask::kLCD16_Format && !fBlitMaskLCD16) {
SkRasterPipeline p;
if (mask.fFormat == SkMask::kLCD16_Format && fBlitMaskLCD16.empty()) {
auto& p = fBlitMaskLCD16;
p.extend(fShader);
this->append_load_d(&p);
this->append_blend(&p);
p.append(SkRasterPipeline::lerp_565, &fMaskPtr);
this->maybe_clamp(&p);
this->append_store(&p);
fBlitMaskLCD16 = p.compile();
}
int x = clip.left();
@ -325,11 +324,11 @@ void SkRasterPipelineBlitter::blitMask(const SkMask& mask, const SkIRect& clip)
switch (mask.fFormat) {
case SkMask::kA8_Format:
fMaskPtr = mask.getAddr8(x,y)-x;
fBlitMaskA8(x,clip.width());
fBlitMaskA8.run(x,clip.width());
break;
case SkMask::kLCD16_Format:
fMaskPtr = mask.getAddrLCD16(x,y)-x;
fBlitMaskLCD16(x,clip.width());
fBlitMaskLCD16.run(x,clip.width());
break;
default:
// TODO

View File

@ -21,6 +21,5 @@ namespace SkOpts {
srcover_srgb_srgb = sse41::srcover_srgb_srgb;
blit_row_s32a_opaque = sse41::blit_row_s32a_opaque;
run_pipeline = sse41::run_pipeline;
compile_pipeline = sse41::compile_pipeline;
}
}

View File

@ -1221,11 +1221,6 @@ namespace {
namespace SK_OPTS_NS {
SI std::function<void(size_t, size_t)>
compile_pipeline(const SkRasterPipeline::Stage* stages, int nstages) {
return Compiled{stages,nstages};
}
SI void run_pipeline(size_t x, size_t n,
const SkRasterPipeline::Stage* stages, int nstages) {
static const int kStackMax = 256;

View File

@ -34,16 +34,6 @@ DEF_TEST(SkRasterPipeline, r) {
REPORTER_ASSERT(r, ((result >> 16) & 0xffff) == 0x0000);
REPORTER_ASSERT(r, ((result >> 32) & 0xffff) == 0x3800);
REPORTER_ASSERT(r, ((result >> 48) & 0xffff) == 0x3c00);
// Run again, this time compiling the pipeline.
result = 0;
auto fn = p.compile();
fn(0,1);
REPORTER_ASSERT(r, ((result >> 0) & 0xffff) == 0x3800);
REPORTER_ASSERT(r, ((result >> 16) & 0xffff) == 0x0000);
REPORTER_ASSERT(r, ((result >> 32) & 0xffff) == 0x3800);
REPORTER_ASSERT(r, ((result >> 48) & 0xffff) == 0x3c00);
}
DEF_TEST(SkRasterPipeline_empty, r) {
@ -79,8 +69,7 @@ DEF_TEST(SkRasterPipeline_JIT, r) {
SkRasterPipeline p;
p.append(SkRasterPipeline:: load_8888, &src);
p.append(SkRasterPipeline::store_8888, &dst);
auto fn = p.compile();
fn(15, 20);
p.run(15, 20);
for (int i = 0; i < 36; i++) {
if (i < 15 || i == 35) {