remove SkMixer, since we have explicit lerps/blends in SkShader
Change-Id: I937861df9d8ae89c0587ea59dd740989bebd35a4 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/207305 Reviewed-by: Florin Malita <fmalita@chromium.org> Reviewed-by: Mike Klein <mtklein@google.com> Commit-Queue: Mike Reed <reed@google.com>
This commit is contained in:
parent
e20f6cae8b
commit
e3f17b911f
@ -279,67 +279,3 @@ DEF_BENCH( return new ColorFilterBrightBlueBench(false); )
|
||||
DEF_BENCH( return new ColorFilterBrightBench(false); )
|
||||
DEF_BENCH( return new ColorFilterBlueBench(false); )
|
||||
DEF_BENCH( return new ColorFilterGrayBench(false); )
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "Resources.h"
|
||||
#include "SkMixer.h"
|
||||
|
||||
class CFMixerBench : public Benchmark {
|
||||
SkString fName;
|
||||
enum Flags {
|
||||
kUseCF0 = 1 << 0,
|
||||
kUseCF1 = 1 << 1,
|
||||
};
|
||||
|
||||
sk_sp<SkShader> fShader;
|
||||
sk_sp<SkColorFilter> fFilter;
|
||||
const unsigned fFlags;
|
||||
|
||||
public:
|
||||
CFMixerBench(unsigned flags) : fFlags(flags) {
|
||||
fName.printf("colorfilter_mixer_%d", flags);
|
||||
}
|
||||
~CFMixerBench() override {}
|
||||
|
||||
protected:
|
||||
const char* onGetName() override { return fName.c_str(); }
|
||||
void onDelayedSetup() override {
|
||||
auto img = GetResourceAsImage("images/mandrill_256.png");
|
||||
if (img) {
|
||||
img = img->makeRasterImage();
|
||||
}
|
||||
fShader = img->makeShader();
|
||||
auto cf0 = SkColorFilters::Blend(0x88FF3366, SkBlendMode::kDstIn);
|
||||
auto cf1 = SkColorFilters::Blend(0x88FF3366, SkBlendMode::kDstATop);
|
||||
auto mx = SkMixer::MakeLerp(0.5f);
|
||||
if (!(fFlags & kUseCF0)) {
|
||||
cf0 = nullptr;
|
||||
}
|
||||
if (!(fFlags & kUseCF1)) {
|
||||
cf1 = nullptr;
|
||||
}
|
||||
fFilter = SkColorFilters::Mixer(mx, cf0, cf1);
|
||||
}
|
||||
void onDraw(int loops, SkCanvas* canvas) override {
|
||||
SkRect r = SkRect::MakeWH(256, 256);
|
||||
SkPaint paint;
|
||||
paint.setShader(fShader);
|
||||
paint.setColorFilter(fFilter);
|
||||
paint.setBlendMode(SkBlendMode::kSrc); // no need to measure this step
|
||||
|
||||
for (int j = 0; j < 100; ++j) {
|
||||
for (int i = 0; i < loops; i++) {
|
||||
canvas->drawRect(r, paint);
|
||||
}
|
||||
}
|
||||
}
|
||||
private:
|
||||
typedef Benchmark INHERITED;
|
||||
};
|
||||
DEF_BENCH(return new CFMixerBench(0);)
|
||||
DEF_BENCH(return new CFMixerBench(1);)
|
||||
DEF_BENCH(return new CFMixerBench(2);)
|
||||
DEF_BENCH(return new CFMixerBench(3);)
|
||||
|
||||
|
||||
|
@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "Benchmark.h"
|
||||
|
||||
#include "SkCanvas.h"
|
||||
#include "SkMixer.h"
|
||||
#include "SkPaint.h"
|
||||
#include "SkShader.h"
|
||||
|
||||
class MixerLerpBench : public Benchmark {
|
||||
public:
|
||||
MixerLerpBench() {}
|
||||
|
||||
protected:
|
||||
const char* onGetName() override { return "mixer-lerp"; }
|
||||
|
||||
void onDelayedSetup() override {
|
||||
auto s0 = SkShaders::Color(SK_ColorRED);
|
||||
auto s1 = SkShaders::Color(SK_ColorBLUE);
|
||||
fShader = SkShaders::Lerp(SkShaders::Color(0xFF880000), s0, s1);
|
||||
}
|
||||
|
||||
void onDraw(int loops, SkCanvas* canvas) override {
|
||||
const SkRect r = {0, 0, 256, 256};
|
||||
SkPaint paint;
|
||||
paint.setShader(fShader);
|
||||
for (int j = 0; j < 100; ++j) {
|
||||
for (int i = 0; i < loops; i++) {
|
||||
canvas->drawRect(r, paint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
sk_sp<SkShader> fShader;
|
||||
typedef Benchmark INHERITED;
|
||||
};
|
||||
DEF_BENCH( return new MixerLerpBench; )
|
@ -9,7 +9,6 @@
|
||||
#include "SkCanvas.h"
|
||||
#include "SkColorMatrixFilter.h"
|
||||
#include "SkColorPriv.h"
|
||||
#include "SkMixer.h"
|
||||
#include "SkShader.h"
|
||||
|
||||
#include "SkBlurImageFilter.h"
|
||||
@ -264,8 +263,6 @@ DEF_SIMPLE_GM(mixershader, canvas, 800, 700) {
|
||||
});
|
||||
}
|
||||
|
||||
#include "SkMixerBase.h"
|
||||
|
||||
DEF_SIMPLE_GM(mixershader2, canvas, 800, 700) {
|
||||
do_mixershader(canvas, [](sk_sp<SkShader> a, sk_sp<SkShader> b, SkBlendMode mode, float t) {
|
||||
return SkShaders::Lerp(t, a, SkShaders::Blend(mode, a, b));
|
||||
|
@ -112,7 +112,6 @@ private:
|
||||
DEF_GM( return new MixerCFGM(SkSize::Make(200, 250), 5); )
|
||||
|
||||
#include "Resources.h"
|
||||
#include "SkMixer.h"
|
||||
|
||||
static sk_sp<SkShader> make_resource_shader(const char path[], int size) {
|
||||
auto img = GetResourceAsImage(path);
|
||||
@ -194,35 +193,3 @@ private:
|
||||
using INHERITED = skiagm::GM;
|
||||
};
|
||||
DEF_GM( return new ShaderMixerGM; )
|
||||
|
||||
static void draw_rect(SkCanvas* c, const SkRect& r, const SkPaint& p, SkScalar x, SkScalar y) {
|
||||
c->save();
|
||||
c->translate(x, y);
|
||||
c->drawRect(r, p);
|
||||
c->restore();
|
||||
}
|
||||
|
||||
DEF_SIMPLE_GM(mixercolorfilter, canvas, 768, 512) {
|
||||
auto cf0 = MakeTintColorFilter(0xff300000, 0xffa00000); // red tint
|
||||
auto cf1 = MakeTintColorFilter(0xff003000, 0xff00a000); // green tint
|
||||
|
||||
SkRect r = { 0, 0, 256, 256 };
|
||||
|
||||
SkPaint p;
|
||||
p.setShader(make_resource_shader("images/mandrill_256.png", 256));
|
||||
|
||||
draw_rect(canvas, r, p, 0, 0);
|
||||
p.setColorFilter(cf0);
|
||||
draw_rect(canvas, r, p, 256, 0);
|
||||
p.setColorFilter(cf1);
|
||||
draw_rect(canvas, r, p, 512, 0);
|
||||
|
||||
auto mx = SkMixer::MakeLerp(0.5f);
|
||||
|
||||
p.setColorFilter(SkColorFilters::Mixer(mx, cf0, cf1));
|
||||
draw_rect(canvas, r, p, 0, 256);
|
||||
p.setColorFilter(SkColorFilters::Mixer(mx, cf0, nullptr));
|
||||
draw_rect(canvas, r, p, 256, 256);
|
||||
p.setColorFilter(SkColorFilters::Mixer(mx, nullptr, cf1));
|
||||
draw_rect(canvas, r, p, 512, 256);
|
||||
}
|
||||
|
@ -75,7 +75,6 @@ bench_sources = [
|
||||
"$_bench/MemsetBench.cpp",
|
||||
"$_bench/MergeBench.cpp",
|
||||
"$_bench/MipMapBench.cpp",
|
||||
"$_bench/MixerBench.cpp",
|
||||
"$_bench/MorphologyBench.cpp",
|
||||
"$_bench/MutexBench.cpp",
|
||||
"$_bench/PatchBench.cpp",
|
||||
|
@ -55,7 +55,6 @@ skia_core_public = [
|
||||
"$_include/core/SkMatrix.h",
|
||||
"$_include/core/SkMatrix44.h",
|
||||
"$_include/core/SkMilestone.h",
|
||||
"$_include/core/SkMixer.h",
|
||||
"$_include/core/SkOverdrawCanvas.h",
|
||||
"$_include/core/SkPaint.h",
|
||||
"$_include/core/SkPath.h",
|
||||
@ -151,7 +150,6 @@ skia_core_sources = [
|
||||
"$_src/core/SkClipStackDevice.h",
|
||||
"$_src/core/SkColor.cpp",
|
||||
"$_src/core/SkColorFilter.cpp",
|
||||
"$_src/core/SkColorFilter_Mixer.cpp",
|
||||
"$_src/core/SkColorMatrixFilterRowMajor255.cpp",
|
||||
"$_src/core/SkColorMatrixFilterRowMajor255.h",
|
||||
"$_src/core/SkColorSpace.cpp",
|
||||
@ -261,7 +259,6 @@ skia_core_sources = [
|
||||
"$_src/core/SkMipMap.h",
|
||||
"$_src/core/SkMiniRecorder.cpp",
|
||||
"$_src/core/SkMiniRecorder.h",
|
||||
"$_src/core/SkMixer.cpp",
|
||||
"$_src/core/SkModeColorFilter.cpp",
|
||||
"$_src/core/SkNextID.h",
|
||||
"$_src/core/SkLatticeIter.cpp",
|
||||
@ -433,7 +430,6 @@ skia_core_sources = [
|
||||
"$_src/shaders/SkLights.h",
|
||||
"$_src/shaders/SkLocalMatrixShader.cpp",
|
||||
"$_src/shaders/SkLocalMatrixShader.h",
|
||||
"$_src/shaders/SkMixerShader.cpp",
|
||||
"$_src/shaders/SkShader.cpp",
|
||||
"$_src/shaders/SkShaderBase.h",
|
||||
|
||||
|
@ -147,7 +147,6 @@ tests_sources = [
|
||||
"$_tests/MessageBusTest.cpp",
|
||||
"$_tests/MetaDataTest.cpp",
|
||||
"$_tests/MipMapTest.cpp",
|
||||
"$_tests/MixerTest.cpp",
|
||||
"$_tests/NonlinearBlendingTest.cpp",
|
||||
"$_tests/OnceTest.cpp",
|
||||
"$_tests/OpChainTest.cpp",
|
||||
|
@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkMixer_DEFINED
|
||||
#define SkMixer_DEFINED
|
||||
|
||||
#include "SkBlendMode.h"
|
||||
#include "SkColor.h"
|
||||
#include "SkFlattenable.h"
|
||||
|
||||
class SkShader;
|
||||
|
||||
/**
|
||||
* A Mixer takes two input colors (A and B) and returns a new color (C)
|
||||
* C = mix(A, B)
|
||||
*
|
||||
* Mixers can be used to combine multiple other effect objects: shaders, colorfilters, imagefilters
|
||||
*/
|
||||
class SK_API SkMixer : public SkFlattenable {
|
||||
public:
|
||||
/**
|
||||
* Returns the first color
|
||||
*/
|
||||
static sk_sp<SkMixer> MakeFirst();
|
||||
|
||||
/**
|
||||
* Returns the second color
|
||||
*/
|
||||
static sk_sp<SkMixer> MakeSecond();
|
||||
|
||||
/**
|
||||
* Returns the specified color, ignoring the input colors.
|
||||
*/
|
||||
static sk_sp<SkMixer> MakeConst(SkColor);
|
||||
static sk_sp<SkMixer> MakeConst(const SkColor4f&);
|
||||
|
||||
/**
|
||||
* Applies the blendmode, treating the 1st color as DST and the 2nd as SRC
|
||||
*
|
||||
* C = blendmode(dst, src)
|
||||
*/
|
||||
static sk_sp<SkMixer> MakeBlend(SkBlendMode);
|
||||
|
||||
/**
|
||||
* Returns a lerp of the two inputs:
|
||||
* C = A*(1 - t) + B*t
|
||||
*/
|
||||
static sk_sp<SkMixer> MakeLerp(float t);
|
||||
|
||||
/**
|
||||
* Uses the first channel (e.g. Red) of the shader's output as the lerp coefficient.
|
||||
*/
|
||||
static sk_sp<SkMixer> MakeShaderLerp(sk_sp<SkShader>);
|
||||
|
||||
/**
|
||||
* Returns a new mixer that invokes this mixer, but with its arguments reversed.
|
||||
* C = this(B, A)
|
||||
*/
|
||||
sk_sp<SkMixer> makeReverse() const;
|
||||
|
||||
/**
|
||||
* Returns a new mixer that forwards its inputs (A, B) to two other mixers, and then calls
|
||||
* the original mixer with their results.
|
||||
* C = this(ma(A, B), mb(A, B))
|
||||
*/
|
||||
sk_sp<SkMixer> makeMerge(sk_sp<SkMixer> ma, sk_sp<SkMixer> mb) const;
|
||||
};
|
||||
|
||||
#endif
|
@ -21,7 +21,6 @@ class SkBitmap;
|
||||
class SkColorFilter;
|
||||
class SkColorSpace;
|
||||
class SkImage;
|
||||
class SkMixer;
|
||||
class SkPath;
|
||||
class SkPicture;
|
||||
class SkRasterPipeline;
|
||||
@ -209,8 +208,6 @@ public:
|
||||
* If weight is NaN then this returns nullptr, otherwise lerp is clamped to [0..1].
|
||||
*/
|
||||
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>);
|
||||
#endif
|
||||
|
||||
#ifdef SK_SUPPORT_LEGACY_BITMAPSHADER_FACTORY
|
||||
|
@ -98,7 +98,6 @@ DEF_SAMPLE( return new MixerView; )
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "SkMaskFilter.h"
|
||||
#include "SkMixer.h"
|
||||
#include "SkSurface.h"
|
||||
|
||||
static sk_sp<SkShader> make_resource_shader(const char path[], int size) {
|
||||
|
@ -7,7 +7,6 @@
|
||||
|
||||
#include "SkArenaAlloc.h"
|
||||
#include "SkColorFilter.h"
|
||||
#include "SkColorFilter_Mixer.h"
|
||||
#include "SkColorFilterPriv.h"
|
||||
#include "SkColorSpacePriv.h"
|
||||
#include "SkColorSpaceXformSteps.h"
|
||||
@ -509,7 +508,6 @@ void SkColorFilter::RegisterFlattenables() {
|
||||
SK_REGISTER_FLATTENABLE(SkModeColorFilter);
|
||||
SK_REGISTER_FLATTENABLE(SkSRGBGammaColorFilter);
|
||||
SK_REGISTER_FLATTENABLE(SkMixerColorFilter);
|
||||
SK_REGISTER_FLATTENABLE(SkColorFilter_Mixer);
|
||||
#if SK_SUPPORT_GPU
|
||||
SK_REGISTER_FLATTENABLE(SkRuntimeColorFilter);
|
||||
#endif
|
||||
|
@ -1,98 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkArenaAlloc.h"
|
||||
#include "SkColorFilter_Mixer.h"
|
||||
#include "SkRasterPipeline.h"
|
||||
#include "SkReadBuffer.h"
|
||||
#include "SkWriteBuffer.h"
|
||||
#include "SkString.h"
|
||||
|
||||
#ifdef SK_SUPPORT_LEGACY_COLORFILTER_FACTORIES
|
||||
sk_sp<SkColorFilter> SkColorFilter::MakeMixer(sk_sp<SkColorFilter> f0, sk_sp<SkColorFilter> f1,
|
||||
sk_sp<SkMixer> mixer) {
|
||||
return SkColorFilters::Mixer(std::move(mixer), std::move(f0), std::move(f1));
|
||||
}
|
||||
#endif
|
||||
|
||||
sk_sp<SkColorFilter> SkColorFilters::Mixer(sk_sp<SkMixer> mixer,
|
||||
sk_sp<SkColorFilter> f0, sk_sp<SkColorFilter> f1) {
|
||||
if (!mixer) {
|
||||
return nullptr;
|
||||
}
|
||||
return sk_sp<SkColorFilter>(new SkColorFilter_Mixer(std::move(f0), std::move(f1),
|
||||
std::move(mixer)));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
sk_sp<SkFlattenable> SkColorFilter_Mixer::CreateProc(SkReadBuffer& buffer) {
|
||||
sk_sp<SkColorFilter> s0(buffer.readColorFilter());
|
||||
sk_sp<SkColorFilter> s1(buffer.readColorFilter());
|
||||
sk_sp<SkMixer> mx(buffer.readMixer());
|
||||
|
||||
return SkColorFilters::Mixer(std::move(mx), std::move(s0), std::move(s1));
|
||||
}
|
||||
|
||||
void SkColorFilter_Mixer::flatten(SkWriteBuffer& buffer) const {
|
||||
buffer.writeFlattenable(fFilter0.get());
|
||||
buffer.writeFlattenable(fFilter1.get());
|
||||
buffer.writeFlattenable(fMixer.get());
|
||||
}
|
||||
|
||||
bool SkColorFilter_Mixer::onAppendStages(const SkStageRec& rec,
|
||||
bool shaderIsOpaque) const {
|
||||
struct Storage {
|
||||
float fOrig[4 * SkRasterPipeline_kMaxStride];
|
||||
float fRes0[4 * SkRasterPipeline_kMaxStride];
|
||||
};
|
||||
Storage* storage = nullptr;
|
||||
|
||||
if (fFilter0 || fFilter1) {
|
||||
storage = rec.fAlloc->make<Storage>();
|
||||
rec.fPipeline->append(SkRasterPipeline::store_src, storage->fOrig);
|
||||
}
|
||||
|
||||
if (fFilter0 && fFilter1) {
|
||||
fFilter0->appendStages(rec, shaderIsOpaque);
|
||||
rec.fPipeline->append(SkRasterPipeline::store_src, storage->fRes0);
|
||||
|
||||
rec.fPipeline->append(SkRasterPipeline::load_src, storage->fOrig);
|
||||
fFilter1->appendStages(rec, shaderIsOpaque);
|
||||
rec.fPipeline->append(SkRasterPipeline::load_dst, storage->fRes0);
|
||||
} else if (fFilter0 && !fFilter1) {
|
||||
fFilter0->appendStages(rec, shaderIsOpaque);
|
||||
rec.fPipeline->append(SkRasterPipeline::move_src_dst);
|
||||
rec.fPipeline->append(SkRasterPipeline::load_src, storage->fOrig);
|
||||
} else if (!fFilter0 && fFilter1) {
|
||||
fFilter1->appendStages(rec, shaderIsOpaque);
|
||||
rec.fPipeline->append(SkRasterPipeline::load_dst, storage->fOrig);
|
||||
} else {
|
||||
SkASSERT(!fFilter0);
|
||||
SkASSERT(!fFilter1);
|
||||
rec.fPipeline->append(SkRasterPipeline::move_src_dst);
|
||||
}
|
||||
|
||||
// 1st color in dr,dg,db,da
|
||||
// 2nd color in r, g, b, a
|
||||
return as_MB(fMixer)->appendStages(rec);
|
||||
}
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
|
||||
#include "effects/generated/GrConstColorProcessor.h"
|
||||
#include "effects/GrXfermodeFragmentProcessor.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::unique_ptr<GrFragmentProcessor>
|
||||
SkColorFilter_Mixer::asFragmentProcessor(GrRecordingContext*,
|
||||
const GrColorSpaceInfo& dstColorSpaceInfo) const {
|
||||
// TODO: need to make a mixer-processor...
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkMixerColorFilter_DEFINED
|
||||
#define SkMixerColorFilter_DEFINED
|
||||
|
||||
#include "SkColorFilter.h"
|
||||
#include "SkMixer.h"
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
#include "GrFPArgs.h"
|
||||
#endif
|
||||
|
||||
class SkColorFilter_Mixer final : public SkColorFilter {
|
||||
public:
|
||||
SkColorFilter_Mixer(sk_sp<SkColorFilter> f0, sk_sp<SkColorFilter> f1, sk_sp<SkMixer> mixer)
|
||||
: fFilter0(std::move(f0))
|
||||
, fFilter1(std::move(f1))
|
||||
, fMixer(std::move(mixer))
|
||||
{
|
||||
SkASSERT(fMixer);
|
||||
}
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(
|
||||
GrRecordingContext*, const GrColorSpaceInfo& dstColorSpaceInfo) const override;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
SkColorFilter_Mixer(SkReadBuffer&);
|
||||
void flatten(SkWriteBuffer&) const override;
|
||||
bool onAppendStages(const SkStageRec&, bool shaderIsOpaque) const override;
|
||||
|
||||
private:
|
||||
SK_FLATTENABLE_HOOKS(SkColorFilter_Mixer)
|
||||
|
||||
sk_sp<SkColorFilter> fFilter0;
|
||||
sk_sp<SkColorFilter> fFilter1;
|
||||
sk_sp<SkMixer> fMixer;
|
||||
|
||||
friend class SkColorFilter;
|
||||
|
||||
typedef SkColorFilter INHERITED;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,455 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkBlendModePriv.h"
|
||||
#include "SkEffectPriv.h"
|
||||
#include "SkMixerBase.h"
|
||||
#include "SkMixerShader.h"
|
||||
#include "SkReadBuffer.h"
|
||||
#include "SkRasterPipeline.h"
|
||||
#include "SkWriteBuffer.h"
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
#include "GrRecordingContext.h"
|
||||
#include "effects/generated/GrConstColorProcessor.h"
|
||||
#include "effects/GrSkSLFP.h"
|
||||
#include "effects/GrXfermodeFragmentProcessor.h"
|
||||
|
||||
static std::unique_ptr<GrFragmentProcessor> sksl_mixer_fp(
|
||||
const GrFPArgs& args,
|
||||
int index,
|
||||
const char* sksl,
|
||||
sk_sp<SkData> inputs,
|
||||
std::unique_ptr<GrFragmentProcessor> fp1,
|
||||
std::unique_ptr<GrFragmentProcessor> fp2,
|
||||
std::unique_ptr<GrFragmentProcessor> fp3 = nullptr) {
|
||||
std::unique_ptr<GrSkSLFP> result = GrSkSLFP::Make(args.fContext, index, "Runtime Mixer", sksl,
|
||||
inputs ? inputs->data() : nullptr,
|
||||
inputs ? inputs->size() : 0,
|
||||
SkSL::Program::kMixer_Kind);
|
||||
result->addChild(std::move(fp1));
|
||||
result->addChild(std::move(fp2));
|
||||
if (fp3) {
|
||||
result->addChild(std::move(fp3));
|
||||
}
|
||||
return std::move(result);
|
||||
}
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class SkMixer_Const final : public SkMixerBase {
|
||||
SkMixer_Const(const SkPMColor4f& pm) : fPM(pm) {}
|
||||
const SkPMColor4f fPM;
|
||||
friend class SkMixer;
|
||||
public:
|
||||
SK_FLATTENABLE_HOOKS(SkMixer_Const)
|
||||
|
||||
void flatten(SkWriteBuffer& buffer) const override {
|
||||
buffer.writePad32(&fPM, sizeof(SkPMColor4f));
|
||||
}
|
||||
|
||||
bool appendStages(const SkStageRec& rec) const override {
|
||||
rec.fPipeline->append_constant_color(rec.fAlloc, (const float*)&fPM);
|
||||
return true;
|
||||
}
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
std::unique_ptr<GrFragmentProcessor>
|
||||
asFragmentProcessor(const GrFPArgs& args, const sk_sp<SkShader> shader1,
|
||||
const sk_sp<SkShader> shader2) const override {
|
||||
return GrConstColorProcessor::Make(fPM, GrConstColorProcessor::InputMode::kIgnore);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
sk_sp<SkFlattenable> SkMixer_Const::CreateProc(SkReadBuffer& buffer) {
|
||||
SkPMColor4f pm;
|
||||
buffer.readPad32(&pm, sizeof(SkPMColor4f));
|
||||
return sk_sp<SkFlattenable>(new SkMixer_Const(pm));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class SkMixer_Reverse final : public SkMixerBase {
|
||||
SkMixer_Reverse(sk_sp<SkMixer> proxy) : fProxy(std::move(proxy)) {
|
||||
SkASSERT(fProxy);
|
||||
}
|
||||
sk_sp<SkMixer> fProxy;
|
||||
friend class SkMixer;
|
||||
public:
|
||||
SK_FLATTENABLE_HOOKS(SkMixer_Reverse)
|
||||
|
||||
void flatten(SkWriteBuffer& buffer) const override {
|
||||
buffer.writeFlattenable(fProxy.get());
|
||||
}
|
||||
|
||||
bool appendStages(const SkStageRec& rec) const override {
|
||||
struct Storage {
|
||||
float fRGBA[4 * SkRasterPipeline_kMaxStride];
|
||||
};
|
||||
auto storage = rec.fAlloc->make<Storage>();
|
||||
SkRasterPipeline* pipeline = rec.fPipeline;
|
||||
|
||||
// swap src,dst
|
||||
pipeline->append(SkRasterPipeline::store_dst, storage->fRGBA);
|
||||
pipeline->append(SkRasterPipeline::move_src_dst);
|
||||
pipeline->append(SkRasterPipeline::load_src, storage->fRGBA);
|
||||
|
||||
return as_MB(fProxy)->appendStages(rec);
|
||||
}
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
std::unique_ptr<GrFragmentProcessor>
|
||||
asFragmentProcessor(const GrFPArgs& args, const sk_sp<SkShader> shader1,
|
||||
const sk_sp<SkShader> shader2) const override {
|
||||
return as_MB(fProxy)->asFragmentProcessor(args, shader2, shader1);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
sk_sp<SkFlattenable> SkMixer_Reverse::CreateProc(SkReadBuffer& buffer) {
|
||||
auto orig = buffer.readMixer();
|
||||
return orig ? orig->makeReverse() : nullptr;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class SkMixer_Blend final : public SkMixerBase {
|
||||
SkMixer_Blend(SkBlendMode mode) : fMode(mode) {}
|
||||
const SkBlendMode fMode;
|
||||
friend class SkMixer;
|
||||
public:
|
||||
SK_FLATTENABLE_HOOKS(SkMixer_Blend)
|
||||
|
||||
void flatten(SkWriteBuffer& buffer) const override {
|
||||
buffer.write32(static_cast<int>(fMode));
|
||||
}
|
||||
|
||||
bool appendStages(const SkStageRec& rec) const override {
|
||||
SkBlendMode_AppendStages(fMode, rec.fPipeline);
|
||||
return true;
|
||||
}
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
std::unique_ptr<GrFragmentProcessor>
|
||||
asFragmentProcessor(const GrFPArgs& args, const sk_sp<SkShader> shader1,
|
||||
const sk_sp<SkShader> shader2) const override {
|
||||
std::unique_ptr<GrFragmentProcessor> fp1 = as_SB(shader1)->asFragmentProcessor(args);
|
||||
if (!fp1) {
|
||||
return nullptr;
|
||||
}
|
||||
std::unique_ptr<GrFragmentProcessor> fp2 = as_SB(shader2)->asFragmentProcessor(args);
|
||||
if (!fp2) {
|
||||
return nullptr;
|
||||
}
|
||||
return GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(fp2), std::move(fp1),
|
||||
fMode);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
sk_sp<SkFlattenable> SkMixer_Blend::CreateProc(SkReadBuffer& buffer) {
|
||||
unsigned mode = buffer.read32();
|
||||
if (!buffer.validate(mode <= (unsigned)SkBlendMode::kLastMode)) {
|
||||
return nullptr;
|
||||
}
|
||||
return MakeBlend(static_cast<SkBlendMode>(mode));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class SkMixer_Lerp final : public SkMixerBase {
|
||||
SkMixer_Lerp(float weight) : fWeight(weight) {
|
||||
SkASSERT(fWeight >= 0 && fWeight <= 1);
|
||||
}
|
||||
const float fWeight;
|
||||
friend class SkMixer;
|
||||
public:
|
||||
SK_FLATTENABLE_HOOKS(SkMixer_Lerp)
|
||||
|
||||
void flatten(SkWriteBuffer& buffer) const override {
|
||||
buffer.writeScalar(fWeight);
|
||||
}
|
||||
|
||||
bool appendStages(const SkStageRec& rec) const override {
|
||||
rec.fPipeline->append(SkRasterPipeline::lerp_1_float, &fWeight);
|
||||
return true;
|
||||
}
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
std::unique_ptr<GrFragmentProcessor>
|
||||
asFragmentProcessor(const GrFPArgs& args, const sk_sp<SkShader> shader1,
|
||||
const sk_sp<SkShader> shader2) const override {
|
||||
std::unique_ptr<GrFragmentProcessor> fp1 = as_SB(shader1)->asFragmentProcessor(args);
|
||||
if (!fp1) {
|
||||
return nullptr;
|
||||
}
|
||||
std::unique_ptr<GrFragmentProcessor> fp2 = as_SB(shader2)->asFragmentProcessor(args);
|
||||
if (!fp2) {
|
||||
return nullptr;
|
||||
}
|
||||
static int index = GrSkSLFP::NewIndex();
|
||||
return sksl_mixer_fp(args,
|
||||
index,
|
||||
"in uniform float weight;"
|
||||
"void main(half4 input1, half4 input2) {"
|
||||
" sk_OutColor = mix(input1, input2, half(weight));"
|
||||
"}",
|
||||
SkData::MakeWithCopy(&fWeight, sizeof(fWeight)),
|
||||
std::move(fp1),
|
||||
std::move(fp2));
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
sk_sp<SkFlattenable> SkMixer_Lerp::CreateProc(SkReadBuffer& buffer) {
|
||||
return MakeLerp(buffer.readScalar());
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class SkMixer_ShaderLerp final : public SkMixerBase {
|
||||
SkMixer_ShaderLerp(sk_sp<SkShader> shader) : fShader(std::move(shader)) {
|
||||
SkASSERT(fShader);
|
||||
}
|
||||
sk_sp<SkShader> fShader;
|
||||
friend class SkMixer;
|
||||
public:
|
||||
SK_FLATTENABLE_HOOKS(SkMixer_ShaderLerp)
|
||||
|
||||
void flatten(SkWriteBuffer& buffer) const override {
|
||||
buffer.writeFlattenable(fShader.get());
|
||||
}
|
||||
|
||||
bool appendStages(const SkStageRec& rec) const override {
|
||||
struct Storage {
|
||||
float fSrc[4 * SkRasterPipeline_kMaxStride];
|
||||
float fDst[4 * SkRasterPipeline_kMaxStride];
|
||||
float fShaderOutput[4 * SkRasterPipeline_kMaxStride];
|
||||
};
|
||||
auto storage = rec.fAlloc->make<Storage>();
|
||||
|
||||
// we've been given our inputs as (drdgdbda, rgba)
|
||||
rec.fPipeline->append(SkRasterPipeline::store_dst, storage->fDst);
|
||||
rec.fPipeline->append(SkRasterPipeline::store_src, storage->fSrc);
|
||||
|
||||
if (!as_SB(fShader)->appendStages(rec)) {
|
||||
return false;
|
||||
}
|
||||
// the shader's output is in rgba. We need to store "r" as our "t" values
|
||||
rec.fPipeline->append(SkRasterPipeline::store_src, storage->fShaderOutput);
|
||||
|
||||
// now we need to reload the original dst and src so we can run our stage (lerp)
|
||||
rec.fPipeline->append(SkRasterPipeline::load_dst, storage->fDst);
|
||||
rec.fPipeline->append(SkRasterPipeline::load_src, storage->fSrc);
|
||||
|
||||
// we use the first channel (e.g. R) as our T values
|
||||
rec.fPipeline->append(SkRasterPipeline::lerp_native, &storage->fShaderOutput[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
std::unique_ptr<GrFragmentProcessor>
|
||||
asFragmentProcessor(const GrFPArgs& args, const sk_sp<SkShader> shader1,
|
||||
const sk_sp<SkShader> shader2) const override {
|
||||
std::unique_ptr<GrFragmentProcessor> fp1 = as_SB(shader1)->asFragmentProcessor(args);
|
||||
if (!fp1) {
|
||||
return nullptr;
|
||||
}
|
||||
std::unique_ptr<GrFragmentProcessor> fp2 = as_SB(shader2)->asFragmentProcessor(args);
|
||||
if (!fp2) {
|
||||
return nullptr;
|
||||
}
|
||||
std::unique_ptr<GrFragmentProcessor> fp3 = as_SB(fShader)->asFragmentProcessor(args);
|
||||
if (!fp3) {
|
||||
return nullptr;
|
||||
}
|
||||
static int index = GrSkSLFP::NewIndex();
|
||||
return sksl_mixer_fp(args,
|
||||
index,
|
||||
"in fragmentProcessor lerpControl;"
|
||||
"void main(half4 input1, half4 input2) {"
|
||||
" sk_OutColor = mix(input1, input2, process(lerpControl).r);"
|
||||
"}",
|
||||
nullptr,
|
||||
std::move(fp1),
|
||||
std::move(fp2),
|
||||
std::move(fp3));
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
sk_sp<SkFlattenable> SkMixer_ShaderLerp::CreateProc(SkReadBuffer& buffer) {
|
||||
return MakeShaderLerp(buffer.readShader());
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class SkMixer_Merge final : public SkMixerBase {
|
||||
SkMixer_Merge(sk_sp<SkMixer> m0, sk_sp<SkMixer> m1, sk_sp<SkMixer> combine)
|
||||
: fM0(std::move(m0))
|
||||
, fM1(std::move(m1))
|
||||
, fCombine(std::move(combine))
|
||||
{
|
||||
SkASSERT(fCombine);
|
||||
SkASSERT(fM0 || fM1); // need at least one. If not, the caller just wants combine
|
||||
}
|
||||
sk_sp<SkMixer> fM0, fM1, fCombine;
|
||||
friend class SkMixer;
|
||||
public:
|
||||
SK_FLATTENABLE_HOOKS(SkMixer_Merge)
|
||||
|
||||
void flatten(SkWriteBuffer& buffer) const override {
|
||||
buffer.writeFlattenable(fM0.get()); // could be null
|
||||
buffer.writeFlattenable(fM1.get()); // could be null
|
||||
buffer.writeFlattenable(fCombine.get());
|
||||
}
|
||||
|
||||
bool appendStages(const SkStageRec& rec) const override {
|
||||
struct Storage {
|
||||
float fDst[4 * SkRasterPipeline_kMaxStride];
|
||||
float fSrc[4 * SkRasterPipeline_kMaxStride];
|
||||
float fM0Output[4 * SkRasterPipeline_kMaxStride];
|
||||
};
|
||||
auto storage = rec.fAlloc->make<Storage>();
|
||||
SkRasterPipeline* pipeline = rec.fPipeline;
|
||||
|
||||
// Need to save off dr,dg,db,da and r,g,b,a so we can use them twice (for fM0 and fM1)
|
||||
pipeline->append(SkRasterPipeline::store_dst, storage->fDst);
|
||||
pipeline->append(SkRasterPipeline::store_src, storage->fSrc);
|
||||
|
||||
if (!as_MB(fM0)->appendStages(rec)) {
|
||||
return false;
|
||||
}
|
||||
// This outputs r,g,b,a, which we'll need later when we apply the mixer, but we save it off
|
||||
// now since fM1 will overwrite them.
|
||||
pipeline->append(SkRasterPipeline::store_src, storage->fM0Output);
|
||||
|
||||
// Now restore the original colors to call the first mixer
|
||||
pipeline->append(SkRasterPipeline::load_dst, storage->fDst);
|
||||
pipeline->append(SkRasterPipeline::load_src, storage->fSrc);
|
||||
if (!as_MB(fM1)->appendStages(rec)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// M1's output is in r,g,b,a, which is the 2nd argument to fCombine, so we just need
|
||||
// to load M0's output back into dr,dg,db,da
|
||||
pipeline->append(SkRasterPipeline::load_dst, storage->fM0Output);
|
||||
|
||||
// 1st color in dr,dg,db,da <-- M0's output
|
||||
// 2nd color in r, g, b, a <-- M1's output
|
||||
return as_MB(fCombine)->appendStages(rec);
|
||||
}
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
std::unique_ptr<GrFragmentProcessor>
|
||||
asFragmentProcessor(const GrFPArgs& args, const sk_sp<SkShader> shader1,
|
||||
const sk_sp<SkShader> shader2) const override {
|
||||
return SkShader_Mixer(sk_sp<SkShader>(new SkShader_Mixer(shader1, shader2, fM0)),
|
||||
sk_sp<SkShader>(new SkShader_Mixer(shader1, shader2, fM1)),
|
||||
fCombine).asFragmentProcessor(args);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
sk_sp<SkFlattenable> SkMixer_Merge::CreateProc(SkReadBuffer& buffer) {
|
||||
sk_sp<SkMixer> m0 = buffer.readMixer();
|
||||
sk_sp<SkMixer> m1 = buffer.readMixer();
|
||||
sk_sp<SkMixer> combine = buffer.readMixer();
|
||||
return combine ? combine->makeMerge(std::move(m0), std::move(m1)) : nullptr;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
sk_sp<SkMixer> SkMixer::MakeFirst() {
|
||||
return MakeBlend(SkBlendMode::kDst);
|
||||
}
|
||||
|
||||
sk_sp<SkMixer> SkMixer::MakeSecond() {
|
||||
return MakeBlend(SkBlendMode::kSrc);
|
||||
}
|
||||
|
||||
sk_sp<SkMixer> SkMixer::MakeConst(const SkColor4f& c) {
|
||||
return sk_sp<SkMixer>(new SkMixer_Const(c.premul()));
|
||||
}
|
||||
|
||||
sk_sp<SkMixer> SkMixer::MakeConst(SkColor c) {
|
||||
return MakeConst(SkColor4f::FromColor(c));
|
||||
}
|
||||
|
||||
sk_sp<SkMixer> SkMixer::MakeBlend(SkBlendMode mode) {
|
||||
return sk_sp<SkMixer>(new SkMixer_Blend(mode));
|
||||
}
|
||||
|
||||
sk_sp<SkMixer> SkMixer::MakeLerp(float t) {
|
||||
if (SkScalarIsNaN(t)) {
|
||||
t = 0; // is some other value better? return null?
|
||||
}
|
||||
if (t <= 0) {
|
||||
return MakeFirst();
|
||||
}
|
||||
if (t >= 1) {
|
||||
return MakeSecond();
|
||||
}
|
||||
return sk_sp<SkMixer>(new SkMixer_Lerp(t));
|
||||
}
|
||||
|
||||
sk_sp<SkMixer> SkMixer::MakeShaderLerp(sk_sp<SkShader> shader) {
|
||||
if (!shader) {
|
||||
return MakeFirst();
|
||||
}
|
||||
return sk_sp<SkMixer>(new SkMixer_ShaderLerp(std::move(shader)));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
sk_sp<SkMixer> SkMixer::makeReverse() const {
|
||||
return sk_sp<SkMixer>(new SkMixer_Reverse(sk_ref_sp(this)));
|
||||
}
|
||||
|
||||
sk_sp<SkMixer> SkMixer::makeMerge(sk_sp<SkMixer> m0, sk_sp<SkMixer> m1) const {
|
||||
auto self = sk_ref_sp(this);
|
||||
if (!m0 && !m1) {
|
||||
return self;
|
||||
}
|
||||
return sk_sp<SkMixer>(new SkMixer_Merge(std::move(m0), std::move(m1), self));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkPMColor4f SkMixerBase::test_mix(const SkPMColor4f& a, const SkPMColor4f& b) const {
|
||||
SkPMColor4f dst = a,
|
||||
src = b;
|
||||
|
||||
SkSTArenaAlloc<128> alloc;
|
||||
SkRasterPipeline pipeline(&alloc);
|
||||
SkPaint dummyPaint;
|
||||
SkStageRec rec = {
|
||||
&pipeline, &alloc, kRGBA_F32_SkColorType, nullptr, dummyPaint, nullptr, SkMatrix::I()
|
||||
};
|
||||
|
||||
SkRasterPipeline_MemoryCtx dstPtr = { &dst, 0 };
|
||||
SkRasterPipeline_MemoryCtx srcPtr = { &src, 0 };
|
||||
|
||||
pipeline.append(SkRasterPipeline::load_f32_dst, &dstPtr); // our 1st arg
|
||||
pipeline.append(SkRasterPipeline::load_f32, &srcPtr); // our 2nd arg
|
||||
as_MB(this)->appendStages(rec);
|
||||
pipeline.append(SkRasterPipeline::store_f32, &dstPtr);
|
||||
pipeline.run(0,0, 1,1);
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
void SkMixerBase::RegisterFlattenables() {
|
||||
SK_REGISTER_FLATTENABLE(SkMixer_Const);
|
||||
SK_REGISTER_FLATTENABLE(SkMixer_Reverse);
|
||||
SK_REGISTER_FLATTENABLE(SkMixer_Blend);
|
||||
SK_REGISTER_FLATTENABLE(SkMixer_Lerp);
|
||||
SK_REGISTER_FLATTENABLE(SkMixer_ShaderLerp);
|
||||
SK_REGISTER_FLATTENABLE(SkMixer_Merge);
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkMixerBase_DEFINED
|
||||
#define SkMixerBase_DEFINED
|
||||
|
||||
#include "SkMixer.h"
|
||||
#include "SkColorData.h"
|
||||
|
||||
class GrColorSpaceInfo;
|
||||
struct GrFPArgs;
|
||||
class GrFragmentProcessor;
|
||||
class GrRecordingContext;
|
||||
struct SkStageRec;
|
||||
class SkString;
|
||||
|
||||
class SkMixerBase : public SkMixer {
|
||||
public:
|
||||
virtual bool appendStages(const SkStageRec&) const = 0;
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
/**
|
||||
* A subclass may implement this factory function to work with the GPU backend. It returns
|
||||
* a GrFragmentProcessor that implements the color filter in GPU shader code.
|
||||
*
|
||||
* The fragment processor receives a premultiplied input color and produces a premultiplied
|
||||
* output color.
|
||||
*
|
||||
* A null return indicates that the color filter isn't implemented for the GPU backend.
|
||||
*/
|
||||
virtual std::unique_ptr<GrFragmentProcessor>
|
||||
asFragmentProcessor(const GrFPArgs& args, const sk_sp<SkShader> shader1,
|
||||
const sk_sp<SkShader> shader2) const = 0;
|
||||
#endif
|
||||
|
||||
static void RegisterFlattenables();
|
||||
|
||||
static SkFlattenable::Type GetFlattenableType() {
|
||||
return kSkMixer_Type;
|
||||
}
|
||||
|
||||
SkFlattenable::Type getFlattenableType() const override {
|
||||
return kSkMixer_Type;
|
||||
}
|
||||
|
||||
static sk_sp<SkMixer> Deserialize(const void* data, size_t size,
|
||||
const SkDeserialProcs* procs = nullptr) {
|
||||
SkFlattenable* ret = SkFlattenable::Deserialize(kSkMixer_Type, data, size, procs).release();
|
||||
SkMixer* mx = static_cast<SkMixer*>(ret);
|
||||
return sk_sp<SkMixer>(mx);
|
||||
}
|
||||
|
||||
SkPMColor4f test_mix(const SkPMColor4f& a, const SkPMColor4f& b) const;
|
||||
|
||||
private:
|
||||
typedef SkMixer INHERITED;
|
||||
};
|
||||
|
||||
|
||||
inline SkMixerBase* as_MB(SkMixer* shader) {
|
||||
return static_cast<SkMixerBase*>(shader);
|
||||
}
|
||||
|
||||
inline const SkMixerBase* as_MB(const SkMixer* shader) {
|
||||
return static_cast<const SkMixerBase*>(shader);
|
||||
}
|
||||
|
||||
inline const SkMixerBase* as_MB(const sk_sp<SkMixer>& shader) {
|
||||
return static_cast<SkMixerBase*>(shader.get());
|
||||
}
|
||||
|
||||
|
||||
#endif
|
@ -14,7 +14,6 @@
|
||||
#include "SkFont.h"
|
||||
#include "SkImageFilter.h"
|
||||
#include "SkMaskFilterBase.h"
|
||||
#include "SkMixerBase.h"
|
||||
#include "SkPaintPriv.h"
|
||||
#include "SkPath.h"
|
||||
#include "SkPathEffect.h"
|
||||
@ -128,7 +127,6 @@ public:
|
||||
sk_sp<SkMaskFilter> readMaskFilter() { return this->readFlattenable<SkMaskFilterBase>(); }
|
||||
sk_sp<SkPathEffect> readPathEffect() { return this->readFlattenable<SkPathEffect>(); }
|
||||
sk_sp<SkShader> readShader() { return this->readFlattenable<SkShaderBase>(); }
|
||||
sk_sp<SkMixer> readMixer() { return this->readFlattenable<SkMixerBase>(); }
|
||||
|
||||
// Reads SkAlign4(bytes), but will only copy bytes into the buffer.
|
||||
bool readPad32(void* buffer, size_t bytes);
|
||||
@ -314,7 +312,6 @@ public:
|
||||
sk_sp<SkMaskFilter> readMaskFilter() { return nullptr; }
|
||||
sk_sp<SkPathEffect> readPathEffect() { return nullptr; }
|
||||
sk_sp<SkShader> readShader() { return nullptr; }
|
||||
sk_sp<SkMixer> readMixer() { return nullptr; }
|
||||
|
||||
bool readPad32 (void*, size_t) { return false; }
|
||||
bool readByteArray (void*, size_t) { return false; }
|
||||
|
@ -36,8 +36,6 @@
|
||||
#include "SkLightingShader.h"
|
||||
#include "SkLocalMatrixShader.h"
|
||||
#include "SkLumaColorFilter.h"
|
||||
#include "SkMixerBase.h"
|
||||
#include "SkMixerShader.h"
|
||||
#include "SkNormalSource.h"
|
||||
#include "SkOverdrawColorFilter.h"
|
||||
#include "SkPathEffect.h"
|
||||
@ -86,7 +84,6 @@
|
||||
SK_REGISTER_FLATTENABLE(SkEmptyShader);
|
||||
SK_REGISTER_FLATTENABLE(SkLocalMatrixShader);
|
||||
SK_REGISTER_FLATTENABLE(SkPictureShader);
|
||||
SK_REGISTER_FLATTENABLE(SkShader_Mixer);
|
||||
SkGradientShader::RegisterFlattenables();
|
||||
SkLightingShader::RegisterFlattenables();
|
||||
SkPerlinNoiseShader::RegisterFlattenables();
|
||||
@ -122,7 +119,6 @@
|
||||
SK_REGISTER_FLATTENABLE(SkLayerDrawLooper);
|
||||
SK_REGISTER_FLATTENABLE(SkRecordedDrawable);
|
||||
SkNormalSource::RegisterFlattenables();
|
||||
SkMixerBase::RegisterFlattenables();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkArenaAlloc.h"
|
||||
#include "SkMixerShader.h"
|
||||
#include "SkRasterPipeline.h"
|
||||
#include "SkReadBuffer.h"
|
||||
#include "SkWriteBuffer.h"
|
||||
#include "SkString.h"
|
||||
|
||||
#ifdef SK_SUPPORT_LEGACY_SHADER_FACTORIES
|
||||
sk_sp<SkShader> SkShader::MakeMixer(sk_sp<SkShader> s0, sk_sp<SkShader> s1, sk_sp<SkMixer> mixer) {
|
||||
if (!mixer) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!s0) {
|
||||
return s1;
|
||||
}
|
||||
if (!s1) {
|
||||
return s0;
|
||||
}
|
||||
return sk_sp<SkShader>(new SkShader_Mixer(std::move(s0), std::move(s1), std::move(mixer)));
|
||||
}
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
sk_sp<SkFlattenable> SkShader_Mixer::CreateProc(SkReadBuffer& buffer) {
|
||||
sk_sp<SkShader> s0(buffer.readShader());
|
||||
sk_sp<SkShader> s1(buffer.readShader());
|
||||
sk_sp<SkMixer> mx(buffer.readMixer());
|
||||
|
||||
#ifdef SK_SUPPORT_LEGACY_SHADER_FACTORIES
|
||||
return MakeMixer(std::move(s0), std::move(s1), std::move(mx));
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
void SkShader_Mixer::flatten(SkWriteBuffer& buffer) const {
|
||||
buffer.writeFlattenable(fShader0.get());
|
||||
buffer.writeFlattenable(fShader1.get());
|
||||
buffer.writeFlattenable(fMixer.get());
|
||||
}
|
||||
|
||||
bool SkShader_Mixer::onAppendStages(const SkStageRec& rec) const {
|
||||
struct Storage {
|
||||
float fRGBA[4 * SkRasterPipeline_kMaxStride];
|
||||
};
|
||||
auto storage = rec.fAlloc->make<Storage>();
|
||||
|
||||
if (!as_SB(fShader0)->appendStages(rec)) {
|
||||
return false;
|
||||
}
|
||||
rec.fPipeline->append(SkRasterPipeline::store_src, storage->fRGBA);
|
||||
|
||||
if (!as_SB(fShader1)->appendStages(rec)) {
|
||||
return false;
|
||||
}
|
||||
// r,g,b,a are good, as output by fShader1
|
||||
// need to restore our previously computed dr,dg,db,da
|
||||
rec.fPipeline->append(SkRasterPipeline::load_dst, storage->fRGBA);
|
||||
|
||||
// 1st color in dr,dg,db,da
|
||||
// 2nd color in r, g, b, a
|
||||
return as_MB(fMixer)->appendStages(rec);
|
||||
}
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
|
||||
#include "effects/generated/GrConstColorProcessor.h"
|
||||
#include "effects/GrXfermodeFragmentProcessor.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::unique_ptr<GrFragmentProcessor>
|
||||
SkShader_Mixer::asFragmentProcessor(const GrFPArgs& args) const {
|
||||
return as_MB(fMixer)->asFragmentProcessor(args, fShader0, fShader1);
|
||||
}
|
||||
#endif
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkMixerShader_DEFINED
|
||||
#define SkMixerShader_DEFINED
|
||||
|
||||
#include "SkShaderBase.h"
|
||||
#include "SkMixer.h"
|
||||
|
||||
class SkShader_Mixer final : public SkShaderBase {
|
||||
public:
|
||||
SkShader_Mixer(sk_sp<SkShader> s0, sk_sp<SkShader> s1, sk_sp<SkMixer> mixer)
|
||||
: fShader0(std::move(s0))
|
||||
, fShader1(std::move(s1))
|
||||
, fMixer(std::move(mixer))
|
||||
{
|
||||
SkASSERT(fShader0);
|
||||
SkASSERT(fShader1);
|
||||
SkASSERT(fMixer);
|
||||
}
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs&) const override;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
SkShader_Mixer(SkReadBuffer&);
|
||||
void flatten(SkWriteBuffer&) const override;
|
||||
bool onAppendStages(const SkStageRec&) const override;
|
||||
|
||||
private:
|
||||
SK_FLATTENABLE_HOOKS(SkShader_Mixer)
|
||||
|
||||
sk_sp<SkShader> fShader0;
|
||||
sk_sp<SkShader> fShader1;
|
||||
sk_sp<SkMixer> fMixer;
|
||||
|
||||
typedef SkShaderBase INHERITED;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkMixer.h"
|
||||
#include "Test.h"
|
||||
#include "SkColorData.h"
|
||||
#include "SkMixerBase.h"
|
||||
|
||||
static void check_color(skiatest::Reporter* reporter,
|
||||
const SkPMColor4f& result, const SkPMColor4f& expected) {
|
||||
const float tol = 1/510.f; // made up
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(result[i], expected[i], tol));
|
||||
}
|
||||
}
|
||||
|
||||
static void check_mixer(skiatest::Reporter* reporter, sk_sp<SkMixer> mixer,
|
||||
const SkPMColor4f& a, const SkPMColor4f& b, const SkPMColor4f& expected) {
|
||||
SkPMColor4f result = as_MB(mixer)->test_mix(a, b);
|
||||
check_color(reporter, result, expected);
|
||||
|
||||
auto data = mixer->serialize();
|
||||
auto m2 = SkMixerBase::Deserialize(data->data(), data->size());
|
||||
SkPMColor4f r2 = as_MB(m2)->test_mix(a, b);
|
||||
REPORTER_ASSERT(reporter, result == r2);
|
||||
}
|
||||
|
||||
DEF_TEST(Mixer, r) {
|
||||
const SkPMColor4f transparent = {0, 0, 0, 0};
|
||||
const SkPMColor4f red = {1, 0, 0, 1};
|
||||
const SkPMColor4f magenta = {1, 0, 1, 1};
|
||||
const SkPMColor4f blue = {0, 0, 1, 1};
|
||||
|
||||
auto first = SkMixer::MakeFirst();
|
||||
auto second = SkMixer::MakeSecond();
|
||||
check_mixer(r, first, red, blue, red);
|
||||
check_mixer(r, second, red, blue, blue);
|
||||
|
||||
check_mixer(r, first->makeReverse(), red, blue, blue);
|
||||
check_mixer(r, second->makeReverse(), red, blue, red);
|
||||
|
||||
check_mixer(r, SkMixer::MakeLerp(0), red, blue, red);
|
||||
check_mixer(r, SkMixer::MakeLerp(0.0001f), red, blue, red);
|
||||
check_mixer(r, SkMixer::MakeLerp(0.5f), red, blue, {0.5f, 0, 0.5f, 1});
|
||||
check_mixer(r, SkMixer::MakeLerp(0.9999f), red, blue, blue);
|
||||
check_mixer(r, SkMixer::MakeLerp(1), red, blue, blue);
|
||||
|
||||
check_mixer(r, SkMixer::MakeBlend(SkBlendMode::kClear), red, blue, transparent);
|
||||
check_mixer(r, SkMixer::MakeBlend(SkBlendMode::kSrc), red, blue, blue);
|
||||
check_mixer(r, SkMixer::MakeBlend(SkBlendMode::kDst), red, blue, red);
|
||||
check_mixer(r, SkMixer::MakeBlend(SkBlendMode::kPlus), red, blue, magenta);
|
||||
|
||||
// mx should average the results of Plus and Clear
|
||||
auto mx = SkMixer::MakeLerp(0.5f)->makeMerge(SkMixer::MakeBlend(SkBlendMode::kPlus),
|
||||
SkMixer::MakeConst(0));
|
||||
check_mixer(r, mx, red, blue, {0.5f, 0, 0.5f, 0.5f});
|
||||
}
|
Loading…
Reference in New Issue
Block a user