remove double compose: lerp and mode

Bug: skia:8937
Change-Id: I5b890c03b0451afe4cbeb6a264798ebbb09b9888
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/205346
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Mike Reed <reed@google.com>
Auto-Submit: Mike Reed <reed@google.com>
This commit is contained in:
Mike Reed 2019-04-02 09:54:14 -04:00 committed by Skia Commit-Bot
parent 3bdb69c55f
commit 9b2c4e94e2
8 changed files with 147 additions and 98 deletions

View File

@ -259,7 +259,8 @@ template <typename Maker> void do_mixershader(SkCanvas* canvas, Maker&& maker) {
DEF_SIMPLE_GM(mixershader, canvas, 800, 700) { DEF_SIMPLE_GM(mixershader, canvas, 800, 700) {
do_mixershader(canvas, [](sk_sp<SkShader> a, sk_sp<SkShader> b, SkBlendMode mode, float t) { do_mixershader(canvas, [](sk_sp<SkShader> a, sk_sp<SkShader> b, SkBlendMode mode, float t) {
return SkShader::MakeCompose(a, b, mode, t); auto sh = SkShader::MakeBlend(mode, a, b);
return SkShader::MakeLerp(t, a, sh);
}); });
} }

View File

@ -297,7 +297,7 @@ static void draw_composed(SkCanvas* canvas, sk_sp<SkShader> src, sk_sp<SkShader>
SkBlendMode mode, SkAlpha alpha) { SkBlendMode mode, SkAlpha alpha) {
SkPaint p; SkPaint p;
p.setAlpha(alpha); p.setAlpha(alpha);
p.setShader(SkShader::MakeCompose(dst, src, mode)); p.setShader(SkShader::MakeBlend(mode, dst, src));
canvas->drawRect(SkRect::MakeWH(gCellSize, gCellSize), p); canvas->drawRect(SkRect::MakeWH(gCellSize, gCellSize), p);
} }

View File

@ -49,17 +49,17 @@ DEF_SIMPLE_GM(localmatrixshader_nested, canvas, 450, 1200) {
// SkLocalMatrixShader(SkComposeShader(SkImageShader(inner)), outer) // SkLocalMatrixShader(SkComposeShader(SkImageShader(inner)), outer)
[](const sk_sp<SkImage>& img, const SkMatrix& inner, const SkMatrix& outer) { [](const sk_sp<SkImage>& img, const SkMatrix& inner, const SkMatrix& outer) {
return SkShader::MakeCompose(SkShader::MakeColorShader(SK_ColorTRANSPARENT), return SkShader::MakeBlend(SkBlendMode::kSrcOver,
img->makeShader(&inner), SkShader::MakeColorShader(SK_ColorTRANSPARENT),
SkBlendMode::kSrcOver) img->makeShader(&inner))
->makeWithLocalMatrix(outer); ->makeWithLocalMatrix(outer);
}, },
// SkLocalMatrixShader(SkComposeShader(SkLocalMatrixShader(SkImageShader(I), inner)), outer) // SkLocalMatrixShader(SkComposeShader(SkLocalMatrixShader(SkImageShader(I), inner)), outer)
[](const sk_sp<SkImage>& img, const SkMatrix& inner, const SkMatrix& outer) { [](const sk_sp<SkImage>& img, const SkMatrix& inner, const SkMatrix& outer) {
return SkShader::MakeCompose(SkShader::MakeColorShader(SK_ColorTRANSPARENT), return SkShader::MakeBlend(SkBlendMode::kSrcOver,
img->makeShader()->makeWithLocalMatrix(inner), SkShader::MakeColorShader(SK_ColorTRANSPARENT),
SkBlendMode::kSrcOver) img->makeShader()->makeWithLocalMatrix(inner))
->makeWithLocalMatrix(outer); ->makeWithLocalMatrix(outer);
}, },
}; };

View File

