[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
This commit is contained in:
Jonah Williams 2024-10-04 23:32:08 -05:00 committed by GitHub
parent 248c2a7062
commit fd33d17487
14 changed files with 388 additions and 1070 deletions

View File

@ -9,8 +9,10 @@
#include <utility>
#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<Contents> 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<Contents> 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> 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<ColorFilter> 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<FilterContents> filter = paint.image_filter->WrapInput(
FilterInput::Make(std::move(contents_copy)));
std::shared_ptr<FilterContents> 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<VerticesGeometry>& vertices,
auto src_paint = paint;
src_paint.color = paint.color.WithAlpha(1.0);
std::shared_ptr<Contents> src_contents =
src_paint.CreateContentsForGeometry(vertices);
std::shared_ptr<ColorSourceContents> 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<VerticesGeometry>& 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<VerticesSimpleBlendContents>();
contents->SetBlendMode(blend_mode);
@ -1049,7 +1069,7 @@ std::optional<Rect> Canvas::GetLocalCoverageLimit() const {
void Canvas::SaveLayer(const Paint& paint,
std::optional<Rect> bounds,
const std::shared_ptr<ImageFilter>& 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;

View File

@ -11,8 +11,8 @@
#include <optional>
#include <vector>
#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<Rect> bounds = std::nullopt,
const std::shared_ptr<ImageFilter>& 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);

View File

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

View File

@ -4,187 +4,99 @@
#include "impeller/display_list/color_filter.h"
#include <utility>
#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> ColorFilter::MakeBlend(BlendMode blend_mode,
Color color) {
return std::make_shared<BlendColorFilter>(blend_mode, color);
}
std::shared_ptr<ColorFilter> ColorFilter::MakeMatrix(ColorMatrix color_matrix) {
return std::make_shared<MatrixColorFilter>(color_matrix);
}
std::shared_ptr<ColorFilter> ColorFilter::MakeSrgbToLinear() {
return std::make_shared<SrgbToLinearColorFilter>();
}
std::shared_ptr<ColorFilter> ColorFilter::MakeLinearToSrgb() {
return std::make_shared<LinearToSrgbColorFilter>();
}
std::shared_ptr<ColorFilter> ColorFilter::MakeComposed(
const std::shared_ptr<ColorFilter>& outer,
const std::shared_ptr<ColorFilter>& inner) {
return std::make_shared<ComposedColorFilter>(outer, inner);
}
/*******************************************************************************
******* BlendColorFilter
******************************************************************************/
BlendColorFilter::BlendColorFilter(BlendMode blend_mode, Color color)
: blend_mode_(blend_mode), color_(color) {}
BlendColorFilter::~BlendColorFilter() = default;
std::shared_ptr<ColorFilterContents> BlendColorFilter::WrapWithGPUColorFilter(
std::shared_ptr<FilterInput> input,
ColorFilterContents::AbsorbOpacity absorb_opacity) const {
auto filter =
ColorFilterContents::MakeBlend(blend_mode_, {std::move(input)}, color_);
std::shared_ptr<ColorFilterContents> WrapWithInvertColors(
const std::shared_ptr<FilterInput>& 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<ColorFilterContents> WrapWithGPUColorFilter(
const flutter::DlColorFilter* filter,
const std::shared_ptr<FilterInput>& 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<BlendMode>(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<ColorFilter> BlendColorFilter::Clone() const {
return std::make_shared<BlendColorFilter>(*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<BlendMode>(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<ColorFilterContents> MatrixColorFilter::WrapWithGPUColorFilter(
std::shared_ptr<FilterInput> 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<ColorFilter> MatrixColorFilter::Clone() const {
return std::make_shared<MatrixColorFilter>(*this);
}
/*******************************************************************************
******* SrgbToLinearColorFilter
******************************************************************************/
SrgbToLinearColorFilter::SrgbToLinearColorFilter() = default;
SrgbToLinearColorFilter::~SrgbToLinearColorFilter() = default;
std::shared_ptr<ColorFilterContents>
SrgbToLinearColorFilter::WrapWithGPUColorFilter(
std::shared_ptr<FilterInput> 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<ColorFilter> SrgbToLinearColorFilter::Clone() const {
return std::make_shared<SrgbToLinearColorFilter>(*this);
}
/*******************************************************************************
******* LinearToSrgbColorFilter
******************************************************************************/
LinearToSrgbColorFilter::LinearToSrgbColorFilter() = default;
LinearToSrgbColorFilter::~LinearToSrgbColorFilter() = default;
std::shared_ptr<ColorFilterContents>
LinearToSrgbColorFilter::WrapWithGPUColorFilter(
std::shared_ptr<FilterInput> 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<ColorFilter> LinearToSrgbColorFilter::Clone() const {
return std::make_shared<LinearToSrgbColorFilter>(*this);
}
/*******************************************************************************
******* ComposedColorFilter
******************************************************************************/
ComposedColorFilter::ComposedColorFilter(
const std::shared_ptr<ColorFilter>& outer,
const std::shared_ptr<ColorFilter>& inner)
: outer_(outer), inner_(inner) {}
ComposedColorFilter::~ComposedColorFilter() = default;
std::shared_ptr<ColorFilterContents>
ComposedColorFilter::WrapWithGPUColorFilter(
std::shared_ptr<FilterInput> input,
ColorFilterContents::AbsorbOpacity absorb_opacity) const {
std::shared_ptr<FilterContents> 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<ColorFilter> ComposedColorFilter::Clone() const {
return std::make_shared<ComposedColorFilter>(outer_, inner_);
FML_UNREACHABLE();
}
} // namespace impeller

View File

@ -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<Color(Color)>;
ColorFilter();
virtual ~ColorFilter();
static std::shared_ptr<ColorFilter> MakeBlend(BlendMode blend_mode,
Color color);
static std::shared_ptr<ColorFilter> MakeMatrix(ColorMatrix color_matrix);
static std::shared_ptr<ColorFilter> MakeSrgbToLinear();
static std::shared_ptr<ColorFilter> MakeLinearToSrgb();
static std::shared_ptr<ColorFilter> MakeComposed(
const std::shared_ptr<ColorFilter>& outer,
const std::shared_ptr<ColorFilter>& 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<ColorFilterContents> WrapWithGPUColorFilter(
std::shared_ptr<FilterInput> 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<ColorFilter> 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<ColorFilterContents> WrapWithInvertColors(
const std::shared_ptr<FilterInput>& input,
ColorFilterContents::AbsorbOpacity absorb_opacity);
class BlendColorFilter final : public ColorFilter {
public:
BlendColorFilter(BlendMode blend_mode, Color color);
std::shared_ptr<ColorFilterContents> WrapWithGPUColorFilter(
const flutter::DlColorFilter* filter,
const std::shared_ptr<FilterInput>& 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<Color(Color)>;
// |ColorFilter|
std::shared_ptr<ColorFilterContents> WrapWithGPUColorFilter(
std::shared_ptr<FilterInput> input,
ColorFilterContents::AbsorbOpacity absorb_opacity) const override;
// |ColorFilter|
ColorFilterProc GetCPUColorFilterProc() const override;
// |ColorFilter|
std::shared_ptr<ColorFilter> 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<ColorFilterContents> WrapWithGPUColorFilter(
std::shared_ptr<FilterInput> input,
ColorFilterContents::AbsorbOpacity absorb_opacity) const override;
// |ColorFilter|
ColorFilterProc GetCPUColorFilterProc() const override;
// |ColorFilter|
std::shared_ptr<ColorFilter> Clone() const override;
private:
ColorMatrix color_matrix_;
};
/*******************************************************************************
******* SrgbToLinearColorFilter
******************************************************************************/
class SrgbToLinearColorFilter final : public ColorFilter {
public:
explicit SrgbToLinearColorFilter();
~SrgbToLinearColorFilter() override;
// |ColorFilter|
std::shared_ptr<ColorFilterContents> WrapWithGPUColorFilter(
std::shared_ptr<FilterInput> input,
ColorFilterContents::AbsorbOpacity absorb_opacity) const override;
// |ColorFilter|
ColorFilterProc GetCPUColorFilterProc() const override;
// |ColorFilter|
std::shared_ptr<ColorFilter> Clone() const override;
};
/*******************************************************************************
******* LinearToSrgbColorFilter
******************************************************************************/
class LinearToSrgbColorFilter final : public ColorFilter {
public:
explicit LinearToSrgbColorFilter();
~LinearToSrgbColorFilter() override;
// |ColorFilter|
std::shared_ptr<ColorFilterContents> WrapWithGPUColorFilter(
std::shared_ptr<FilterInput> input,
ColorFilterContents::AbsorbOpacity absorb_opacity) const override;
// |ColorFilter|
ColorFilterProc GetCPUColorFilterProc() const override;
// |ColorFilter|
std::shared_ptr<ColorFilter> 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<ColorFilter>& outer,
const std::shared_ptr<ColorFilter>& inner);
~ComposedColorFilter() override;
// |ColorFilter|
std::shared_ptr<ColorFilterContents> WrapWithGPUColorFilter(
std::shared_ptr<FilterInput> input,
ColorFilterContents::AbsorbOpacity absorb_opacity) const override;
// |ColorFilter|
ColorFilterProc GetCPUColorFilterProc() const override;
// |ColorFilter|
std::shared_ptr<ColorFilter> Clone() const override;
private:
std::shared_ptr<ColorFilter> outer_;
std::shared_ptr<ColorFilter> inner_;
};
ColorFilterProc GetCPUColorFilterProc(const flutter::DlColorFilter* filter);
} // namespace impeller

View File

@ -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<ColorFilter> 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<ImageFilter> 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<Entity::TileMode>(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<flutter::DlImage> atlas,
tex, //
colors, //
static_cast<size_t>(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<DlVerticesGeometry>(vertices, renderer_),
ToBlendMode(dl_mode), paint_);
skia_conversions::ToBlendMode(dl_mode), paint_);
}
//// Text Frame Dispatcher

View File

@ -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<FilterContents> 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<Entity::TileMode>(blur_filter->tile_mode()), //
FilterContents::BlurStyle::kNormal //
);
}
case flutter::DlImageFilterType::kDilate: {
auto dilate_filter = filter->asDilate();
FML_DCHECK(dilate_filter);
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);
}
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> ImageFilter::MakeDilate(Radius radius_x,
Radius radius_y) {
return std::make_shared<DilateImageFilter>(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> ImageFilter::MakeErode(Radius radius_x,
Radius radius_y) {
return std::make_shared<ErodeImageFilter>(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> ImageFilter::MakeMatrix(
const Matrix& matrix,
SamplerDescriptor sampler_descriptor) {
return std::make_shared<MatrixImageFilter>(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> ImageFilter::MakeCompose(
const ImageFilter& inner,
const ImageFilter& outer) {
return std::make_shared<ComposeImageFilter>(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> ImageFilter::MakeFromColorFilter(
const ColorFilter& color_filter) {
return std::make_shared<ColorImageFilter>(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> 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_, tile_mode_,
blur_style_);
}
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, ColorFilterContents::AbsorbOpacity::kNo);
}
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);
return WrapInput(
outer_dl_filter.get(),
FilterInput::Make(WrapInput(inner_dl_filter.get(), input)));
}
}
FML_UNREACHABLE();
}
} // namespace impeller

View File

@ -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<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;
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<FilterContents> WrapInput(
const FilterInput::Ref& input) const override;
// |ImageFilter|
std::shared_ptr<ImageFilter> 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<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;
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<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_;
};
/// @brief Generate a new FilterContents using this filter's configuration.
///
std::shared_ptr<FilterContents> WrapInput(const flutter::DlImageFilter* filter,
const FilterInput::Ref& input);
} // namespace impeller

View File

@ -6,9 +6,11 @@
#include <memory>
#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<ColorSourceContents> Paint::CreateContents() const {
if (color_source == nullptr) {
auto contents = std::make_shared<SolidColorContents>();
@ -194,11 +184,26 @@ std::shared_ptr<ColorSourceContents> 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<FilterContents> 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<ColorSourceContents> Paint::CreateContents() const {
FML_UNREACHABLE();
}
std::shared_ptr<Contents> Paint::CreateContentsForGeometry(
const std::shared_ptr<Geometry>& 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<Contents> Paint::WithFilters(
std::shared_ptr<Contents> input) const {
input = WithColorFilter(input, ColorFilterContents::AbsorbOpacity::kYes);
@ -314,7 +293,7 @@ std::shared_ptr<FilterContents> 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<Contents> 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<FilterContents> Paint::MaskBlurDescriptor::CreateMaskBlur(
@ -375,10 +369,11 @@ std::shared_ptr<FilterContents> Paint::MaskBlurDescriptor::CreateMaskBlur(
std::shared_ptr<FilterContents> Paint::MaskBlurDescriptor::CreateMaskBlur(
std::shared_ptr<ColorSourceContents> color_source_contents,
const std::shared_ptr<ColorFilter>& 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<FilterContents> Paint::MaskBlurDescriptor::CreateMaskBlur(
std::shared_ptr<Contents> 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<FilterContents> Paint::MaskBlurDescriptor::CreateMaskBlur(
Sigma(blur_sigma.y), style);
}
std::shared_ptr<ColorFilter> 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

View File

@ -7,7 +7,9 @@
#include <memory>
#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<FilterContents> CreateMaskBlur(
std::shared_ptr<ColorSourceContents> color_source_contents,
const std::shared_ptr<ColorFilter>& color_filter) const;
const flutter::DlColorFilter* color_filter,
bool invert_colors) const;
std::shared_ptr<FilterContents> CreateMaskBlur(
std::shared_ptr<TextureContents> 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<ImageFilter> image_filter;
std::shared_ptr<ColorFilter> color_filter;
std::optional<MaskBlurDescriptor> mask_blur_descriptor;
std::shared_ptr<ColorFilter> 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<Contents> input,
const Matrix& effect_transform = Matrix()) const;
std::shared_ptr<Contents> CreateContentsForGeometry(
const std::shared_ptr<Geometry>& geometry) const;
/// @brief Whether this paint has a color filter that can apply opacity
bool HasColorFilter() const;

View File

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

View File

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

View File

@ -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<int>(flutter::DlBlendMode::kLastMode); i++) {
EXPECT_EQ(
skia_conversions::ToBlendMode(static_cast<flutter::DlBlendMode>(i)),
static_cast<BlendMode>(i));
}
}
} // namespace testing
} // namespace impeller

View File

@ -7,13 +7,11 @@
#include <functional>
#include <memory>
#include <vector>
#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 {