[Impeller] Aiks image filters; allow setting effect transforms after FilterContents instantiation. (flutter/engine#45530)

These are API improvements on the way to solving
https://github.com/flutter/flutter/issues/131182.

* Remove `effect_transform` and `is_subpass` from the static
`FilterContents` factories. These are for internal use only.
* Replace `impeller::Paint` filter procs with Aiks `ImageFilter`
factories similar to `ColorFilter`. This gives Aiks a simple interface
for constructing filters and prevents possible state cloning bugs when
copying filters into `EntityPass`.
* Allow for setting filter inputs, setting the effect transform, and
enabling subpass mode on a filter chain after it has been instantiated.
This will allow us to sample coverage in `EntityPass` without rendering
any snapshots using rect filter inputs.
This commit is contained in:
Brandon DeRosier
2023-09-07 23:54:45 -07:00
committed by GitHub
parent c0a795a6b1
commit 07803f501e
23 changed files with 687 additions and 267 deletions

View File

@@ -1029,6 +1029,8 @@ ORIGIN: ../../../flutter/impeller/aiks/color_source.cc + ../../../flutter/LICENS
ORIGIN: ../../../flutter/impeller/aiks/color_source.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/aiks/image.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/aiks/image.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/aiks/image_filter.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/aiks/image_filter.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/aiks/paint.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/aiks/paint.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/aiks/paint_pass_delegate.cc + ../../../flutter/LICENSE
@@ -3773,6 +3775,8 @@ FILE: ../../../flutter/impeller/aiks/color_source.cc
FILE: ../../../flutter/impeller/aiks/color_source.h
FILE: ../../../flutter/impeller/aiks/image.cc
FILE: ../../../flutter/impeller/aiks/image.h
FILE: ../../../flutter/impeller/aiks/image_filter.cc
FILE: ../../../flutter/impeller/aiks/image_filter.h
FILE: ../../../flutter/impeller/aiks/paint.cc
FILE: ../../../flutter/impeller/aiks/paint.h
FILE: ../../../flutter/impeller/aiks/paint_pass_delegate.cc

View File

@@ -16,6 +16,8 @@ impeller_component("aiks") {
"color_source.h",
"image.cc",
"image.h",
"image_filter.cc",
"image_filter.h",
"paint.cc",
"paint.h",
"paint_pass_delegate.cc",

View File

@@ -14,6 +14,7 @@
#include "impeller/aiks/aiks_playground.h"
#include "impeller/aiks/canvas.h"
#include "impeller/aiks/image.h"
#include "impeller/aiks/image_filter.h"
#include "impeller/aiks/paint_pass_delegate.h"
#include "impeller/aiks/testing/context_spy.h"
#include "impeller/core/capture.h"
@@ -2110,12 +2111,9 @@ TEST_P(AiksTest, PaintWithFilters) {
ASSERT_TRUE(paint.HasColorFilter());
paint.image_filter = [](const FilterInput::Ref& input,
const Matrix& effect_transform, bool is_subpass) {
return FilterContents::MakeGaussianBlur(
input, Sigma(1.0), Sigma(1.0), FilterContents::BlurStyle::kNormal,
Entity::TileMode::kClamp, effect_transform);
};
paint.image_filter = ImageFilter::MakeBlur(Sigma(1.0), Sigma(1.0),
FilterContents::BlurStyle::kNormal,
Entity::TileMode::kClamp);
ASSERT_TRUE(paint.HasColorFilter());
@@ -2141,12 +2139,9 @@ TEST_P(AiksTest, OpacityPeepHoleApplicationTest) {
ASSERT_FALSE(delegate->CanCollapseIntoParentPass(entity_pass.get()));
paint.color_filter = nullptr;
paint.image_filter = [](const FilterInput::Ref& input,
const Matrix& effect_transform, bool is_subpass) {
return FilterContents::MakeGaussianBlur(
input, Sigma(1.0), Sigma(1.0), FilterContents::BlurStyle::kNormal,
Entity::TileMode::kClamp, effect_transform);
};
paint.image_filter = ImageFilter::MakeBlur(Sigma(1.0), Sigma(1.0),
FilterContents::BlurStyle::kNormal,
Entity::TileMode::kClamp);
// Paint has image filter, can't elide.
delegate = std::make_shared<OpacityPeepholePassDelegate>(paint);
@@ -2313,11 +2308,9 @@ TEST_P(AiksTest, CollapsedDrawPaintInSubpassBackdropFilter) {
canvas.DrawPaint(
{.color = Color::Yellow(), .blend_mode = BlendMode::kSource});
canvas.SaveLayer({}, {},
[](const FilterInput::Ref& input,
const Matrix& effect_transform, bool is_subpass) {
return FilterContents::MakeGaussianBlur(input, Sigma(20.0),
Sigma(20.0));
});
ImageFilter::MakeBlur(Sigma(20.0), Sigma(20.0),
FilterContents::BlurStyle::kNormal,
Entity::TileMode::kDecal));
canvas.DrawPaint(
{.color = Color::CornflowerBlue(), .blend_mode = BlendMode::kSourceOver});
@@ -2515,12 +2508,8 @@ TEST_P(AiksTest, TranslucentSaveLayerWithBlendImageFilterDrawsCorrectly) {
canvas.SaveLayer({
.color = Color::Black().WithAlpha(0.5),
.image_filter =
[](FilterInput::Ref input, const Matrix& effect_transform,
bool is_subpass) {
return ColorFilterContents::MakeBlend(
BlendMode::kDestinationOver, {std::move(input)}, Color::Red());
},
.image_filter = ImageFilter::MakeFromColorFilter(
*ColorFilter::MakeBlend(BlendMode::kDestinationOver, Color::Red())),
});
canvas.DrawRect(Rect::MakeXYWH(100, 500, 300, 300), {.color = Color::Blue()});
@@ -2589,17 +2578,14 @@ TEST_P(AiksTest, TranslucentSaveLayerWithColorMatrixImageFilterDrawsCorrectly) {
canvas.SaveLayer({
.color = Color::Black().WithAlpha(0.5),
.image_filter =
[](FilterInput::Ref input, const Matrix& effect_transform,
bool is_subpass) {
return ColorFilterContents::MakeColorMatrix({std::move(input)},
{.array = {
1, 0, 0, 0, 0, //
0, 1, 0, 0, 0, //
0, 0, 1, 0, 0, //
0, 0, 0, 2, 0 //
}});
},
.image_filter = ImageFilter::MakeFromColorFilter(
*ColorFilter::MakeMatrix({.array =
{
1, 0, 0, 0, 0, //
0, 1, 0, 0, 0, //
0, 0, 1, 0, 0, //
0, 0, 0, 2, 0 //
}})),
});
canvas.DrawImage(image, {100, 500}, {});
canvas.Restore();
@@ -2616,17 +2602,14 @@ TEST_P(AiksTest,
canvas.SaveLayer({
.color = Color::Black().WithAlpha(0.5),
.image_filter =
[](FilterInput::Ref input, const Matrix& effect_transform,
bool is_subpass) {
return ColorFilterContents::MakeColorMatrix(
{std::move(input)}, {.array = {
1, 0, 0, 0, 0, //
0, 1, 0, 0, 0, //
0, 0.2, 1, 0, 0, //
0, 0, 0, 0.5, 0 //
}});
},
.image_filter = ImageFilter::MakeFromColorFilter(
*ColorFilter::MakeMatrix({.array =
{
1, 0, 0, 0, 0, //
0, 1, 0, 0, 0, //
0, 0.2, 1, 0, 0, //
0, 0, 0, 0.5, 0 //
}})),
.color_filter =
ColorFilter::MakeBlend(BlendMode::kModulate, Color::Green()),
});
@@ -2758,13 +2741,9 @@ TEST_P(AiksTest, CanRenderBackdropBlurInteractive) {
canvas.DrawCircle({180, 120}, 100, {.color = Color::OrangeRed()});
canvas.ClipRRect(Rect::MakeLTRB(a.x, a.y, b.x, b.y), 20);
canvas.SaveLayer({.blend_mode = BlendMode::kSource}, std::nullopt,
[](const FilterInput::Ref& input,
const Matrix& effect_transform, bool is_subpass) {
return FilterContents::MakeGaussianBlur(
input, Sigma(20.0), Sigma(20.0),
FilterContents::BlurStyle::kNormal,
Entity::TileMode::kClamp, effect_transform);
});
ImageFilter::MakeBlur(Sigma(20.0), Sigma(20.0),
FilterContents::BlurStyle::kNormal,
Entity::TileMode::kClamp));
canvas.Restore();
return canvas.EndRecordingAsPicture();
@@ -2781,13 +2760,9 @@ TEST_P(AiksTest, CanRenderBackdropBlur) {
canvas.DrawCircle({180, 120}, 100, {.color = Color::OrangeRed()});
canvas.ClipRRect(Rect::MakeLTRB(75, 50, 375, 275), 20);
canvas.SaveLayer({.blend_mode = BlendMode::kSource}, std::nullopt,
[](const FilterInput::Ref& input,
const Matrix& effect_transform, bool is_subpass) {
return FilterContents::MakeGaussianBlur(
input, Sigma(30.0), Sigma(30.0),
FilterContents::BlurStyle::kNormal,
Entity::TileMode::kClamp, effect_transform);
});
ImageFilter::MakeBlur(Sigma(30.0), Sigma(30.0),
FilterContents::BlurStyle::kNormal,
Entity::TileMode::kClamp));
canvas.Restore();
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
@@ -2797,13 +2772,9 @@ TEST_P(AiksTest, CanRenderBackdropBlurHugeSigma) {
Canvas canvas;
canvas.DrawCircle({400, 400}, 300, {.color = Color::Green()});
canvas.SaveLayer({.blend_mode = BlendMode::kSource}, std::nullopt,
[](const FilterInput::Ref& input,
const Matrix& effect_transform, bool is_subpass) {
return FilterContents::MakeGaussianBlur(
input, Sigma(999999), Sigma(999999),
FilterContents::BlurStyle::kNormal,
Entity::TileMode::kClamp, effect_transform);
});
ImageFilter::MakeBlur(Sigma(999999), Sigma(999999),
FilterContents::BlurStyle::kNormal,
Entity::TileMode::kClamp));
canvas.Restore();
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
@@ -2816,14 +2787,9 @@ TEST_P(AiksTest, CanRenderClippedBlur) {
{400, 400}, 200,
{
.color = Color::Green(),
.image_filter =
[](const FilterInput::Ref& input, const Matrix& effect_transform,
bool is_subpass) {
return FilterContents::MakeGaussianBlur(
input, Sigma(20), Sigma(20),
FilterContents::BlurStyle::kNormal,
Entity::TileMode::kClamp, effect_transform);
},
.image_filter = ImageFilter::MakeBlur(
Sigma(20.0), Sigma(20.0), FilterContents::BlurStyle::kNormal,
Entity::TileMode::kClamp),
});
canvas.Restore();
@@ -3127,11 +3093,9 @@ TEST_P(AiksTest, CanCanvasDrawPictureWithAdvancedBlend) {
TEST_P(AiksTest, CanCanvasDrawPictureWithBackdropFilter) {
Canvas subcanvas;
subcanvas.SaveLayer({}, {},
[](const FilterInput::Ref& input,
const Matrix& effect_transform, bool is_subpass) {
return FilterContents::MakeGaussianBlur(
input, Sigma(20.0), Sigma(20.0));
});
ImageFilter::MakeBlur(Sigma(20.0), Sigma(20.0),
FilterContents::BlurStyle::kNormal,
Entity::TileMode::kDecal));
auto image = std::make_shared<Image>(CreateTextureForFixture("kalimba.jpg"));
Paint paint;
paint.color = Color::Red().WithAlpha(0.5);
@@ -3206,17 +3170,12 @@ TEST_P(AiksTest, MatrixSaveLayerFilter) {
.blend_mode = BlendMode::kPlus});
// Should render a second circle, centered on the bottom-right-most edge of
// the circle.
canvas.SaveLayer({.image_filter =
[](const FilterInput::Ref& input,
const Matrix& effect_transform, bool is_subpass) {
Matrix matrix =
Matrix::MakeTranslation(
Vector2(1, 1) * (100 + 100 * k1OverSqrt2)) *
Matrix::MakeScale(Vector2(1, 1) * 0.2) *
Matrix::MakeTranslation(Vector2(-100, -100));
return FilterContents::MakeMatrixFilter(
input, matrix, {}, Matrix(), true);
}},
canvas.SaveLayer({.image_filter = ImageFilter::MakeMatrix(
Matrix::MakeTranslation(Vector2(1, 1) *
(200 + 100 * k1OverSqrt2)) *
Matrix::MakeScale(Vector2(1, 1) * 0.2) *
Matrix::MakeTranslation(Vector2(-200, -200)),
SamplerDescriptor{})},
std::nullopt);
canvas.DrawCircle(Point(200, 200), 100,
{.color = Color::Green().WithAlpha(0.5),
@@ -3238,17 +3197,13 @@ TEST_P(AiksTest, MatrixBackdropFilter) {
.blend_mode = BlendMode::kPlus});
// Should render a second circle, centered on the bottom-right-most edge of
// the circle.
canvas.SaveLayer({}, std::nullopt,
[](const FilterInput::Ref& input,
const Matrix& effect_transform, bool is_subpass) {
Matrix matrix =
Matrix::MakeTranslation(Vector2(1, 1) *
(100 + 100 * k1OverSqrt2)) *
Matrix::MakeScale(Vector2(1, 1) * 0.2) *
Matrix::MakeTranslation(Vector2(-100, -100));
return FilterContents::MakeMatrixFilter(
input, matrix, {}, Matrix(), true);
});
canvas.SaveLayer(
{}, std::nullopt,
ImageFilter::MakeMatrix(
Matrix::MakeTranslation(Vector2(1, 1) * (100 + 100 * k1OverSqrt2)) *
Matrix::MakeScale(Vector2(1, 1) * 0.2) *
Matrix::MakeTranslation(Vector2(-100, -100)),
SamplerDescriptor{}));
canvas.Restore();
}
canvas.Restore();
@@ -3329,14 +3284,14 @@ TEST_P(AiksTest, PipelineBlendSingleParameter) {
canvas.Translate(Point(100, 100));
canvas.DrawCircle(Point(200, 200), 200, {.color = Color::Blue()});
canvas.ClipRect(Rect(100, 100, 200, 200));
canvas.DrawCircle(
Point(200, 200), 200,
{.color = Color::Green(),
.blend_mode = BlendMode::kSourceOver,
.image_filter = [](const FilterInput::Ref& input,
const Matrix& effect_transform, bool is_subpass) {
return ColorFilterContents::MakeBlend(BlendMode::kSource, {input});
}});
canvas.DrawCircle(Point(200, 200), 200,
{
.color = Color::Green(),
.blend_mode = BlendMode::kSourceOver,
.image_filter = ImageFilter::MakeFromColorFilter(
*ColorFilter::MakeBlend(BlendMode::kDestination,
Color::White())),
});
canvas.Restore();
}

View File

@@ -9,6 +9,7 @@
#include <utility>
#include "flutter/fml/logging.h"
#include "impeller/aiks/image_filter.h"
#include "impeller/aiks/paint_pass_delegate.h"
#include "impeller/entity/contents/atlas_contents.h"
#include "impeller/entity/contents/clip_contents.h"
@@ -57,7 +58,7 @@ void Canvas::Save() {
void Canvas::Save(bool create_subpass,
BlendMode blend_mode,
EntityPass::BackdropFilterProc backdrop_filter) {
const std::shared_ptr<ImageFilter>& backdrop_filter) {
auto entry = CanvasStackEntry{};
entry.xformation = xformation_stack_.back().xformation;
entry.cull_rect = xformation_stack_.back().cull_rect;
@@ -67,7 +68,18 @@ void Canvas::Save(bool create_subpass,
auto subpass = std::make_unique<EntityPass>();
subpass->SetEnableOffscreenCheckerboard(
debug_options.offscreen_texture_checkerboard);
subpass->SetBackdropFilter(std::move(backdrop_filter));
if (backdrop_filter) {
EntityPass::BackdropFilterProc backdrop_filter_proc =
[backdrop_filter = backdrop_filter->Clone()](
const FilterInput::Ref& input, const Matrix& effect_transform,
bool is_subpass) {
auto filter = backdrop_filter->WrapInput(input);
filter->SetEffectTransform(effect_transform);
filter->SetIsForSubpass(is_subpass);
return filter;
};
subpass->SetBackdropFilter(backdrop_filter_proc);
}
subpass->SetBlendMode(blend_mode);
current_pass_ = GetCurrentPass().AddSubpass(std::move(subpass));
current_pass_->SetTransformation(xformation_stack_.back().xformation);
@@ -518,7 +530,7 @@ size_t Canvas::GetStencilDepth() const {
void Canvas::SaveLayer(const Paint& paint,
std::optional<Rect> bounds,
const Paint::ImageFilterProc& backdrop_filter) {
const std::shared_ptr<ImageFilter>& backdrop_filter) {
Save(true, paint.blend_mode, backdrop_filter);
auto& new_layer_pass = GetCurrentPass();

View File

@@ -12,6 +12,7 @@
#include "flutter/fml/macros.h"
#include "impeller/aiks/image.h"
#include "impeller/aiks/image_filter.h"
#include "impeller/aiks/paint.h"
#include "impeller/aiks/picture.h"
#include "impeller/core/sampler_descriptor.h"
@@ -68,7 +69,7 @@ class Canvas {
void SaveLayer(const Paint& paint,
std::optional<Rect> bounds = std::nullopt,
const Paint::ImageFilterProc& backdrop_filter = nullptr);
const std::shared_ptr<ImageFilter>& backdrop_filter = nullptr);
bool Restore();
@@ -180,7 +181,7 @@ class Canvas {
void Save(bool create_subpass,
BlendMode = BlendMode::kSourceOver,
EntityPass::BackdropFilterProc backdrop_filter = nullptr);
const std::shared_ptr<ImageFilter>& backdrop_filter = nullptr);
void RestoreClip();

View File

@@ -58,6 +58,10 @@ ColorFilter::ColorFilterProc BlendColorFilter::GetCPUColorFilterProc() const {
};
}
std::shared_ptr<ColorFilter> BlendColorFilter::Clone() const {
return std::make_shared<BlendColorFilter>(*this);
}
/*******************************************************************************
******* MatrixColorFilter
******************************************************************************/
@@ -82,6 +86,10 @@ ColorFilter::ColorFilterProc MatrixColorFilter::GetCPUColorFilterProc() const {
};
}
std::shared_ptr<ColorFilter> MatrixColorFilter::Clone() const {
return std::make_shared<MatrixColorFilter>(*this);
}
/*******************************************************************************
******* SrgbToLinearColorFilter
******************************************************************************/
@@ -104,6 +112,10 @@ ColorFilter::ColorFilterProc SrgbToLinearColorFilter::GetCPUColorFilterProc()
return [](Color color) { return color.SRGBToLinear(); };
}
std::shared_ptr<ColorFilter> SrgbToLinearColorFilter::Clone() const {
return std::make_shared<SrgbToLinearColorFilter>(*this);
}
/*******************************************************************************
******* LinearToSrgbColorFilter
******************************************************************************/
@@ -126,4 +138,8 @@ ColorFilter::ColorFilterProc LinearToSrgbColorFilter::GetCPUColorFilterProc()
return [](Color color) { return color.LinearToSRGB(); };
}
std::shared_ptr<ColorFilter> LinearToSrgbColorFilter::Clone() const {
return std::make_shared<LinearToSrgbColorFilter>(*this);
}
} // namespace impeller

View File

@@ -48,6 +48,8 @@ class ColorFilter {
/// @brief Returns a function that can be used to filter unpremultiplied
/// Impeller Colors on the CPU.
virtual ColorFilterProc GetCPUColorFilterProc() const = 0;
virtual std::shared_ptr<ColorFilter> Clone() const = 0;
};
/*******************************************************************************
@@ -68,6 +70,9 @@ class BlendColorFilter final : public ColorFilter {
// |ColorFilter|
ColorFilterProc GetCPUColorFilterProc() const override;
// |ColorFilter|
std::shared_ptr<ColorFilter> Clone() const override;
private:
BlendMode blend_mode_;
Color color_;
@@ -91,6 +96,9 @@ class MatrixColorFilter final : public ColorFilter {
// |ColorFilter|
ColorFilterProc GetCPUColorFilterProc() const override;
// |ColorFilter|
std::shared_ptr<ColorFilter> Clone() const override;
private:
ColorMatrix color_matrix_;
};
@@ -112,6 +120,9 @@ class SrgbToLinearColorFilter final : public ColorFilter {
// |ColorFilter|
ColorFilterProc GetCPUColorFilterProc() const override;
// |ColorFilter|
std::shared_ptr<ColorFilter> Clone() const override;
};
/*******************************************************************************
@@ -131,6 +142,9 @@ class LinearToSrgbColorFilter final : public ColorFilter {
// |ColorFilter|
ColorFilterProc GetCPUColorFilterProc() const override;
// |ColorFilter|
std::shared_ptr<ColorFilter> Clone() const override;
};
} // namespace impeller

View File

@@ -0,0 +1,206 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "impeller/aiks/image_filter.h"
#include "impeller/entity/contents/filters/filter_contents.h"
#include "impeller/entity/contents/filters/inputs/filter_input.h"
namespace impeller {
/*******************************************************************************
******* ImageFilter
******************************************************************************/
ImageFilter::ImageFilter() = default;
ImageFilter::~ImageFilter() = default;
std::shared_ptr<ImageFilter> ImageFilter::MakeBlur(
Sigma sigma_x,
Sigma sigma_y,
FilterContents::BlurStyle blur_style,
Entity::TileMode tile_mode) {
return std::make_shared<BlurImageFilter>(sigma_x, sigma_y, blur_style,
tile_mode);
}
std::shared_ptr<ImageFilter> ImageFilter::MakeDilate(Radius radius_x,
Radius radius_y) {
return std::make_shared<DilateImageFilter>(radius_x, radius_y);
}
std::shared_ptr<ImageFilter> ImageFilter::MakeErode(Radius radius_x,
Radius radius_y) {
return std::make_shared<ErodeImageFilter>(radius_x, radius_y);
}
std::shared_ptr<ImageFilter> ImageFilter::MakeMatrix(
const Matrix& matrix,
SamplerDescriptor sampler_descriptor) {
return std::make_shared<MatrixImageFilter>(matrix,
std::move(sampler_descriptor));
}
std::shared_ptr<ImageFilter> ImageFilter::MakeCompose(
const ImageFilter& inner,
const ImageFilter& outer) {
return std::make_shared<ComposeImageFilter>(inner, outer);
}
std::shared_ptr<ImageFilter> ImageFilter::MakeFromColorFilter(
const ColorFilter& color_filter) {
return std::make_shared<ColorImageFilter>(color_filter);
}
std::shared_ptr<ImageFilter> ImageFilter::MakeLocalMatrix(
const Matrix& matrix,
const ImageFilter& internal_filter) {
return std::make_shared<LocalMatrixImageFilter>(matrix, internal_filter);
}
std::shared_ptr<FilterContents> ImageFilter::GetFilterContents() const {
return WrapInput(FilterInput::Make(Rect()));
}
/*******************************************************************************
******* BlurImageFilter
******************************************************************************/
BlurImageFilter::BlurImageFilter(Sigma sigma_x,
Sigma sigma_y,
FilterContents::BlurStyle blur_style,
Entity::TileMode tile_mode)
: sigma_x_(sigma_x),
sigma_y_(sigma_y),
blur_style_(blur_style),
tile_mode_(tile_mode) {}
BlurImageFilter::~BlurImageFilter() = default;
std::shared_ptr<FilterContents> BlurImageFilter::WrapInput(
const FilterInput::Ref& input) const {
return FilterContents::MakeGaussianBlur(input, sigma_x_, sigma_y_,
blur_style_, tile_mode_);
}
std::shared_ptr<ImageFilter> BlurImageFilter::Clone() const {
return std::make_shared<BlurImageFilter>(*this);
}
/*******************************************************************************
******* DilateImageFilter
******************************************************************************/
DilateImageFilter::DilateImageFilter(Radius radius_x, Radius radius_y)
: radius_x_(radius_x), radius_y_(radius_y) {}
DilateImageFilter::~DilateImageFilter() = default;
std::shared_ptr<FilterContents> DilateImageFilter::WrapInput(
const FilterInput::Ref& input) const {
return FilterContents::MakeMorphology(input, radius_x_, radius_y_,
FilterContents::MorphType::kDilate);
}
std::shared_ptr<ImageFilter> DilateImageFilter::Clone() const {
return std::make_shared<DilateImageFilter>(*this);
}
/*******************************************************************************
******* ErodeImageFilter
******************************************************************************/
ErodeImageFilter::ErodeImageFilter(Radius radius_x, Radius radius_y)
: radius_x_(radius_x), radius_y_(radius_y) {}
ErodeImageFilter::~ErodeImageFilter() = default;
std::shared_ptr<FilterContents> ErodeImageFilter::WrapInput(
const FilterInput::Ref& input) const {
return FilterContents::MakeMorphology(input, radius_x_, radius_y_,
FilterContents::MorphType::kErode);
}
std::shared_ptr<ImageFilter> ErodeImageFilter::Clone() const {
return std::make_shared<ErodeImageFilter>(*this);
}
/*******************************************************************************
******* MatrixImageFilter
******************************************************************************/
MatrixImageFilter::MatrixImageFilter(const Matrix& matrix,
SamplerDescriptor sampler_descriptor)
: matrix_(matrix), sampler_descriptor_(std::move(sampler_descriptor)) {}
MatrixImageFilter::~MatrixImageFilter() = default;
std::shared_ptr<FilterContents> MatrixImageFilter::WrapInput(
const FilterInput::Ref& input) const {
return FilterContents::MakeMatrixFilter(input, matrix_, sampler_descriptor_);
}
std::shared_ptr<ImageFilter> MatrixImageFilter::Clone() const {
return std::make_shared<MatrixImageFilter>(*this);
}
/*******************************************************************************
******* ComposeImageFilter
******************************************************************************/
ComposeImageFilter::ComposeImageFilter(const ImageFilter& inner,
const ImageFilter& outer)
: inner_(inner.Clone()), outer_(outer.Clone()) {}
ComposeImageFilter::~ComposeImageFilter() = default;
std::shared_ptr<FilterContents> ComposeImageFilter::WrapInput(
const FilterInput::Ref& input) const {
return outer_->WrapInput(FilterInput::Make(inner_->WrapInput(input)));
}
std::shared_ptr<ImageFilter> ComposeImageFilter::Clone() const {
return std::make_shared<ComposeImageFilter>(*this);
}
/*******************************************************************************
******* ColorImageFilter
******************************************************************************/
ColorImageFilter::ColorImageFilter(const ColorFilter& color_filter)
: color_filter_(color_filter.Clone()) {}
ColorImageFilter::~ColorImageFilter() = default;
std::shared_ptr<FilterContents> ColorImageFilter::WrapInput(
const FilterInput::Ref& input) const {
return color_filter_->WrapWithGPUColorFilter(input, false);
}
std::shared_ptr<ImageFilter> ColorImageFilter::Clone() const {
return std::make_shared<ColorImageFilter>(*this);
}
/*******************************************************************************
******* LocalMatrixImageFilter
******************************************************************************/
LocalMatrixImageFilter::LocalMatrixImageFilter(
const Matrix& matrix,
const ImageFilter& internal_filter)
: matrix_(matrix), internal_filter_(internal_filter.Clone()) {}
LocalMatrixImageFilter::~LocalMatrixImageFilter() = default;
std::shared_ptr<FilterContents> LocalMatrixImageFilter::WrapInput(
const FilterInput::Ref& input) const {
return FilterContents::MakeLocalMatrixFilter(
FilterInput::Make(internal_filter_->WrapInput(input)), matrix_);
}
std::shared_ptr<ImageFilter> LocalMatrixImageFilter::Clone() const {
return std::make_shared<LocalMatrixImageFilter>(*this);
}
} // namespace impeller

View File

@@ -0,0 +1,229 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include "impeller/aiks/color_filter.h"
#include "impeller/core/sampler_descriptor.h"
#include "impeller/entity/contents/filters/filter_contents.h"
#include "impeller/entity/entity.h"
#include "impeller/geometry/matrix.h"
#include "impeller/geometry/sigma.h"
namespace impeller {
struct Paint;
/*******************************************************************************
******* ImageFilter
******************************************************************************/
class ImageFilter {
public:
ImageFilter();
virtual ~ImageFilter();
static std::shared_ptr<ImageFilter> MakeBlur(
Sigma sigma_x,
Sigma sigma_y,
FilterContents::BlurStyle blur_style,
Entity::TileMode tile_mode);
static std::shared_ptr<ImageFilter> MakeDilate(Radius radius_x,
Radius radius_y);
static std::shared_ptr<ImageFilter> MakeErode(Radius radius_x,
Radius radius_y);
static std::shared_ptr<ImageFilter> MakeMatrix(
const Matrix& matrix,
SamplerDescriptor sampler_descriptor);
static std::shared_ptr<ImageFilter> MakeCompose(const ImageFilter& inner,
const ImageFilter& outer);
static std::shared_ptr<ImageFilter> MakeFromColorFilter(
const ColorFilter& color_filter);
static std::shared_ptr<ImageFilter> MakeLocalMatrix(
const Matrix& matrix,
const ImageFilter& internal_filter);
/// @brief Generate a new FilterContents using this filter's configuration.
///
/// This is the same as WrapInput, except no input is set. The input
/// for the filter chain can be set later using.
/// FilterContents::SetLeafInputs().
///
/// @see `FilterContents::SetLeafInputs`
std::shared_ptr<FilterContents> GetFilterContents() const;
/// @brief Wraps the given filter input with a GPU-based image filter.
virtual std::shared_ptr<FilterContents> WrapInput(
const FilterInput::Ref& input) const = 0;
virtual std::shared_ptr<ImageFilter> Clone() const = 0;
};
/*******************************************************************************
******* BlurImageFilter
******************************************************************************/
class BlurImageFilter : public ImageFilter {
public:
BlurImageFilter(Sigma sigma_x,
Sigma sigma_y,
FilterContents::BlurStyle blur_style,
Entity::TileMode tile_mode);
~BlurImageFilter() override;
// |ImageFilter|
std::shared_ptr<FilterContents> WrapInput(
const FilterInput::Ref& input) const override;
// |ImageFilter|
std::shared_ptr<ImageFilter> Clone() const override;
private:
Sigma sigma_x_;
Sigma sigma_y_;
FilterContents::BlurStyle blur_style_;
Entity::TileMode tile_mode_;
};
/*******************************************************************************
******* DilateImageFilter
******************************************************************************/
class DilateImageFilter : public ImageFilter {
public:
DilateImageFilter(Radius radius_x, Radius radius_y);
~DilateImageFilter() override;
// |ImageFilter|
std::shared_ptr<FilterContents> WrapInput(
const FilterInput::Ref& input) const override;
// |ImageFilter|
std::shared_ptr<ImageFilter> Clone() const override;
private:
Radius radius_x_;
Radius radius_y_;
};
/*******************************************************************************
******* ErodeImageFilter
******************************************************************************/
class ErodeImageFilter : public ImageFilter {
public:
ErodeImageFilter(Radius radius_x, Radius radius_y);
~ErodeImageFilter() override;
// |ImageFilter|
std::shared_ptr<FilterContents> WrapInput(
const FilterInput::Ref& input) const override;
// |ImageFilter|
std::shared_ptr<ImageFilter> Clone() const override;
private:
Radius radius_x_;
Radius radius_y_;
};
/*******************************************************************************
******* MatrixImageFilter
******************************************************************************/
class MatrixImageFilter : public ImageFilter {
public:
MatrixImageFilter(const Matrix& matrix, SamplerDescriptor sampler_descriptor);
~MatrixImageFilter() override;
// |ImageFilter|
std::shared_ptr<FilterContents> WrapInput(
const FilterInput::Ref& input) const override;
// |ImageFilter|
std::shared_ptr<ImageFilter> Clone() const override;
private:
Matrix matrix_;
SamplerDescriptor sampler_descriptor_;
};
/*******************************************************************************
******* ComposeImageFilter
******************************************************************************/
class ComposeImageFilter : public ImageFilter {
public:
ComposeImageFilter(const ImageFilter& inner, const ImageFilter& outer);
~ComposeImageFilter() override;
// |ImageFilter|
std::shared_ptr<FilterContents> WrapInput(
const FilterInput::Ref& input) const override;
// |ImageFilter|
std::shared_ptr<ImageFilter> Clone() const override;
private:
std::shared_ptr<ImageFilter> inner_;
std::shared_ptr<ImageFilter> outer_;
};
/*******************************************************************************
******* ColorImageFilter
******************************************************************************/
class ColorImageFilter : public ImageFilter {
public:
explicit ColorImageFilter(const ColorFilter& color_filter);
~ColorImageFilter() override;
// |ImageFilter|
std::shared_ptr<FilterContents> WrapInput(
const FilterInput::Ref& input) const override;
// |ImageFilter|
std::shared_ptr<ImageFilter> Clone() const override;
private:
std::shared_ptr<ColorFilter> color_filter_;
};
/*******************************************************************************
******* LocalMatrixImageFilter
******************************************************************************/
class LocalMatrixImageFilter : public ImageFilter {
public:
LocalMatrixImageFilter(const Matrix& matrix,
const ImageFilter& internal_filter);
~LocalMatrixImageFilter() override;
// |ImageFilter|
std::shared_ptr<FilterContents> WrapInput(
const FilterInput::Ref& input) const override;
// |ImageFilter|
std::shared_ptr<ImageFilter> Clone() const override;
private:
Matrix matrix_;
std::shared_ptr<ImageFilter> internal_filter_;
};
} // namespace impeller

View File

@@ -85,11 +85,13 @@ std::shared_ptr<Contents> Paint::WithImageFilter(
std::shared_ptr<Contents> input,
const Matrix& effect_transform,
bool is_subpass) const {
if (image_filter) {
input =
image_filter(FilterInput::Make(input), effect_transform, is_subpass);
if (!image_filter) {
return input;
}
return input;
auto filter = image_filter->WrapInput(FilterInput::Make(input));
filter->SetIsForSubpass(is_subpass);
filter->SetEffectTransform(effect_transform);
return filter;
}
std::shared_ptr<Contents> Paint::WithColorFilter(
@@ -146,7 +148,7 @@ std::shared_ptr<FilterContents> Paint::MaskBlurDescriptor::CreateMaskBlur(
if (color_source_contents->IsSolidColor() && !color_filter) {
return FilterContents::MakeGaussianBlur(
FilterInput::Make(color_source_contents), sigma, sigma, style,
Entity::TileMode::kDecal, Matrix());
Entity::TileMode::kDecal);
}
/// 1. Create an opaque white mask of the original geometry.
@@ -158,8 +160,7 @@ std::shared_ptr<FilterContents> Paint::MaskBlurDescriptor::CreateMaskBlur(
/// 2. Blur the mask.
auto blurred_mask = FilterContents::MakeGaussianBlur(
FilterInput::Make(mask), sigma, sigma, style, Entity::TileMode::kDecal,
Matrix());
FilterInput::Make(mask), sigma, sigma, style, Entity::TileMode::kDecal);
/// 3. Replace the geometry of the original color source with a rectangle that
/// covers the full region of the blurred mask. Note that geometry is in
@@ -193,10 +194,9 @@ std::shared_ptr<FilterContents> Paint::MaskBlurDescriptor::CreateMaskBlur(
bool is_solid_color) const {
if (is_solid_color) {
return FilterContents::MakeGaussianBlur(input, sigma, sigma, style,
Entity::TileMode::kDecal, Matrix());
Entity::TileMode::kDecal);
}
return FilterContents::MakeBorderMaskBlur(input, sigma, sigma, style,
Matrix());
return FilterContents::MakeBorderMaskBlur(input, sigma, sigma, style);
}
bool Paint::HasColorFilter() const {

View File

@@ -9,6 +9,7 @@
#include "flutter/fml/macros.h"
#include "impeller/aiks/color_filter.h"
#include "impeller/aiks/color_source.h"
#include "impeller/aiks/image_filter.h"
#include "impeller/entity/contents/contents.h"
#include "impeller/entity/contents/filters/color_filter_contents.h"
#include "impeller/entity/contents/filters/filter_contents.h"
@@ -62,7 +63,7 @@ struct Paint {
BlendMode blend_mode = BlendMode::kSourceOver;
bool invert_colors = false;
ImageFilterProc image_filter = nullptr;
std::shared_ptr<ImageFilter> image_filter;
std::shared_ptr<ColorFilter> color_filter;
std::optional<MaskBlurDescriptor> mask_blur_descriptor;

View File

@@ -560,7 +560,7 @@ void DlDispatcher::setMaskFilter(const flutter::DlMaskFilter* filter) {
}
}
static Paint::ImageFilterProc ToImageFilterProc(
static std::shared_ptr<ImageFilter> ToImageFilter(
const flutter::DlImageFilter* filter) {
if (filter == nullptr) {
return nullptr;
@@ -572,16 +572,8 @@ static Paint::ImageFilterProc ToImageFilterProc(
auto sigma_x = Sigma(blur->sigma_x());
auto sigma_y = Sigma(blur->sigma_y());
auto tile_mode = ToTileMode(blur->tile_mode());
return [sigma_x, sigma_y, tile_mode](const FilterInput::Ref& input,
const Matrix& effect_transform,
bool is_subpass) {
return FilterContents::MakeGaussianBlur(
input, sigma_x, sigma_y, FilterContents::BlurStyle::kNormal,
tile_mode, effect_transform);
};
break;
return ImageFilter::MakeBlur(
sigma_x, sigma_y, FilterContents::BlurStyle::kNormal, tile_mode);
}
case flutter::DlImageFilterType::kDilate: {
auto dilate = filter->asDilate();
@@ -591,14 +583,7 @@ static Paint::ImageFilterProc ToImageFilterProc(
}
auto radius_x = Radius(dilate->radius_x());
auto radius_y = Radius(dilate->radius_y());
return [radius_x, radius_y](FilterInput::Ref input,
const Matrix& effect_transform,
bool is_subpass) {
return FilterContents::MakeMorphology(
std::move(input), radius_x, radius_y,
FilterContents::MorphType::kDilate, effect_transform);
};
break;
return ImageFilter::MakeDilate(radius_x, radius_y);
}
case flutter::DlImageFilterType::kErode: {
auto erode = filter->asErode();
@@ -608,51 +593,31 @@ static Paint::ImageFilterProc ToImageFilterProc(
}
auto radius_x = Radius(erode->radius_x());
auto radius_y = Radius(erode->radius_y());
return [radius_x, radius_y](FilterInput::Ref input,
const Matrix& effect_transform,
bool is_subpass) {
return FilterContents::MakeMorphology(
std::move(input), radius_x, radius_y,
FilterContents::MorphType::kErode, effect_transform);
};
break;
return ImageFilter::MakeErode(radius_x, radius_y);
}
case flutter::DlImageFilterType::kMatrix: {
auto matrix_filter = filter->asMatrix();
FML_DCHECK(matrix_filter);
auto matrix = ToMatrix(matrix_filter->matrix());
auto desc = ToSamplerDescriptor(matrix_filter->sampling());
return [matrix, desc](FilterInput::Ref input,
const Matrix& effect_transform, bool is_subpass) {
return FilterContents::MakeMatrixFilter(std::move(input), matrix, desc,
effect_transform, is_subpass);
};
break;
return ImageFilter::MakeMatrix(matrix, desc);
}
case flutter::DlImageFilterType::kCompose: {
auto compose = filter->asCompose();
FML_DCHECK(compose);
auto outer = compose->outer();
auto inner = compose->inner();
auto outer_proc = ToImageFilterProc(outer.get());
auto inner_proc = ToImageFilterProc(inner.get());
if (!outer_proc) {
return inner_proc;
auto outer_dl_filter = compose->outer();
auto inner_dl_filter = compose->inner();
auto outer_filter = ToImageFilter(outer_dl_filter.get());
auto inner_filter = ToImageFilter(inner_dl_filter.get());
if (!outer_filter) {
return inner_filter;
}
if (!inner_proc) {
return outer_proc;
if (!inner_filter) {
return outer_filter;
}
FML_DCHECK(outer_proc && inner_proc);
return [outer_filter = outer_proc, inner_filter = inner_proc](
FilterInput::Ref input, const Matrix& effect_transform,
bool is_subpass) {
auto contents =
inner_filter(std::move(input), effect_transform, is_subpass);
contents = outer_filter(FilterInput::Make(contents), effect_transform,
is_subpass);
return contents;
};
break;
FML_DCHECK(outer_filter && inner_filter);
return ImageFilter::MakeCompose(*inner_filter, *outer_filter);
}
case flutter::DlImageFilterType::kColorFilter: {
auto color_filter_image_filter = filter->asColorFilter();
@@ -662,16 +627,11 @@ static Paint::ImageFilterProc ToImageFilterProc(
if (!color_filter) {
return nullptr;
}
return [filter = color_filter](FilterInput::Ref input,
const Matrix& effect_transform,
bool is_subpass) {
// When color filters are used as image filters, set the color filter's
// "absorb opacity" flag to false. For image filters, the snapshot
// opacity needs to be deferred until the result of the filter chain is
// being blended with the layer.
return filter->WrapWithGPUColorFilter(std::move(input), false);
};
break;
// When color filters are used as image filters, set the color filter's
// "absorb opacity" flag to false. For image filters, the snapshot
// opacity needs to be deferred until the result of the filter chain is
// being blended with the layer.
return ImageFilter::MakeFromColorFilter(*color_filter);
}
case flutter::DlImageFilterType::kLocalMatrix: {
auto local_matrix_filter = filter->asLocalMatrix();
@@ -679,29 +639,20 @@ static Paint::ImageFilterProc ToImageFilterProc(
auto internal_filter = local_matrix_filter->image_filter();
FML_DCHECK(internal_filter);
auto image_filter_proc = ToImageFilterProc(internal_filter.get());
if (!image_filter_proc) {
auto image_filter = ToImageFilter(internal_filter.get());
if (!image_filter) {
return nullptr;
}
auto matrix = ToMatrix(local_matrix_filter->matrix());
return [matrix, filter_proc = image_filter_proc](
FilterInput::Ref input, const Matrix& effect_transform,
bool is_subpass) {
std::shared_ptr<FilterContents> filter =
filter_proc(std::move(input), effect_transform, is_subpass);
return FilterContents::MakeLocalMatrixFilter(FilterInput::Make(filter),
matrix);
};
break;
return ImageFilter::MakeLocalMatrix(matrix, *image_filter);
}
}
}
// |flutter::DlOpReceiver|
void DlDispatcher::setImageFilter(const flutter::DlImageFilter* filter) {
paint_.image_filter = ToImageFilterProc(filter);
paint_.image_filter = ToImageFilter(filter);
}
// |flutter::DlOpReceiver|
@@ -715,7 +666,7 @@ void DlDispatcher::saveLayer(const SkRect* bounds,
const flutter::DlImageFilter* backdrop) {
auto paint = options.renders_with_attributes() ? paint_ : Paint{};
canvas_.SaveLayer(paint, skia_conversions::ToRect(bounds),
ToImageFilterProc(backdrop));
ToImageFilter(backdrop));
}
// |flutter::DlOpReceiver|

View File

@@ -37,8 +37,7 @@ std::shared_ptr<FilterContents> FilterContents::MakeDirectionalGaussianBlur(
BlurStyle blur_style,
Entity::TileMode tile_mode,
bool is_second_pass,
Sigma secondary_sigma,
const Matrix& effect_transform) {
Sigma secondary_sigma) {
auto blur = std::make_shared<DirectionalGaussianBlurFilterContents>();
blur->SetInputs({std::move(input)});
blur->SetSigma(sigma);
@@ -47,7 +46,6 @@ std::shared_ptr<FilterContents> FilterContents::MakeDirectionalGaussianBlur(
blur->SetTileMode(tile_mode);
blur->SetIsSecondPass(is_second_pass);
blur->SetSecondarySigma(secondary_sigma);
blur->SetEffectTransform(effect_transform);
return blur;
}
@@ -56,14 +54,12 @@ std::shared_ptr<FilterContents> FilterContents::MakeGaussianBlur(
Sigma sigma_x,
Sigma sigma_y,
BlurStyle blur_style,
Entity::TileMode tile_mode,
const Matrix& effect_transform) {
auto x_blur = MakeDirectionalGaussianBlur(input, sigma_x, Point(1, 0),
BlurStyle::kNormal, tile_mode,
false, {}, effect_transform);
Entity::TileMode tile_mode) {
auto x_blur = MakeDirectionalGaussianBlur(
input, sigma_x, Point(1, 0), BlurStyle::kNormal, tile_mode, false, {});
auto y_blur = MakeDirectionalGaussianBlur(FilterInput::Make(x_blur), sigma_y,
Point(0, 1), blur_style, tile_mode,
true, sigma_x, effect_transform);
true, sigma_x);
return y_blur;
}
@@ -71,13 +67,11 @@ std::shared_ptr<FilterContents> FilterContents::MakeBorderMaskBlur(
FilterInput::Ref input,
Sigma sigma_x,
Sigma sigma_y,
BlurStyle blur_style,
const Matrix& effect_transform) {
BlurStyle blur_style) {
auto filter = std::make_shared<BorderMaskBlurFilterContents>();
filter->SetInputs({std::move(input)});
filter->SetSigma(sigma_x, sigma_y);
filter->SetBlurStyle(blur_style);
filter->SetEffectTransform(effect_transform);
return filter;
}
@@ -85,14 +79,12 @@ std::shared_ptr<FilterContents> FilterContents::MakeDirectionalMorphology(
FilterInput::Ref input,
Radius radius,
Vector2 direction,
MorphType morph_type,
const Matrix& effect_transform) {
MorphType morph_type) {
auto filter = std::make_shared<DirectionalMorphologyFilterContents>();
filter->SetInputs({std::move(input)});
filter->SetRadius(radius);
filter->SetDirection(direction);
filter->SetMorphType(morph_type);
filter->SetEffectTransform(effect_transform);
return filter;
}
@@ -100,28 +92,22 @@ std::shared_ptr<FilterContents> FilterContents::MakeMorphology(
FilterInput::Ref input,
Radius radius_x,
Radius radius_y,
MorphType morph_type,
const Matrix& effect_transform) {
auto x_morphology = MakeDirectionalMorphology(
std::move(input), radius_x, Point(1, 0), morph_type, effect_transform);
auto y_morphology =
MakeDirectionalMorphology(FilterInput::Make(x_morphology), radius_y,
Point(0, 1), morph_type, effect_transform);
MorphType morph_type) {
auto x_morphology = MakeDirectionalMorphology(std::move(input), radius_x,
Point(1, 0), morph_type);
auto y_morphology = MakeDirectionalMorphology(
FilterInput::Make(x_morphology), radius_y, Point(0, 1), morph_type);
return y_morphology;
}
std::shared_ptr<FilterContents> FilterContents::MakeMatrixFilter(
FilterInput::Ref input,
const Matrix& matrix,
const SamplerDescriptor& desc,
const Matrix& effect_transform,
bool is_subpass) {
const SamplerDescriptor& desc) {
auto filter = std::make_shared<MatrixFilterContents>();
filter->SetInputs({std::move(input)});
filter->SetMatrix(matrix);
filter->SetSamplerDescriptor(desc);
filter->SetEffectTransform(effect_transform);
filter->SetIsSubpass(is_subpass);
return filter;
}
@@ -153,8 +139,12 @@ void FilterContents::SetInputs(FilterInput::Vector inputs) {
inputs_ = std::move(inputs);
}
void FilterContents::SetEffectTransform(Matrix effect_transform) {
void FilterContents::SetEffectTransform(const Matrix& effect_transform) {
effect_transform_ = effect_transform;
for (auto& input : inputs_) {
input->SetEffectTransform(effect_transform);
}
}
bool FilterContents::Render(const ContentContext& renderer,
@@ -296,4 +286,10 @@ void FilterContents::SetLeafInputs(const FilterInput::Vector& inputs) {
}
}
void FilterContents::SetIsForSubpass(bool is_subpass) {
for (auto& input : inputs_) {
input->SetIsForSubpass(is_subpass);
}
}
} // namespace impeller

View File

@@ -38,44 +38,36 @@ class FilterContents : public Contents {
BlurStyle blur_style = BlurStyle::kNormal,
Entity::TileMode tile_mode = Entity::TileMode::kDecal,
bool is_second_pass = false,
Sigma secondary_sigma = {},
const Matrix& effect_transform = Matrix());
Sigma secondary_sigma = {});
static std::shared_ptr<FilterContents> MakeGaussianBlur(
const FilterInput::Ref& input,
Sigma sigma_x,
Sigma sigma_y,
BlurStyle blur_style = BlurStyle::kNormal,
Entity::TileMode tile_mode = Entity::TileMode::kDecal,
const Matrix& effect_transform = Matrix());
Entity::TileMode tile_mode = Entity::TileMode::kDecal);
static std::shared_ptr<FilterContents> MakeBorderMaskBlur(
FilterInput::Ref input,
Sigma sigma_x,
Sigma sigma_y,
BlurStyle blur_style = BlurStyle::kNormal,
const Matrix& effect_transform = Matrix());
BlurStyle blur_style = BlurStyle::kNormal);
static std::shared_ptr<FilterContents> MakeDirectionalMorphology(
FilterInput::Ref input,
Radius radius,
Vector2 direction,
MorphType morph_type,
const Matrix& effect_transform = Matrix());
MorphType morph_type);
static std::shared_ptr<FilterContents> MakeMorphology(
FilterInput::Ref input,
Radius radius_x,
Radius radius_y,
MorphType morph_type,
const Matrix& effect_transform = Matrix());
static std::shared_ptr<FilterContents> MakeMorphology(FilterInput::Ref input,
Radius radius_x,
Radius radius_y,
MorphType morph_type);
static std::shared_ptr<FilterContents> MakeMatrixFilter(
FilterInput::Ref input,
const Matrix& matrix,
const SamplerDescriptor& desc,
const Matrix& effect_transform,
bool is_subpass);
const SamplerDescriptor& desc);
static std::shared_ptr<FilterContents> MakeLocalMatrixFilter(
FilterInput::Ref input,
@@ -99,7 +91,11 @@ class FilterContents : public Contents {
/// @brief Sets the transform which gets appended to the effect of this
/// filter. Note that this is in addition to the entity's transform.
void SetEffectTransform(Matrix effect_transform);
///
/// This is useful for subpass rendering scenarios where it's
/// difficult to encode the current transform of the layer into the
/// Entity being rendered.
void SetEffectTransform(const Matrix& effect_transform);
/// @brief Create an Entity that renders this filter's output.
std::optional<Entity> GetEntity(
@@ -137,11 +133,19 @@ class FilterContents : public Contents {
/// children.
bool IsLeaf() const;
/// @brief Replaces the leaf of all leaf `FilterContents` with a new set
/// of `inputs`.
/// @brief Replaces the set of all leaf `FilterContents` with a new set
/// of `FilterInput`s.
/// @see `FilterContents::IsLeaf`
void SetLeafInputs(const FilterInput::Vector& inputs);
/// @brief Marks this filter chain as applying in a subpass scenario.
///
/// Subpasses render in screenspace, and this setting informs filters
/// that the current transformation matrix of the entity is not stored
/// in the Entity transformation matrix. Instead, the effect transform
/// is used in this case.
virtual void SetIsForSubpass(bool is_subpass);
private:
virtual std::optional<Rect> GetFilterCoverage(
const FilterInput::Vector& inputs,

View File

@@ -67,4 +67,12 @@ void FilterContentsFilterInput::SetLeafInputs(
filter_->SetLeafInputs(inputs);
}
void FilterContentsFilterInput::SetEffectTransform(const Matrix& matrix) {
filter_->SetEffectTransform(matrix);
}
void FilterContentsFilterInput::SetIsForSubpass(bool is_for_subpass) {
filter_->SetIsForSubpass(is_for_subpass);
}
} // namespace impeller

View File

@@ -42,6 +42,12 @@ class FilterContentsFilterInput final : public FilterInput {
// |FilterInput|
void SetLeafInputs(const FilterInput::Vector& inputs) override;
// |FilterInput|
virtual void SetEffectTransform(const Matrix& matrix) override;
// |FilterInput|
virtual void SetIsForSubpass(bool is_for_subpass) override;
private:
explicit FilterContentsFilterInput(std::shared_ptr<FilterContents> filter);

View File

@@ -82,4 +82,8 @@ bool FilterInput::IsLeaf() const {
void FilterInput::SetLeafInputs(const FilterInput::Vector& inputs) {}
void FilterInput::SetEffectTransform(const Matrix& matrix) {}
void FilterInput::SetIsForSubpass(bool is_for_subpass) {}
} // namespace impeller

View File

@@ -77,6 +77,12 @@ class FilterInput {
/// of `inputs`.
/// @see `FilterInput::IsLeaf`
virtual void SetLeafInputs(const FilterInput::Vector& inputs);
/// @brief Sets the effect transform of filter inputs.
virtual void SetEffectTransform(const Matrix& matrix);
/// @brief Turns on subpass mode for filter inputs.
virtual void SetIsForSubpass(bool is_for_subpass);
};
} // namespace impeller

View File

@@ -32,8 +32,8 @@ TEST(FilterInputTest, IsLeaf) {
ColorFilterContents::MakeBlend(BlendMode::kSource, {});
ASSERT_TRUE(leaf->IsLeaf());
auto base = ColorFilterContents::MakeMatrixFilter(
FilterInput::Make(leaf), Matrix(), {}, Matrix(), false);
auto base = ColorFilterContents::MakeMatrixFilter(FilterInput::Make(leaf),
Matrix(), {});
ASSERT_TRUE(leaf->IsLeaf());
ASSERT_FALSE(base->IsLeaf());
@@ -44,8 +44,8 @@ TEST(FilterInputTest, SetCoverageInputs) {
ColorFilterContents::MakeBlend(BlendMode::kSource, {});
ASSERT_TRUE(leaf->IsLeaf());
auto base = ColorFilterContents::MakeMatrixFilter(
FilterInput::Make(leaf), Matrix(), {}, Matrix(), false);
auto base = ColorFilterContents::MakeMatrixFilter(FilterInput::Make(leaf),
Matrix(), {});
{
auto result = base->GetCoverage({});

View File

@@ -14,8 +14,9 @@ void MatrixFilterContents::SetMatrix(Matrix matrix) {
matrix_ = matrix;
}
void MatrixFilterContents::SetIsSubpass(bool is_subpass) {
is_subpass_ = is_subpass;
void MatrixFilterContents::SetIsForSubpass(bool is_subpass) {
is_for_subpass_ = is_subpass;
FilterContents::SetIsForSubpass(is_subpass);
}
void MatrixFilterContents::SetSamplerDescriptor(SamplerDescriptor desc) {
@@ -49,7 +50,8 @@ std::optional<Entity> MatrixFilterContents::RenderFilter(
// mentioned above). And so we sneak the subpass's captured CTM in through the
// effect transform.
auto transform = is_subpass_ ? effect_transform : entity.GetTransformation();
auto transform =
is_for_subpass_ ? effect_transform : entity.GetTransformation();
snapshot->transform = transform * //
matrix_ * //
transform.Invert() * //
@@ -72,7 +74,8 @@ std::optional<Rect> MatrixFilterContents::GetFilterCoverage(
if (!coverage.has_value()) {
return std::nullopt;
}
auto& m = is_subpass_ ? effect_transform : inputs[0]->GetTransform(entity);
auto& m =
is_for_subpass_ ? effect_transform : inputs[0]->GetTransform(entity);
auto transform = m * //
matrix_ * //
m.Invert(); //

View File

@@ -17,7 +17,8 @@ class MatrixFilterContents final : public FilterContents {
void SetMatrix(Matrix matrix);
void SetIsSubpass(bool is_subpass);
// |FilterContents|
void SetIsForSubpass(bool is_for_subpass) override;
void SetSamplerDescriptor(SamplerDescriptor desc);
@@ -39,7 +40,7 @@ class MatrixFilterContents final : public FilterContents {
Matrix matrix_;
SamplerDescriptor sampler_descriptor_ = {};
bool is_subpass_ = false;
bool is_for_subpass_ = false;
FML_DISALLOW_COPY_AND_ASSIGN(MatrixFilterContents);
};

View File

@@ -604,13 +604,15 @@ EntityPass::EntityResult EntityPass::GetEntityForElement(
// right thing.
return EntityPass::EntityResult::Failure();
}
element_entity.SetCapture(capture.CreateChild("Entity (Subpass texture)"));
Capture subpass_texture_capture =
capture.CreateChild("Entity (Subpass texture)");
element_entity.SetCapture(subpass_texture_capture);
element_entity.SetContents(std::move(offscreen_texture_contents));
element_entity.SetStencilDepth(subpass->stencil_depth_);
element_entity.SetBlendMode(subpass->blend_mode_);
element_entity.SetTransformation(Matrix::MakeTranslation(
Vector3(subpass_coverage->origin - global_pass_position)));
element_entity.SetTransformation(subpass_texture_capture.AddMatrix(
"Transform", Matrix::MakeTranslation(Vector3(subpass_coverage->origin -
global_pass_position))));
} else {
FML_UNREACHABLE();
}

View File

@@ -1191,12 +1191,11 @@ TEST_P(EntityTest, MorphologyFilter) {
input = texture;
input_size = input_rect.size;
auto effect_transform = Matrix::MakeScale(
Vector2{effect_transform_scale, effect_transform_scale});
auto contents = FilterContents::MakeMorphology(
FilterInput::Make(input), Radius{radius[0]}, Radius{radius[1]},
morphology_types[selected_morphology_type], effect_transform);
morphology_types[selected_morphology_type]);
contents->SetEffectTransform(Matrix::MakeScale(
Vector2{effect_transform_scale, effect_transform_scale}));
auto ctm = Matrix::MakeScale(GetContentScale()) *
Matrix::MakeTranslation(Vector3(offset[0], offset[1])) *