@ -185,38 +185,25 @@ public:
*/ */
static sk_sp<SkShader> MakeColorShader(const SkColor4f&, sk_sp<SkColorSpace>); static sk_sp<SkShader> MakeColorShader(const SkColor4f&, sk_sp<SkColorSpace>);
/** static sk_sp<SkShader> MakeBlend(SkBlendMode mode, sk_sp<SkShader> dst, sk_sp<SkShader> src);
* Compose two shaders together, using two operators: mode and lerp. The resulting colors
* are computed by first combining the src and dst shaders using mode, and then linearly
* interpolating between the dst and result colors using lerp.
*
* result = dst * (1 - lerp) + (src (mode) dst) * lerp
*
* If either shader is nullptr, then this returns nullptr.
* If lerp is NaN then this returns nullptr, otherwise lerp is clamped to [0..1].
*/
static sk_sp<SkShader> MakeCompose(sk_sp<SkShader> dst, sk_sp<SkShader> src,
SkBlendMode mode, float lerp = 1);
/* /*
* DEPRECATED: call MakeCompose. * DEPRECATED: call MakeBlend.
*/ */
static sk_sp<SkShader> MakeComposeShader(sk_sp<SkShader> dst, sk_sp<SkShader> src, static sk_sp<SkShader> MakeComposeShader(sk_sp<SkShader> dst, sk_sp<SkShader> src,
SkBlendMode mode) { SkBlendMode mode) {
return MakeCompose(std::move(dst), std::move(src), mode, 1); return MakeBlend(mode, std::move(dst), std::move(src));
} }
/** /**
* Compose two shaders together using a weighted average. * Compose two shaders together using a weighted average.
* *
* result = dst * (1 - lerp) + src * lerp * result = dst * (1 - weight) + src * weight
* *
* If either shader is nullptr, then this returns nullptr. * If either shader is nullptr, then this returns nullptr.
* If lerp is NaN then this returns nullptr, otherwise lerp is clamped to [0..1]. * If weight is NaN then this returns nullptr, otherwise lerp is clamped to [0..1].
*/ */
static sk_sp<SkShader> MakeLerp(sk_sp<SkShader> dst, sk_sp<SkShader> src, float lerp) { static sk_sp<SkShader> MakeLerp(float weight, sk_sp<SkShader> dst, sk_sp<SkShader> src);
return MakeCompose(std::move(dst), std::move(src), SkBlendMode::kSrc, lerp);
}
static sk_sp<SkShader> MakeMixer(sk_sp<SkShader> dst, sk_sp<SkShader> src, sk_sp<SkMixer>); static sk_sp<SkShader> MakeMixer(sk_sp<SkShader> dst, sk_sp<SkShader> src, sk_sp<SkMixer>);

View File

@ -204,7 +204,7 @@ void SkDraw::drawVertices(SkVertices::VertexMode vmode, int vertexCount,
constexpr size_t kDefVertexCount = 16; constexpr size_t kDefVertexCount = 16;
constexpr size_t kOuterSize = sizeof(SkTriColorShader) + constexpr size_t kOuterSize = sizeof(SkTriColorShader) +
sizeof(SkComposeShader) + sizeof(SkShader_Blend) +
(2 * sizeof(SkPoint) + sizeof(SkColor4f)) * kDefVertexCount; (2 * sizeof(SkPoint) + sizeof(SkColor4f)) * kDefVertexCount;
SkSTArenaAlloc<kOuterSize> outerAlloc; SkSTArenaAlloc<kOuterSize> outerAlloc;
@ -277,8 +277,8 @@ void SkDraw::drawVertices(SkVertices::VertexMode vmode, int vertexCount,
vertexCount)); vertexCount));
matrix43 = triShader->getMatrix43(); matrix43 = triShader->getMatrix43();
if (shader) { if (shader) {
shader = outerAlloc.make<SkComposeShader>(sk_ref_sp(triShader), sk_ref_sp(shader), shader = outerAlloc.make<SkShader_Blend>(bmode,
bmode, 1); sk_ref_sp(triShader), sk_ref_sp(shader));
} else { } else {
shader = triShader; shader = triShader;
} }

View File

