diff options
author | Florin Malita <fmalita@chromium.org> | 2017-06-06 12:26:54 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-06-06 18:51:59 +0000 |
commit | 47e55a5115bd1d47bdb097d37b6b9e0ecdd4fa86 (patch) | |
tree | c5cf66fbebd5974028bf16675a0e20c02c5940f0 /src | |
parent | 15f4d02738895663daa484e4c8677cbad41bcab5 (diff) |
Opt-in burst mechanism for pipeline shaders
Add a dedicated virtual for shaders to select burst mode.
Enabled for linear gradients with more than 8 stops, as a start.
BUG=skia:6710
Change-Id: I1b19124f42d1d805de27a5db6a26601c386bb9ff
Reviewed-on: https://skia-review.googlesource.com/18628
Commit-Queue: Florin Malita <fmalita@chromium.org>
Reviewed-by: Mike Reed <reed@google.com>
Reviewed-by: Mike Klein <mtklein@chromium.org>
Diffstat (limited to 'src')
-rw-r--r-- | src/core/SkRasterPipelineBlitter.cpp | 53 | ||||
-rw-r--r-- | src/shaders/SkShader.cpp | 9 | ||||
-rw-r--r-- | src/shaders/SkShaderBase.h | 16 | ||||
-rw-r--r-- | src/shaders/gradients/SkLinearGradient.cpp | 10 | ||||
-rw-r--r-- | src/shaders/gradients/SkLinearGradient.h | 1 |
5 files changed, 83 insertions, 6 deletions
diff --git a/src/core/SkRasterPipelineBlitter.cpp b/src/core/SkRasterPipelineBlitter.cpp index cba39f021d..3502174de1 100644 --- a/src/core/SkRasterPipelineBlitter.cpp +++ b/src/core/SkRasterPipelineBlitter.cpp @@ -25,14 +25,17 @@ public: // 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, + SkShaderBase::Context*, bool is_opaque, bool is_constant, bool wants_dither); SkRasterPipelineBlitter(SkPixmap dst, SkBlendMode blend, - SkArenaAlloc* alloc) + SkArenaAlloc* alloc, + SkShaderBase::Context* burstCtx) : fDst(dst) , fBlend(blend) , fAlloc(alloc) + , fBurstCtx(burstCtx) , fColorPipeline(alloc) {} @@ -51,9 +54,13 @@ private: void maybe_clamp (SkRasterPipeline*) const; void append_store (SkRasterPipeline*) const; + // If we have an burst context, use it to fill our shader buffer. + void maybe_shade(int x, int y, int w); + SkPixmap fDst; SkBlendMode fBlend; SkArenaAlloc* fAlloc; + SkShaderBase::Context* fBurstCtx; SkRasterPipeline fColorPipeline; // We may be able to specialize blitH() into a memset. @@ -68,11 +75,14 @@ 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; float fDitherRate = 0.0f; + std::vector<SkPM4f> fShaderBuffer; + typedef SkBlitter INHERITED; }; @@ -96,20 +106,31 @@ SkBlitter* SkCreateRasterPipelineBlitter(const SkPixmap& dst, bool is_opaque = paintColor->a() == 1.0f, is_constant = true; return SkRasterPipelineBlitter::Create(dst, paint, alloc, - shaderPipeline, + shaderPipeline, nullptr, is_opaque, is_constant, wants_dither); } bool is_opaque = shader->isOpaque() && paintColor->a() == 1.0f; bool is_constant = shader->isConstant(); + + // Check whether the shader prefers to run in burst mode. + if (auto* burstCtx = shader->makeBurstPipelineContext( + SkShaderBase::ContextRec(paint, ctm, nullptr, SkShaderBase::ContextRec::kPM4f_DstType, + dstCS), alloc)) { + return SkRasterPipelineBlitter::Create(dst, paint, alloc, + shaderPipeline, burstCtx, + is_opaque, is_constant, wants_dither); + } + 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, + return SkRasterPipelineBlitter::Create(dst, paint, alloc, shaderPipeline, nullptr, is_opaque, is_constant, wants_dither); } + // The shader has opted out of drawing anything. return alloc->make<SkNullBlitter>(); } @@ -120,7 +141,7 @@ SkBlitter* SkCreateRasterPipelineBlitter(const SkPixmap& dst, bool wants_dither, 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, + return SkRasterPipelineBlitter::Create(dst, paint, alloc, shaderPipeline, nullptr, is_opaque, is_constant, wants_dither); } @@ -128,12 +149,14 @@ SkBlitter* SkRasterPipelineBlitter::Create(const SkPixmap& dst, const SkPaint& paint, SkArenaAlloc* alloc, const SkRasterPipeline& shaderPipeline, + SkShaderBase::Context* burstCtx, bool is_opaque, bool is_constant, bool wants_dither) { auto blitter = alloc->make<SkRasterPipelineBlitter>(dst, paint.getBlendMode(), - alloc); + alloc, + burstCtx); // 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. @@ -141,7 +164,11 @@ SkBlitter* SkRasterPipelineBlitter::Create(const SkPixmap& dst, auto colorPipeline = &blitter->fColorPipeline; // Let's get the shader in first. - colorPipeline->extend(shaderPipeline); + if (burstCtx) { + colorPipeline->append(SkRasterPipeline::load_f32, &blitter->fShaderOutput); + } else { + colorPipeline->extend(shaderPipeline); + } // If there's a color filter it comes next. if (auto colorFilter = paint.getColorFilter()) { @@ -250,6 +277,17 @@ void SkRasterPipelineBlitter::maybe_clamp(SkRasterPipeline* p) const { } } +void SkRasterPipelineBlitter::maybe_shade(int x, int y, int w) { + if (fBurstCtx) { + if (w > SkToInt(fShaderBuffer.size())) { + fShaderBuffer.resize(w); + } + fBurstCtx->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); @@ -281,6 +319,7 @@ void SkRasterPipelineBlitter::blitH(int x, int y, int w) { } fBlitH = p.compile(); } + this->maybe_shade(x,y,w); fBlitH(x,y,w); } @@ -308,6 +347,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,y,run); } @@ -368,6 +408,7 @@ void SkRasterPipelineBlitter::blitMask(const SkMask& mask, const SkIRect& clip) for (int y = clip.top(); y < clip.bottom(); y++) { fDstPtr = fDst.writable_addr(0,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/shaders/SkShader.cpp b/src/shaders/SkShader.cpp index d7587604af..07ddc6d006 100644 --- a/src/shaders/SkShader.cpp +++ b/src/shaders/SkShader.cpp @@ -9,6 +9,7 @@ #include "SkAtomics.h" #include "SkBitmapProcShader.h" #include "SkColorShader.h" +#include "SkColorSpaceXformer.h" #include "SkEmptyShader.h" #include "SkMallocPixelRef.h" #include "SkPaint.h" @@ -96,6 +97,14 @@ SkShaderBase::Context* SkShaderBase::makeContext(const ContextRec& rec, SkArenaA return this->onMakeContext(rec, alloc); } +SkShaderBase::Context* SkShaderBase::makeBurstPipelineContext(const ContextRec& rec, + SkArenaAlloc* alloc) const { + + SkASSERT(rec.fPreferredDstType == ContextRec::kPM4f_DstType); + + return this->onMakeBurstPipelineContext(rec, alloc); +} + SkShaderBase::Context::Context(const SkShaderBase& shader, const ContextRec& rec) : fShader(shader), fCTM(*rec.fMatrix) { diff --git a/src/shaders/SkShaderBase.h b/src/shaders/SkShaderBase.h index ee8d5c02dc..8dc9354e53 100644 --- a/src/shaders/SkShaderBase.h +++ b/src/shaders/SkShaderBase.h @@ -148,6 +148,15 @@ public: */ Context* makeContext(const ContextRec&, SkArenaAlloc*) const; + /** + * Shaders may opt-in for burst mode, if they can operate + * significantly more efficiently in that mode. + * + * Burst mode is prioritized in SkRasterPipelineBlitter over + * regular (appendStages) pipeline operation. + */ + Context* makeBurstPipelineContext(const ContextRec&, SkArenaAlloc*) const; + #if SK_SUPPORT_GPU struct AsFPArgs { AsFPArgs() {} @@ -240,6 +249,13 @@ protected: return nullptr; } + /** + * Overriden by shaders which prefer burst mode. + */ + virtual Context* onMakeBurstPipelineContext(const ContextRec&, SkArenaAlloc*) const { + return nullptr; + } + virtual bool onAsLuminanceColor(SkColor*) const { return false; } diff --git a/src/shaders/gradients/SkLinearGradient.cpp b/src/shaders/gradients/SkLinearGradient.cpp index aef724389a..52f380b3d3 100644 --- a/src/shaders/gradients/SkLinearGradient.cpp +++ b/src/shaders/gradients/SkLinearGradient.cpp @@ -83,6 +83,16 @@ SkShaderBase::Context* SkLinearGradient::onMakeContext( : CheckedMakeContext< LinearGradientContext>(alloc, *this, rec); } +SkShaderBase::Context* SkLinearGradient::onMakeBurstPipelineContext( + const ContextRec& rec, SkArenaAlloc* alloc) const { + + // TODO: refine heuristic. + if (fColorCount <= 8) { + return nullptr; + } + return CheckedMakeContext<LinearGradient4fContext>(alloc, *this, rec); +} + bool SkLinearGradient::adjustMatrixAndAppendStages(SkArenaAlloc* alloc, SkMatrix* matrix, SkRasterPipeline* p) const { diff --git a/src/shaders/gradients/SkLinearGradient.h b/src/shaders/gradients/SkLinearGradient.h index 19a965c7bb..300807c1f4 100644 --- a/src/shaders/gradients/SkLinearGradient.h +++ b/src/shaders/gradients/SkLinearGradient.h @@ -67,6 +67,7 @@ protected: SkLinearGradient(SkReadBuffer& buffer); void flatten(SkWriteBuffer& buffer) const override; Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const override; + Context* onMakeBurstPipelineContext(const ContextRec&, SkArenaAlloc*) const override; bool adjustMatrixAndAppendStages(SkArenaAlloc* alloc, SkMatrix* matrix, |