Rudimentary SkRuntimeImageFilter
This is really just a runtime shader with a late-bound input. Bug: skia:12074 chromium:1213217 Change-Id: Ie92650a3e1e03d0c43ce4745eb33d49d582094f5 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/416476 Commit-Queue: Brian Osman <brianosman@google.com> Reviewed-by: Michael Ludwig <michaelludwig@google.com>
This commit is contained in:
parent
9e67891b72
commit
a784914e74
73
gm/runtimeimagefilter.cpp
Normal file
73
gm/runtimeimagefilter.cpp
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "gm/gm.h"
|
||||
#include "include/core/SkCanvas.h"
|
||||
#include "include/core/SkColor.h"
|
||||
#include "include/core/SkFont.h"
|
||||
#include "include/core/SkImageFilter.h"
|
||||
#include "include/core/SkImageInfo.h"
|
||||
#include "include/core/SkPaint.h"
|
||||
#include "include/core/SkPixelRef.h"
|
||||
#include "include/core/SkRect.h"
|
||||
#include "include/core/SkRefCnt.h"
|
||||
#include "include/core/SkScalar.h"
|
||||
#include "include/effects/SkImageFilters.h"
|
||||
#include "include/effects/SkRuntimeEffect.h"
|
||||
#include "include/utils/SkRandom.h"
|
||||
#include "src/effects/imagefilters/SkRuntimeImageFilter.h"
|
||||
#include "tools/ToolUtils.h"
|
||||
|
||||
static sk_sp<SkImageFilter> make_filter() {
|
||||
sk_sp<SkRuntimeEffect> effect = SkRuntimeEffect::MakeForShader(SkString(R"(
|
||||
uniform shader input;
|
||||
half4 main(float2 coord) {
|
||||
coord.x += sin(coord.y / 3) * 4;
|
||||
return sample(input, coord);
|
||||
}
|
||||
)")).effect;
|
||||
return SkMakeRuntimeImageFilter(std::move(effect),
|
||||
/*uniforms=*/nullptr,
|
||||
/*input=*/nullptr);
|
||||
}
|
||||
|
||||
DEF_SIMPLE_GM_BG(rtif_distort, canvas, 500, 750, SK_ColorBLACK) {
|
||||
SkRect clip = SkRect::MakeWH(250, 250);
|
||||
SkPaint filterPaint;
|
||||
filterPaint.setImageFilter(make_filter());
|
||||
|
||||
auto draw_layer = [&](SkScalar tx, SkScalar ty, SkMatrix m) {
|
||||
canvas->save();
|
||||
canvas->translate(tx, ty);
|
||||
canvas->clipRect(clip);
|
||||
canvas->concat(m);
|
||||
canvas->saveLayer(nullptr, &filterPaint);
|
||||
const char* str = "The quick brown fox jumped over the lazy dog.";
|
||||
SkRandom rand;
|
||||
SkFont font(ToolUtils::create_portable_typeface());
|
||||
for (int i = 0; i < 25; ++i) {
|
||||
int x = rand.nextULessThan(500);
|
||||
int y = rand.nextULessThan(500);
|
||||
SkPaint paint;
|
||||
paint.setColor(ToolUtils::color_to_565(rand.nextBits(24) | 0xFF000000));
|
||||
font.setSize(rand.nextRangeScalar(0, 300));
|
||||
canvas->drawString(str, SkIntToScalar(x), SkIntToScalar(y), font, paint);
|
||||
}
|
||||
canvas->restore();
|
||||
canvas->restore();
|
||||
};
|
||||
|
||||
draw_layer( 0, 0, SkMatrix::I());
|
||||
draw_layer(250, 0, SkMatrix::Scale(0.5f, 0.5f));
|
||||
draw_layer( 0, 250, SkMatrix::RotateDeg(45, {125, 125}));
|
||||
draw_layer(250, 250, SkMatrix::Scale(0.5f, 0.5f) * SkMatrix::RotateDeg(45, {125, 125}));
|
||||
draw_layer( 0, 500, SkMatrix::Skew(-0.5f, 0));
|
||||
SkMatrix p = SkMatrix::I();
|
||||
p.setPerspX(0.0015f);
|
||||
p.setPerspY(-0.0015f);
|
||||
draw_layer(250, 500, p);
|
||||
}
|
@ -26,6 +26,7 @@ skia_effects_imagefilter_sources = [
|
||||
"$_src/effects/imagefilters/SkMorphologyImageFilter.cpp",
|
||||
"$_src/effects/imagefilters/SkOffsetImageFilter.cpp",
|
||||
"$_src/effects/imagefilters/SkPictureImageFilter.cpp",
|
||||
"$_src/effects/imagefilters/SkRuntimeImageFilter.cpp",
|
||||
"$_src/effects/imagefilters/SkShaderImageFilter.cpp",
|
||||
"$_src/effects/imagefilters/SkTileImageFilter.cpp",
|
||||
]
|
||||
|
@ -325,6 +325,7 @@ gm_sources = [
|
||||
"$_gm/runtimecolorfilter.cpp",
|
||||
"$_gm/runtimeeffectimage.cpp",
|
||||
"$_gm/runtimefunctions.cpp",
|
||||
"$_gm/runtimeimagefilter.cpp",
|
||||
"$_gm/runtimeintrinsics.cpp",
|
||||
"$_gm/runtimeshader.cpp",
|
||||
"$_gm/samplerstress.cpp",
|
||||
|
@ -491,6 +491,7 @@ void SkRegisterMergeImageFilterFlattenable();
|
||||
void SkRegisterMorphologyImageFilterFlattenables();
|
||||
void SkRegisterOffsetImageFilterFlattenable();
|
||||
void SkRegisterPictureImageFilterFlattenable();
|
||||
void SkRegisterRuntimeImageFilterFlattenable();
|
||||
void SkRegisterShaderImageFilterFlattenable();
|
||||
void SkRegisterTileImageFilterFlattenable();
|
||||
|
||||
|
139
src/effects/imagefilters/SkRuntimeImageFilter.cpp
Normal file
139
src/effects/imagefilters/SkRuntimeImageFilter.cpp
Normal file
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* 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/core/SkCanvas.h"
|
||||
#include "include/core/SkPaint.h"
|
||||
#include "include/effects/SkImageFilters.h"
|
||||
#include "include/effects/SkRuntimeEffect.h"
|
||||
#include "src/core/SkImageFilter_Base.h"
|
||||
#include "src/core/SkReadBuffer.h"
|
||||
#include "src/core/SkRuntimeEffectPriv.h"
|
||||
#include "src/core/SkSpecialImage.h"
|
||||
#include "src/core/SkSpecialSurface.h"
|
||||
#include "src/core/SkWriteBuffer.h"
|
||||
#include "src/effects/imagefilters/SkRuntimeImageFilter.h"
|
||||
|
||||
namespace {
|
||||
|
||||
class SkRuntimeImageFilter final : public SkImageFilter_Base {
|
||||
public:
|
||||
SkRuntimeImageFilter(sk_sp<SkRuntimeEffect> effect,
|
||||
sk_sp<SkData> uniforms,
|
||||
sk_sp<SkImageFilter> input)
|
||||
: INHERITED(&input, 1, /*cropRect=*/nullptr)
|
||||
, fEffect(std::move(effect))
|
||||
, fUniforms(std::move(uniforms)) {}
|
||||
|
||||
bool affectsTransparentBlack() const override { return true; }
|
||||
MatrixCapability onGetCTMCapability() const override { return MatrixCapability::kTranslate; }
|
||||
|
||||
protected:
|
||||
void flatten(SkWriteBuffer&) const override;
|
||||
sk_sp<SkSpecialImage> onFilterImage(const Context&, SkIPoint* offset) const override;
|
||||
|
||||
private:
|
||||
friend void ::SkRegisterRuntimeImageFilterFlattenable();
|
||||
SK_FLATTENABLE_HOOKS(SkRuntimeImageFilter)
|
||||
|
||||
sk_sp<SkRuntimeEffect> fEffect;
|
||||
sk_sp<SkData> fUniforms;
|
||||
|
||||
using INHERITED = SkImageFilter_Base;
|
||||
};
|
||||
|
||||
} // end namespace
|
||||
|
||||
sk_sp<SkImageFilter> SkMakeRuntimeImageFilter(sk_sp<SkRuntimeEffect> effect,
|
||||
sk_sp<SkData> uniforms,
|
||||
sk_sp<SkImageFilter> input) {
|
||||
// Rather than replicate all of the checks from makeShader here, just try to create a shader
|
||||
// once, to determine if everything is valid.
|
||||
sk_sp<SkShader> child = nullptr;
|
||||
auto shader = effect->makeShader(uniforms, &child, 1, nullptr, false);
|
||||
if (!shader) {
|
||||
// Could be wrong signature, wrong uniform block size, wrong number/type of children, etc...
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return sk_sp<SkImageFilter>(
|
||||
new SkRuntimeImageFilter(std::move(effect), std::move(uniforms), std::move(input)));
|
||||
}
|
||||
|
||||
void SkRegisterRuntimeImageFilterFlattenable() {
|
||||
SK_REGISTER_FLATTENABLE(SkRuntimeImageFilter);
|
||||
}
|
||||
|
||||
sk_sp<SkFlattenable> SkRuntimeImageFilter::CreateProc(SkReadBuffer& buffer) {
|
||||
SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
|
||||
SkString sksl;
|
||||
buffer.readString(&sksl);
|
||||
sk_sp<SkData> uniforms = buffer.readByteArrayAsData();
|
||||
|
||||
auto effect = SkMakeCachedRuntimeEffect(SkRuntimeEffect::MakeForShader, std::move(sksl));
|
||||
if (!buffer.validate(effect != nullptr)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (common.cropRect()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return SkMakeRuntimeImageFilter(std::move(effect), std::move(uniforms), common.getInput(0));
|
||||
}
|
||||
|
||||
void SkRuntimeImageFilter::flatten(SkWriteBuffer& buffer) const {
|
||||
this->INHERITED::flatten(buffer);
|
||||
buffer.writeString(fEffect->source().c_str());
|
||||
buffer.writeDataAsByteArray(fUniforms.get());
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
sk_sp<SkSpecialImage> SkRuntimeImageFilter::onFilterImage(const Context& ctx,
|
||||
SkIPoint* offset) const {
|
||||
SkIPoint inputOffset = SkIPoint::Make(0, 0);
|
||||
sk_sp<SkSpecialImage> input(this->filterInput(0, ctx, &inputOffset));
|
||||
if (!input) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SkIRect outputBounds = SkIRect(ctx.desiredOutput());
|
||||
sk_sp<SkSpecialSurface> surf(ctx.makeSurface(outputBounds.size()));
|
||||
if (!surf) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SkMatrix ctm = ctx.ctm();
|
||||
SkMatrix inverse;
|
||||
SkAssertResult(ctm.invert(&inverse));
|
||||
|
||||
SkMatrix localM = inverse *
|
||||
SkMatrix::Translate(inputOffset) *
|
||||
SkMatrix::Translate(-input->subset().topLeft());
|
||||
sk_sp<SkShader> inputShader =
|
||||
input->asImage()->makeShader(SkSamplingOptions(SkFilterMode::kLinear), &localM);
|
||||
SkASSERT(inputShader);
|
||||
|
||||
auto shader = fEffect->makeShader(fUniforms, &inputShader, 1, nullptr, false);
|
||||
SkASSERT(shader);
|
||||
|
||||
SkPaint paint;
|
||||
paint.setShader(std::move(shader));
|
||||
paint.setBlendMode(SkBlendMode::kSrc);
|
||||
|
||||
SkCanvas* canvas = surf->getCanvas();
|
||||
SkASSERT(canvas);
|
||||
|
||||
// Translate from layer space into surf's image space
|
||||
canvas->translate(-outputBounds.fLeft, -outputBounds.fTop);
|
||||
// Ensure shader parameters are relative to parameter space, not layer space
|
||||
canvas->concat(ctx.ctm());
|
||||
|
||||
canvas->drawPaint(paint);
|
||||
|
||||
*offset = outputBounds.topLeft();
|
||||
return surf->makeImageSnapshot();
|
||||
}
|
22
src/effects/imagefilters/SkRuntimeImageFilter.h
Normal file
22
src/effects/imagefilters/SkRuntimeImageFilter.h
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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 SkRuntimeImageFilter_DEFINED
|
||||
#define SkRuntimeImageFilter_DEFINED
|
||||
|
||||
#include "include/core/SkRefCnt.h"
|
||||
|
||||
class SkData;
|
||||
class SkImageFilter;
|
||||
struct SkRect;
|
||||
class SkRuntimeEffect;
|
||||
|
||||
SK_API sk_sp<SkImageFilter> SkMakeRuntimeImageFilter(sk_sp<SkRuntimeEffect> effect,
|
||||
sk_sp<SkData> uniforms,
|
||||
sk_sp<SkImageFilter> input);
|
||||
|
||||
#endif
|
@ -130,6 +130,7 @@
|
||||
SkRegisterMorphologyImageFilterFlattenables();
|
||||
SkRegisterOffsetImageFilterFlattenable();
|
||||
SkRegisterPictureImageFilterFlattenable();
|
||||
SkRegisterRuntimeImageFilterFlattenable();
|
||||
SkRegisterShaderImageFilterFlattenable();
|
||||
SkRegisterTileImageFilterFlattenable();
|
||||
SK_REGISTER_FLATTENABLE(SkLocalMatrixImageFilter);
|
||||
|
Loading…
Reference in New Issue
Block a user