@ -80,7 +80,8 @@
SK_REGISTER_FLATTENABLE(SkColor4Shader); SK_REGISTER_FLATTENABLE(SkColor4Shader);
SK_REGISTER_FLATTENABLE(SkColorFilterShader); SK_REGISTER_FLATTENABLE(SkColorFilterShader);
SK_REGISTER_FLATTENABLE(SkColorShader); SK_REGISTER_FLATTENABLE(SkColorShader);
SK_REGISTER_FLATTENABLE(SkComposeShader); SK_REGISTER_FLATTENABLE(SkShader_Blend);
SK_REGISTER_FLATTENABLE(SkShader_Lerp);
SK_REGISTER_FLATTENABLE(SkEmptyShader); SK_REGISTER_FLATTENABLE(SkEmptyShader);
SK_REGISTER_FLATTENABLE(SkLocalMatrixShader); SK_REGISTER_FLATTENABLE(SkLocalMatrixShader);
SK_REGISTER_FLATTENABLE(SkPictureShader); SK_REGISTER_FLATTENABLE(SkPictureShader);

View File

@ -16,74 +16,114 @@
#include "SkWriteBuffer.h" #include "SkWriteBuffer.h"
#include "SkString.h" #include "SkString.h"
sk_sp<SkShader> SkShader::MakeCompose(sk_sp<SkShader> dst, sk_sp<SkShader> src, SkBlendMode mode, sk_sp<SkShader> SkShader::MakeBlend(SkBlendMode mode, sk_sp<SkShader> dst, sk_sp<SkShader> src) {
float lerpT) { switch (mode) {
if (!src || !dst || SkScalarIsNaN(lerpT)) { case SkBlendMode::kClear: return MakeColorShader(0);
case SkBlendMode::kDst: return dst;
case SkBlendMode::kSrc: return src;
default: break;
}
return sk_sp<SkShader>(new SkShader_Blend(mode, std::move(dst), std::move(src)));
}
sk_sp<SkShader> SkShader::MakeLerp(float weight, sk_sp<SkShader> dst, sk_sp<SkShader> src) {
if (SkScalarIsNaN(weight)) {
return nullptr; return nullptr;
} }
lerpT = SkScalarPin(lerpT, 0, 1); if (dst == src) {
if (lerpT == 0) {
return dst; return dst;
} else if (lerpT == 1) { }
if (mode == SkBlendMode::kSrc) { if (weight <= 0) {
return dst;
} else if (weight >= 1) {
return src; return src;
} }
if (mode == SkBlendMode::kDst) { return sk_sp<SkShader>(new SkShader_Lerp(weight, std::move(dst), std::move(src)));
return dst;
}
}
return sk_sp<SkShader>(new SkComposeShader(std::move(dst), std::move(src), mode, lerpT));
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
sk_sp<SkFlattenable> SkComposeShader::CreateProc(SkReadBuffer& buffer) { static bool append_shader_or_paint(const SkStageRec& rec, SkShader* shader) {
if (shader) {
if (!as_SB(shader)->appendStages(rec)) {
return false;
}
} else {
rec.fPipeline->append_constant_color(rec.fAlloc, rec.fPaint.getColor4f().premul().vec());
}
return true;
}
// Returns the output of e0, and leaves the output of e1 in r,g,b,a
static float* append_two_shaders(const SkStageRec& rec, SkShader* s0, SkShader* s1) {
struct Storage {
float fRes0[4 * SkRasterPipeline_kMaxStride];
};
auto storage = rec.fAlloc->make<Storage>();
if (!append_shader_or_paint(rec, s0)) {
return nullptr;
}
rec.fPipeline->append(SkRasterPipeline::store_src, storage->fRes0);
if (!append_shader_or_paint(rec, s1)) {
return nullptr;
}
return storage->fRes0;
}
///////////////////////////////////////////////////////////////////////////////
sk_sp<SkFlattenable> SkShader_Blend::CreateProc(SkReadBuffer& buffer) {
sk_sp<SkShader> dst(buffer.readShader()); sk_sp<SkShader> dst(buffer.readShader());
sk_sp<SkShader> src(buffer.readShader()); sk_sp<SkShader> src(buffer.readShader());
unsigned mode = buffer.read32(); unsigned mode = buffer.read32();
float lerp = buffer.readScalar();
// check for valid mode before we cast to the enum type // check for valid mode before we cast to the enum type
if (!buffer.validate(mode <= (unsigned)SkBlendMode::kLastMode)) { if (!buffer.validate(mode <= (unsigned)SkBlendMode::kLastMode)) {
return nullptr; return nullptr;
} }
return MakeCompose(std::move(dst), std::move(src), static_cast<SkBlendMode>(mode), lerp); return MakeBlend(static_cast<SkBlendMode>(mode), std::move(dst), std::move(src));
} }
void SkComposeShader::flatten(SkWriteBuffer& buffer) const { void SkShader_Blend::flatten(SkWriteBuffer& buffer) const {
buffer.writeFlattenable(fDst.get()); buffer.writeFlattenable(fDst.get());
buffer.writeFlattenable(fSrc.get()); buffer.writeFlattenable(fSrc.get());
buffer.write32((int)fMode); buffer.write32((int)fMode);
buffer.writeScalar(fLerpT);
} }
bool SkComposeShader::onAppendStages(const SkStageRec& rec) const { bool SkShader_Blend::onAppendStages(const SkStageRec& rec) const {
struct Storage { float* res0 = append_two_shaders(rec, fDst.get(), fSrc.get());
float fRGBA[4 * SkRasterPipeline_kMaxStride]; if (!res0) {
float fAlpha;
};
auto storage = rec.fAlloc->make<Storage>();
if (!as_SB(fDst)->appendStages(rec)) {
return false; return false;
} }
// This outputs r,g,b,a, which we'll need later when we apply the mode, so we save it off now
rec.fPipeline->append(SkRasterPipeline::store_src, storage->fRGBA);
if (!as_SB(fSrc)->appendStages(rec)) { rec.fPipeline->append(SkRasterPipeline::load_dst, res0);
return false;
}
// r,g,b,a now have the right input for the next step (lerp and/or mode), but we need to
// reload dr,dg,db,da from memory, since we stashed that from our fDst invocation earlier.
rec.fPipeline->append(SkRasterPipeline::load_dst, storage->fRGBA);
if (!this->isJustLerp()) {
SkBlendMode_AppendStages(fMode, rec.fPipeline); SkBlendMode_AppendStages(fMode, rec.fPipeline);
return true;
} }
if (!this->isJustMode()) {
rec.fPipeline->append(SkRasterPipeline::lerp_1_float, &fLerpT); sk_sp<SkFlattenable> SkShader_Lerp::CreateProc(SkReadBuffer& buffer) {
sk_sp<SkShader> dst(buffer.readShader());
sk_sp<SkShader> src(buffer.readShader());
float t = buffer.readScalar();
return buffer.isValid() ? MakeLerp(t, std::move(dst), std::move(src)) : nullptr;
} }
void SkShader_Lerp::flatten(SkWriteBuffer& buffer) const {
buffer.writeFlattenable(fDst.get());
buffer.writeFlattenable(fSrc.get());
buffer.writeScalar(fWeight);
}
bool SkShader_Lerp::onAppendStages(const SkStageRec& rec) const {
float* res0 = append_two_shaders(rec, fDst.get(), fSrc.get());
if (!res0) {
return false;
}
rec.fPipeline->append(SkRasterPipeline::load_dst, res0);
rec.fPipeline->append(SkRasterPipeline::lerp_1_float, &fWeight);
return true; return true;
} }
@ -94,16 +134,8 @@ bool SkComposeShader::onAppendStages(const SkStageRec& rec) const {
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
std::unique_ptr<GrFragmentProcessor> SkComposeShader::asFragmentProcessor( std::unique_ptr<GrFragmentProcessor> SkShader_Blend::asFragmentProcessor(
const GrFPArgs& args) const { const GrFPArgs& args) const {
if (this->isJustMode()) {
SkASSERT(fMode != SkBlendMode::kSrc && fMode != SkBlendMode::kDst); // caught in factory
if (fMode == SkBlendMode::kClear) {
return GrConstColorProcessor::Make(SK_PMColor4fTRANSPARENT,
GrConstColorProcessor::InputMode::kIgnore);
}
}
std::unique_ptr<GrFragmentProcessor> fpA(as_SB(fDst)->asFragmentProcessor(args)); std::unique_ptr<GrFragmentProcessor> fpA(as_SB(fDst)->asFragmentProcessor(args));
if (!fpA) { if (!fpA) {
return nullptr; return nullptr;
@ -112,8 +144,19 @@ std::unique_ptr<GrFragmentProcessor> SkComposeShader::asFragmentProcessor(
if (!fpB) { if (!fpB) {
return nullptr; return nullptr;
} }
// TODO: account for fLerpT when it is < 1
return GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(fpB), return GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(fpB),
std::move(fpA), fMode); std::move(fpA), fMode);
} }
std::unique_ptr<GrFragmentProcessor> SkShader_Lerp::asFragmentProcessor(const GrFPArgs& args) const {
std::unique_ptr<GrFragmentProcessor> fpA(as_SB(fDst)->asFragmentProcessor(args));
if (!fpA) {
return nullptr;
}
std::unique_ptr<GrFragmentProcessor> fpB(as_SB(fSrc)->asFragmentProcessor(args));
if (!fpB) {
return nullptr;
}
return nullptr; // todo
}
#endif #endif

View File

@ -11,41 +11,58 @@
#include "SkShaderBase.h" #include "SkShaderBase.h"
#include "SkBlendMode.h" #include "SkBlendMode.h"
class SkComposeShader final : public SkShaderBase { class SkShader_Blend final : public SkShaderBase {
public: public:
SkComposeShader(sk_sp<SkShader> dst, sk_sp<SkShader> src, SkBlendMode mode, float lerpT) SkShader_Blend(SkBlendMode mode, sk_sp<SkShader> dst, sk_sp<SkShader> src)
: fDst(std::move(dst)) : fDst(std::move(dst))
, fSrc(std::move(src)) , fSrc(std::move(src))
, fLerpT(lerpT)
, fMode(mode) , fMode(mode)
{}
#if SK_SUPPORT_GPU
std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs&) const override;
#endif
protected:
SkShader_Blend(SkReadBuffer&);
void flatten(SkWriteBuffer&) const override;
bool onAppendStages(const SkStageRec&) const override;
private:
SK_FLATTENABLE_HOOKS(SkShader_Blend)
sk_sp<SkShader> fDst;
sk_sp<SkShader> fSrc;
const SkBlendMode fMode;
typedef SkShaderBase INHERITED;
};
class SkShader_Lerp final : public SkShaderBase {
public:
SkShader_Lerp(float weight, sk_sp<SkShader> dst, sk_sp<SkShader> src)
: fDst(std::move(dst))
, fSrc(std::move(src))
, fWeight(weight)
{ {
SkASSERT(lerpT >= 0 && lerpT <= 1); SkASSERT(weight >= 0 && weight <= 1);
} }
#if SK_SUPPORT_GPU #if SK_SUPPORT_GPU
std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs&) const override; std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs&) const override;
#endif #endif
#ifdef SK_DEBUGx
SkShader* getShaderA() { return fShaderA.get(); }
SkShader* getShaderB() { return fShaderB.get(); }
#endif
protected: protected:
SkComposeShader(SkReadBuffer&); SkShader_Lerp(SkReadBuffer&);
void flatten(SkWriteBuffer&) const override; void flatten(SkWriteBuffer&) const override;
bool onAppendStages(const SkStageRec&) const override; bool onAppendStages(const SkStageRec&) const override;
private: private:
SK_FLATTENABLE_HOOKS(SkComposeShader) SK_FLATTENABLE_HOOKS(SkShader_Lerp)
sk_sp<SkShader> fDst; sk_sp<SkShader> fDst;
sk_sp<SkShader> fSrc; sk_sp<SkShader> fSrc;
const float fLerpT; const float fWeight;
const SkBlendMode fMode;
bool isJustMode() const { return fLerpT == 1; }
bool isJustLerp() const { return fMode == SkBlendMode::kSrc; }
typedef SkShaderBase INHERITED; typedef SkShaderBase INHERITED;
}; };