diff options
author | Mike Reed <reed@google.com> | 2018-01-18 16:06:54 -0500 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-01-18 21:24:38 +0000 |
commit | 6e87eee2a0494e11610e5535427a9f86ccffa4bb (patch) | |
tree | d035bf913332edbcd746527cdc211c6938eb609d | |
parent | e97e792c79afd01fe1d83e5d1e94918145794c54 (diff) |
add shadermaskfilter
next steps:
- gpu impl (will look a lot like shader's asFragProcessor
- special-case rect-input (?)
- explore stages w/ mtklein
Bug: skia:7500
Change-Id: I71089e421d32443a3ddded6967b3e5bc67ed43f2
Reviewed-on: https://skia-review.googlesource.com/95104
Commit-Queue: Mike Reed <reed@google.com>
Reviewed-by: Florin Malita <fmalita@chromium.org>
Reviewed-by: Brian Salomon <bsalomon@google.com>
-rw-r--r-- | gm/shadermaskfilter.cpp | 57 | ||||
-rw-r--r-- | gn/effects.gni | 1 | ||||
-rw-r--r-- | gn/gm.gni | 1 | ||||
-rw-r--r-- | include/effects/SkShaderMaskFilter.h | 24 | ||||
-rw-r--r-- | src/effects/SkShaderMaskFilter.cpp | 117 | ||||
-rw-r--r-- | src/ports/SkGlobalInitialization_default.cpp | 2 |
6 files changed, 202 insertions, 0 deletions
diff --git a/gm/shadermaskfilter.cpp b/gm/shadermaskfilter.cpp new file mode 100644 index 0000000000..35d8fd7040 --- /dev/null +++ b/gm/shadermaskfilter.cpp @@ -0,0 +1,57 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "gm.h" +#include "sk_tool_utils.h" +#include "SkCanvas.h" +#include "SkImage.h" +#include "SkShaderMaskFilter.h" + +static void draw_masked_image(SkCanvas* canvas, const SkImage* image, SkScalar x, SkScalar y, + const SkImage* mask) { + SkMatrix matrix = SkMatrix::MakeScale(SkIntToScalar(image->width()) / mask->width(), + SkIntToScalar(image->height() / mask->height())); + SkPaint paint; + paint.setMaskFilter(SkShaderMaskFilter::Make(mask->makeShader(&matrix))); + canvas->drawImage(image, x, y, &paint); +} + +#include "SkGradientShader.h" +static sk_sp<SkShader> make_shader(const SkRect& r) { + const SkPoint pts[] = { + { r.fLeft, r.fTop }, { r.fRight, r.fBottom }, + }; + const SkColor colors[] = { 0, SK_ColorWHITE }; + return SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkShader::kRepeat_TileMode); +} + +DEF_SIMPLE_GM(shadermaskfilter_gradient, canvas, 512, 512) { + SkRect r = { 0, 0, 100, 150 }; + auto shader = make_shader(r); + auto mf = SkShaderMaskFilter::Make(shader); + + canvas->translate(20, 20); + canvas->scale(2, 2); + + SkPaint paint; + paint.setMaskFilter(mf); + paint.setColor(SK_ColorRED); + canvas->drawOval(r, paint); +} + +#include "Resources.h" +DEF_SIMPLE_GM(shadermaskfilter_image, canvas, 512, 512) { + canvas->scale(1.25f, 1.25f); + + auto image = GetResourceAsImage("images/mandrill_128.png"); + auto mask = GetResourceAsImage("images/color_wheel.png"); + + canvas->drawImage(image, 10, 10, nullptr); + canvas->drawImage(mask, 10 + image->width() + 10.f, 10, nullptr); + + draw_masked_image(canvas, image.get(), 10, 10 + image->height() + 10.f, mask.get()); +} diff --git a/gn/effects.gni b/gn/effects.gni index da0ce8c06b..09fac9f474 100644 --- a/gn/effects.gni +++ b/gn/effects.gni @@ -52,6 +52,7 @@ skia_effects_sources = [ "$_src/effects/SkPaintImageFilter.cpp", "$_src/effects/SkPictureImageFilter.cpp", "$_src/effects/SkRRectsGaussianEdgeMaskFilter.cpp", + "$_src/effects/SkShaderMaskFilter.cpp", "$_src/effects/SkTableColorFilter.cpp", "$_src/effects/SkTableMaskFilter.cpp", "$_src/effects/SkTileImageFilter.cpp", @@ -263,6 +263,7 @@ gm_sources = [ "$_gm/samplerstress.cpp", "$_gm/savelayer.cpp", "$_gm/scaledstrokes.cpp", + "$_gm/shadermaskfilter.cpp", "$_gm/shadertext.cpp", "$_gm/shadertext2.cpp", "$_gm/shadertext3.cpp", diff --git a/include/effects/SkShaderMaskFilter.h b/include/effects/SkShaderMaskFilter.h new file mode 100644 index 0000000000..4ebc4fc468 --- /dev/null +++ b/include/effects/SkShaderMaskFilter.h @@ -0,0 +1,24 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkShaderMaskFilter_DEFINED +#define SkShaderMaskFilter_DEFINED + +#include "SkMaskFilter.h" + +class SkShader; + +class SK_API SkShaderMaskFilter { +public: + static sk_sp<SkMaskFilter> Make(sk_sp<SkShader> shader); + +private: + static void InitializeFlattenables(); + friend class SkFlattenable; +}; + +#endif diff --git a/src/effects/SkShaderMaskFilter.cpp b/src/effects/SkShaderMaskFilter.cpp new file mode 100644 index 0000000000..8693751899 --- /dev/null +++ b/src/effects/SkShaderMaskFilter.cpp @@ -0,0 +1,117 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkCanvas.h" +#include "SkReadBuffer.h" +#include "SkShaderMaskFilter.h" +#include "SkShader.h" +#include "SkString.h" + +class SkShaderMF : public SkMaskFilter { +public: + SkShaderMF(sk_sp<SkShader> shader) : fShader(std::move(shader)) {} + + SkMask::Format getFormat() const override { return SkMask::kA8_Format; } + + bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&, + SkIPoint* margin) const override; + + void computeFastBounds(const SkRect& src, SkRect* dst) const override { + *dst = src; + } + + bool asABlur(BlurRec*) const override { return false; } + + SK_TO_STRING_OVERRIDE() + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkShaderMF) + +private: + sk_sp<SkShader> fShader; + + SkShaderMF(SkReadBuffer&); + void flatten(SkWriteBuffer&) const override; + + friend class SkShaderMaskFilter; + + typedef SkMaskFilter INHERITED; +}; + +#ifndef SK_IGNORE_TO_STRING +void SkShaderMF::toString(SkString* str) const { + str->set("SkShaderMF:"); +} +#endif + +sk_sp<SkFlattenable> SkShaderMF::CreateProc(SkReadBuffer& buffer) { + return SkShaderMaskFilter::Make(buffer.readShader()); +} + +void SkShaderMF::flatten(SkWriteBuffer& buffer) const { + buffer.writeFlattenable(fShader.get()); +} + +static void rect_memcpy(void* dst, size_t dstRB, const void* src, size_t srcRB, + size_t copyBytes, int rows) { + for (int i = 0; i < rows; ++i) { + memcpy(dst, src, copyBytes); + dst = (char*)dst + dstRB; + src = (const char*)src + srcRB; + } +} + +bool SkShaderMF::filterMask(SkMask* dst, const SkMask& src, const SkMatrix& ctm, + SkIPoint* margin) const { + SkASSERT(src.fFormat == SkMask::kA8_Format); + + if (margin) { + margin->set(0, 0); + } + dst->fBounds = src.fBounds; + dst->fRowBytes = src.fBounds.width(); // need alignment? + dst->fFormat = SkMask::kA8_Format; + + if (src.fImage == nullptr) { + dst->fImage = nullptr; + return true; + } + size_t size = dst->computeImageSize(); + if (0 == size) { + return false; // too big to allocate, abort + } + + // Allocate and initialize dst image with a copy of the src image + dst->fImage = SkMask::AllocImage(size); + rect_memcpy(dst->fImage, dst->fRowBytes, src.fImage, src.fRowBytes, + src.fBounds.width() * sizeof(uint8_t), src.fBounds.height()); + + // Now we have a dst-mask, just need to setup a canvas and draw into it + SkBitmap bitmap; + if (!bitmap.installMaskPixels(*dst)) { + return false; + } + + SkPaint paint; + paint.setShader(fShader); + // this blendmode is the trick: we only draw the shader where the mask is + paint.setBlendMode(SkBlendMode::kSrcIn); + + SkCanvas canvas(bitmap); + canvas.translate(-SkIntToScalar(dst->fBounds.fLeft), -SkIntToScalar(dst->fBounds.fTop)); + canvas.concat(ctm); + canvas.drawPaint(paint); + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +sk_sp<SkMaskFilter> SkShaderMaskFilter::Make(sk_sp<SkShader> shader) { + return shader ? sk_sp<SkMaskFilter>(new SkShaderMF(std::move(shader))) : nullptr; +} + +SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkShaderMaskFilter) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkShaderMF) +SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END diff --git a/src/ports/SkGlobalInitialization_default.cpp b/src/ports/SkGlobalInitialization_default.cpp index c1256ef85c..a98083aa7f 100644 --- a/src/ports/SkGlobalInitialization_default.cpp +++ b/src/ports/SkGlobalInitialization_default.cpp @@ -37,6 +37,7 @@ #include "SkPerlinNoiseShader.h" #include "SkPictureImageFilter.h" #include "SkRRectsGaussianEdgeMaskFilter.h" +#include "SkShaderMaskFilter.h" #include "SkTableColorFilter.h" #include "SkTileImageFilter.h" #include "SkToSRGBColorFilter.h" @@ -64,6 +65,7 @@ void SkFlattenable::PrivateInitializer::InitEffects() { SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkEmbossMaskFilter) SkBlurMaskFilter::InitializeFlattenables(); SkRRectsGaussianEdgeMaskFilter::InitializeFlattenables(); + SkShaderMaskFilter::InitializeFlattenables(); // DrawLooper SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLayerDrawLooper) |