From fd33d174870d75b6c074d43d0ab61cbd79486bbe Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Fri, 4 Oct 2024 23:32:08 -0500 Subject: [PATCH] [Impeller] remove aiks color_filter and image_filter types. (flutter/engine#55654) Like the color_source, these classes are just copies of the DL types. Use the DLTypes instead. Part of https://github.com/flutter/flutter/issues/142054 --- .../flutter/impeller/display_list/canvas.cc | 82 ++++-- .../flutter/impeller/display_list/canvas.h | 4 +- .../impeller/display_list/canvas_unittests.cc | 34 --- .../impeller/display_list/color_filter.cc | 240 +++++----------- .../impeller/display_list/color_filter.h | 181 ++---------- .../impeller/display_list/dl_dispatcher.cc | 199 +------------ .../impeller/display_list/image_filter.cc | 271 ++++++------------ .../impeller/display_list/image_filter.h | 228 +-------------- .../flutter/impeller/display_list/paint.cc | 127 ++++---- .../src/flutter/impeller/display_list/paint.h | 14 +- .../impeller/display_list/skia_conversions.cc | 64 +++++ .../impeller/display_list/skia_conversions.h | 2 + .../skia_conversions_unittests.cc | 10 + .../entity/contents/tiled_texture_contents.h | 2 - 14 files changed, 388 insertions(+), 1070 deletions(-) diff --git a/engine/src/flutter/impeller/display_list/canvas.cc b/engine/src/flutter/impeller/display_list/canvas.cc index 1fe68bb5b8..9c45f8d6dc 100644 --- a/engine/src/flutter/impeller/display_list/canvas.cc +++ b/engine/src/flutter/impeller/display_list/canvas.cc @@ -9,8 +9,10 @@ #include #include "display_list/effects/dl_color_source.h" +#include "display_list/effects/dl_image_filter.h" #include "flutter/fml/logging.h" #include "flutter/fml/trace_event.h" +#include "impeller/display_list/color_filter.h" #include "impeller/display_list/image_filter.h" #include "impeller/display_list/skia_conversions.h" #include "impeller/entity/contents/atlas_contents.h" @@ -41,12 +43,18 @@ static std::shared_ptr CreateContentsForGeometryWithFilters( // Attempt to apply the color filter on the CPU first. // Note: This is not just an optimization; some color sources rely on // CPU-applied color filters to behave properly. - bool needs_color_filter = paint.HasColorFilter(); - if (needs_color_filter) { - auto color_filter = paint.GetColorFilter(); - if (contents->ApplyColorFilter(color_filter->GetCPUColorFilterProc())) { - needs_color_filter = false; - } + bool needs_color_filter = paint.color_filter || paint.invert_colors; + if (needs_color_filter && + contents->ApplyColorFilter([&](Color color) -> Color { + if (paint.color_filter) { + color = GetCPUColorFilterProc(paint.color_filter)(color); + } + if (paint.invert_colors) { + color = color.ApplyColorMatrix(kColorInversion); + } + return color; + })) { + needs_color_filter = false; } bool can_apply_mask_filter = geometry->CanApplyMaskFilter(); @@ -57,24 +65,32 @@ static std::shared_ptr CreateContentsForGeometryWithFilters( // we need to be careful to only apply the color filter to the source // colors. CreateMaskBlur is able to handle this case. return paint.mask_blur_descriptor->CreateMaskBlur( - contents, needs_color_filter ? paint.GetColorFilter() : nullptr); + contents, needs_color_filter ? paint.color_filter : nullptr, + needs_color_filter ? paint.invert_colors : false); } std::shared_ptr contents_copy = std::move(contents); + // Image input types will directly set their color filter, // if any. See `TiledTextureContents.SetColorFilter`. if (needs_color_filter && (!paint.color_source || paint.color_source->type() != flutter::DlColorSourceType::kImage)) { - std::shared_ptr color_filter = paint.GetColorFilter(); - contents_copy = color_filter->WrapWithGPUColorFilter( - FilterInput::Make(std::move(contents_copy)), - ColorFilterContents::AbsorbOpacity::kYes); + if (paint.color_filter) { + contents_copy = WrapWithGPUColorFilter( + paint.color_filter, FilterInput::Make(std::move(contents_copy)), + ColorFilterContents::AbsorbOpacity::kYes); + } + if (paint.invert_colors) { + contents_copy = + WrapWithInvertColors(FilterInput::Make(contents_copy), + ColorFilterContents::AbsorbOpacity::kYes); + } } if (paint.image_filter) { - std::shared_ptr filter = paint.image_filter->WrapInput( - FilterInput::Make(std::move(contents_copy))); + std::shared_ptr filter = WrapInput( + paint.image_filter, FilterInput::Make(std::move(contents_copy))); filter->SetRenderingMode(Entity::RenderingMode::kDirect); return filter; } @@ -471,12 +487,13 @@ bool Canvas::AttemptDrawBlurredRRect(const Rect& rect, // For symmetrically mask blurred solid RRects, absorb the mask blur and use // a faster SDF approximation. - - Color rrect_color = - paint.HasColorFilter() - // Absorb the color filter, if any. - ? paint.GetColorFilter()->GetCPUColorFilterProc()(paint.color) - : paint.color; + Color rrect_color = paint.color; + if (paint.invert_colors) { + rrect_color = rrect_color.ApplyColorMatrix(kColorInversion); + } + if (paint.color_filter) { + rrect_color = GetCPUColorFilterProc(paint.color_filter)(rrect_color); + } Paint rrect_paint = {.mask_blur_descriptor = paint.mask_blur_descriptor}; @@ -512,11 +529,13 @@ bool Canvas::AttemptDrawBlurredRRect(const Rect& rect, render_bounds.Expand(paint.mask_blur_descriptor->sigma.sigma * 4.0); } // Defer the alpha, blend mode, and image filter to a separate layer. - SaveLayer({.color = Color::White().WithAlpha(rrect_color.alpha), - .blend_mode = paint.blend_mode, - .image_filter = paint.image_filter}, - render_bounds, nullptr, ContentBoundsPromise::kContainsContents, - 1u); + SaveLayer( + Paint{ + .color = Color::White().WithAlpha(rrect_color.alpha), + .image_filter = paint.image_filter, + .blend_mode = paint.blend_mode, + }, + render_bounds, nullptr, ContentBoundsPromise::kContainsContents, 1u); rrect_paint.color = rrect_color.WithAlpha(1); } else { rrect_paint.color = rrect_color; @@ -892,8 +911,9 @@ void Canvas::DrawVertices(const std::shared_ptr& vertices, auto src_paint = paint; src_paint.color = paint.color.WithAlpha(1.0); - std::shared_ptr src_contents = - src_paint.CreateContentsForGeometry(vertices); + std::shared_ptr src_contents = + src_paint.CreateContents(); + src_contents->SetGeometry(vertices); // If the color source has an intrinsic size, then we use that to // create the src contents as a simplification. Otherwise we use @@ -912,8 +932,8 @@ void Canvas::DrawVertices(const std::shared_ptr& vertices, // NOLINTNEXTLINE(bugprone-unchecked-optional-access) vertices->GetTextureCoordinateCoverge().value_or(cvg.value()); } - src_contents = src_paint.CreateContentsForGeometry( - Geometry::MakeRect(Rect::Round(src_coverage))); + src_contents = src_paint.CreateContents(); + src_contents->SetGeometry(Geometry::MakeRect(Rect::Round(src_coverage))); auto contents = std::make_shared(); contents->SetBlendMode(blend_mode); @@ -1049,7 +1069,7 @@ std::optional Canvas::GetLocalCoverageLimit() const { void Canvas::SaveLayer(const Paint& paint, std::optional bounds, - const std::shared_ptr& backdrop_filter, + const flutter::DlImageFilter* backdrop_filter, ContentBoundsPromise bounds_promise, uint32_t total_content_depth, bool can_distribute_opacity) { @@ -1125,10 +1145,10 @@ void Canvas::SaveLayer(const Paint& paint, if (backdrop_filter) { local_position = subpass_coverage.GetOrigin() - GetGlobalPassPosition(); Canvas::BackdropFilterProc backdrop_filter_proc = - [backdrop_filter = backdrop_filter->Clone()]( + [backdrop_filter = backdrop_filter]( const FilterInput::Ref& input, const Matrix& effect_transform, Entity::RenderingMode rendering_mode) { - auto filter = backdrop_filter->WrapInput(input); + auto filter = WrapInput(backdrop_filter, input); filter->SetEffectTransform(effect_transform); filter->SetRenderingMode(rendering_mode); return filter; diff --git a/engine/src/flutter/impeller/display_list/canvas.h b/engine/src/flutter/impeller/display_list/canvas.h index d7287d3e10..e1cc8e2afd 100644 --- a/engine/src/flutter/impeller/display_list/canvas.h +++ b/engine/src/flutter/impeller/display_list/canvas.h @@ -11,8 +11,8 @@ #include #include +#include "display_list/effects/dl_image_filter.h" #include "impeller/core/sampler_descriptor.h" -#include "impeller/display_list/image_filter.h" #include "impeller/display_list/paint.h" #include "impeller/entity/contents/atlas_contents.h" #include "impeller/entity/entity.h" @@ -132,7 +132,7 @@ class Canvas { void SaveLayer( const Paint& paint, std::optional bounds = std::nullopt, - const std::shared_ptr& backdrop_filter = nullptr, + const flutter::DlImageFilter* backdrop_filter = nullptr, ContentBoundsPromise bounds_promise = ContentBoundsPromise::kUnknown, uint32_t total_content_depth = kMaxDepth, bool can_distribute_opacity = false); diff --git a/engine/src/flutter/impeller/display_list/canvas_unittests.cc b/engine/src/flutter/impeller/display_list/canvas_unittests.cc index 9dde79204c..dae5e25451 100644 --- a/engine/src/flutter/impeller/display_list/canvas_unittests.cc +++ b/engine/src/flutter/impeller/display_list/canvas_unittests.cc @@ -3,14 +3,9 @@ // found in the LICENSE file. #include "flutter/testing/testing.h" -#include "impeller/display_list/aiks_context.h" #include "impeller/display_list/aiks_unittests.h" #include "impeller/display_list/canvas.h" #include "impeller/geometry/geometry_asserts.h" -#include "impeller/geometry/path_builder.h" - -// TODO(zanderso): https://github.com/flutter/flutter/issues/127701 -// NOLINTBEGIN(bugprone-unchecked-optional-access) namespace impeller { namespace testing { @@ -98,34 +93,5 @@ TEST_P(AiksTest, CanvasCTMCanBeUpdated) { Matrix::MakeTranslation({100.0, 100.0, 0.0})); } -TEST_P(AiksTest, PaintWithFilters) { - // validate that a paint with a color filter "HasFilters", no other filters - // impact this setting. - Paint paint; - - ASSERT_FALSE(paint.HasColorFilter()); - - paint.color_filter = - ColorFilter::MakeBlend(BlendMode::kSourceOver, Color::Blue()); - - ASSERT_TRUE(paint.HasColorFilter()); - - paint.image_filter = ImageFilter::MakeBlur(Sigma(1.0), Sigma(1.0), - FilterContents::BlurStyle::kNormal, - Entity::TileMode::kClamp); - - ASSERT_TRUE(paint.HasColorFilter()); - - paint.mask_blur_descriptor = {}; - - ASSERT_TRUE(paint.HasColorFilter()); - - paint.color_filter = nullptr; - - ASSERT_FALSE(paint.HasColorFilter()); -} - } // namespace testing } // namespace impeller - -// NOLINTEND(bugprone-unchecked-optional-access) diff --git a/engine/src/flutter/impeller/display_list/color_filter.cc b/engine/src/flutter/impeller/display_list/color_filter.cc index ab81d771fc..e248ba6e09 100644 --- a/engine/src/flutter/impeller/display_list/color_filter.cc +++ b/engine/src/flutter/impeller/display_list/color_filter.cc @@ -4,187 +4,99 @@ #include "impeller/display_list/color_filter.h" -#include +#include "display_list/effects/dl_color_filter.h" +#include "fml/logging.h" +#include "impeller/display_list/skia_conversions.h" #include "impeller/entity/contents/filters/color_filter_contents.h" -#include "impeller/entity/contents/filters/filter_contents.h" #include "impeller/entity/contents/filters/inputs/filter_input.h" #include "impeller/geometry/color.h" namespace impeller { -/******************************************************************************* - ******* ColorFilter - ******************************************************************************/ - -ColorFilter::ColorFilter() = default; - -ColorFilter::~ColorFilter() = default; - -std::shared_ptr ColorFilter::MakeBlend(BlendMode blend_mode, - Color color) { - return std::make_shared(blend_mode, color); -} - -std::shared_ptr ColorFilter::MakeMatrix(ColorMatrix color_matrix) { - return std::make_shared(color_matrix); -} - -std::shared_ptr ColorFilter::MakeSrgbToLinear() { - return std::make_shared(); -} - -std::shared_ptr ColorFilter::MakeLinearToSrgb() { - return std::make_shared(); -} - -std::shared_ptr ColorFilter::MakeComposed( - const std::shared_ptr& outer, - const std::shared_ptr& inner) { - return std::make_shared(outer, inner); -} - -/******************************************************************************* - ******* BlendColorFilter - ******************************************************************************/ - -BlendColorFilter::BlendColorFilter(BlendMode blend_mode, Color color) - : blend_mode_(blend_mode), color_(color) {} - -BlendColorFilter::~BlendColorFilter() = default; - -std::shared_ptr BlendColorFilter::WrapWithGPUColorFilter( - std::shared_ptr input, - ColorFilterContents::AbsorbOpacity absorb_opacity) const { - auto filter = - ColorFilterContents::MakeBlend(blend_mode_, {std::move(input)}, color_); +std::shared_ptr WrapWithInvertColors( + const std::shared_ptr& input, + ColorFilterContents::AbsorbOpacity absorb_opacity) { + auto filter = ColorFilterContents::MakeColorMatrix({input}, kColorInversion); filter->SetAbsorbOpacity(absorb_opacity); return filter; } -ColorFilter::ColorFilterProc BlendColorFilter::GetCPUColorFilterProc() const { - return [filter_blend_mode = blend_mode_, filter_color = color_](Color color) { - return color.Blend(filter_color, filter_blend_mode); - }; +std::shared_ptr WrapWithGPUColorFilter( + const flutter::DlColorFilter* filter, + const std::shared_ptr& input, + ColorFilterContents::AbsorbOpacity absorb_opacity) { + FML_DCHECK(filter); + + switch (filter->type()) { + case flutter::DlColorFilterType::kBlend: { + const flutter::DlBlendColorFilter* blend_filter = filter->asBlend(); + FML_DCHECK(blend_filter); + + auto filter = ColorFilterContents::MakeBlend( + static_cast(blend_filter->mode()), {input}, + skia_conversions::ToColor(blend_filter->color())); + filter->SetAbsorbOpacity(absorb_opacity); + return filter; + } + case flutter::DlColorFilterType::kMatrix: { + const flutter::DlMatrixColorFilter* matrix_filter = filter->asMatrix(); + FML_DCHECK(matrix_filter); + + impeller::ColorMatrix color_matrix; + matrix_filter->get_matrix(color_matrix.array); + auto filter = ColorFilterContents::MakeColorMatrix({input}, color_matrix); + filter->SetAbsorbOpacity(absorb_opacity); + return filter; + } + case flutter::DlColorFilterType::kSrgbToLinearGamma: { + auto filter = ColorFilterContents::MakeSrgbToLinearFilter({input}); + filter->SetAbsorbOpacity(absorb_opacity); + return filter; + } + case flutter::DlColorFilterType::kLinearToSrgbGamma: { + auto filter = ColorFilterContents::MakeLinearToSrgbFilter({input}); + filter->SetAbsorbOpacity(absorb_opacity); + return filter; + } + } + + FML_UNREACHABLE(); } -std::shared_ptr BlendColorFilter::Clone() const { - return std::make_shared(*this); -} +ColorFilterProc GetCPUColorFilterProc(const flutter::DlColorFilter* filter) { + FML_DCHECK(filter); -/******************************************************************************* - ******* MatrixColorFilter - ******************************************************************************/ + switch (filter->type()) { + case flutter::DlColorFilterType::kBlend: { + const flutter::DlBlendColorFilter* blend_filter = filter->asBlend(); + FML_DCHECK(blend_filter); -MatrixColorFilter::MatrixColorFilter(ColorMatrix color_matrix) - : color_matrix_(color_matrix) {} + return [filter_blend_mode = static_cast(blend_filter->mode()), + filter_color = skia_conversions::ToColor(blend_filter->color())]( + Color color) { + return color.Blend(filter_color, filter_blend_mode); + }; + } + case flutter::DlColorFilterType::kMatrix: { + const flutter::DlMatrixColorFilter* matrix_filter = filter->asMatrix(); + FML_DCHECK(matrix_filter); -MatrixColorFilter::~MatrixColorFilter() = default; + impeller::ColorMatrix color_matrix; + matrix_filter->get_matrix(color_matrix.array); + return [color_matrix = color_matrix](Color color) { + return color.ApplyColorMatrix(color_matrix); + }; + } + case flutter::DlColorFilterType::kSrgbToLinearGamma: { + return [](Color color) { return color.SRGBToLinear(); }; + } -std::shared_ptr MatrixColorFilter::WrapWithGPUColorFilter( - std::shared_ptr input, - ColorFilterContents::AbsorbOpacity absorb_opacity) const { - auto filter = - ColorFilterContents::MakeColorMatrix({std::move(input)}, color_matrix_); - filter->SetAbsorbOpacity(absorb_opacity); - return filter; -} + case flutter::DlColorFilterType::kLinearToSrgbGamma: { + return [](Color color) { return color.LinearToSRGB(); }; + } + } -ColorFilter::ColorFilterProc MatrixColorFilter::GetCPUColorFilterProc() const { - return [color_matrix = color_matrix_](Color color) { - return color.ApplyColorMatrix(color_matrix); - }; -} - -std::shared_ptr MatrixColorFilter::Clone() const { - return std::make_shared(*this); -} - -/******************************************************************************* - ******* SrgbToLinearColorFilter - ******************************************************************************/ - -SrgbToLinearColorFilter::SrgbToLinearColorFilter() = default; - -SrgbToLinearColorFilter::~SrgbToLinearColorFilter() = default; - -std::shared_ptr -SrgbToLinearColorFilter::WrapWithGPUColorFilter( - std::shared_ptr input, - ColorFilterContents::AbsorbOpacity absorb_opacity) const { - auto filter = ColorFilterContents::MakeSrgbToLinearFilter({std::move(input)}); - filter->SetAbsorbOpacity(absorb_opacity); - return filter; -} - -ColorFilter::ColorFilterProc SrgbToLinearColorFilter::GetCPUColorFilterProc() - const { - return [](Color color) { return color.SRGBToLinear(); }; -} - -std::shared_ptr SrgbToLinearColorFilter::Clone() const { - return std::make_shared(*this); -} - -/******************************************************************************* - ******* LinearToSrgbColorFilter - ******************************************************************************/ - -LinearToSrgbColorFilter::LinearToSrgbColorFilter() = default; - -LinearToSrgbColorFilter::~LinearToSrgbColorFilter() = default; - -std::shared_ptr -LinearToSrgbColorFilter::WrapWithGPUColorFilter( - std::shared_ptr input, - ColorFilterContents::AbsorbOpacity absorb_opacity) const { - auto filter = ColorFilterContents::MakeSrgbToLinearFilter({std::move(input)}); - filter->SetAbsorbOpacity(absorb_opacity); - return filter; -} - -ColorFilter::ColorFilterProc LinearToSrgbColorFilter::GetCPUColorFilterProc() - const { - return [](Color color) { return color.LinearToSRGB(); }; -} - -std::shared_ptr LinearToSrgbColorFilter::Clone() const { - return std::make_shared(*this); -} - -/******************************************************************************* - ******* ComposedColorFilter - ******************************************************************************/ - -ComposedColorFilter::ComposedColorFilter( - const std::shared_ptr& outer, - const std::shared_ptr& inner) - : outer_(outer), inner_(inner) {} - -ComposedColorFilter::~ComposedColorFilter() = default; - -std::shared_ptr -ComposedColorFilter::WrapWithGPUColorFilter( - std::shared_ptr input, - ColorFilterContents::AbsorbOpacity absorb_opacity) const { - std::shared_ptr inner = inner_->WrapWithGPUColorFilter( - input, ColorFilterContents::AbsorbOpacity::kNo); - return outer_->WrapWithGPUColorFilter(FilterInput::Make(inner), - absorb_opacity); -} - -// |ColorFilter| -ColorFilter::ColorFilterProc ComposedColorFilter::GetCPUColorFilterProc() - const { - return [inner = inner_, outer = outer_](Color color) { - auto inner_proc = inner->GetCPUColorFilterProc(); - auto outer_proc = outer->GetCPUColorFilterProc(); - return outer_proc(inner_proc(color)); - }; -} - -// |ColorFilter| -std::shared_ptr ComposedColorFilter::Clone() const { - return std::make_shared(outer_, inner_); + FML_UNREACHABLE(); } } // namespace impeller diff --git a/engine/src/flutter/impeller/display_list/color_filter.h b/engine/src/flutter/impeller/display_list/color_filter.h index 29904fcbb8..2532980c22 100644 --- a/engine/src/flutter/impeller/display_list/color_filter.h +++ b/engine/src/flutter/impeller/display_list/color_filter.h @@ -5,176 +5,37 @@ #ifndef FLUTTER_IMPELLER_DISPLAY_LIST_COLOR_FILTER_H_ #define FLUTTER_IMPELLER_DISPLAY_LIST_COLOR_FILTER_H_ +#include "display_list/effects/dl_color_filter.h" #include "impeller/entity/contents/filters/color_filter_contents.h" #include "impeller/geometry/color.h" namespace impeller { -struct Paint; - -/******************************************************************************* - ******* ColorFilter - ******************************************************************************/ - -class ColorFilter { - public: - /// A procedure that filters a given unpremultiplied color to produce a new - /// unpremultiplied color. - using ColorFilterProc = std::function; - - ColorFilter(); - - virtual ~ColorFilter(); - - static std::shared_ptr MakeBlend(BlendMode blend_mode, - Color color); - - static std::shared_ptr MakeMatrix(ColorMatrix color_matrix); - - static std::shared_ptr MakeSrgbToLinear(); - - static std::shared_ptr MakeLinearToSrgb(); - - static std::shared_ptr MakeComposed( - const std::shared_ptr& outer, - const std::shared_ptr& inner); - - /// @brief Wraps the given filter input with a GPU-based filter that will - /// perform the color operation. The given input will first be - /// rendered to a texture and then filtered. - /// - /// Note that this operation has no consideration for the original - /// geometry mask of the filter input. And the entire input texture is - /// treated as color information. - virtual std::shared_ptr WrapWithGPUColorFilter( - std::shared_ptr input, - ColorFilterContents::AbsorbOpacity absorb_opacity) const = 0; - - /// @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 Clone() const = 0; +/// A color matrix which inverts colors. +// clang-format off +static const constexpr ColorMatrix kColorInversion = { + .array = { + -1.0, 0, 0, 1.0, 0, // + 0, -1.0, 0, 1.0, 0, // + 0, 0, -1.0, 1.0, 0, // + 1.0, 1.0, 1.0, 1.0, 0 // + } }; -/******************************************************************************* - ******* BlendColorFilter - ******************************************************************************/ +std::shared_ptr WrapWithInvertColors( + const std::shared_ptr& input, + ColorFilterContents::AbsorbOpacity absorb_opacity); -class BlendColorFilter final : public ColorFilter { - public: - BlendColorFilter(BlendMode blend_mode, Color color); +std::shared_ptr WrapWithGPUColorFilter( + const flutter::DlColorFilter* filter, + const std::shared_ptr& input, + ColorFilterContents::AbsorbOpacity absorb_opacity); - ~BlendColorFilter() override; +/// A procedure that filters a given unpremultiplied color to produce a new +/// unpremultiplied color. +using ColorFilterProc = std::function; - // |ColorFilter| - std::shared_ptr WrapWithGPUColorFilter( - std::shared_ptr input, - ColorFilterContents::AbsorbOpacity absorb_opacity) const override; - - // |ColorFilter| - ColorFilterProc GetCPUColorFilterProc() const override; - - // |ColorFilter| - std::shared_ptr Clone() const override; - - private: - BlendMode blend_mode_; - Color color_; -}; - -/******************************************************************************* - ******* MatrixColorFilter - ******************************************************************************/ - -class MatrixColorFilter final : public ColorFilter { - public: - explicit MatrixColorFilter(ColorMatrix color_matrix); - - ~MatrixColorFilter() override; - - // |ColorFilter| - std::shared_ptr WrapWithGPUColorFilter( - std::shared_ptr input, - ColorFilterContents::AbsorbOpacity absorb_opacity) const override; - - // |ColorFilter| - ColorFilterProc GetCPUColorFilterProc() const override; - - // |ColorFilter| - std::shared_ptr Clone() const override; - - private: - ColorMatrix color_matrix_; -}; - -/******************************************************************************* - ******* SrgbToLinearColorFilter - ******************************************************************************/ - -class SrgbToLinearColorFilter final : public ColorFilter { - public: - explicit SrgbToLinearColorFilter(); - - ~SrgbToLinearColorFilter() override; - - // |ColorFilter| - std::shared_ptr WrapWithGPUColorFilter( - std::shared_ptr input, - ColorFilterContents::AbsorbOpacity absorb_opacity) const override; - - // |ColorFilter| - ColorFilterProc GetCPUColorFilterProc() const override; - - // |ColorFilter| - std::shared_ptr Clone() const override; -}; - -/******************************************************************************* - ******* LinearToSrgbColorFilter - ******************************************************************************/ - -class LinearToSrgbColorFilter final : public ColorFilter { - public: - explicit LinearToSrgbColorFilter(); - - ~LinearToSrgbColorFilter() override; - - // |ColorFilter| - std::shared_ptr WrapWithGPUColorFilter( - std::shared_ptr input, - ColorFilterContents::AbsorbOpacity absorb_opacity) const override; - - // |ColorFilter| - ColorFilterProc GetCPUColorFilterProc() const override; - - // |ColorFilter| - std::shared_ptr Clone() const override; -}; - -/// @brief Applies color filters as f(g(x)), where x is the input color. -class ComposedColorFilter final : public ColorFilter { - public: - ComposedColorFilter(const std::shared_ptr& outer, - const std::shared_ptr& inner); - - ~ComposedColorFilter() override; - - // |ColorFilter| - std::shared_ptr WrapWithGPUColorFilter( - std::shared_ptr input, - ColorFilterContents::AbsorbOpacity absorb_opacity) const override; - - // |ColorFilter| - ColorFilterProc GetCPUColorFilterProc() const override; - - // |ColorFilter| - std::shared_ptr Clone() const override; - - private: - std::shared_ptr outer_; - std::shared_ptr inner_; -}; +ColorFilterProc GetCPUColorFilterProc(const flutter::DlColorFilter* filter); } // namespace impeller diff --git a/engine/src/flutter/impeller/display_list/dl_dispatcher.cc b/engine/src/flutter/impeller/display_list/dl_dispatcher.cc index ceabd4ff52..6a06ce5ff5 100644 --- a/engine/src/flutter/impeller/display_list/dl_dispatcher.cc +++ b/engine/src/flutter/impeller/display_list/dl_dispatcher.cc @@ -114,70 +114,6 @@ struct DepthWatcher { #define UNIMPLEMENTED \ FML_DLOG(ERROR) << "Unimplemented detail in " << __FUNCTION__; -static BlendMode ToBlendMode(flutter::DlBlendMode mode) { - switch (mode) { - case flutter::DlBlendMode::kClear: - return BlendMode::kClear; - case flutter::DlBlendMode::kSrc: - return BlendMode::kSource; - case flutter::DlBlendMode::kDst: - return BlendMode::kDestination; - case flutter::DlBlendMode::kSrcOver: - return BlendMode::kSourceOver; - case flutter::DlBlendMode::kDstOver: - return BlendMode::kDestinationOver; - case flutter::DlBlendMode::kSrcIn: - return BlendMode::kSourceIn; - case flutter::DlBlendMode::kDstIn: - return BlendMode::kDestinationIn; - case flutter::DlBlendMode::kSrcOut: - return BlendMode::kSourceOut; - case flutter::DlBlendMode::kDstOut: - return BlendMode::kDestinationOut; - case flutter::DlBlendMode::kSrcATop: - return BlendMode::kSourceATop; - case flutter::DlBlendMode::kDstATop: - return BlendMode::kDestinationATop; - case flutter::DlBlendMode::kXor: - return BlendMode::kXor; - case flutter::DlBlendMode::kPlus: - return BlendMode::kPlus; - case flutter::DlBlendMode::kModulate: - return BlendMode::kModulate; - case flutter::DlBlendMode::kScreen: - return BlendMode::kScreen; - case flutter::DlBlendMode::kOverlay: - return BlendMode::kOverlay; - case flutter::DlBlendMode::kDarken: - return BlendMode::kDarken; - case flutter::DlBlendMode::kLighten: - return BlendMode::kLighten; - case flutter::DlBlendMode::kColorDodge: - return BlendMode::kColorDodge; - case flutter::DlBlendMode::kColorBurn: - return BlendMode::kColorBurn; - case flutter::DlBlendMode::kHardLight: - return BlendMode::kHardLight; - case flutter::DlBlendMode::kSoftLight: - return BlendMode::kSoftLight; - case flutter::DlBlendMode::kDifference: - return BlendMode::kDifference; - case flutter::DlBlendMode::kExclusion: - return BlendMode::kExclusion; - case flutter::DlBlendMode::kMultiply: - return BlendMode::kMultiply; - case flutter::DlBlendMode::kHue: - return BlendMode::kHue; - case flutter::DlBlendMode::kSaturation: - return BlendMode::kSaturation; - case flutter::DlBlendMode::kColor: - return BlendMode::kColor; - case flutter::DlBlendMode::kLuminosity: - return BlendMode::kLuminosity; - } - FML_UNREACHABLE(); -} - static impeller::SamplerDescriptor ToSamplerDescriptor( const flutter::DlFilterMode options) { impeller::SamplerDescriptor desc; @@ -289,37 +225,11 @@ void DlDispatcherBase::setColorSource(const flutter::DlColorSource* source) { } } -static std::shared_ptr ToColorFilter( - const flutter::DlColorFilter* filter) { - if (filter == nullptr) { - return nullptr; - } - switch (filter->type()) { - case flutter::DlColorFilterType::kBlend: { - auto dl_blend = filter->asBlend(); - auto blend_mode = ToBlendMode(dl_blend->mode()); - auto color = skia_conversions::ToColor(dl_blend->color()); - return ColorFilter::MakeBlend(blend_mode, color); - } - case flutter::DlColorFilterType::kMatrix: { - const flutter::DlMatrixColorFilter* dl_matrix = filter->asMatrix(); - impeller::ColorMatrix color_matrix; - dl_matrix->get_matrix(color_matrix.array); - return ColorFilter::MakeMatrix(color_matrix); - } - case flutter::DlColorFilterType::kSrgbToLinearGamma: - return ColorFilter::MakeSrgbToLinear(); - case flutter::DlColorFilterType::kLinearToSrgbGamma: - return ColorFilter::MakeLinearToSrgb(); - } - return nullptr; -} - // |flutter::DlOpReceiver| void DlDispatcherBase::setColorFilter(const flutter::DlColorFilter* filter) { AUTO_DEPTH_WATCHER(0u); - paint_.color_filter = ToColorFilter(filter); + paint_.color_filter = filter; } // |flutter::DlOpReceiver| @@ -333,7 +243,7 @@ void DlDispatcherBase::setInvertColors(bool invert) { void DlDispatcherBase::setBlendMode(flutter::DlBlendMode dl_mode) { AUTO_DEPTH_WATCHER(0u); - paint_.blend_mode = ToBlendMode(dl_mode); + paint_.blend_mode = skia_conversions::ToBlendMode(dl_mode); } static FilterContents::BlurStyle ToBlurStyle(flutter::DlBlurStyle blur_style) { @@ -372,102 +282,11 @@ void DlDispatcherBase::setMaskFilter(const flutter::DlMaskFilter* filter) { } } -static std::shared_ptr ToImageFilter( - const flutter::DlImageFilter* filter) { - if (filter == nullptr) { - return nullptr; - } - - switch (filter->type()) { - case flutter::DlImageFilterType::kBlur: { - auto blur = filter->asBlur(); - auto sigma_x = Sigma(blur->sigma_x()); - auto sigma_y = Sigma(blur->sigma_y()); - auto tile_mode = static_cast(blur->tile_mode()); - return ImageFilter::MakeBlur( - sigma_x, sigma_y, FilterContents::BlurStyle::kNormal, tile_mode); - } - case flutter::DlImageFilterType::kDilate: { - auto dilate = filter->asDilate(); - FML_DCHECK(dilate); - if (dilate->radius_x() < 0 || dilate->radius_y() < 0) { - return nullptr; - } - auto radius_x = Radius(dilate->radius_x()); - auto radius_y = Radius(dilate->radius_y()); - return ImageFilter::MakeDilate(radius_x, radius_y); - } - case flutter::DlImageFilterType::kErode: { - auto erode = filter->asErode(); - FML_DCHECK(erode); - if (erode->radius_x() < 0 || erode->radius_y() < 0) { - return nullptr; - } - auto radius_x = Radius(erode->radius_x()); - auto radius_y = Radius(erode->radius_y()); - return ImageFilter::MakeErode(radius_x, radius_y); - } - case flutter::DlImageFilterType::kMatrix: { - auto matrix_filter = filter->asMatrix(); - FML_DCHECK(matrix_filter); - auto matrix = skia_conversions::ToMatrix(matrix_filter->matrix()); - auto desc = - skia_conversions::ToSamplerDescriptor(matrix_filter->sampling()); - return ImageFilter::MakeMatrix(matrix, desc); - } - case flutter::DlImageFilterType::kCompose: { - auto compose = filter->asCompose(); - FML_DCHECK(compose); - 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_filter) { - return outer_filter; - } - FML_DCHECK(outer_filter && inner_filter); - - return ImageFilter::MakeCompose(*inner_filter, *outer_filter); - } - case flutter::DlImageFilterType::kColorFilter: { - auto color_filter_image_filter = filter->asColorFilter(); - FML_DCHECK(color_filter_image_filter); - auto color_filter = - ToColorFilter(color_filter_image_filter->color_filter().get()); - if (!color_filter) { - return nullptr; - } - // 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(); - FML_DCHECK(local_matrix_filter); - auto internal_filter = local_matrix_filter->image_filter(); - FML_DCHECK(internal_filter); - - auto image_filter = ToImageFilter(internal_filter.get()); - if (!image_filter) { - return nullptr; - } - - auto matrix = skia_conversions::ToMatrix(local_matrix_filter->matrix()); - return ImageFilter::MakeLocalMatrix(matrix, *image_filter); - } - } -} - // |flutter::DlOpReceiver| void DlDispatcherBase::setImageFilter(const flutter::DlImageFilter* filter) { AUTO_DEPTH_WATCHER(0u); - paint_.image_filter = ToImageFilter(filter); + paint_.image_filter = filter; } // |flutter::DlOpReceiver| @@ -497,8 +316,7 @@ void DlDispatcherBase::saveLayer(const DlRect& bounds, } GetCanvas().SaveLayer( - paint, impeller_bounds, ToImageFilter(backdrop), promise, - total_content_depth, + paint, impeller_bounds, backdrop, promise, total_content_depth, // Unbounded content can still have user specified bounds that require a // saveLayer to be created to perform the clip. options.can_distribute_opacity() && !options.content_is_unbounded()); @@ -674,7 +492,7 @@ void DlDispatcherBase::drawColor(flutter::DlColor color, Paint paint; paint.color = skia_conversions::ToColor(color); - paint.blend_mode = ToBlendMode(dl_mode); + paint.blend_mode = skia_conversions::ToBlendMode(dl_mode); GetCanvas().DrawPaint(paint); } @@ -950,7 +768,7 @@ void DlDispatcherBase::drawAtlas(const sk_sp atlas, tex, // colors, // static_cast(count), // - ToBlendMode(mode), // + skia_conversions::ToBlendMode(mode), // skia_conversions::ToSamplerDescriptor(sampling), // skia_conversions::ToRect(cull_rect) // ); @@ -1117,7 +935,8 @@ static bool RequiresReadbackForBlends( const ContentContext& renderer, flutter::DlBlendMode max_root_blend_mode) { return !renderer.GetDeviceCapabilities().SupportsFramebufferFetch() && - ToBlendMode(max_root_blend_mode) > Entity::kLastPipelineBlendMode; + skia_conversions::ToBlendMode(max_root_blend_mode) > + Entity::kLastPipelineBlendMode; } CanvasDlDispatcher::CanvasDlDispatcher(ContentContext& renderer, @@ -1143,7 +962,7 @@ void CanvasDlDispatcher::drawVertices( GetCanvas().DrawVertices( std::make_shared(vertices, renderer_), - ToBlendMode(dl_mode), paint_); + skia_conversions::ToBlendMode(dl_mode), paint_); } //// Text Frame Dispatcher diff --git a/engine/src/flutter/impeller/display_list/image_filter.cc b/engine/src/flutter/impeller/display_list/image_filter.cc index b06c1e38ed..2f0af79c66 100644 --- a/engine/src/flutter/impeller/display_list/image_filter.cc +++ b/engine/src/flutter/impeller/display_list/image_filter.cc @@ -3,206 +3,107 @@ // found in the LICENSE file. #include "impeller/display_list/image_filter.h" +#include "fml/logging.h" +#include "impeller/display_list/color_filter.h" +#include "impeller/display_list/skia_conversions.h" #include "impeller/entity/contents/filters/color_filter_contents.h" #include "impeller/entity/contents/filters/filter_contents.h" #include "impeller/entity/contents/filters/inputs/filter_input.h" namespace impeller { -/******************************************************************************* - ******* ImageFilter - ******************************************************************************/ +std::shared_ptr WrapInput(const flutter::DlImageFilter* filter, + const FilterInput::Ref& input) { + FML_DCHECK(filter); -ImageFilter::ImageFilter() = default; + switch (filter->type()) { + case flutter::DlImageFilterType::kBlur: { + auto blur_filter = filter->asBlur(); + FML_DCHECK(blur_filter); -ImageFilter::~ImageFilter() = default; + return FilterContents::MakeGaussianBlur( + input, // + Sigma(blur_filter->sigma_x()), // + Sigma(blur_filter->sigma_y()), // + static_cast(blur_filter->tile_mode()), // + FilterContents::BlurStyle::kNormal // + ); + } + case flutter::DlImageFilterType::kDilate: { + auto dilate_filter = filter->asDilate(); + FML_DCHECK(dilate_filter); -std::shared_ptr ImageFilter::MakeBlur( - Sigma sigma_x, - Sigma sigma_y, - FilterContents::BlurStyle blur_style, - Entity::TileMode tile_mode) { - return std::make_shared(sigma_x, sigma_y, blur_style, - tile_mode); -} + return FilterContents::MakeMorphology( + input, // + Radius(dilate_filter->radius_x()), // + Radius(dilate_filter->radius_y()), // + FilterContents::MorphType::kDilate // + ); + } + case flutter::DlImageFilterType::kErode: { + auto erode_filter = filter->asErode(); + FML_DCHECK(erode_filter); -std::shared_ptr ImageFilter::MakeDilate(Radius radius_x, - Radius radius_y) { - return std::make_shared(radius_x, radius_y); -} + return FilterContents::MakeMorphology( + input, // + Radius(erode_filter->radius_x()), // + Radius(erode_filter->radius_y()), // + FilterContents::MorphType::kErode // + ); + } + case flutter::DlImageFilterType::kMatrix: { + auto matrix_filter = filter->asMatrix(); + FML_DCHECK(matrix_filter); -std::shared_ptr ImageFilter::MakeErode(Radius radius_x, - Radius radius_y) { - return std::make_shared(radius_x, radius_y); -} + auto matrix = skia_conversions::ToMatrix(matrix_filter->matrix()); + auto desc = + skia_conversions::ToSamplerDescriptor(matrix_filter->sampling()); + return FilterContents::MakeMatrixFilter(input, matrix, desc); + } + case flutter::DlImageFilterType::kLocalMatrix: { + auto matrix_filter = filter->asLocalMatrix(); + FML_DCHECK(matrix_filter); + FML_DCHECK(matrix_filter->image_filter()); -std::shared_ptr ImageFilter::MakeMatrix( - const Matrix& matrix, - SamplerDescriptor sampler_descriptor) { - return std::make_shared(matrix, - std::move(sampler_descriptor)); -} + auto matrix = skia_conversions::ToMatrix(matrix_filter->matrix()); + return FilterContents::MakeLocalMatrixFilter( + FilterInput::Make( + WrapInput(matrix_filter->image_filter().get(), input)), + matrix); + } + case flutter::DlImageFilterType::kColorFilter: { + auto image_color_filter = filter->asColorFilter(); + FML_DCHECK(image_color_filter); + auto color_filter = image_color_filter->color_filter(); + FML_DCHECK(color_filter); -std::shared_ptr ImageFilter::MakeCompose( - const ImageFilter& inner, - const ImageFilter& outer) { - return std::make_shared(inner, outer); -} + // 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 WrapWithGPUColorFilter(color_filter.get(), input, + ColorFilterContents::AbsorbOpacity::kNo); + } + case flutter::DlImageFilterType::kCompose: { + auto compose = filter->asCompose(); + FML_DCHECK(compose); -std::shared_ptr ImageFilter::MakeFromColorFilter( - const ColorFilter& color_filter) { - return std::make_shared(color_filter); -} + auto outer_dl_filter = compose->outer(); + auto inner_dl_filter = compose->inner(); + if (!outer_dl_filter) { + return WrapInput(inner_dl_filter.get(), input); + } + if (!inner_dl_filter) { + return WrapInput(outer_dl_filter.get(), input); + } + FML_DCHECK(outer_dl_filter && inner_dl_filter); -std::shared_ptr ImageFilter::MakeLocalMatrix( - const Matrix& matrix, - const ImageFilter& internal_filter) { - return std::make_shared(matrix, internal_filter); -} - -std::shared_ptr 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 BlurImageFilter::WrapInput( - const FilterInput::Ref& input) const { - return FilterContents::MakeGaussianBlur(input, sigma_x_, sigma_y_, tile_mode_, - blur_style_); -} - -std::shared_ptr BlurImageFilter::Clone() const { - return std::make_shared(*this); -} - -/******************************************************************************* - ******* DilateImageFilter - ******************************************************************************/ - -DilateImageFilter::DilateImageFilter(Radius radius_x, Radius radius_y) - : radius_x_(radius_x), radius_y_(radius_y) {} - -DilateImageFilter::~DilateImageFilter() = default; - -std::shared_ptr DilateImageFilter::WrapInput( - const FilterInput::Ref& input) const { - return FilterContents::MakeMorphology(input, radius_x_, radius_y_, - FilterContents::MorphType::kDilate); -} - -std::shared_ptr DilateImageFilter::Clone() const { - return std::make_shared(*this); -} - -/******************************************************************************* - ******* ErodeImageFilter - ******************************************************************************/ - -ErodeImageFilter::ErodeImageFilter(Radius radius_x, Radius radius_y) - : radius_x_(radius_x), radius_y_(radius_y) {} - -ErodeImageFilter::~ErodeImageFilter() = default; - -std::shared_ptr ErodeImageFilter::WrapInput( - const FilterInput::Ref& input) const { - return FilterContents::MakeMorphology(input, radius_x_, radius_y_, - FilterContents::MorphType::kErode); -} - -std::shared_ptr ErodeImageFilter::Clone() const { - return std::make_shared(*this); -} - -/******************************************************************************* - ******* MatrixImageFilter - ******************************************************************************/ - -MatrixImageFilter::MatrixImageFilter(const Matrix& matrix, - SamplerDescriptor sampler_descriptor) - : matrix_(matrix), sampler_descriptor_(std::move(sampler_descriptor)) {} - -MatrixImageFilter::~MatrixImageFilter() = default; - -std::shared_ptr MatrixImageFilter::WrapInput( - const FilterInput::Ref& input) const { - return FilterContents::MakeMatrixFilter(input, matrix_, sampler_descriptor_); -} - -std::shared_ptr MatrixImageFilter::Clone() const { - return std::make_shared(*this); -} - -/******************************************************************************* - ******* ComposeImageFilter - ******************************************************************************/ - -ComposeImageFilter::ComposeImageFilter(const ImageFilter& inner, - const ImageFilter& outer) - : inner_(inner.Clone()), outer_(outer.Clone()) {} - -ComposeImageFilter::~ComposeImageFilter() = default; - -std::shared_ptr ComposeImageFilter::WrapInput( - const FilterInput::Ref& input) const { - return outer_->WrapInput(FilterInput::Make(inner_->WrapInput(input))); -} - -std::shared_ptr ComposeImageFilter::Clone() const { - return std::make_shared(*this); -} - -/******************************************************************************* - ******* ColorImageFilter - ******************************************************************************/ - -ColorImageFilter::ColorImageFilter(const ColorFilter& color_filter) - : color_filter_(color_filter.Clone()) {} - -ColorImageFilter::~ColorImageFilter() = default; - -std::shared_ptr ColorImageFilter::WrapInput( - const FilterInput::Ref& input) const { - return color_filter_->WrapWithGPUColorFilter( - input, ColorFilterContents::AbsorbOpacity::kNo); -} - -std::shared_ptr ColorImageFilter::Clone() const { - return std::make_shared(*this); -} - -/******************************************************************************* - ******* LocalMatrixImageFilter - ******************************************************************************/ - -LocalMatrixImageFilter::LocalMatrixImageFilter( - const Matrix& matrix, - const ImageFilter& internal_filter) - : matrix_(matrix), internal_filter_(internal_filter.Clone()) {} - -LocalMatrixImageFilter::~LocalMatrixImageFilter() = default; - -std::shared_ptr LocalMatrixImageFilter::WrapInput( - const FilterInput::Ref& input) const { - return FilterContents::MakeLocalMatrixFilter( - FilterInput::Make(internal_filter_->WrapInput(input)), matrix_); -} - -std::shared_ptr LocalMatrixImageFilter::Clone() const { - return std::make_shared(*this); + return WrapInput( + outer_dl_filter.get(), + FilterInput::Make(WrapInput(inner_dl_filter.get(), input))); + } + } + FML_UNREACHABLE(); } } // namespace impeller diff --git a/engine/src/flutter/impeller/display_list/image_filter.h b/engine/src/flutter/impeller/display_list/image_filter.h index 0c3d32192d..13c3164c2b 100644 --- a/engine/src/flutter/impeller/display_list/image_filter.h +++ b/engine/src/flutter/impeller/display_list/image_filter.h @@ -5,233 +5,15 @@ #ifndef FLUTTER_IMPELLER_DISPLAY_LIST_IMAGE_FILTER_H_ #define FLUTTER_IMPELLER_DISPLAY_LIST_IMAGE_FILTER_H_ -#include "impeller/core/sampler_descriptor.h" -#include "impeller/display_list/color_filter.h" +#include "display_list/effects/dl_image_filter.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 MakeBlur( - Sigma sigma_x, - Sigma sigma_y, - FilterContents::BlurStyle blur_style, - Entity::TileMode tile_mode); - - static std::shared_ptr MakeDilate(Radius radius_x, - Radius radius_y); - - static std::shared_ptr MakeErode(Radius radius_x, - Radius radius_y); - - static std::shared_ptr MakeMatrix( - const Matrix& matrix, - SamplerDescriptor sampler_descriptor); - - static std::shared_ptr MakeCompose(const ImageFilter& inner, - const ImageFilter& outer); - - static std::shared_ptr MakeFromColorFilter( - const ColorFilter& color_filter); - - static std::shared_ptr 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 GetFilterContents() const; - - /// @brief Wraps the given filter input with a GPU-based image filter. - virtual std::shared_ptr WrapInput( - const FilterInput::Ref& input) const = 0; - - virtual std::shared_ptr Clone() const = 0; - - virtual int GetRequiredMipCount() const { return 1; } -}; - -/******************************************************************************* - ******* 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 WrapInput( - const FilterInput::Ref& input) const override; - - // |ImageFilter| - std::shared_ptr Clone() const override; - - int GetRequiredMipCount() const override { return 4; } - - 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 WrapInput( - const FilterInput::Ref& input) const override; - - // |ImageFilter| - std::shared_ptr 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 WrapInput( - const FilterInput::Ref& input) const override; - - // |ImageFilter| - std::shared_ptr 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 WrapInput( - const FilterInput::Ref& input) const override; - - // |ImageFilter| - std::shared_ptr Clone() const override; - - const Matrix& GetMatrix() const { return matrix_; } - - 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 WrapInput( - const FilterInput::Ref& input) const override; - - // |ImageFilter| - std::shared_ptr Clone() const override; - - private: - std::shared_ptr inner_; - std::shared_ptr outer_; -}; - -/******************************************************************************* - ******* ColorImageFilter - ******************************************************************************/ - -class ColorImageFilter : public ImageFilter { - public: - explicit ColorImageFilter(const ColorFilter& color_filter); - - ~ColorImageFilter() override; - - // |ImageFilter| - std::shared_ptr WrapInput( - const FilterInput::Ref& input) const override; - - // |ImageFilter| - std::shared_ptr Clone() const override; - - private: - std::shared_ptr color_filter_; -}; - -/******************************************************************************* - ******* LocalMatrixImageFilter - ******************************************************************************/ - -class LocalMatrixImageFilter : public ImageFilter { - public: - LocalMatrixImageFilter(const Matrix& matrix, - const ImageFilter& internal_filter); - - ~LocalMatrixImageFilter() override; - - // |ImageFilter| - std::shared_ptr WrapInput( - const FilterInput::Ref& input) const override; - - // |ImageFilter| - std::shared_ptr Clone() const override; - - private: - Matrix matrix_; - std::shared_ptr internal_filter_; -}; +/// @brief Generate a new FilterContents using this filter's configuration. +/// +std::shared_ptr WrapInput(const flutter::DlImageFilter* filter, + const FilterInput::Ref& input); } // namespace impeller diff --git a/engine/src/flutter/impeller/display_list/paint.cc b/engine/src/flutter/impeller/display_list/paint.cc index cf7029a916..59105b462c 100644 --- a/engine/src/flutter/impeller/display_list/paint.cc +++ b/engine/src/flutter/impeller/display_list/paint.cc @@ -6,9 +6,11 @@ #include +#include "display_list/effects/dl_color_filter.h" #include "display_list/effects/dl_color_source.h" #include "display_list/geometry/dl_path.h" #include "fml/logging.h" +#include "impeller/display_list/color_filter.h" #include "impeller/display_list/skia_conversions.h" #include "impeller/entity/contents/color_source_contents.h" #include "impeller/entity/contents/conical_gradient_contents.h" @@ -31,18 +33,6 @@ using DlRect = flutter::DlRect; using DlIRect = flutter::DlIRect; using DlPath = flutter::DlPath; -/// A color matrix which inverts colors. -// clang-format off -constexpr ColorMatrix kColorInversion = { - .array = { - -1.0, 0, 0, 1.0, 0, // - 0, -1.0, 0, 1.0, 0, // - 0, 0, -1.0, 1.0, 0, // - 1.0, 1.0, 1.0, 1.0, 0 // - } -}; -// clang-format on - std::shared_ptr Paint::CreateContents() const { if (color_source == nullptr) { auto contents = std::make_shared(); @@ -194,11 +184,26 @@ std::shared_ptr Paint::CreateContents() const { contents->SetTileModes(x_tile_mode, y_tile_mode); contents->SetSamplerDescriptor(sampler_descriptor); contents->SetEffectTransform(effect_transform); - if (color_filter) { + if (color_filter || invert_colors) { TiledTextureContents::ColorFilterProc filter_proc = - [color_filter = color_filter](FilterInput::Ref input) { - return color_filter->WrapWithGPUColorFilter( - std::move(input), ColorFilterContents::AbsorbOpacity::kNo); + [color_filter = color_filter, + invert_colors = invert_colors](const FilterInput::Ref& input) { + if (invert_colors && color_filter) { + std::shared_ptr color_filter_output = + WrapWithGPUColorFilter( + color_filter, input, + ColorFilterContents::AbsorbOpacity::kNo); + return WrapWithInvertColors( + FilterInput::Make(color_filter_output), + ColorFilterContents::AbsorbOpacity::kNo); + } + if (color_filter) { + return WrapWithGPUColorFilter( + color_filter, input, + ColorFilterContents::AbsorbOpacity::kNo); + } + return WrapWithInvertColors( + input, ColorFilterContents::AbsorbOpacity::kNo); }; contents->SetColorFilter(filter_proc); } @@ -247,32 +252,6 @@ std::shared_ptr Paint::CreateContents() const { FML_UNREACHABLE(); } -std::shared_ptr Paint::CreateContentsForGeometry( - const std::shared_ptr& geometry) const { - auto contents = CreateContents(); - - // Attempt to apply the color filter on the CPU first. - // Note: This is not just an optimization; some color sources rely on - // CPU-applied color filters to behave properly. - auto color_filter = GetColorFilter(); - bool needs_color_filter = !!color_filter; - if (color_filter && - contents->ApplyColorFilter(color_filter->GetCPUColorFilterProc())) { - needs_color_filter = false; - } - - contents->SetGeometry(geometry); - if (mask_blur_descriptor.has_value()) { - // If there's a mask blur and we need to apply the color filter on the GPU, - // we need to be careful to only apply the color filter to the source - // colors. CreateMaskBlur is able to handle this case. - return mask_blur_descriptor->CreateMaskBlur( - contents, needs_color_filter ? color_filter : nullptr); - } - - return contents; -} - std::shared_ptr Paint::WithFilters( std::shared_ptr input) const { input = WithColorFilter(input, ColorFilterContents::AbsorbOpacity::kYes); @@ -314,7 +293,7 @@ std::shared_ptr Paint::WithImageFilter( if (!image_filter) { return nullptr; } - auto filter = image_filter->WrapInput(FilterInput::Make(input)); + auto filter = WrapInput(image_filter, FilterInput::Make(input)); filter->SetRenderingMode(rendering_mode); filter->SetEffectTransform(effect_transform); return filter; @@ -330,19 +309,34 @@ std::shared_ptr Paint::WithColorFilter( return input; } - auto color_filter = GetColorFilter(); - if (!color_filter) { + if (!color_filter && !invert_colors) { return input; } // Attempt to apply the color filter on the CPU first. // Note: This is not just an optimization; some color sources rely on // CPU-applied color filters to behave properly. - if (input->ApplyColorFilter(color_filter->GetCPUColorFilterProc())) { + if (input->ApplyColorFilter([&](Color color) -> Color { + if (color_filter) { + color = GetCPUColorFilterProc(color_filter)(color); + } + if (invert_colors) { + color = color.ApplyColorMatrix(kColorInversion); + } + return color; + })) { return input; } - return color_filter->WrapWithGPUColorFilter(FilterInput::Make(input), - absorb_opacity); + + if (color_filter) { + input = WrapWithGPUColorFilter(color_filter, FilterInput::Make(input), + absorb_opacity); + } + if (invert_colors) { + input = WrapWithInvertColors(FilterInput::Make(input), absorb_opacity); + } + + return input; } std::shared_ptr Paint::MaskBlurDescriptor::CreateMaskBlur( @@ -375,10 +369,11 @@ std::shared_ptr Paint::MaskBlurDescriptor::CreateMaskBlur( std::shared_ptr Paint::MaskBlurDescriptor::CreateMaskBlur( std::shared_ptr color_source_contents, - const std::shared_ptr& color_filter) const { - // If it's a solid color and there is no color filter, then we can just get - // away with doing one Gaussian blur. - if (color_source_contents->IsSolidColor() && !color_filter) { + const flutter::DlColorFilter* color_filter, + bool invert_colors) const { + // If it's a solid color then we can just get away with doing one Gaussian + // blur. The color filter will always be applied on the CPU. + if (color_source_contents->IsSolidColor()) { return FilterContents::MakeGaussianBlur( FilterInput::Make(color_source_contents), sigma, sigma, Entity::TileMode::kDecal, style, color_source_contents->GetGeometry()); @@ -409,11 +404,15 @@ std::shared_ptr Paint::MaskBlurDescriptor::CreateMaskBlur( std::shared_ptr color_contents = color_source_contents; /// 4. Apply the user set color filter on the GPU, if applicable. - if (color_filter) { - color_contents = color_filter->WrapWithGPUColorFilter( - FilterInput::Make(color_source_contents), - ColorFilterContents::AbsorbOpacity::kYes); + color_contents = + WrapWithGPUColorFilter(color_filter, FilterInput::Make(color_contents), + ColorFilterContents::AbsorbOpacity::kYes); + } + if (invert_colors) { + color_contents = + WrapWithInvertColors(FilterInput::Make(color_contents), + ColorFilterContents::AbsorbOpacity::kYes); } /// 5. Composite the color source with the blurred mask. @@ -441,22 +440,8 @@ std::shared_ptr Paint::MaskBlurDescriptor::CreateMaskBlur( Sigma(blur_sigma.y), style); } -std::shared_ptr Paint::GetColorFilter() const { - if (invert_colors && color_filter) { - auto filter = ColorFilter::MakeMatrix(kColorInversion); - return ColorFilter::MakeComposed(filter, color_filter); - } - if (invert_colors) { - return ColorFilter::MakeMatrix(kColorInversion); - } - if (color_filter) { - return color_filter; - } - return nullptr; -} - bool Paint::HasColorFilter() const { - return !!color_filter || invert_colors; + return color_filter || invert_colors; } } // namespace impeller diff --git a/engine/src/flutter/impeller/display_list/paint.h b/engine/src/flutter/impeller/display_list/paint.h index c482a02b2d..620b5126a1 100644 --- a/engine/src/flutter/impeller/display_list/paint.h +++ b/engine/src/flutter/impeller/display_list/paint.h @@ -7,7 +7,9 @@ #include +#include "display_list/effects/dl_color_filter.h" #include "display_list/effects/dl_color_source.h" +#include "display_list/effects/dl_image_filter.h" #include "impeller/display_list/color_filter.h" #include "impeller/display_list/image_filter.h" #include "impeller/entity/contents/color_source_contents.h" @@ -55,7 +57,8 @@ struct Paint { std::shared_ptr CreateMaskBlur( std::shared_ptr color_source_contents, - const std::shared_ptr& color_filter) const; + const flutter::DlColorFilter* color_filter, + bool invert_colors) const; std::shared_ptr CreateMaskBlur( std::shared_ptr texture_contents) const; @@ -68,6 +71,8 @@ struct Paint { Color color = Color::Black(); const flutter::DlColorSource* color_source = nullptr; + const flutter::DlColorFilter* color_filter = nullptr; + const flutter::DlImageFilter* image_filter = nullptr; Scalar stroke_width = 0.0; Cap stroke_cap = Cap::kButt; @@ -77,12 +82,8 @@ struct Paint { BlendMode blend_mode = BlendMode::kSourceOver; bool invert_colors = false; - std::shared_ptr image_filter; - std::shared_ptr color_filter; std::optional mask_blur_descriptor; - std::shared_ptr GetColorFilter() const; - /// @brief Wrap this paint's configured filters to the given contents. /// @param[in] input The contents to wrap with paint's filters. /// @return The filter-wrapped contents. If there are no filters that need @@ -102,9 +103,6 @@ struct Paint { std::shared_ptr input, const Matrix& effect_transform = Matrix()) const; - std::shared_ptr CreateContentsForGeometry( - const std::shared_ptr& geometry) const; - /// @brief Whether this paint has a color filter that can apply opacity bool HasColorFilter() const; diff --git a/engine/src/flutter/impeller/display_list/skia_conversions.cc b/engine/src/flutter/impeller/display_list/skia_conversions.cc index e61e766d28..0171165ba7 100644 --- a/engine/src/flutter/impeller/display_list/skia_conversions.cc +++ b/engine/src/flutter/impeller/display_list/skia_conversions.cc @@ -201,5 +201,69 @@ Matrix ToMatrix(const SkMatrix& m) { }; } +BlendMode ToBlendMode(flutter::DlBlendMode mode) { + switch (mode) { + case flutter::DlBlendMode::kClear: + return BlendMode::kClear; + case flutter::DlBlendMode::kSrc: + return BlendMode::kSource; + case flutter::DlBlendMode::kDst: + return BlendMode::kDestination; + case flutter::DlBlendMode::kSrcOver: + return BlendMode::kSourceOver; + case flutter::DlBlendMode::kDstOver: + return BlendMode::kDestinationOver; + case flutter::DlBlendMode::kSrcIn: + return BlendMode::kSourceIn; + case flutter::DlBlendMode::kDstIn: + return BlendMode::kDestinationIn; + case flutter::DlBlendMode::kSrcOut: + return BlendMode::kSourceOut; + case flutter::DlBlendMode::kDstOut: + return BlendMode::kDestinationOut; + case flutter::DlBlendMode::kSrcATop: + return BlendMode::kSourceATop; + case flutter::DlBlendMode::kDstATop: + return BlendMode::kDestinationATop; + case flutter::DlBlendMode::kXor: + return BlendMode::kXor; + case flutter::DlBlendMode::kPlus: + return BlendMode::kPlus; + case flutter::DlBlendMode::kModulate: + return BlendMode::kModulate; + case flutter::DlBlendMode::kScreen: + return BlendMode::kScreen; + case flutter::DlBlendMode::kOverlay: + return BlendMode::kOverlay; + case flutter::DlBlendMode::kDarken: + return BlendMode::kDarken; + case flutter::DlBlendMode::kLighten: + return BlendMode::kLighten; + case flutter::DlBlendMode::kColorDodge: + return BlendMode::kColorDodge; + case flutter::DlBlendMode::kColorBurn: + return BlendMode::kColorBurn; + case flutter::DlBlendMode::kHardLight: + return BlendMode::kHardLight; + case flutter::DlBlendMode::kSoftLight: + return BlendMode::kSoftLight; + case flutter::DlBlendMode::kDifference: + return BlendMode::kDifference; + case flutter::DlBlendMode::kExclusion: + return BlendMode::kExclusion; + case flutter::DlBlendMode::kMultiply: + return BlendMode::kMultiply; + case flutter::DlBlendMode::kHue: + return BlendMode::kHue; + case flutter::DlBlendMode::kSaturation: + return BlendMode::kSaturation; + case flutter::DlBlendMode::kColor: + return BlendMode::kColor; + case flutter::DlBlendMode::kLuminosity: + return BlendMode::kLuminosity; + } + FML_UNREACHABLE(); +} + } // namespace skia_conversions } // namespace impeller diff --git a/engine/src/flutter/impeller/display_list/skia_conversions.h b/engine/src/flutter/impeller/display_list/skia_conversions.h index 133a857e52..e29f1146fa 100644 --- a/engine/src/flutter/impeller/display_list/skia_conversions.h +++ b/engine/src/flutter/impeller/display_list/skia_conversions.h @@ -61,6 +61,8 @@ impeller::SamplerDescriptor ToSamplerDescriptor( Matrix ToMatrix(const SkMatrix& m); +BlendMode ToBlendMode(flutter::DlBlendMode mode); + /// @brief Convert display list colors + stops into impeller colors and stops, /// taking care to ensure that the stops monotonically increase from 0.0 to 1.0. /// diff --git a/engine/src/flutter/impeller/display_list/skia_conversions_unittests.cc b/engine/src/flutter/impeller/display_list/skia_conversions_unittests.cc index 73791782a5..9e9d9e4876 100644 --- a/engine/src/flutter/impeller/display_list/skia_conversions_unittests.cc +++ b/engine/src/flutter/impeller/display_list/skia_conversions_unittests.cc @@ -2,11 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "display_list/dl_blend_mode.h" #include "display_list/dl_color.h" #include "display_list/dl_tile_mode.h" #include "flutter/testing/testing.h" #include "impeller/core/formats.h" #include "impeller/display_list/skia_conversions.h" +#include "impeller/geometry/color.h" #include "impeller/geometry/scalar.h" #include "include/core/SkMatrix.h" #include "include/core/SkRRect.h" @@ -292,5 +294,13 @@ TEST(SkiaConversionsTest, IsNearlySimpleRRect) { } } +TEST(SkiaConversionsTest, BlendMode) { + for (auto i = 0; i < static_cast(flutter::DlBlendMode::kLastMode); i++) { + EXPECT_EQ( + skia_conversions::ToBlendMode(static_cast(i)), + static_cast(i)); + } +} + } // namespace testing } // namespace impeller diff --git a/engine/src/flutter/impeller/entity/contents/tiled_texture_contents.h b/engine/src/flutter/impeller/entity/contents/tiled_texture_contents.h index b561a5e658..3c883aabab 100644 --- a/engine/src/flutter/impeller/entity/contents/tiled_texture_contents.h +++ b/engine/src/flutter/impeller/entity/contents/tiled_texture_contents.h @@ -7,13 +7,11 @@ #include #include -#include #include "impeller/core/sampler_descriptor.h" #include "impeller/entity/contents/color_source_contents.h" #include "impeller/entity/contents/filters/color_filter_contents.h" #include "impeller/entity/entity.h" -#include "impeller/geometry/path.h" #include "impeller/renderer/capabilities.h" namespace impeller {