Arithmetic blender
... to aid in removing special ArithmeticImageFilter. Can we use something like this to reimpl the ArithmeticImageFilter --> BlenderImageFilter? I see some special checking in filterBounds for ArithIF -- is that required? Is that generalizable for any BlenderImageFilter? If we can generalize blend[er]imagefilter, let's just move this logic into Chrome -- no need for Arithmetic to appear in Skia in any form! Re: https://skia-review.googlesource.com/c/skia/+/424436 Change-Id: Ifa0ff2fa25de6385f6f60505e73ecc28463a80b3 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/424417 Commit-Queue: Mike Reed <reed@google.com> Reviewed-by: Florin Malita <fmalita@chromium.org>
This commit is contained in:
parent
8c26479048
commit
26ea975e6c
@ -30,15 +30,12 @@
|
||||
|
||||
#include <utility>
|
||||
|
||||
#define WW 100
|
||||
#define HH 32
|
||||
|
||||
static sk_sp<SkImage> make_src() {
|
||||
sk_sp<SkSurface> surface(SkSurface::MakeRasterN32Premul(WW, HH));
|
||||
static sk_sp<SkImage> make_src(int w, int h) {
|
||||
sk_sp<SkSurface> surface(SkSurface::MakeRasterN32Premul(w, h));
|
||||
SkCanvas* canvas = surface->getCanvas();
|
||||
|
||||
SkPaint paint;
|
||||
SkPoint pts[] = { {0, 0}, {SkIntToScalar(WW), SkIntToScalar(HH)} };
|
||||
SkPoint pts[] = { {0, 0}, {SkIntToScalar(w), SkIntToScalar(h)} };
|
||||
SkColor colors[] = {
|
||||
SK_ColorTRANSPARENT, SK_ColorGREEN, SK_ColorCYAN,
|
||||
SK_ColorRED, SK_ColorMAGENTA, SK_ColorWHITE,
|
||||
@ -49,12 +46,12 @@ static sk_sp<SkImage> make_src() {
|
||||
return surface->makeImageSnapshot();
|
||||
}
|
||||
|
||||
static sk_sp<SkImage> make_dst() {
|
||||
sk_sp<SkSurface> surface(SkSurface::MakeRasterN32Premul(WW, HH));
|
||||
static sk_sp<SkImage> make_dst(int w, int h) {
|
||||
sk_sp<SkSurface> surface(SkSurface::MakeRasterN32Premul(w, h));
|
||||
SkCanvas* canvas = surface->getCanvas();
|
||||
|
||||
SkPaint paint;
|
||||
SkPoint pts[] = { {0, SkIntToScalar(HH)}, {SkIntToScalar(WW), 0} };
|
||||
SkPoint pts[] = { {0, SkIntToScalar(h)}, {SkIntToScalar(w), 0} };
|
||||
SkColor colors[] = {
|
||||
SK_ColorBLUE, SK_ColorYELLOW, SK_ColorBLACK, SK_ColorGREEN,
|
||||
SK_ColorGRAY,
|
||||
@ -85,8 +82,11 @@ class ArithmodeGM : public skiagm::GM {
|
||||
SkISize onISize() override { return {640, 572}; }
|
||||
|
||||
void onDraw(SkCanvas* canvas) override {
|
||||
sk_sp<SkImage> src = make_src();
|
||||
sk_sp<SkImage> dst = make_dst();
|
||||
constexpr int WW = 100,
|
||||
HH = 32;
|
||||
|
||||
sk_sp<SkImage> src = make_src(WW, HH);
|
||||
sk_sp<SkImage> dst = make_dst(WW, HH);
|
||||
sk_sp<SkImageFilter> srcFilter = SkImageFilters::Image(src);
|
||||
sk_sp<SkImageFilter> dstFilter = SkImageFilters::Image(dst);
|
||||
|
||||
@ -166,7 +166,66 @@ class ArithmodeGM : public skiagm::GM {
|
||||
private:
|
||||
using INHERITED = GM;
|
||||
};
|
||||
DEF_GM( return new ArithmodeGM; )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DEF_GM( return new ArithmodeGM; )
|
||||
#include "include/effects/SkBlenders.h"
|
||||
|
||||
class Arithmode2GM : public skiagm::GM {
|
||||
float fK1, fK2, fK3, fK4;
|
||||
sk_sp<SkImage> fSrc, fDst, fChecker;
|
||||
|
||||
SkString onShortName() override { return SkString("arithmode_blender"); }
|
||||
|
||||
SkISize onISize() override { return {430, 430}; }
|
||||
|
||||
enum {
|
||||
W = 200,
|
||||
H = 200,
|
||||
};
|
||||
|
||||
void onOnceBeforeDraw() override {
|
||||
// need something interesting, in case we're drawn w/o calling animate()
|
||||
fK1 = -0.25f;
|
||||
fK2 = 0.25f;
|
||||
fK3 = 0.25f;
|
||||
fK4 = 0;
|
||||
|
||||
fSrc = make_src(W, H);
|
||||
fDst = make_dst(W, H);
|
||||
|
||||
fChecker = ToolUtils::create_checkerboard_image(W, H, 0xFF999999, 0xFFCCCCCC, 8);
|
||||
}
|
||||
|
||||
bool onAnimate(double nanos) override {
|
||||
double theta = nanos * 1e-6 * 0.001;
|
||||
fK1 = sin(theta + 0) * 0.25;
|
||||
fK2 = cos(theta + 1) * 0.25;
|
||||
fK3 = sin(theta + 2) * 0.25;
|
||||
fK4 = 0.5;
|
||||
return true;
|
||||
}
|
||||
|
||||
void onDraw(SkCanvas* canvas) override {
|
||||
const SkRect rect = SkRect::MakeWH(W, H);
|
||||
|
||||
canvas->drawImage(fSrc, 10, 10);
|
||||
canvas->drawImage(fDst, 10, 10 + fSrc->height() + 10);
|
||||
|
||||
canvas->translate(10 + fSrc->width() + 10, 10);
|
||||
canvas->drawImage(fChecker, 0, 0);
|
||||
|
||||
SkPaint paint;
|
||||
paint.setBlender(SkBlenders::Arithmetic(fK1, fK2, fK3, fK4, true));
|
||||
|
||||
canvas->saveLayer(&rect, nullptr);
|
||||
canvas->drawImage(fDst, 0, 0);
|
||||
canvas->drawImage(fSrc, 0, 0, SkSamplingOptions(), &paint);
|
||||
canvas->restore();
|
||||
}
|
||||
|
||||
private:
|
||||
using INHERITED = GM;
|
||||
};
|
||||
DEF_GM( return new Arithmode2GM; )
|
||||
|
@ -10,6 +10,7 @@ _include = get_path_info("../include", "abspath")
|
||||
skia_effects_public = [
|
||||
"$_include/effects/Sk1DPathEffect.h",
|
||||
"$_include/effects/Sk2DPathEffect.h",
|
||||
"$_include/effects/SkBlenders.h",
|
||||
"$_include/effects/SkBlurMaskFilter.h",
|
||||
"$_include/effects/SkColorMatrix.h",
|
||||
"$_include/effects/SkColorMatrixFilter.h",
|
||||
@ -31,6 +32,7 @@ skia_effects_sources = [
|
||||
"$_src/c/sk_effects.cpp",
|
||||
"$_src/effects/Sk1DPathEffect.cpp",
|
||||
"$_src/effects/Sk2DPathEffect.cpp",
|
||||
"$_src/effects/SkBlenders.cpp",
|
||||
"$_src/effects/SkColorMatrix.cpp",
|
||||
"$_src/effects/SkColorMatrixFilter.cpp",
|
||||
"$_src/effects/SkCornerPathEffect.cpp",
|
||||
|
27
include/effects/SkBlenders.h
Normal file
27
include/effects/SkBlenders.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2021 Google LLC
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkBlenders_DEFINED
|
||||
#define SkBlenders_DEFINED
|
||||
|
||||
#include "include/core/SkBlender.h"
|
||||
|
||||
class SK_API SkBlenders {
|
||||
public:
|
||||
/**
|
||||
* Create a blender that implements the following:
|
||||
* k1 * src * dst + k2 * src + k3 * dst + k4
|
||||
* @param k1, k2, k3, k4 The four coefficients.
|
||||
* @param enforcePMColor If true, the RGB channels will be clamped to the calculated alpha.
|
||||
*/
|
||||
static sk_sp<SkBlender> Arithmetic(float k1, float k2, float k3, float k4, bool enforcePremul);
|
||||
|
||||
private:
|
||||
SkBlenders() = delete;
|
||||
};
|
||||
|
||||
#endif
|
62
src/effects/SkBlenders.cpp
Normal file
62
src/effects/SkBlenders.cpp
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2021 Google LLC
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "include/effects/SkBlenders.h"
|
||||
#include "include/effects/SkRuntimeEffect.h"
|
||||
|
||||
sk_sp<SkBlender> SkBlenders::Arithmetic(float k1, float k2, float k3, float k4,
|
||||
bool enforcePremul) {
|
||||
if (!SkScalarIsFinite(k1) ||
|
||||
!SkScalarIsFinite(k2) ||
|
||||
!SkScalarIsFinite(k3) ||
|
||||
!SkScalarIsFinite(k4)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Are we nearly a SkBlendMode?
|
||||
const struct {
|
||||
float k1, k2, k3, k4;
|
||||
SkBlendMode mode;
|
||||
} table[] = {
|
||||
{ 0, 1, 0, 0, SkBlendMode::kSrc },
|
||||
{ 0, 0, 1, 0, SkBlendMode::kDst },
|
||||
{ 0, 0, 0, 0, SkBlendMode::kClear },
|
||||
};
|
||||
for (const auto& t : table) {
|
||||
if (SkScalarNearlyEqual(k1, t.k1) &&
|
||||
SkScalarNearlyEqual(k2, t.k2) &&
|
||||
SkScalarNearlyEqual(k3, t.k3) &&
|
||||
SkScalarNearlyEqual(k4, t.k4)) {
|
||||
return SkBlender::Mode(t.mode);
|
||||
}
|
||||
}
|
||||
|
||||
// If we get here, we need the actual blender effect.
|
||||
|
||||
static SkRuntimeEffect* gArithmeticEffect = []{
|
||||
const char prog[] = R"(
|
||||
uniform half4 k;
|
||||
uniform half pmClamp;
|
||||
|
||||
half4 main(half4 src, half4 dst) {
|
||||
half4 c = k.x * src * dst + k.y * src + k.z * dst + k.w;
|
||||
c.rgb = min(c.rgb, max(c.a, pmClamp));
|
||||
// rely on skia to saturate our alpha
|
||||
return c;
|
||||
}
|
||||
)";
|
||||
auto result = SkRuntimeEffect::MakeForBlender(SkString(prog));
|
||||
SkASSERTF(result.effect, "SkBlenders::Arithmetic: %s", result.errorText.c_str());
|
||||
return result.effect.release();
|
||||
}();
|
||||
|
||||
const float array[] = {
|
||||
k1, k2, k3, k4,
|
||||
enforcePremul ? 0.0f : 1.0f,
|
||||
};
|
||||
return gArithmeticEffect->makeBlender(SkData::MakeWithCopy(array, sizeof(array)));
|
||||
}
|
Loading…
Reference in New Issue
Block a user