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>
This commit is contained in:
Mike Reed 2018-01-18 16:06:54 -05:00 committed by Skia Commit-Bot
parent e97e792c79
commit 6e87eee2a0
6 changed files with 202 additions and 0 deletions

57
gm/shadermaskfilter.cpp Normal file
View File

@ -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());
}

View File

@ -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",

View File

@ -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",

View File

@ -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

View File

@ -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

View File

@ -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)