aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/core/SkRasterPipelineBlitter.cpp147
-rw-r--r--src/core/SkShader.cpp37
2 files changed, 98 insertions, 86 deletions
diff --git a/src/core/SkRasterPipelineBlitter.cpp b/src/core/SkRasterPipelineBlitter.cpp
index e5c532597a..023ff1e234 100644
--- a/src/core/SkRasterPipelineBlitter.cpp
+++ b/src/core/SkRasterPipelineBlitter.cpp
@@ -10,6 +10,7 @@
#include "SkBlendModePriv.h"
#include "SkColor.h"
#include "SkColorFilter.h"
+#include "SkColorSpaceXformer.h"
#include "SkOpts.h"
#include "SkPM4f.h"
#include "SkPM4fPriv.h"
@@ -20,20 +21,19 @@
class SkRasterPipelineBlitter final : public SkBlitter {
public:
- // Create using paint.getShader() or paint.getColor() if there is no shader.
- // If there's a shader, we will modulate the shader color by the paint alpha.
- static SkBlitter* Create(const SkPixmap&, const SkPaint&, SkArenaAlloc*, const SkMatrix& ctm);
-
- // Create using pre-built shader pipeline.
- // This pre-built pipeline must already have handled modulating with the paint alpha.
+ // This is our common entrypoint for creating the blitter once we've sorted out shaders.
static SkBlitter* Create(const SkPixmap&, const SkPaint&, SkArenaAlloc*,
- const SkRasterPipeline& shaderPipeline,
+ const SkRasterPipeline& shaderPipeline, SkShader::Context* shaderCtx,
bool is_opaque, bool is_constant, bool wants_dither);
- SkRasterPipelineBlitter(SkPixmap dst, SkBlendMode blend, SkArenaAlloc* alloc)
+ SkRasterPipelineBlitter(SkPixmap dst,
+ SkBlendMode blend,
+ SkArenaAlloc* alloc,
+ SkShader::Context* shaderCtx)
: fDst(dst)
, fBlend(blend)
, fAlloc(alloc)
+ , fShaderCtx(shaderCtx)
, fColorPipeline(alloc)
{}
@@ -51,10 +51,14 @@ private:
void maybe_clamp (SkRasterPipeline*) const;
void append_store (SkRasterPipeline*) const;
- SkPixmap fDst;
- SkBlendMode fBlend;
- SkArenaAlloc* fAlloc;
- SkRasterPipeline fColorPipeline;
+ // If we have an SkShader::Context, use it to fill our shader buffer.
+ void maybe_shade(int x, int y, int w);
+
+ SkPixmap fDst;
+ SkBlendMode fBlend;
+ SkArenaAlloc* fAlloc;
+ SkShader::Context* fShaderCtx;
+ SkRasterPipeline fColorPipeline;
// We may be able to specialize blitH() into a memset.
bool fCanMemsetInBlitH = false;
@@ -68,12 +72,15 @@ private:
// These values are pointed to by the blit pipelines above,
// which allows us to adjust them from call to call.
+ void* fShaderOutput = nullptr;
void* fDstPtr = nullptr;
const void* fMaskPtr = nullptr;
float fCurrentCoverage = 0.0f;
int fCurrentY = 0;
SkJumper_DitherCtx fDitherCtx = { &fCurrentY, 0.0f };
+ std::vector<SkPM4f> fShaderBuffer;
+
typedef SkBlitter INHERITED;
};
@@ -81,7 +88,54 @@ SkBlitter* SkCreateRasterPipelineBlitter(const SkPixmap& dst,
const SkPaint& paint,
const SkMatrix& ctm,
SkArenaAlloc* alloc) {
- return SkRasterPipelineBlitter::Create(dst, paint, alloc, ctm);
+ SkColorSpace* dstCS = dst.colorSpace();
+ auto paintColor = alloc->make<SkPM4f>(SkPM4f_from_SkColor(paint.getColor(), dstCS));
+ auto shader = paint.getShader();
+
+ SkRasterPipeline_<256> shaderPipeline;
+ if (!shader) {
+ // Having no shader makes things nice and easy... just use the paint color.
+ shaderPipeline.append(SkRasterPipeline::constant_color, paintColor);
+ bool is_opaque = paintColor->a() == 1.0f,
+ is_constant = true,
+ wants_dither = false;
+ return SkRasterPipelineBlitter::Create(dst, paint, alloc,
+ shaderPipeline, nullptr,
+ is_opaque, is_constant, wants_dither);
+ }
+
+ bool is_opaque = shader->isOpaque() && paintColor->a() == 1.0f;
+ bool is_constant = shader->isConstant();
+ bool wants_dither = shader->asAGradient(nullptr) >= SkShader::kLinear_GradientType;
+
+ // See if the shader can express itself by appending pipeline stages.
+ if (shader->appendStages(&shaderPipeline, dstCS, alloc, ctm, paint)) {
+ if (paintColor->a() != 1.0f) {
+ shaderPipeline.append(SkRasterPipeline::scale_1_float, &paintColor->fVec[SkPM4f::A]);
+ }
+ return SkRasterPipelineBlitter::Create(dst, paint, alloc,
+ shaderPipeline, nullptr,
+ is_opaque, is_constant, wants_dither);
+ }
+
+ // No, the shader wants us to create a context and call shadeSpan4f().
+ SkASSERT(!is_constant); // All constant shaders should be able to appendStages().
+
+ if (dstCS) {
+ // We need to transform the shader into the dst color space, and extend its lifetime.
+ sk_sp<SkShader> in_dstCS = SkColorSpaceXformer::Make(sk_ref_sp(dstCS))->apply(shader);
+ shader = in_dstCS.get();
+ alloc->make<sk_sp<SkShader>>(std::move(in_dstCS));
+ }
+ SkShader::ContextRec rec(paint, ctm, nullptr, SkShader::ContextRec::kPM4f_DstType, dstCS);
+ SkShader::Context* shaderCtx = shader->makeContext(rec, alloc);
+ if (!shaderCtx) {
+ // When a shader fails to create a context, it has vetoed drawing entirely.
+ return alloc->make<SkNullBlitter>();
+ }
+ return SkRasterPipelineBlitter::Create(dst, paint, alloc,
+ shaderPipeline, shaderCtx,
+ is_opaque, is_constant, wants_dither);
}
SkBlitter* SkCreateRasterPipelineBlitter(const SkPixmap& dst,
@@ -92,59 +146,38 @@ SkBlitter* SkCreateRasterPipelineBlitter(const SkPixmap& dst,
SkArenaAlloc* alloc) {
bool is_constant = false; // If this were the case, it'd be better to just set a paint color.
return SkRasterPipelineBlitter::Create(dst, paint, alloc,
- shaderPipeline, is_opaque, is_constant, wants_dither);
-}
-
-SkBlitter* SkRasterPipelineBlitter::Create(const SkPixmap& dst,
- const SkPaint& paint,
- SkArenaAlloc* alloc,
- const SkMatrix& ctm) {
- auto paintColor = alloc->make<SkPM4f>(SkPM4f_from_SkColor(paint.getColor(),
- dst.colorSpace()));
- SkRasterPipeline_<256> shaderPipeline;
- if (auto shader = paint.getShader()) {
- if (!shader->appendStages(&shaderPipeline, dst.colorSpace(), alloc, ctm, paint)) {
- // When a shader fails to append stages, it means it has vetoed drawing entirely.
- return alloc->make<SkNullBlitter>();
- }
-
- bool is_opaque = shader->isOpaque();
- if (paintColor->a() != 1.0f) {
- shaderPipeline.append(SkRasterPipeline::scale_1_float, &paintColor->fVec[SkPM4f::A]);
- is_opaque = false;
- }
-
- bool is_constant = shader->isConstant();
- bool wants_dither = shader->asAGradient(nullptr) >= SkShader::kLinear_GradientType;
- return Create(dst, paint, alloc, shaderPipeline, is_opaque, is_constant, wants_dither);
- }
-
- shaderPipeline.append(SkRasterPipeline::constant_color, paintColor);
- bool is_opaque = paintColor->a() == 1.0f,
- is_constant = true,
- wants_dither = false;
- return Create(dst, paint, alloc, shaderPipeline, is_opaque, is_constant, wants_dither);
+ shaderPipeline, nullptr,
+ is_opaque, is_constant, wants_dither);
}
SkBlitter* SkRasterPipelineBlitter::Create(const SkPixmap& dst,
const SkPaint& paint,
SkArenaAlloc* alloc,
const SkRasterPipeline& shaderPipeline,
+ SkShader::Context* shaderCtx,
bool is_opaque,
bool is_constant,
bool wants_dither) {
- auto blitter = alloc->make<SkRasterPipelineBlitter>(dst, paint.getBlendMode(), alloc);
+ auto blitter = alloc->make<SkRasterPipelineBlitter>(dst,
+ paint.getBlendMode(),
+ alloc,
+ shaderCtx);
// Our job in this factory is to fill out the blitter's color pipeline.
// This is the common front of the full blit pipelines, each constructed lazily on first use.
// The full blit pipelines handle reading and writing the dst, blending, coverage, dithering.
auto colorPipeline = &blitter->fColorPipeline;
- // Let's get the shader in first. If the shader's not constant, it'll need seeding with x,y.
- if (!is_constant) {
- colorPipeline->append(SkRasterPipeline::seed_shader, &blitter->fCurrentY);
+ // Let's get the shader in first.
+ if (shaderCtx) {
+ colorPipeline->append(SkRasterPipeline::load_f32, &blitter->fShaderOutput);
+ } else {
+ // If the shader's not constant, it'll need seeding with x,y.
+ if (!is_constant) {
+ colorPipeline->append(SkRasterPipeline::seed_shader, &blitter->fCurrentY);
+ }
+ colorPipeline->extend(shaderPipeline);
}
- colorPipeline->extend(shaderPipeline);
// If there's a color filter it comes next.
if (auto colorFilter = paint.getColorFilter()) {
@@ -253,6 +286,17 @@ void SkRasterPipelineBlitter::maybe_clamp(SkRasterPipeline* p) const {
}
}
+void SkRasterPipelineBlitter::maybe_shade(int x, int y, int w) {
+ if (fShaderCtx) {
+ if (w > SkToInt(fShaderBuffer.size())) {
+ fShaderBuffer.resize(w);
+ }
+ fShaderCtx->shadeSpan4f(x,y, fShaderBuffer.data(), w);
+ // We'll be reading from fShaderOutput + x.
+ fShaderOutput = fShaderBuffer.data() - x;
+ }
+}
+
void SkRasterPipelineBlitter::blitH(int x, int y, int w) {
fDstPtr = fDst.writable_addr(0,y);
fCurrentY = y;
@@ -278,6 +322,7 @@ void SkRasterPipelineBlitter::blitH(int x, int y, int w) {
this->append_store(&p);
fBlitH = p.compile();
}
+ this->maybe_shade(x,y,w);
fBlitH(x,w);
}
@@ -306,6 +351,7 @@ void SkRasterPipelineBlitter::blitAntiH(int x, int y, const SkAlpha aa[], const
case 0x00: break;
case 0xff: this->blitH(x,y,run); break;
default:
+ this->maybe_shade(x,y,run);
fCurrentCoverage = *aa * (1/255.0f);
fBlitAntiH(x,run);
}
@@ -354,6 +400,7 @@ void SkRasterPipelineBlitter::blitMask(const SkMask& mask, const SkIRect& clip)
fDstPtr = fDst.writable_addr(0,y);
fCurrentY = y;
+ this->maybe_shade(x,y,clip.width());
switch (mask.fFormat) {
case SkMask::kA8_Format:
fMaskPtr = mask.getAddr8(x,y)-x;
diff --git a/src/core/SkShader.cpp b/src/core/SkShader.cpp
index c8d5f08776..ff5b400a25 100644
--- a/src/core/SkShader.cpp
+++ b/src/core/SkShader.cpp
@@ -264,42 +264,7 @@ bool SkShader::appendStages(SkRasterPipeline* p,
const SkMatrix& ctm,
const SkPaint& paint,
const SkMatrix* localM) const {
- SkRasterPipeline_<256> subclass;
- if (this->onAppendStages(&subclass, dstCS, alloc, ctm, paint, localM)) {
- p->extend(subclass);
- return true;
- }
-
- // SkShader::Context::shadeSpan4f() handles the paint opacity internally,
- // but SkRasterPipelineBlitter applies it as a separate stage.
- // We skip the internal shadeSpan4f() step by forcing the paint opaque.
- SkTCopyOnFirstWrite<SkPaint> opaquePaint(paint);
- if (paint.getAlpha() != SK_AlphaOPAQUE) {
- opaquePaint.writable()->setAlpha(SK_AlphaOPAQUE);
- }
-
- ContextRec rec(*opaquePaint, ctm, localM, ContextRec::kPM4f_DstType, dstCS);
-
- struct CallbackCtx : SkJumper_CallbackCtx {
- sk_sp<SkShader> shader;
- Context* ctx;
- };
- auto cb = alloc->make<CallbackCtx>();
- cb->shader = dstCS ? SkColorSpaceXformer::Make(sk_ref_sp(dstCS))->apply(this)
- : sk_ref_sp(const_cast<SkShader*>(this));
- cb->ctx = cb->shader->makeContext(rec, alloc);
- cb->fn = [](SkJumper_CallbackCtx* self, int active_pixels) {
- auto c = (CallbackCtx*)self;
- int x = (int)c->rgba[0],
- y = (int)c->rgba[1];
- c->ctx->shadeSpan4f(x,y, (SkPM4f*)c->rgba, active_pixels);
- };
-
- if (cb->ctx) {
- p->append(SkRasterPipeline::callback, cb);
- return true;
- }
- return false;
+ return this->onAppendStages(p, dstCS, alloc, ctm, paint, localM);
}
bool SkShader::onAppendStages(SkRasterPipeline* p,