aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Brian Salomon <bsalomon@google.com>2017-01-09 10:48:23 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-01-09 18:31:29 +0000
commit89cb821e9e9033281a33394709a1feed7eb0523a (patch)
tree4d1324c9a4e2f341d091268d987f8994cdc805f4
parente94255d456ad86e045e0c3aeab57395566cf49a5 (diff)
Separate SkArithmeticImageFilter from SkXfermodeImageFilter.
Change-Id: I145eed7276456b546ca5c66bc1a0f0f74a84f138 Reviewed-on: https://skia-review.googlesource.com/6728 Reviewed-by: Mike Reed <reed@google.com> Commit-Queue: Brian Salomon <bsalomon@google.com>
-rw-r--r--gm/arithmode.cpp14
-rw-r--r--gm/imagefiltersgraph.cpp12
-rw-r--r--gm/xfermodeimagefilter.cpp3
-rw-r--r--gn/effects.gni4
-rw-r--r--include/effects/SkArithmeticImageFilter.h30
-rw-r--r--include/effects/SkXfermodeImageFilter.h19
-rw-r--r--src/effects/SkArithmeticImageFilter.cpp514
-rw-r--r--src/effects/SkArithmeticMode.cpp92
-rw-r--r--src/effects/SkArithmeticModePriv.h2
-rw-r--r--src/effects/SkArithmeticMode_gpu.cpp180
-rw-r--r--src/effects/SkArithmeticMode_gpu.h75
-rw-r--r--src/effects/SkXfermodeImageFilter.cpp203
-rw-r--r--src/ports/SkGlobalInitialization_default.cpp1
13 files changed, 600 insertions, 549 deletions
diff --git a/gm/arithmode.cpp b/gm/arithmode.cpp
index caa3e283bb..aec079cfe2 100644
--- a/gm/arithmode.cpp
+++ b/gm/arithmode.cpp
@@ -6,6 +6,7 @@
*/
#include "gm.h"
+#include "SkArithmeticImageFilter.h"
#include "SkCanvas.h"
#include "SkColorPriv.h"
#include "SkGradientShader.h"
@@ -13,7 +14,6 @@
#include "SkImageSource.h"
#include "SkShader.h"
#include "SkSurface.h"
-#include "SkXfermodeImageFilter.h"
#define WW 100
#define HH 32
@@ -109,8 +109,8 @@ protected:
canvas->drawImage(dst, 0, 0);
canvas->translate(gap, 0);
SkPaint paint;
- paint.setImageFilter(SkXfermodeImageFilter::MakeArithmetic(k[0], k[1], k[2], k[3],
- true, dstFilter, srcFilter, nullptr));
+ paint.setImageFilter(SkArithmeticImageFilter::Make(k[0], k[1], k[2], k[3], true,
+ dstFilter, srcFilter, nullptr));
canvas->saveLayer(&rect, &paint);
canvas->restore();
@@ -137,12 +137,10 @@ protected:
canvas->translate(gap, 0);
sk_sp<SkImageFilter> bg =
- SkXfermodeImageFilter::MakeArithmetic(0, 0, -one / 2, 1, enforcePMColor,
- dstFilter);
+ SkArithmeticImageFilter::Make(0, 0, -one / 2, 1, enforcePMColor, dstFilter);
SkPaint p;
- p.setImageFilter(SkXfermodeImageFilter::MakeArithmetic(0, one / 2, -one, 1, true,
- std::move(bg), dstFilter,
- nullptr));
+ p.setImageFilter(SkArithmeticImageFilter::Make(0, one / 2, -one, 1, true,
+ std::move(bg), dstFilter, nullptr));
canvas->saveLayer(&rect, &p);
canvas->restore();
canvas->translate(gap, 0);
diff --git a/gm/imagefiltersgraph.cpp b/gm/imagefiltersgraph.cpp
index fd4d5cf516..30c987aa86 100644
--- a/gm/imagefiltersgraph.cpp
+++ b/gm/imagefiltersgraph.cpp
@@ -7,6 +7,7 @@
#include "gm.h"
+#include "SkArithmeticImageFilter.h"
#include "SkBlurImageFilter.h"
#include "SkColorFilter.h"
#include "SkColorFilterImageFilter.h"
@@ -14,13 +15,13 @@
#include "SkImage.h"
#include "SkImageSource.h"
#include "SkMatrixConvolutionImageFilter.h"
+#include "SkMergeImageFilter.h"
+#include "SkMorphologyImageFilter.h"
#include "SkOffsetImageFilter.h"
#include "SkReadBuffer.h"
#include "SkSpecialImage.h"
#include "SkSpecialSurface.h"
#include "SkWriteBuffer.h"
-#include "SkMergeImageFilter.h"
-#include "SkMorphologyImageFilter.h"
#include "SkXfermodeImageFilter.h"
class ImageFiltersGraphGM : public skiagm::GM {
@@ -88,11 +89,8 @@ protected:
matrixFilter));
SkPaint paint;
- paint.setImageFilter(
- SkXfermodeImageFilter::MakeArithmetic(0, 1, 1, 0, true,
- std::move(matrixFilter),
- std::move(offsetFilter),
- nullptr));
+ paint.setImageFilter(SkArithmeticImageFilter::Make(
+ 0, 1, 1, 0, true, std::move(matrixFilter), std::move(offsetFilter), nullptr));
DrawClippedImage(canvas, fImage.get(), paint);
canvas->translate(SkIntToScalar(100), 0);
diff --git a/gm/xfermodeimagefilter.cpp b/gm/xfermodeimagefilter.cpp
index 91908599ff..77c350235b 100644
--- a/gm/xfermodeimagefilter.cpp
+++ b/gm/xfermodeimagefilter.cpp
@@ -7,6 +7,7 @@
#include "gm.h"
#include "sk_tool_utils.h"
+#include "SkArithmeticImageFilter.h"
#include "SkImage.h"
#include "SkImageSource.h"
#include "SkOffsetImageFilter.h"
@@ -95,7 +96,7 @@ protected:
}
}
// Test arithmetic mode as image filter
- paint.setImageFilter(SkXfermodeImageFilter::MakeArithmetic(0, 1, 1, 0, true, background));
+ paint.setImageFilter(SkArithmeticImageFilter::Make(0, 1, 1, 0, true, background));
DrawClippedBitmap(canvas, fBitmap, paint, x, y);
x += fBitmap.width() + MARGIN;
if (x + fBitmap.width() > WIDTH) {
diff --git a/gn/effects.gni b/gn/effects.gni
index 10a2576daa..30e36b22d8 100644
--- a/gn/effects.gni
+++ b/gn/effects.gni
@@ -17,9 +17,8 @@ skia_effects_sources = [
"$_src/effects/Sk2DPathEffect.cpp",
"$_src/effects/SkAlphaThresholdFilter.cpp",
"$_src/effects/SkArcToPathEffect.cpp",
+ "$_src/effects/SkArithmeticImageFilter.cpp",
"$_src/effects/SkArithmeticMode.cpp",
- "$_src/effects/SkArithmeticMode_gpu.cpp",
- "$_src/effects/SkArithmeticMode_gpu.h",
"$_src/effects/SkBlurDrawLooper.cpp",
"$_src/effects/SkBlurMask.cpp",
"$_src/effects/SkBlurMask.h",
@@ -91,6 +90,7 @@ skia_effects_sources = [
"$_include/effects/Sk2DPathEffect.h",
"$_include/effects/SkAlphaThresholdFilter.h",
"$_include/effects/SkArithmeticMode.h",
+ "$_include/effects/SkArithmeticImageFilter.h",
"$_include/effects/SkBlurDrawLooper.h",
"$_include/effects/SkBlurImageFilter.h",
"$_include/effects/SkBlurMaskFilter.h",
diff --git a/include/effects/SkArithmeticImageFilter.h b/include/effects/SkArithmeticImageFilter.h
new file mode 100644
index 0000000000..ef596030a7
--- /dev/null
+++ b/include/effects/SkArithmeticImageFilter.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkArithmeticImageFilter_DEFINED
+#define SkArithmeticImageFilter_DEFINED
+
+#include "SkImageFilter.h"
+
+class SK_API SkArithmeticImageFilter {
+public:
+ static sk_sp<SkImageFilter> Make(float k1, float k2, float k3, float k4, bool enforcePMColor,
+ sk_sp<SkImageFilter> background,
+ sk_sp<SkImageFilter> foreground,
+ const SkImageFilter::CropRect* cropRect);
+ static sk_sp<SkImageFilter> Make(float k1, float k2, float k3, float k4, bool enforcePMColor,
+ sk_sp<SkImageFilter> background) {
+ return Make(k1, k2, k3, k4, enforcePMColor, std::move(background), nullptr, nullptr);
+ }
+
+ SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP();
+
+private:
+ SkArithmeticImageFilter(); // can't instantiate
+};
+
+#endif
diff --git a/include/effects/SkXfermodeImageFilter.h b/include/effects/SkXfermodeImageFilter.h
index 5fbd1af590..5e8b587241 100644
--- a/include/effects/SkXfermodeImageFilter.h
+++ b/include/effects/SkXfermodeImageFilter.h
@@ -8,13 +8,13 @@
#ifndef SkXfermodeImageFilter_DEFINED
#define SkXfermodeImageFilter_DEFINED
+#include "SkArithmeticImageFilter.h"
#include "SkBlendMode.h"
#include "SkImageFilter.h"
/**
- * This filter takes an xfermode, and uses it to composite the foreground
- * over the background. If foreground or background is NULL, the input
- * bitmap (src) is used instead.
+ * This filter takes a SkBlendMode, and uses it to composite the foreground over the background.
+ * If foreground or background is NULL, the input bitmap (src) is used instead.
*/
class SK_API SkXfermodeImageFilter {
public:
@@ -25,16 +25,19 @@ public:
return Make(mode, std::move(background), nullptr, nullptr);
}
+ // Arithmetic image filtering used to be implemented using SkXfermode. Some clients still rely
+ // on these factories existing in this class.
static sk_sp<SkImageFilter> MakeArithmetic(float k1, float k2, float k3, float k4,
- bool enforcePMColor,
- sk_sp<SkImageFilter> background,
+ bool enforcePMColor, sk_sp<SkImageFilter> background,
sk_sp<SkImageFilter> foreground,
- const SkImageFilter::CropRect* cropRect);
+ const SkImageFilter::CropRect* cropRect) {
+ return SkArithmeticImageFilter::Make(k1, k2, k3, k4, enforcePMColor, std::move(background),
+ std::move(foreground), cropRect);
+ }
static sk_sp<SkImageFilter> MakeArithmetic(float k1, float k2, float k3, float k4,
bool enforcePMColor,
sk_sp<SkImageFilter> background) {
- return MakeArithmetic(k1, k2, k3, k4, enforcePMColor, std::move(background),
- nullptr, nullptr);
+ return SkArithmeticImageFilter::Make(k1, k2, k3, k4, enforcePMColor, std::move(background));
}
SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP();
diff --git a/src/effects/SkArithmeticImageFilter.cpp b/src/effects/SkArithmeticImageFilter.cpp
new file mode 100644
index 0000000000..984aedc823
--- /dev/null
+++ b/src/effects/SkArithmeticImageFilter.cpp
@@ -0,0 +1,514 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkArithmeticImageFilter.h"
+#include "SkArithmeticModePriv.h"
+#include "SkCanvas.h"
+#include "SkNx.h"
+#include "SkReadBuffer.h"
+#include "SkSpecialImage.h"
+#include "SkSpecialSurface.h"
+#include "SkWriteBuffer.h"
+#include "SkXfermodeImageFilter.h"
+#if SK_SUPPORT_GPU
+#include "GrContext.h"
+#include "GrRenderTargetContext.h"
+#include "GrTextureProxy.h"
+#include "SkGr.h"
+#include "SkGrPriv.h"
+#include "effects/GrConstColorProcessor.h"
+#include "effects/GrTextureDomain.h"
+#include "glsl/GrGLSLFragmentProcessor.h"
+#include "glsl/GrGLSLFragmentShaderBuilder.h"
+#include "glsl/GrGLSLProgramDataManager.h"
+#include "glsl/GrGLSLUniformHandler.h"
+#endif
+
+namespace {
+class ArithmeticImageFilterImpl : public SkImageFilter {
+public:
+ ArithmeticImageFilterImpl(float k1, float k2, float k3, float k4, bool enforcePMColor,
+ sk_sp<SkImageFilter> inputs[2], const CropRect* cropRect)
+ : INHERITED(inputs, 2, cropRect), fK{k1, k2, k3, k4}, fEnforcePMColor(enforcePMColor) {}
+
+ SK_TO_STRING_OVERRIDE()
+ SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(ArithmeticImageFilterImpl)
+
+protected:
+ sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source, const Context&,
+ SkIPoint* offset) const override;
+
+#if SK_SUPPORT_GPU
+ sk_sp<SkSpecialImage> filterImageGPU(SkSpecialImage* source,
+ sk_sp<SkSpecialImage> background,
+ const SkIPoint& backgroundOffset,
+ sk_sp<SkSpecialImage> foreground,
+ const SkIPoint& foregroundOffset,
+ const SkIRect& bounds,
+ const OutputProperties& outputProperties) const;
+#endif
+
+ void flatten(SkWriteBuffer& buffer) const override {
+ this->INHERITED::flatten(buffer);
+ for (int i = 0; i < 4; ++i) {
+ buffer.writeScalar(fK[i]);
+ }
+ buffer.writeBool(fEnforcePMColor);
+ }
+
+ void drawForeground(SkCanvas* canvas, SkSpecialImage*, const SkIRect&) const;
+
+private:
+ const float fK[4];
+ const bool fEnforcePMColor;
+
+ friend class ::SkArithmeticImageFilter;
+
+ typedef SkImageFilter INHERITED;
+};
+}
+
+sk_sp<SkFlattenable> ArithmeticImageFilterImpl::CreateProc(SkReadBuffer& buffer) {
+ SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 2);
+ float k[4];
+ for (int i = 0; i < 4; ++i) {
+ k[i] = buffer.readScalar();
+ }
+ const bool enforcePMColor = buffer.readBool();
+ return SkArithmeticImageFilter::Make(k[0], k[1], k[2], k[3], enforcePMColor, common.getInput(0),
+ common.getInput(1), &common.cropRect());
+}
+
+static Sk4f pin(float min, const Sk4f& val, float max) {
+ return Sk4f::Max(min, Sk4f::Min(val, max));
+}
+
+template <bool EnforcePMColor>
+void arith_span(const float k[], SkPMColor dst[], const SkPMColor src[], int count) {
+ const Sk4f k1 = k[0] * (1/255.0f),
+ k2 = k[1],
+ k3 = k[2],
+ k4 = k[3] * 255.0f + 0.5f;
+
+ for (int i = 0; i < count; i++) {
+ Sk4f s = SkNx_cast<float>(Sk4b::Load(src+i)),
+ d = SkNx_cast<float>(Sk4b::Load(dst+i)),
+ r = pin(0, k1*s*d + k2*s + k3*d + k4, 255);
+ if (EnforcePMColor) {
+ Sk4f a = SkNx_shuffle<3,3,3,3>(r);
+ r = Sk4f::Min(a, r);
+ }
+ SkNx_cast<uint8_t>(r).store(dst+i);
+ }
+}
+
+// apply mode to src==transparent (0)
+template<bool EnforcePMColor> void arith_transparent(const float k[], SkPMColor dst[], int count) {
+ const Sk4f k3 = k[2],
+ k4 = k[3] * 255.0f + 0.5f;
+
+ for (int i = 0; i < count; i++) {
+ Sk4f d = SkNx_cast<float>(Sk4b::Load(dst+i)),
+ r = pin(0, k3*d + k4, 255);
+ if (EnforcePMColor) {
+ Sk4f a = SkNx_shuffle<3,3,3,3>(r);
+ r = Sk4f::Min(a, r);
+ }
+ SkNx_cast<uint8_t>(r).store(dst+i);
+ }
+}
+
+static bool intersect(SkPixmap* dst, SkPixmap* src, int srcDx, int srcDy) {
+ SkIRect dstR = SkIRect::MakeWH(dst->width(), dst->height());
+ SkIRect srcR = SkIRect::MakeXYWH(srcDx, srcDy, src->width(), src->height());
+ SkIRect sect;
+ if (!sect.intersect(dstR, srcR)) {
+ return false;
+ }
+ *dst = SkPixmap(dst->info().makeWH(sect.width(), sect.height()),
+ dst->addr(sect.fLeft, sect.fTop),
+ dst->rowBytes());
+ *src = SkPixmap(src->info().makeWH(sect.width(), sect.height()),
+ src->addr(SkTMax(0, -srcDx), SkTMax(0, -srcDy)),
+ src->rowBytes());
+ return true;
+}
+
+sk_sp<SkSpecialImage> ArithmeticImageFilterImpl::onFilterImage(SkSpecialImage* source,
+ const Context& ctx,
+ SkIPoint* offset) const {
+ SkIPoint backgroundOffset = SkIPoint::Make(0, 0);
+ sk_sp<SkSpecialImage> background(this->filterInput(0, source, ctx, &backgroundOffset));
+
+ SkIPoint foregroundOffset = SkIPoint::Make(0, 0);
+ sk_sp<SkSpecialImage> foreground(this->filterInput(1, source, ctx, &foregroundOffset));
+
+ SkIRect foregroundBounds = SkIRect::EmptyIRect();
+ if (foreground) {
+ foregroundBounds = SkIRect::MakeXYWH(foregroundOffset.x(), foregroundOffset.y(),
+ foreground->width(), foreground->height());
+ }
+
+ SkIRect srcBounds = SkIRect::EmptyIRect();
+ if (background) {
+ srcBounds = SkIRect::MakeXYWH(backgroundOffset.x(), backgroundOffset.y(),
+ background->width(), background->height());
+ }
+
+ srcBounds.join(foregroundBounds);
+ if (srcBounds.isEmpty()) {
+ return nullptr;
+ }
+
+ SkIRect bounds;
+ if (!this->applyCropRect(ctx, srcBounds, &bounds)) {
+ return nullptr;
+ }
+
+ offset->fX = bounds.left();
+ offset->fY = bounds.top();
+
+#if SK_SUPPORT_GPU
+ if (source->isTextureBacked()) {
+ return this->filterImageGPU(source, background, backgroundOffset, foreground,
+ foregroundOffset, bounds, ctx.outputProperties());
+ }
+#endif
+
+ sk_sp<SkSpecialSurface> surf(source->makeSurface(ctx.outputProperties(), bounds.size()));
+ if (!surf) {
+ return nullptr;
+ }
+
+ SkCanvas* canvas = surf->getCanvas();
+ SkASSERT(canvas);
+
+ canvas->clear(0x0); // can't count on background to fully clear the background
+ canvas->translate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
+
+ if (background) {
+ SkPaint paint;
+ paint.setBlendMode(SkBlendMode::kSrc);
+ background->draw(canvas, SkIntToScalar(backgroundOffset.fX),
+ SkIntToScalar(backgroundOffset.fY), &paint);
+ }
+
+ this->drawForeground(canvas, foreground.get(), foregroundBounds);
+
+ return surf->makeImageSnapshot();
+}
+
+#if SK_SUPPORT_GPU
+
+namespace {
+class ArithmeticFP : public GrFragmentProcessor {
+public:
+ static sk_sp<GrFragmentProcessor> Make(float k1, float k2, float k3, float k4,
+ bool enforcePMColor, sk_sp<GrFragmentProcessor> dst) {
+ return sk_sp<GrFragmentProcessor>(
+ new ArithmeticFP(k1, k2, k3, k4, enforcePMColor, std::move(dst)));
+ }
+
+ ~ArithmeticFP() override {}
+
+ const char* name() const override { return "Arithmetic"; }
+
+ SkString dumpInfo() const override {
+ SkString str;
+ str.appendf("K1: %.2f K2: %.2f K3: %.2f K4: %.2f", fK1, fK2, fK3, fK4);
+ return str;
+ }
+
+ float k1() const { return fK1; }
+ float k2() const { return fK2; }
+ float k3() const { return fK3; }
+ float k4() const { return fK4; }
+ bool enforcePMColor() const { return fEnforcePMColor; }
+
+private:
+ GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
+ class GLSLFP : public GrGLSLFragmentProcessor {
+ public:
+ void emitCode(EmitArgs& args) override {
+ const ArithmeticFP& arith = args.fFp.cast<ArithmeticFP>();
+
+ GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+ SkString dstColor("dstColor");
+ this->emitChild(0, nullptr, &dstColor, args);
+
+ fKUni = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kVec4f_GrSLType,
+ kDefault_GrSLPrecision, "k");
+ const char* kUni = args.fUniformHandler->getUniformCStr(fKUni);
+
+ // We don't try to optimize for this case at all
+ if (!args.fInputColor) {
+ fragBuilder->codeAppend("const vec4 src = vec4(1);");
+ } else {
+ fragBuilder->codeAppendf("vec4 src = %s;", args.fInputColor);
+ }
+
+ fragBuilder->codeAppendf("vec4 dst = %s;", dstColor.c_str());
+ fragBuilder->codeAppendf("%s = %s.x * src * dst + %s.y * src + %s.z * dst + %s.w;",
+ args.fOutputColor, kUni, kUni, kUni, kUni);
+ fragBuilder->codeAppendf("%s = clamp(%s, 0.0, 1.0);\n", args.fOutputColor,
+ args.fOutputColor);
+ if (arith.fEnforcePMColor) {
+ fragBuilder->codeAppendf("%s.rgb = min(%s.rgb, %s.a);", args.fOutputColor,
+ args.fOutputColor, args.fOutputColor);
+ }
+ }
+
+ protected:
+ void onSetData(const GrGLSLProgramDataManager& pdman,
+ const GrProcessor& proc) override {
+ const ArithmeticFP& arith = proc.cast<ArithmeticFP>();
+ pdman.set4f(fKUni, arith.k1(), arith.k2(), arith.k3(), arith.k4());
+ }
+
+ private:
+ GrGLSLProgramDataManager::UniformHandle fKUni;
+ };
+ return new GLSLFP;
+ }
+
+ void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
+ b->add32(fEnforcePMColor ? 1 : 0);
+ }
+
+ bool onIsEqual(const GrFragmentProcessor& fpBase) const override {
+ const ArithmeticFP& fp = fpBase.cast<ArithmeticFP>();
+ return fK1 == fp.fK1 && fK2 == fp.fK2 && fK3 == fp.fK3 && fK4 == fp.fK4 &&
+ fEnforcePMColor == fp.fEnforcePMColor;
+ }
+
+ void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
+ // TODO: optimize this
+ inout->setToUnknown(GrInvariantOutput::kWill_ReadInput);
+ }
+
+ ArithmeticFP(float k1, float k2, float k3, float k4, bool enforcePMColor,
+ sk_sp<GrFragmentProcessor> dst)
+ : fK1(k1), fK2(k2), fK3(k3), fK4(k4), fEnforcePMColor(enforcePMColor) {
+ this->initClassID<ArithmeticFP>();
+ SkASSERT(dst);
+ SkDEBUGCODE(int dstIndex =) this->registerChildProcessor(std::move(dst));
+ SkASSERT(0 == dstIndex);
+ }
+
+ float fK1, fK2, fK3, fK4;
+ bool fEnforcePMColor;
+
+ GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
+ typedef GrFragmentProcessor INHERITED;
+};
+}
+
+sk_sp<GrFragmentProcessor> ArithmeticFP::TestCreate(GrProcessorTestData* d) {
+ float k1 = d->fRandom->nextF();
+ float k2 = d->fRandom->nextF();
+ float k3 = d->fRandom->nextF();
+ float k4 = d->fRandom->nextF();
+ bool enforcePMColor = d->fRandom->nextBool();
+
+ sk_sp<GrFragmentProcessor> dst(GrProcessorUnitTest::MakeChildFP(d));
+ return ArithmeticFP::Make(k1, k2, k3, k4, enforcePMColor, std::move(dst));
+}
+
+GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ArithmeticFP);
+
+sk_sp<SkSpecialImage> ArithmeticImageFilterImpl::filterImageGPU(
+ SkSpecialImage* source,
+ sk_sp<SkSpecialImage>
+ background,
+ const SkIPoint& backgroundOffset,
+ sk_sp<SkSpecialImage>
+ foreground,
+ const SkIPoint& foregroundOffset,
+ const SkIRect& bounds,
+ const OutputProperties& outputProperties) const {
+ SkASSERT(source->isTextureBacked());
+
+ GrContext* context = source->getContext();
+
+ sk_sp<GrTexture> backgroundTex, foregroundTex;
+
+ if (background) {
+ backgroundTex = background->asTextureRef(context);
+ }
+
+ if (foreground) {
+ foregroundTex = foreground->asTextureRef(context);
+ }
+
+ GrPaint paint;
+ sk_sp<GrFragmentProcessor> bgFP;
+
+ if (backgroundTex) {
+ SkMatrix backgroundMatrix;
+ backgroundMatrix.setIDiv(backgroundTex->width(), backgroundTex->height());
+ backgroundMatrix.preTranslate(-SkIntToScalar(backgroundOffset.fX),
+ -SkIntToScalar(backgroundOffset.fY));
+ sk_sp<GrColorSpaceXform> bgXform =
+ GrColorSpaceXform::Make(background->getColorSpace(), outputProperties.colorSpace());
+ bgFP = GrTextureDomainEffect::Make(
+ backgroundTex.get(), std::move(bgXform), backgroundMatrix,
+ GrTextureDomain::MakeTexelDomain(backgroundTex.get(), background->subset()),
+ GrTextureDomain::kDecal_Mode, GrSamplerParams::kNone_FilterMode);
+ } else {
+ bgFP = GrConstColorProcessor::Make(GrColor4f::TransparentBlack(),
+ GrConstColorProcessor::kIgnore_InputMode);
+ }
+
+ if (foregroundTex) {
+ SkMatrix foregroundMatrix;
+ foregroundMatrix.setIDiv(foregroundTex->width(), foregroundTex->height());
+ foregroundMatrix.preTranslate(-SkIntToScalar(foregroundOffset.fX),
+ -SkIntToScalar(foregroundOffset.fY));
+ sk_sp<GrColorSpaceXform> fgXform =
+ GrColorSpaceXform::Make(foreground->getColorSpace(), outputProperties.colorSpace());
+ sk_sp<GrFragmentProcessor> foregroundFP;
+
+ foregroundFP = GrTextureDomainEffect::Make(
+ foregroundTex.get(), std::move(fgXform), foregroundMatrix,
+ GrTextureDomain::MakeTexelDomain(foregroundTex.get(), foreground->subset()),
+ GrTextureDomain::kDecal_Mode, GrSamplerParams::kNone_FilterMode);
+
+ paint.addColorFragmentProcessor(std::move(foregroundFP));
+
+ sk_sp<GrFragmentProcessor> xferFP =
+ ArithmeticFP::Make(fK[0], fK[1], fK[2], fK[3], fEnforcePMColor, std::move(bgFP));
+
+ // A null 'xferFP' here means kSrc_Mode was used in which case we can just proceed
+ if (xferFP) {
+ paint.addColorFragmentProcessor(std::move(xferFP));
+ }
+ } else {
+ paint.addColorFragmentProcessor(std::move(bgFP));
+ }
+
+ paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
+
+ sk_sp<GrRenderTargetContext> renderTargetContext(context->makeDeferredRenderTargetContext(
+ SkBackingFit::kApprox, bounds.width(), bounds.height(),
+ GrRenderableConfigForColorSpace(outputProperties.colorSpace()),
+ sk_ref_sp(outputProperties.colorSpace())));
+ if (!renderTargetContext) {
+ return nullptr;
+ }
+ paint.setGammaCorrect(renderTargetContext->isGammaCorrect());
+
+ SkMatrix matrix;
+ matrix.setTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
+ renderTargetContext->drawRect(GrNoClip(), paint, GrAA::kNo, matrix, SkRect::Make(bounds));
+
+ return SkSpecialImage::MakeDeferredFromGpu(context,
+ SkIRect::MakeWH(bounds.width(), bounds.height()),
+ kNeedNewImageUniqueID_SpecialImage,
+ sk_ref_sp(renderTargetContext->asDeferredTexture()),
+ sk_ref_sp(renderTargetContext->getColorSpace()));
+}
+#endif
+
+void ArithmeticImageFilterImpl::drawForeground(SkCanvas* canvas, SkSpecialImage* img,
+ const SkIRect& fgBounds) const {
+ SkPixmap dst;
+ if (!canvas->peekPixels(&dst)) {
+ return;
+ }
+
+ const SkMatrix& ctm = canvas->getTotalMatrix();
+ SkASSERT(ctm.getType() <= SkMatrix::kTranslate_Mask);
+ const int dx = SkScalarRoundToInt(ctm.getTranslateX());
+ const int dy = SkScalarRoundToInt(ctm.getTranslateY());
+
+ if (img) {
+ SkBitmap srcBM;
+ SkPixmap src;
+ if (!img->getROPixels(&srcBM)) {
+ return;
+ }
+ srcBM.lockPixels();
+ if (!srcBM.peekPixels(&src)) {
+ return;
+ }
+
+ auto proc = fEnforcePMColor ? arith_span<true> : arith_span<false>;
+ SkPixmap tmpDst = dst;
+ if (intersect(&tmpDst, &src, fgBounds.fLeft + dx, fgBounds.fTop + dy)) {
+ for (int y = 0; y < tmpDst.height(); ++y) {
+ proc(fK, tmpDst.writable_addr32(0, y), src.addr32(0, y), tmpDst.width());
+ }
+ }
+ }
+
+ // Now apply the mode with transparent-color to the outside of the fg image
+ SkRegion outside(SkIRect::MakeWH(dst.width(), dst.height()));
+ outside.op(fgBounds.makeOffset(dx, dy), SkRegion::kDifference_Op);
+ auto proc = fEnforcePMColor ? arith_transparent<true> : arith_transparent<false>;
+ for (SkRegion::Iterator iter(outside); !iter.done(); iter.next()) {
+ const SkIRect r = iter.rect();
+ for (int y = r.fTop; y < r.fBottom; ++y) {
+ proc(fK, dst.writable_addr32(r.fLeft, y), r.width());
+ }
+ }
+}
+
+#ifndef SK_IGNORE_TO_STRING
+void ArithmeticImageFilterImpl::toString(SkString* str) const {
+ str->appendf("SkArithmeticImageFilter: (");
+ str->appendf("K[]: (%f %f %f %f)", fK[0], fK[1], fK[2], fK[3]);
+ if (this->getInput(0)) {
+ str->appendf("foreground: (");
+ this->getInput(0)->toString(str);
+ str->appendf(")");
+ }
+ if (this->getInput(1)) {
+ str->appendf("background: (");
+ this->getInput(1)->toString(str);
+ str->appendf(")");
+ }
+ str->append(")");
+}
+#endif
+
+sk_sp<SkImageFilter> SkArithmeticImageFilter::Make(float k1, float k2, float k3, float k4,
+ bool enforcePMColor,
+ sk_sp<SkImageFilter> background,
+ sk_sp<SkImageFilter> foreground,
+ const SkImageFilter::CropRect* crop) {
+ if (!SkScalarIsFinite(k1) || !SkScalarIsFinite(k2) || !SkScalarIsFinite(k3) ||
+ !SkScalarIsFinite(k4)) {
+ return nullptr;
+ }
+
+ // are we nearly some other "std" mode?
+ int mode = -1; // illegal mode
+ if (SkScalarNearlyZero(k1) && SkScalarNearlyEqual(k2, SK_Scalar1) && SkScalarNearlyZero(k3) &&
+ SkScalarNearlyZero(k4)) {
+ mode = (int)SkBlendMode::kSrc;
+ } else if (SkScalarNearlyZero(k1) && SkScalarNearlyZero(k2) &&
+ SkScalarNearlyEqual(k3, SK_Scalar1) && SkScalarNearlyZero(k4)) {
+ mode = (int)SkBlendMode::kDst;
+ } else if (SkScalarNearlyZero(k1) && SkScalarNearlyZero(k2) && SkScalarNearlyZero(k3) &&
+ SkScalarNearlyZero(k4)) {
+ mode = (int)SkBlendMode::kClear;
+ }
+ if (mode >= 0) {
+ return SkXfermodeImageFilter::Make((SkBlendMode)mode, std::move(background),
+ std::move(foreground), crop);
+ }
+
+ sk_sp<SkImageFilter> inputs[2] = {std::move(background), std::move(foreground)};
+ return sk_sp<SkImageFilter>(
+ new ArithmeticImageFilterImpl(k1, k2, k3, k4, enforcePMColor, inputs, crop));
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkArithmeticImageFilter)
+ SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(ArithmeticImageFilterImpl)
+SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
diff --git a/src/effects/SkArithmeticMode.cpp b/src/effects/SkArithmeticMode.cpp
index c85d5c378d..d604a12fbb 100644
--- a/src/effects/SkArithmeticMode.cpp
+++ b/src/effects/SkArithmeticMode.cpp
@@ -6,17 +6,11 @@
*/
#include "SkArithmeticModePriv.h"
-#include "SkColorPriv.h"
-#include "SkNx.h"
-#include "SkRasterPipeline.h"
#include "SkReadBuffer.h"
-#include "SkString.h"
-#include "SkUnPreMultiply.h"
-#include "SkWriteBuffer.h"
-#if SK_SUPPORT_GPU
-#include "SkArithmeticMode_gpu.h"
-#endif
+// This class only exists to unflatten instances that were serialized into old pictures as part of
+// SkXfermodeImageFilter before the advent of SkBlendMode. Those image filters will now be
+// transformed to SkArithmeticImageFilter which does not use this class in its implementation.
class SkArithmeticMode_scalar : public SkXfermode {
public:
SkArithmeticMode_scalar(SkScalar k1, SkScalar k2, SkScalar k3, SkScalar k4,
@@ -28,20 +22,15 @@ public:
fEnforcePMColor = enforcePMColor;
}
- void xfer32(SkPMColor[], const SkPMColor[], int count, const SkAlpha[]) const override;
+ void xfer32(SkPMColor[], const SkPMColor[], int count, const SkAlpha[]) const override {
+ SkFAIL("This should never be called.");
+ }
SK_TO_STRING_OVERRIDE()
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkArithmeticMode_scalar)
-#if SK_SUPPORT_GPU
- sk_sp<GrFragmentProcessor> makeFragmentProcessorForImageFilter(
- sk_sp<GrFragmentProcessor> dst) const override;
- const GrXPFactory* asXPFactory() const override {
- SkFAIL("This should only be used as a FP.");
- return nullptr;
- }
-#endif
-
+ // This is used to extract the arithmetic params into an SkArithmeticImageFilter. Afterwards,
+ // this object is destroyed and arithemtic blending is implemented directly in the image filter.
bool isArithmetic(SkArithmeticParams* params) const override {
if (params) {
memcpy(params->fK, fK, 4 * sizeof(float));
@@ -51,13 +40,7 @@ public:
}
private:
- void flatten(SkWriteBuffer& buffer) const override {
- buffer.writeScalar(fK[0]);
- buffer.writeScalar(fK[1]);
- buffer.writeScalar(fK[2]);
- buffer.writeScalar(fK[3]);
- buffer.writeBool(fEnforcePMColor);
- }
+ void flatten(SkWriteBuffer& buffer) const override { SkFAIL("This shouild never be called."); }
SkScalar fK[4];
bool fEnforcePMColor;
@@ -76,48 +59,9 @@ sk_sp<SkFlattenable> SkArithmeticMode_scalar::CreateProc(SkReadBuffer& buffer) {
return SkArithmeticMode::Make(k1, k2, k3, k4, enforcePMColor);
}
-void SkArithmeticMode_scalar::xfer32(SkPMColor dst[], const SkPMColor src[],
- int count, const SkAlpha aaCoverage[]) const {
- const Sk4f k1 = fK[0] * (1/255.0f),
- k2 = fK[1],
- k3 = fK[2],
- k4 = fK[3] * 255.0f + 0.5f;
-
- auto pin = [](float min, const Sk4f& val, float max) {
- return Sk4f::Max(min, Sk4f::Min(val, max));
- };
-
- for (int i = 0; i < count; i++) {
- if (aaCoverage && aaCoverage[i] == 0) {
- continue;
- }
-
- Sk4f s = SkNx_cast<float>(Sk4b::Load(src+i)),
- d = SkNx_cast<float>(Sk4b::Load(dst+i)),
- r = pin(0, k1*s*d + k2*s + k3*d + k4, 255);
-
- if (fEnforcePMColor) {
- Sk4f a = SkNx_shuffle<3,3,3,3>(r);
- r = Sk4f::Min(a, r);
- }
-
- if (aaCoverage && aaCoverage[i] != 255) {
- Sk4f c = aaCoverage[i] * (1/255.0f);
- r = d + (r-d)*c;
- }
-
- SkNx_cast<uint8_t>(r).store(dst+i);
- }
-}
-
#ifndef SK_IGNORE_TO_STRING
void SkArithmeticMode_scalar::toString(SkString* str) const {
- str->append("SkArithmeticMode_scalar: ");
- for (int i = 0; i < 4; ++i) {
- str->appendScalar(fK[i]);
- str->append(" ");
- }
- str->appendS32(fEnforcePMColor ? 1 : 0);
+ SkFAIL("This should never be called.");
}
#endif
@@ -135,22 +79,6 @@ sk_sp<SkXfermode> SkArithmeticMode::Make(SkScalar k1, SkScalar k2, SkScalar k3,
return sk_make_sp<SkArithmeticMode_scalar>(k1, k2, k3, k4, enforcePMColor);
}
-
-//////////////////////////////////////////////////////////////////////////////
-
-#if SK_SUPPORT_GPU
-sk_sp<GrFragmentProcessor> SkArithmeticMode_scalar::makeFragmentProcessorForImageFilter(
- sk_sp<GrFragmentProcessor> dst) const {
- return GrArithmeticFP::Make(SkScalarToFloat(fK[0]),
- SkScalarToFloat(fK[1]),
- SkScalarToFloat(fK[2]),
- SkScalarToFloat(fK[3]),
- fEnforcePMColor,
- std::move(dst));
-}
-
-#endif
-
SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkArithmeticMode)
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkArithmeticMode_scalar)
SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
diff --git a/src/effects/SkArithmeticModePriv.h b/src/effects/SkArithmeticModePriv.h
index ff7f357189..4c13a8163e 100644
--- a/src/effects/SkArithmeticModePriv.h
+++ b/src/effects/SkArithmeticModePriv.h
@@ -18,6 +18,8 @@ struct SkArithmeticParams {
bool fEnforcePMColor;
};
+// This only exists to unflatten instances that were serialized into old pictures as part of
+// SkXfermodeImageFilter before the advent of SkBlendMode.
class SK_API SkArithmeticMode {
public:
/**
diff --git a/src/effects/SkArithmeticMode_gpu.cpp b/src/effects/SkArithmeticMode_gpu.cpp
deleted file mode 100644
index a6c78661da..0000000000
--- a/src/effects/SkArithmeticMode_gpu.cpp
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright 2015 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkArithmeticMode_gpu.h"
-
-#if SK_SUPPORT_GPU
-#include "GrContext.h"
-#include "GrFragmentProcessor.h"
-#include "GrInvariantOutput.h"
-#include "GrProcessor.h"
-#include "GrTexture.h"
-#include "glsl/GrGLSLFragmentProcessor.h"
-#include "glsl/GrGLSLFragmentShaderBuilder.h"
-#include "glsl/GrGLSLProgramDataManager.h"
-#include "glsl/GrGLSLUniformHandler.h"
-#include "glsl/GrGLSLXferProcessor.h"
-
-static void add_arithmetic_code(GrGLSLFragmentBuilder* fragBuilder,
- const char* srcColor,
- const char* dstColor,
- const char* outputColor,
- const char* kUni,
- bool enforcePMColor) {
- // We don't try to optimize for this case at all
- if (nullptr == srcColor) {
- fragBuilder->codeAppend("const vec4 src = vec4(1);");
- } else {
- fragBuilder->codeAppendf("vec4 src = %s;", srcColor);
- }
-
- fragBuilder->codeAppendf("vec4 dst = %s;", dstColor);
- fragBuilder->codeAppendf("%s = %s.x * src * dst + %s.y * src + %s.z * dst + %s.w;",
- outputColor, kUni, kUni, kUni, kUni);
- fragBuilder->codeAppendf("%s = clamp(%s, 0.0, 1.0);\n", outputColor, outputColor);
- if (enforcePMColor) {
- fragBuilder->codeAppendf("%s.rgb = min(%s.rgb, %s.a);",
- outputColor, outputColor, outputColor);
- }
-}
-
-class GLArithmeticFP : public GrGLSLFragmentProcessor {
-public:
- void emitCode(EmitArgs& args) override {
- const GrArithmeticFP& arith = args.fFp.cast<GrArithmeticFP>();
-
- GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
- SkString dstColor("dstColor");
- this->emitChild(0, nullptr, &dstColor, args);
-
- fKUni = args.fUniformHandler->addUniform(kFragment_GrShaderFlag,
- kVec4f_GrSLType, kDefault_GrSLPrecision,
- "k");
- const char* kUni = args.fUniformHandler->getUniformCStr(fKUni);
-
- add_arithmetic_code(fragBuilder,
- args.fInputColor,
- dstColor.c_str(),
- args.fOutputColor,
- kUni,
- arith.enforcePMColor());
- }
-
- static void GenKey(const GrProcessor& proc, const GrShaderCaps&, GrProcessorKeyBuilder* b) {
- const GrArithmeticFP& arith = proc.cast<GrArithmeticFP>();
- uint32_t key = arith.enforcePMColor() ? 1 : 0;
- b->add32(key);
- }
-
-protected:
- void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override {
- const GrArithmeticFP& arith = proc.cast<GrArithmeticFP>();
- pdman.set4f(fKUni, arith.k1(), arith.k2(), arith.k3(), arith.k4());
- }
-
-private:
- GrGLSLProgramDataManager::UniformHandle fKUni;
-
- typedef GrGLSLFragmentProcessor INHERITED;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-
-GrArithmeticFP::GrArithmeticFP(float k1, float k2, float k3, float k4, bool enforcePMColor,
- sk_sp<GrFragmentProcessor> dst)
- : fK1(k1), fK2(k2), fK3(k3), fK4(k4), fEnforcePMColor(enforcePMColor) {
- this->initClassID<GrArithmeticFP>();
-
- SkASSERT(dst);
- SkDEBUGCODE(int dstIndex = )this->registerChildProcessor(std::move(dst));
- SkASSERT(0 == dstIndex);
-}
-
-void GrArithmeticFP::onGetGLSLProcessorKey(const GrShaderCaps& caps,
- GrProcessorKeyBuilder* b) const {
- GLArithmeticFP::GenKey(*this, caps, b);
-}
-
-GrGLSLFragmentProcessor* GrArithmeticFP::onCreateGLSLInstance() const {
- return new GLArithmeticFP;
-}
-
-bool GrArithmeticFP::onIsEqual(const GrFragmentProcessor& fpBase) const {
- const GrArithmeticFP& fp = fpBase.cast<GrArithmeticFP>();
- return fK1 == fp.fK1 &&
- fK2 == fp.fK2 &&
- fK3 == fp.fK3 &&
- fK4 == fp.fK4 &&
- fEnforcePMColor == fp.fEnforcePMColor;
-}
-
-void GrArithmeticFP::onComputeInvariantOutput(GrInvariantOutput* inout) const {
- // TODO: optimize this
- inout->setToUnknown(GrInvariantOutput::kWill_ReadInput);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-sk_sp<GrFragmentProcessor> GrArithmeticFP::TestCreate(GrProcessorTestData* d) {
- float k1 = d->fRandom->nextF();
- float k2 = d->fRandom->nextF();
- float k3 = d->fRandom->nextF();
- float k4 = d->fRandom->nextF();
- bool enforcePMColor = d->fRandom->nextBool();
-
- sk_sp<GrFragmentProcessor> dst(GrProcessorUnitTest::MakeChildFP(d));
- return GrArithmeticFP::Make(k1, k2, k3, k4, enforcePMColor, std::move(dst));
-}
-
-GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrArithmeticFP);
-
-///////////////////////////////////////////////////////////////////////////////
-// Xfer Processor
-///////////////////////////////////////////////////////////////////////////////
-
-class ArithmeticXP : public GrXferProcessor {
-public:
- ArithmeticXP(const DstTexture*, bool hasMixedSamples,
- float k1, float k2, float k3, float k4, bool enforcePMColor);
-
- const char* name() const override { return "Arithmetic"; }
-
- GrGLSLXferProcessor* createGLSLInstance() const override;
-
- float k1() const { return fK1; }
- float k2() const { return fK2; }
- float k3() const { return fK3; }
- float k4() const { return fK4; }
- bool enforcePMColor() const { return fEnforcePMColor; }
-
-private:
- GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineAnalysis&,
- bool doesStencilWrite,
- GrColor* overrideColor,
- const GrCaps& caps) const override;
-
- void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
-
- bool onIsEqual(const GrXferProcessor& xpBase) const override {
- const ArithmeticXP& xp = xpBase.cast<ArithmeticXP>();
- if (fK1 != xp.fK1 ||
- fK2 != xp.fK2 ||
- fK3 != xp.fK3 ||
- fK4 != xp.fK4 ||
- fEnforcePMColor != xp.fEnforcePMColor) {
- return false;
- }
- return true;
- }
-
- float fK1, fK2, fK3, fK4;
- bool fEnforcePMColor;
-
- typedef GrXferProcessor INHERITED;
-};
-
-#endif
diff --git a/src/effects/SkArithmeticMode_gpu.h b/src/effects/SkArithmeticMode_gpu.h
deleted file mode 100644
index f7ded9becd..0000000000
--- a/src/effects/SkArithmeticMode_gpu.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2015 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkArithmeticMode_gpu_DEFINED
-#define SkArithmeticMode_gpu_DEFINED
-
-#include "SkTypes.h"
-
-#if SK_SUPPORT_GPU
-
-#include "GrCaps.h"
-#include "GrCoordTransform.h"
-#include "GrFragmentProcessor.h"
-#include "GrTypes.h"
-#include "GrXferProcessor.h"
-
-class GrInvariantOutput;
-class GrProcOptInfo;
-class GrTexture;
-
-///////////////////////////////////////////////////////////////////////////////
-// Fragment Processor
-///////////////////////////////////////////////////////////////////////////////
-
-class GrGLArtithmeticFP;
-
-class GrArithmeticFP : public GrFragmentProcessor {
-public:
- static sk_sp<GrFragmentProcessor> Make(float k1, float k2, float k3, float k4,
- bool enforcePMColor, sk_sp<GrFragmentProcessor> dst) {
- return sk_sp<GrFragmentProcessor>(new GrArithmeticFP(k1, k2, k3, k4, enforcePMColor,
- std::move(dst)));
- }
-
- ~GrArithmeticFP() override {}
-
- const char* name() const override { return "Arithmetic"; }
-
- SkString dumpInfo() const override {
- SkString str;
- str.appendf("K1: %.2f K2: %.2f K3: %.2f K4: %.2f", fK1, fK2, fK3, fK4);
- return str;
- }
-
- float k1() const { return fK1; }
- float k2() const { return fK2; }
- float k3() const { return fK3; }
- float k4() const { return fK4; }
- bool enforcePMColor() const { return fEnforcePMColor; }
-
-private:
- GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
-
- void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
-
- bool onIsEqual(const GrFragmentProcessor&) const override;
-
- void onComputeInvariantOutput(GrInvariantOutput* inout) const override;
-
- GrArithmeticFP(float k1, float k2, float k3, float k4, bool enforcePMColor,
- sk_sp<GrFragmentProcessor> dst);
-
- float fK1, fK2, fK3, fK4;
- bool fEnforcePMColor;
-
- GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
- typedef GrFragmentProcessor INHERITED;
-};
-
-#endif
-#endif
diff --git a/src/effects/SkXfermodeImageFilter.cpp b/src/effects/SkXfermodeImageFilter.cpp
index d90cb91cbc..24086197ea 100644
--- a/src/effects/SkXfermodeImageFilter.cpp
+++ b/src/effects/SkXfermodeImageFilter.cpp
@@ -6,8 +6,8 @@
*/
#include "SkXfermodeImageFilter.h"
+#include "SkArithmeticImageFilter.h"
#include "SkArithmeticModePriv.h"
-
#include "SkCanvas.h"
#include "SkColorPriv.h"
#include "SkReadBuffer.h"
@@ -22,7 +22,6 @@
#include "effects/GrConstColorProcessor.h"
#include "effects/GrTextureDomain.h"
#include "effects/GrSimpleTextureEffect.h"
-#include "SkArithmeticMode_gpu.h"
#include "SkGr.h"
#include "SkGrPriv.h"
#endif
@@ -52,12 +51,14 @@ protected:
void flatten(SkWriteBuffer&) const override;
- virtual void drawForeground(SkCanvas* canvas, SkSpecialImage*, const SkIRect&) const;
+ void drawForeground(SkCanvas* canvas, SkSpecialImage*, const SkIRect&) const;
#if SK_SUPPORT_GPU
- virtual sk_sp<GrFragmentProcessor> makeFGFrag(sk_sp<GrFragmentProcessor> bgFP) const;
+ sk_sp<GrFragmentProcessor> makeFGFrag(sk_sp<GrFragmentProcessor> bgFP) const;
#endif
private:
+ static sk_sp<SkFlattenable> LegacyArithmeticCreateProc(SkReadBuffer& buffer);
+
SkBlendMode fMode;
friend class SkXfermodeImageFilter;
@@ -108,10 +109,9 @@ sk_sp<SkFlattenable> SkXfermodeImageFilter_Base::CreateProc(SkReadBuffer& buffer
return SkXfermodeImageFilter::Make((SkBlendMode)mode, common.getInput(0),
common.getInput(1), &common.cropRect());
} else {
- return SkXfermodeImageFilter::MakeArithmetic(arith.fK[0], arith.fK[1], arith.fK[2],
- arith.fK[3], arith.fEnforcePMColor,
- common.getInput(0),
- common.getInput(1), &common.cropRect());
+ return SkArithmeticImageFilter::Make(arith.fK[0], arith.fK[1], arith.fK[2], arith.fK[3],
+ arith.fEnforcePMColor, common.getInput(0),
+ common.getInput(1), &common.cropRect());
}
}
@@ -337,196 +337,23 @@ SkXfermodeImageFilter_Base::makeFGFrag(sk_sp<GrFragmentProcessor> bgFP) const {
}
#endif
-
///////////////////////////////////////////////////////////////////////////////////////////////////
-class SkArithmeticImageFilter : public SkXfermodeImageFilter_Base {
-public:
- SkArithmeticImageFilter(float k1, float k2, float k3, float k4, bool enforcePMColor,
- sk_sp<SkImageFilter> inputs[2], const CropRect* cropRect)
- // need to pass a blendmode to our inherited constructor, but we ignore it
- : SkXfermodeImageFilter_Base(SkBlendMode::kSrcOver, inputs, cropRect)
- , fK{ k1, k2, k3, k4 }
- , fEnforcePMColor(enforcePMColor)
- {}
-
- SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkArithmeticImageFilter)
-
-protected:
- void flatten(SkWriteBuffer& buffer) const override {
- this->INHERITED::flatten(buffer);
- for (int i = 0; i < 4; ++i) {
- buffer.writeScalar(fK[i]);
- }
- buffer.writeBool(fEnforcePMColor);
- }
- void drawForeground(SkCanvas* canvas, SkSpecialImage*, const SkIRect&) const override;
-#if SK_SUPPORT_GPU
- sk_sp<GrFragmentProcessor> makeFGFrag(sk_sp<GrFragmentProcessor> bgFP) const override {
- return GrArithmeticFP::Make(fK[0], fK[1], fK[2], fK[3], fEnforcePMColor, std::move(bgFP));
- }
-#endif
-
-private:
- const float fK[4];
- const bool fEnforcePMColor;
-
- friend class SkXfermodeImageFilter;
-
- typedef SkXfermodeImageFilter_Base INHERITED;
-};
-
-sk_sp<SkFlattenable> SkArithmeticImageFilter::CreateProc(SkReadBuffer& buffer) {
+sk_sp<SkFlattenable> SkXfermodeImageFilter_Base::LegacyArithmeticCreateProc(SkReadBuffer& buffer) {
SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 2);
-
- // skip the mode (srcover) our parent-class wrote
+ // skip the unused mode (srcover) field
SkDEBUGCODE(int mode =) unflatten_blendmode(buffer, nullptr);
if (!buffer.isValid()) {
return nullptr;
}
SkASSERT(SkBlendMode::kSrcOver == (SkBlendMode)mode);
-
float k[4];
for (int i = 0; i < 4; ++i) {
k[i] = buffer.readScalar();
}
const bool enforcePMColor = buffer.readBool();
- return SkXfermodeImageFilter::MakeArithmetic(k[0], k[1], k[2], k[3], enforcePMColor,
- common.getInput(0), common.getInput(1),
- &common.cropRect());
-}
-
-#include "SkNx.h"
-
-static Sk4f pin(float min, const Sk4f& val, float max) {
- return Sk4f::Max(min, Sk4f::Min(val, max));
-}
-
-template<bool EnforcePMColor> void arith_span(const float k[], SkPMColor dst[],
- const SkPMColor src[], int count) {
- const Sk4f k1 = k[0] * (1/255.0f),
- k2 = k[1],
- k3 = k[2],
- k4 = k[3] * 255.0f + 0.5f;
-
- for (int i = 0; i < count; i++) {
- Sk4f s = SkNx_cast<float>(Sk4b::Load(src+i)),
- d = SkNx_cast<float>(Sk4b::Load(dst+i)),
- r = pin(0, k1*s*d + k2*s + k3*d + k4, 255);
- if (EnforcePMColor) {
- Sk4f a = SkNx_shuffle<3,3,3,3>(r);
- r = Sk4f::Min(a, r);
- }
- SkNx_cast<uint8_t>(r).store(dst+i);
- }
-}
-
-// apply mode to src==transparent (0)
-template<bool EnforcePMColor> void arith_transparent(const float k[], SkPMColor dst[], int count) {
- const Sk4f k3 = k[2],
- k4 = k[3] * 255.0f + 0.5f;
-
- for (int i = 0; i < count; i++) {
- Sk4f d = SkNx_cast<float>(Sk4b::Load(dst+i)),
- r = pin(0, k3*d + k4, 255);
- if (EnforcePMColor) {
- Sk4f a = SkNx_shuffle<3,3,3,3>(r);
- r = Sk4f::Min(a, r);
- }
- SkNx_cast<uint8_t>(r).store(dst+i);
- }
-}
-
-static bool intersect(SkPixmap* dst, SkPixmap* src, int srcDx, int srcDy) {
- SkIRect dstR = SkIRect::MakeWH(dst->width(), dst->height());
- SkIRect srcR = SkIRect::MakeXYWH(srcDx, srcDy, src->width(), src->height());
- SkIRect sect;
- if (!sect.intersect(dstR, srcR)) {
- return false;
- }
- *dst = SkPixmap(dst->info().makeWH(sect.width(), sect.height()),
- dst->addr(sect.fLeft, sect.fTop),
- dst->rowBytes());
- *src = SkPixmap(src->info().makeWH(sect.width(), sect.height()),
- src->addr(SkTMax(0, -srcDx), SkTMax(0, -srcDy)),
- src->rowBytes());
- return true;
-}
-
-void SkArithmeticImageFilter::drawForeground(SkCanvas* canvas, SkSpecialImage* img,
- const SkIRect& fgBounds) const {
- SkPixmap dst;
- if (!canvas->peekPixels(&dst)) {
- return;
- }
-
- const SkMatrix& ctm = canvas->getTotalMatrix();
- SkASSERT(ctm.getType() <= SkMatrix::kTranslate_Mask);
- const int dx = SkScalarRoundToInt(ctm.getTranslateX());
- const int dy = SkScalarRoundToInt(ctm.getTranslateY());
-
- if (img) {
- SkBitmap srcBM;
- SkPixmap src;
- if (!img->getROPixels(&srcBM)) {
- return;
- }
- srcBM.lockPixels();
- if (!srcBM.peekPixels(&src)) {
- return;
- }
-
- auto proc = fEnforcePMColor ? arith_span<true> : arith_span<false>;
- SkPixmap tmpDst = dst;
- if (intersect(&tmpDst, &src, fgBounds.fLeft + dx, fgBounds.fTop + dy)) {
- for (int y = 0; y < tmpDst.height(); ++y) {
- proc(fK, tmpDst.writable_addr32(0, y), src.addr32(0, y), tmpDst.width());
- }
- }
- }
-
- // Now apply the mode with transparent-color to the outside of the fg image
- SkRegion outside(SkIRect::MakeWH(dst.width(), dst.height()));
- outside.op(fgBounds.makeOffset(dx, dy), SkRegion::kDifference_Op);
- auto proc = fEnforcePMColor ? arith_transparent<true> : arith_transparent<false>;
- for (SkRegion::Iterator iter(outside); !iter.done(); iter.next()) {
- const SkIRect r = iter.rect();
- for (int y = r.fTop; y < r.fBottom; ++y) {
- proc(fK, dst.writable_addr32(r.fLeft, y), r.width());
- }
- }
-}
-
-sk_sp<SkImageFilter> SkXfermodeImageFilter::MakeArithmetic(float k1, float k2, float k3, float k4,
- bool enforcePMColor,
- sk_sp<SkImageFilter> background,
- sk_sp<SkImageFilter> foreground,
- const SkImageFilter::CropRect* crop) {
- if (!SkScalarIsFinite(k1) || !SkScalarIsFinite(k2) ||
- !SkScalarIsFinite(k3) || !SkScalarIsFinite(k4)) {
- return nullptr;
- }
-
- // are we nearly some other "std" mode?
- int mode = -1; // illegal mode
- if (SkScalarNearlyZero(k1) && SkScalarNearlyEqual(k2, SK_Scalar1) &&
- SkScalarNearlyZero(k3) && SkScalarNearlyZero(k4)) {
- mode = (int)SkBlendMode::kSrc;
- } else if (SkScalarNearlyZero(k1) && SkScalarNearlyZero(k2) &&
- SkScalarNearlyEqual(k3, SK_Scalar1) && SkScalarNearlyZero(k4)) {
- mode = (int)SkBlendMode::kDst;
- } else if (SkScalarNearlyZero(k1) && SkScalarNearlyZero(k2) &&
- SkScalarNearlyZero(k3) && SkScalarNearlyZero(k4)) {
- mode = (int)SkBlendMode::kClear;
- }
- if (mode >= 0) {
- return SkXfermodeImageFilter::Make((SkBlendMode)mode,
- std::move(background), std::move(foreground), crop);
- }
-
- sk_sp<SkImageFilter> inputs[2] = { std::move(background), std::move(foreground) };
- return sk_sp<SkImageFilter>(new SkArithmeticImageFilter(k1, k2, k3, k4, enforcePMColor,
- inputs, crop));
+ return SkArithmeticImageFilter::Make(k[0], k[1], k[2], k[3], enforcePMColor, common.getInput(0),
+ common.getInput(1), &common.cropRect());
}
///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -536,5 +363,9 @@ SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkXfermodeImageFilter)
// manually register the legacy serialized name "SkXfermodeImageFilter"
SkFlattenable::Register("SkXfermodeImageFilter", SkXfermodeImageFilter_Base::CreateProc,
SkFlattenable::kSkImageFilter_Type);
- SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkArithmeticImageFilter)
+ // manually register the legacy serialized name "SkArithmeticImageFilter" from when that filter
+ // was implemented as a xfermode image filter.
+ SkFlattenable::Register("SkArithmeticImageFilter",
+ SkXfermodeImageFilter_Base::LegacyArithmeticCreateProc,
+ SkFlattenable::kSkImageFilter_Type);
SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
diff --git a/src/ports/SkGlobalInitialization_default.cpp b/src/ports/SkGlobalInitialization_default.cpp
index 0a4e8f6a36..abf318af52 100644
--- a/src/ports/SkGlobalInitialization_default.cpp
+++ b/src/ports/SkGlobalInitialization_default.cpp
@@ -108,6 +108,7 @@ void SkFlattenable::PrivateInitializer::InitEffects() {
// ImageFilter
SkImageFilter::InitializeFlattenables();
+ SkArithmeticImageFilter::InitializeFlattenables();
SkXfermodeImageFilter::InitializeFlattenables();
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDilateImageFilter)
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDisplacementMapEffect)