aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/shaders
diff options
context:
space:
mode:
authorGravatar Mike Reed <reed@google.com>2017-06-09 10:51:52 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-06-09 17:13:53 +0000
commit01b2b83aba10bc3767d660cd619c1da58b5eb0b5 (patch)
treee9336afbe6552b1d603ed11645af813ea91c01bb /src/shaders
parent6a0feba05bd57e84103cebc695d4a217ec9e472e (diff)
Extend composeshader to support a lerp parameter
Bug: skia: Change-Id: I3bbb2cb8d0a84fca0309654498548ebc94d8938f Reviewed-on: https://skia-review.googlesource.com/18460 Commit-Queue: Mike Reed <reed@google.com> Reviewed-by: Florin Malita <fmalita@chromium.org>
Diffstat (limited to 'src/shaders')
-rw-r--r--src/shaders/SkComposeShader.cpp130
-rw-r--r--src/shaders/SkComposeShader.h42
2 files changed, 88 insertions, 84 deletions
diff --git a/src/shaders/SkComposeShader.cpp b/src/shaders/SkComposeShader.cpp
index 75f9cd2654..3155784338 100644
--- a/src/shaders/SkComposeShader.cpp
+++ b/src/shaders/SkComposeShader.cpp
@@ -17,57 +17,71 @@
#include "SkString.h"
#include "../jumper/SkJumper.h"
-sk_sp<SkShader> SkShader::MakeComposeShader(sk_sp<SkShader> dst, sk_sp<SkShader> src,
- SkBlendMode mode) {
- if (!src || !dst) {
+sk_sp<SkShader> SkShader::MakeCompose(sk_sp<SkShader> dst, sk_sp<SkShader> src, SkBlendMode mode,
+ float lerpT) {
+ if (!src || !dst || SkScalarIsNaN(lerpT)) {
return nullptr;
}
- if (SkBlendMode::kSrc == mode) {
- return src;
- }
- if (SkBlendMode::kDst == mode) {
+ lerpT = SkScalarPin(lerpT, 0, 1);
+
+ if (lerpT == 0) {
return dst;
+ } else if (lerpT == 1) {
+ if (mode == SkBlendMode::kSrc) {
+ return src;
+ }
+ if (mode == SkBlendMode::kDst) {
+ return dst;
+ }
}
- return sk_sp<SkShader>(new SkComposeShader(std::move(dst), std::move(src), mode));
+ return sk_sp<SkShader>(new SkComposeShader(std::move(dst), std::move(src), mode, lerpT));
}
///////////////////////////////////////////////////////////////////////////////
sk_sp<SkFlattenable> SkComposeShader::CreateProc(SkReadBuffer& buffer) {
- sk_sp<SkShader> shaderA(buffer.readShader());
- sk_sp<SkShader> shaderB(buffer.readShader());
- SkBlendMode mode = (SkBlendMode)buffer.read32();
+ sk_sp<SkShader> dst(buffer.readShader());
+ sk_sp<SkShader> src(buffer.readShader());
+ unsigned mode = buffer.read32();
- if (!shaderA || !shaderB) {
+ float lerp = 1;
+ if (!buffer.isVersionLT(SkReadBuffer::kComposeShaderCanLerp_Version)) {
+ lerp = buffer.readScalar();
+ }
+
+ // check for valid mode before we cast to the enum type
+ if (mode > (unsigned)SkBlendMode::kLastMode) {
return nullptr;
}
- return sk_make_sp<SkComposeShader>(std::move(shaderA), std::move(shaderB), mode);
+
+ return MakeCompose(std::move(dst), std::move(src), static_cast<SkBlendMode>(mode), lerp);
}
void SkComposeShader::flatten(SkWriteBuffer& buffer) const {
- buffer.writeFlattenable(fShaderA.get());
- buffer.writeFlattenable(fShaderB.get());
+ buffer.writeFlattenable(fDst.get());
+ buffer.writeFlattenable(fSrc.get());
buffer.write32((int)fMode);
+ buffer.writeScalar(fLerpT);
}
sk_sp<SkShader> SkComposeShader::onMakeColorSpace(SkColorSpaceXformer* xformer) const {
- return SkShader::MakeComposeShader(xformer->apply(fShaderA.get()),
- xformer->apply(fShaderB.get()), fMode);
+ return MakeCompose(xformer->apply(fDst.get()), xformer->apply(fSrc.get()),
+ fMode, fLerpT);
}
bool SkComposeShader::asACompose(ComposeRec* rec) const {
+ if (!this->isJustMode()) {
+ return false;
+ }
+
if (rec) {
- rec->fShaderA = fShaderA.get();
- rec->fShaderB = fShaderB.get();
+ rec->fShaderA = fDst.get();
+ rec->fShaderB = fSrc.get();
rec->fBlendMode = fMode;
}
return true;
}
-bool SkComposeShader::isRasterPipelineOnly() const {
- return true;
-}
-
bool SkComposeShader::onAppendStages(SkRasterPipeline* pipeline, SkColorSpace* dstCS,
SkArenaAlloc* alloc, const SkMatrix& ctm,
const SkPaint& paint, const SkMatrix* localM) const {
@@ -77,27 +91,32 @@ bool SkComposeShader::onAppendStages(SkRasterPipeline* pipeline, SkColorSpace* d
};
auto storage = alloc->make<Storage>();
- if (!as_SB(fShaderB)->appendStages(pipeline, dstCS, alloc, ctm, paint, localM)) { // SRC
+ if (!as_SB(fSrc)->appendStages(pipeline, dstCS, alloc, ctm, paint, localM)) {
return false;
}
// This outputs r,g,b,a, which we'll need later when we apply the mode, but we save it off now
// since fShaderB will overwrite them.
pipeline->append(SkRasterPipeline::store_rgba, storage->fRGBA);
- if (!as_SB(fShaderA)->appendStages(pipeline, dstCS, alloc, ctm, paint, localM)) { // DST
+ if (!as_SB(fDst)->appendStages(pipeline, dstCS, alloc, ctm, paint, localM)) {
return false;
}
- // We now have our logical 'dst' in r,g,b,a, but we need it in dr,dg,db,da for the mode
+ // We now have our logical 'dst' in r,g,b,a, but we need it in dr,dg,db,da for the mode/lerp
// so we have to shuttle them. If we had a stage the would load_into_dst, then we could
// reverse the two shader invocations, and avoid this move...
pipeline->append(SkRasterPipeline::move_src_dst);
pipeline->append(SkRasterPipeline::load_rgba, storage->fRGBA);
- // Idea: should time this, and see if it helps to have custom versions of the overflow modes
- // that do their own clamping, avoiding the overhead of an extra stage.
- SkBlendMode_AppendStages(fMode, pipeline);
- if (SkBlendMode_CanOverflow(fMode)) {
- pipeline->append(SkRasterPipeline::clamp_a);
+ if (!this->isJustLerp()) {
+ // Idea: should time this, and see if it helps to have custom versions of the overflow modes
+ // that do their own clamping, avoiding the overhead of an extra stage.
+ SkBlendMode_AppendStages(fMode, pipeline);
+ if (SkBlendMode_CanOverflow(fMode)) {
+ pipeline->append(SkRasterPipeline::clamp_a);
+ }
+ }
+ if (!this->isJustMode()) {
+ pipeline->append(SkRasterPipeline::lerp_1_float, &fLerpT);
}
return true;
}
@@ -110,29 +129,25 @@ bool SkComposeShader::onAppendStages(SkRasterPipeline* pipeline, SkColorSpace* d
/////////////////////////////////////////////////////////////////////
sk_sp<GrFragmentProcessor> SkComposeShader::asFragmentProcessor(const AsFPArgs& args) const {
- switch (fMode) {
- case SkBlendMode::kClear:
+ if (this->isJustMode()) {
+ SkASSERT(fMode != SkBlendMode::kSrc && fMode != SkBlendMode::kDst); // caught in factory
+ if (fMode == SkBlendMode::kClear) {
return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(),
GrConstColorProcessor::kIgnore_InputMode);
- break;
- case SkBlendMode::kSrc:
- return as_SB(fShaderB)->asFragmentProcessor(args);
- break;
- case SkBlendMode::kDst:
- return as_SB(fShaderA)->asFragmentProcessor(args);
- break;
- default:
- sk_sp<GrFragmentProcessor> fpA(as_SB(fShaderA)->asFragmentProcessor(args));
- if (!fpA) {
- return nullptr;
- }
- sk_sp<GrFragmentProcessor> fpB(as_SB(fShaderB)->asFragmentProcessor(args));
- if (!fpB) {
- return nullptr;
- }
- return GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(fpB),
- std::move(fpA), fMode);
+ }
}
+
+ sk_sp<GrFragmentProcessor> fpA(as_SB(fDst)->asFragmentProcessor(args));
+ if (!fpA) {
+ return nullptr;
+ }
+ sk_sp<GrFragmentProcessor> fpB(as_SB(fSrc)->asFragmentProcessor(args));
+ if (!fpB) {
+ return nullptr;
+ }
+ // TODO: account for fLerpT when it is < 1
+ return GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(fpB),
+ std::move(fpA), fMode);
}
#endif
@@ -140,13 +155,12 @@ sk_sp<GrFragmentProcessor> SkComposeShader::asFragmentProcessor(const AsFPArgs&
void SkComposeShader::toString(SkString* str) const {
str->append("SkComposeShader: (");
- str->append("ShaderA: ");
- as_SB(fShaderA)->toString(str);
- str->append(" ShaderB: ");
- as_SB(fShaderB)->toString(str);
- if (SkBlendMode::kSrcOver != fMode) {
- str->appendf(" Xfermode: %s", SkBlendMode_Name(fMode));
- }
+ str->append("dst: ");
+ as_SB(fDst)->toString(str);
+ str->append(" src: ");
+ as_SB(fSrc)->toString(str);
+ str->appendf(" mode: %s", SkBlendMode_Name(fMode));
+ str->appendf(" lerpT: %g", fLerpT);
this->INHERITED::toString(str);
diff --git a/src/shaders/SkComposeShader.h b/src/shaders/SkComposeShader.h
index 39c43d6b77..03861009a9 100644
--- a/src/shaders/SkComposeShader.h
+++ b/src/shaders/SkComposeShader.h
@@ -11,36 +11,22 @@
#include "SkShaderBase.h"
#include "SkBlendMode.h"
-class SkColorSpacXformer;
-
-///////////////////////////////////////////////////////////////////////////////////////////
-
-/** \class SkComposeShader
- This subclass of shader returns the composition of two other shaders, combined by
- a xfermode.
-*/
class SkComposeShader : public SkShaderBase {
public:
- /** Create a new compose shader, given shaders A, B, and a combining xfermode mode.
- When the xfermode is called, it will be given the result from shader A as its
- "dst", and the result from shader B as its "src".
- mode->xfer32(sA_result, sB_result, ...)
- @param shaderA The colors from this shader are seen as the "dst" by the xfermode
- @param shaderB The colors from this shader are seen as the "src" by the xfermode
- @param mode The xfermode that combines the colors from the two shaders. If mode
- is null, then SRC_OVER is assumed.
- */
- SkComposeShader(sk_sp<SkShader> sA, sk_sp<SkShader> sB, SkBlendMode mode)
- : fShaderA(std::move(sA))
- , fShaderB(std::move(sB))
+ SkComposeShader(sk_sp<SkShader> dst, sk_sp<SkShader> src, SkBlendMode mode, float lerpT)
+ : fDst(std::move(dst))
+ , fSrc(std::move(src))
+ , fLerpT(lerpT)
, fMode(mode)
- {}
+ {
+ SkASSERT(lerpT >= 0 && lerpT <= 1);
+ }
#if SK_SUPPORT_GPU
sk_sp<GrFragmentProcessor> asFragmentProcessor(const AsFPArgs&) const override;
#endif
-#ifdef SK_DEBUG
+#ifdef SK_DEBUGx
SkShader* getShaderA() { return fShaderA.get(); }
SkShader* getShaderB() { return fShaderB.get(); }
#endif
@@ -57,12 +43,16 @@ protected:
bool onAppendStages(SkRasterPipeline*, SkColorSpace* dstCS, SkArenaAlloc*,
const SkMatrix&, const SkPaint&, const SkMatrix* localM) const override;
- bool isRasterPipelineOnly() const final;
+ bool isRasterPipelineOnly() const final { return true; }
private:
- sk_sp<SkShader> fShaderA;
- sk_sp<SkShader> fShaderB;
- SkBlendMode fMode;
+ sk_sp<SkShader> fDst;
+ sk_sp<SkShader> fSrc;
+ const float fLerpT;
+ const SkBlendMode fMode;
+
+ bool isJustMode() const { return fLerpT == 1; }
+ bool isJustLerp() const { return fMode == SkBlendMode::kSrc; }
typedef SkShaderBase INHERITED;
};