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) {
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) {
SkPaint p;
p.setAlpha(alpha);
p.setShader(SkShader::MakeCompose(dst, src, mode));
p.setShader(SkShader::MakeBlend(mode, dst, src));
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)
[](const sk_sp<SkImage>& img, const SkMatrix& inner, const SkMatrix& outer) {
return SkShader::MakeCompose(SkShader::MakeColorShader(SK_ColorTRANSPARENT),
img->makeShader(&inner),
SkBlendMode::kSrcOver)
return SkShader::MakeBlend(SkBlendMode::kSrcOver,
SkShader::MakeColorShader(SK_ColorTRANSPARENT),
img->makeShader(&inner))
->makeWithLocalMatrix(outer);
},
// SkLocalMatrixShader(SkComposeShader(SkLocalMatrixShader(SkImageShader(I), inner)), outer)
[](const sk_sp<SkImage>& img, const SkMatrix& inner, const SkMatrix& outer) {
return SkShader::MakeCompose(SkShader::MakeColorShader(SK_ColorTRANSPARENT),
img->makeShader()->makeWithLocalMatrix(inner),
SkBlendMode::kSrcOver)
return SkShader::MakeBlend(SkBlendMode::kSrcOver,
SkShader::MakeColorShader(SK_ColorTRANSPARENT),
img->makeShader()->makeWithLocalMatrix(inner))
->makeWithLocalMatrix(outer);
},
};

View File

@ -185,38 +185,25 @@ public:
*/
static sk_sp<SkShader> MakeColorShader(const SkColor4f&, sk_sp<SkColorSpace>);
/**
* 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);
static sk_sp<SkShader> MakeBlend(SkBlendMode mode, sk_sp<SkShader> dst, sk_sp<SkShader> src);
/*
* DEPRECATED: call MakeCompose.
* DEPRECATED: call MakeBlend.
*/
static sk_sp<SkShader> MakeComposeShader(sk_sp<SkShader> dst, sk_sp<SkShader> src,
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.
*
* result = dst * (1 - lerp) + src * lerp
* result = dst * (1 - weight) + src * weight
*
* 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) {
return MakeCompose(std::move(dst), std::move(src), SkBlendMode::kSrc, lerp);
}
static sk_sp<SkShader> MakeLerp(float weight, sk_sp<SkShader> dst, sk_sp<SkShader> src);
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 kOuterSize = sizeof(SkTriColorShader) +
sizeof(SkComposeShader) +
sizeof(SkShader_Blend) +
(2 * sizeof(SkPoint) + sizeof(SkColor4f)) * kDefVertexCount;
SkSTArenaAlloc<kOuterSize> outerAlloc;
@ -277,8 +277,8 @@ void SkDraw::drawVertices(SkVertices::VertexMode vmode, int vertexCount,
vertexCount));
matrix43 = triShader->getMatrix43();
if (shader) {
shader = outerAlloc.make<SkComposeShader>(sk_ref_sp(triShader), sk_ref_sp(shader),
bmode, 1);
shader = outerAlloc.make<SkShader_Blend>(bmode,
sk_ref_sp(triShader), sk_ref_sp(shader));
} else {
shader = triShader;
}

View File

@ -80,7 +80,8 @@
SK_REGISTER_FLATTENABLE(SkColor4Shader);
SK_REGISTER_FLATTENABLE(SkColorFilterShader);
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(SkLocalMatrixShader);
SK_REGISTER_FLATTENABLE(SkPictureShader);

View File

@ -16,74 +16,114 @@
#include "SkWriteBuffer.h"
#include "SkString.h"
sk_sp<SkShader> SkShader::MakeCompose(sk_sp<SkShader> dst, sk_sp<SkShader> src, SkBlendMode mode,
float lerpT) {
if (!src || !dst || SkScalarIsNaN(lerpT)) {
sk_sp<SkShader> SkShader::MakeBlend(SkBlendMode mode, sk_sp<SkShader> dst, sk_sp<SkShader> src) {
switch (mode) {
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;
}
lerpT = SkScalarPin(lerpT, 0, 1);
if (lerpT == 0) {
if (dst == src) {
return dst;
} else if (lerpT == 1) {
if (mode == SkBlendMode::kSrc) {
}
if (weight <= 0) {
return dst;
} else if (weight >= 1) {
return src;
}
if (mode == SkBlendMode::kDst) {
return dst;
}
}
return sk_sp<SkShader>(new SkComposeShader(std::move(dst), std::move(src), mode, lerpT));
return sk_sp<SkShader>(new SkShader_Lerp(weight, std::move(dst), std::move(src)));
}
///////////////////////////////////////////////////////////////////////////////
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> src(buffer.readShader());
unsigned mode = buffer.read32();
float lerp = buffer.readScalar();
// check for valid mode before we cast to the enum type
if (!buffer.validate(mode <= (unsigned)SkBlendMode::kLastMode)) {
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(fSrc.get());
buffer.write32((int)fMode);
buffer.writeScalar(fLerpT);
}
bool SkComposeShader::onAppendStages(const SkStageRec& rec) const {
struct Storage {
float fRGBA[4 * SkRasterPipeline_kMaxStride];
float fAlpha;
};
auto storage = rec.fAlloc->make<Storage>();
if (!as_SB(fDst)->appendStages(rec)) {
bool SkShader_Blend::onAppendStages(const SkStageRec& rec) const {
float* res0 = append_two_shaders(rec, fDst.get(), fSrc.get());
if (!res0) {
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)) {
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()) {
rec.fPipeline->append(SkRasterPipeline::load_dst, res0);
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;
}
@ -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 {
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));
if (!fpA) {
return nullptr;
@ -112,8 +144,19 @@ std::unique_ptr<GrFragmentProcessor> SkComposeShader::asFragmentProcessor(
if (!fpB) {
return nullptr;
}
// TODO: account for fLerpT when it is < 1
return GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(fpB),
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

View File

@ -11,41 +11,58 @@
#include "SkShaderBase.h"
#include "SkBlendMode.h"
class SkComposeShader final : public SkShaderBase {
class SkShader_Blend final : public SkShaderBase {
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))
, fSrc(std::move(src))
, fLerpT(lerpT)
, 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
std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs&) const override;
#endif
#ifdef SK_DEBUGx
SkShader* getShaderA() { return fShaderA.get(); }
SkShader* getShaderB() { return fShaderB.get(); }
#endif
protected:
SkComposeShader(SkReadBuffer&);
SkShader_Lerp(SkReadBuffer&);
void flatten(SkWriteBuffer&) const override;
bool onAppendStages(const SkStageRec&) const override;
private:
SK_FLATTENABLE_HOOKS(SkComposeShader)
SK_FLATTENABLE_HOOKS(SkShader_Lerp)
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; }
const float fWeight;
typedef SkShaderBase INHERITED;
};