aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar Florin Malita <fmalita@chromium.org>2017-06-06 12:26:54 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-06-06 18:51:59 +0000
commit47e55a5115bd1d47bdb097d37b6b9e0ecdd4fa86 (patch)
treec5cf66fbebd5974028bf16675a0e20c02c5940f0 /src
parent15f4d02738895663daa484e4c8677cbad41bcab5 (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.cpp53
-rw-r--r--src/shaders/SkShader.cpp9
-rw-r--r--src/shaders/SkShaderBase.h16
-rw-r--r--src/shaders/gradients/SkLinearGradient.cpp10
-rw-r--r--src/shaders/gradients/SkLinearGradient.h1
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,