Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions impeller/aiks/aiks_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
#include "impeller/aiks/paint_pass_delegate.h"
#include "impeller/aiks/testing/context_spy.h"
#include "impeller/entity/contents/color_source_contents.h"
#include "impeller/entity/contents/conical_gradient_contents.h"
#include "impeller/entity/contents/filters/inputs/filter_input.h"
#include "impeller/entity/contents/linear_gradient_contents.h"
#include "impeller/entity/contents/scene_contents.h"
#include "impeller/entity/contents/solid_color_contents.h"
#include "impeller/entity/contents/tiled_texture_contents.h"
Expand Down Expand Up @@ -2867,5 +2869,35 @@ TEST_P(AiksTest, MatrixBackdropFilter) {
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
}

TEST_P(AiksTest, SolidColorApplyColorFilter) {
auto contents = SolidColorContents();
contents.SetColor(Color::CornflowerBlue().WithAlpha(0.75));
auto result = contents.ApplyColorFilter([](const Color& color) {
return color.Blend(Color::LimeGreen().WithAlpha(0.75), BlendMode::kScreen);
});
ASSERT_TRUE(result);
ASSERT_COLOR_NEAR(contents.GetColor(),
Color(0.433247, 0.879523, 0.825324, 0.75));
}

#define APPLY_COLOR_FILTER_GRADIENT_TEST(name) \
TEST_P(AiksTest, name##GradientApplyColorFilter) { \
auto contents = name##GradientContents(); \
contents.SetColors({Color::CornflowerBlue().WithAlpha(0.75)}); \
auto result = contents.ApplyColorFilter([](const Color& color) { \
return color.Blend(Color::LimeGreen().WithAlpha(0.75), \
BlendMode::kScreen); \
}); \
ASSERT_TRUE(result); \
\
std::vector<Color> expected = {Color(0.433247, 0.879523, 0.825324, 0.75)}; \
ASSERT_COLORS_NEAR(contents.GetColors(), expected); \
}

APPLY_COLOR_FILTER_GRADIENT_TEST(Linear);
APPLY_COLOR_FILTER_GRADIENT_TEST(Radial);
APPLY_COLOR_FILTER_GRADIENT_TEST(Conical);
APPLY_COLOR_FILTER_GRADIENT_TEST(Sweep);

} // namespace testing
} // namespace impeller
10 changes: 6 additions & 4 deletions impeller/aiks/color_filter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ BlendColorFilter::BlendColorFilter(BlendMode blend_mode, Color color)

BlendColorFilter::~BlendColorFilter() = default;

std::shared_ptr<ColorFilterContents> BlendColorFilter::GetColorFilter(
std::shared_ptr<ColorFilterContents> BlendColorFilter::WrapWithGPUColorFilter(
std::shared_ptr<FilterInput> input,
bool absorb_opacity) const {
auto filter =
Expand All @@ -67,7 +67,7 @@ MatrixColorFilter::MatrixColorFilter(ColorMatrix color_matrix)

MatrixColorFilter::~MatrixColorFilter() = default;

std::shared_ptr<ColorFilterContents> MatrixColorFilter::GetColorFilter(
std::shared_ptr<ColorFilterContents> MatrixColorFilter::WrapWithGPUColorFilter(
std::shared_ptr<FilterInput> input,
bool absorb_opacity) const {
auto filter =
Expand All @@ -90,7 +90,8 @@ SrgbToLinearColorFilter::SrgbToLinearColorFilter() = default;

SrgbToLinearColorFilter::~SrgbToLinearColorFilter() = default;

std::shared_ptr<ColorFilterContents> SrgbToLinearColorFilter::GetColorFilter(
std::shared_ptr<ColorFilterContents>
SrgbToLinearColorFilter::WrapWithGPUColorFilter(
std::shared_ptr<FilterInput> input,
bool absorb_opacity) const {
auto filter = ColorFilterContents::MakeSrgbToLinearFilter({std::move(input)});
Expand All @@ -111,7 +112,8 @@ LinearToSrgbColorFilter::LinearToSrgbColorFilter() = default;

LinearToSrgbColorFilter::~LinearToSrgbColorFilter() = default;

std::shared_ptr<ColorFilterContents> LinearToSrgbColorFilter::GetColorFilter(
std::shared_ptr<ColorFilterContents>
LinearToSrgbColorFilter::WrapWithGPUColorFilter(
std::shared_ptr<FilterInput> input,
bool absorb_opacity) const {
auto filter = ColorFilterContents::MakeSrgbToLinearFilter({std::move(input)});
Expand Down
21 changes: 16 additions & 5 deletions impeller/aiks/color_filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ struct Paint;

class ColorFilter {
public:
/// A procedure that filters a given unpremultiplied color to produce a new
/// unpremultiplied color.
using ColorFilterProc = std::function<Color(Color)>;

ColorFilter();
Expand All @@ -32,10 +34,19 @@ class ColorFilter {

static std::shared_ptr<ColorFilter> MakeLinearToSrgb();

virtual std::shared_ptr<ColorFilterContents> GetColorFilter(
/// @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,
bool 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;
};

Expand All @@ -50,7 +61,7 @@ class BlendColorFilter final : public ColorFilter {
~BlendColorFilter() override;

// |ColorFilter|
std::shared_ptr<ColorFilterContents> GetColorFilter(
std::shared_ptr<ColorFilterContents> WrapWithGPUColorFilter(
std::shared_ptr<FilterInput> input,
bool absorb_opacity) const override;

Expand All @@ -73,7 +84,7 @@ class MatrixColorFilter final : public ColorFilter {
~MatrixColorFilter() override;

// |ColorFilter|
std::shared_ptr<ColorFilterContents> GetColorFilter(
std::shared_ptr<ColorFilterContents> WrapWithGPUColorFilter(
std::shared_ptr<FilterInput> input,
bool absorb_opacity) const override;

Expand All @@ -95,7 +106,7 @@ class SrgbToLinearColorFilter final : public ColorFilter {
~SrgbToLinearColorFilter() override;

// |ColorFilter|
std::shared_ptr<ColorFilterContents> GetColorFilter(
std::shared_ptr<ColorFilterContents> WrapWithGPUColorFilter(
std::shared_ptr<FilterInput> input,
bool absorb_opacity) const override;

Expand All @@ -114,7 +125,7 @@ class LinearToSrgbColorFilter final : public ColorFilter {
~LinearToSrgbColorFilter() override;

// |ColorFilter|
std::shared_ptr<ColorFilterContents> GetColorFilter(
std::shared_ptr<ColorFilterContents> WrapWithGPUColorFilter(
std::shared_ptr<FilterInput> input,
bool absorb_opacity) const override;

Expand Down
3 changes: 2 additions & 1 deletion impeller/aiks/color_source.cc
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,8 @@ ColorSource ColorSource::MakeImage(std::shared_ptr<Texture> texture,
if (paint.color_filter) {
TiledTextureContents::ColorFilterProc filter_proc =
[color_filter = paint.color_filter](FilterInput::Ref input) {
return color_filter->GetColorFilter(std::move(input), false);
return color_filter->WrapWithGPUColorFilter(std::move(input),
false);
};
contents->SetColorFilter(filter_proc);
}
Expand Down
17 changes: 13 additions & 4 deletions impeller/aiks/paint.cc
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,20 @@ std::shared_ptr<Contents> Paint::WithColorFilter(
if (color_source.GetType() == ColorSource::Type::kImage) {
return input;
}
if (color_filter) {
input =
color_filter->GetColorFilter(FilterInput::Make(input), absorb_opacity);

if (!color_filter) {
return input;
}
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())) {
return input;
}

return color_filter->WrapWithGPUColorFilter(FilterInput::Make(input),
absorb_opacity);
}

/// A color matrix which inverts colors.
Expand Down
2 changes: 1 addition & 1 deletion impeller/display_list/dl_dispatcher.cc
Original file line number Diff line number Diff line change
Expand Up @@ -665,7 +665,7 @@ static Paint::ImageFilterProc ToImageFilterProc(
// "absorb opacity" flag to false. For image filters, the snapshot
// opacity needs to be deferred until the result of the filter chain is
// being blended with the layer.
return filter->GetColorFilter(std::move(input), false);
return filter->WrapWithGPUColorFilter(std::move(input), false);
};
break;
}
Expand Down
8 changes: 8 additions & 0 deletions impeller/entity/contents/conical_gradient_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -193,4 +193,12 @@ bool ConicalGradientContents::RenderTexture(const ContentContext& renderer,
return true;
}

bool ConicalGradientContents::ApplyColorFilter(
const ColorFilterProc& color_filter_proc) {
for (Color& color : colors_) {
color = color_filter_proc(color);
}
return true;
}

} // namespace impeller
4 changes: 4 additions & 0 deletions impeller/entity/contents/conical_gradient_contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ class ConicalGradientContents final : public ColorSourceContents {
const Entity& entity,
RenderPass& pass) const override;

// |Contents|
[[nodiscard]] bool ApplyColorFilter(
const ColorFilterProc& color_filter_proc) override;

void SetCenterAndRadius(Point center, Scalar radius);

void SetColors(std::vector<Color> colors);
Expand Down
5 changes: 5 additions & 0 deletions impeller/entity/contents/contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,11 @@ std::optional<Color> Contents::AsBackgroundColor(const Entity& entity,
return {};
}

bool Contents::ApplyColorFilter(
const Contents::ColorFilterProc& color_filter_proc) {
return false;
}

bool Contents::ShouldRender(const Entity& entity,
const std::optional<Rect>& stencil_coverage) const {
if (!stencil_coverage.has_value()) {
Expand Down
21 changes: 21 additions & 0 deletions impeller/entity/contents/contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ ContentContextOptions OptionsFromPassAndEntity(const RenderPass& pass,

class Contents {
public:
/// A procedure that filters a given unpremultiplied color to produce a new
/// unpremultiplied color.
using ColorFilterProc = std::function<Color(Color)>;

struct StencilCoverage {
enum class Type { kNoChange, kAppend, kRestore };

Expand Down Expand Up @@ -126,6 +130,23 @@ class Contents {
virtual std::optional<Color> AsBackgroundColor(const Entity& entity,
ISize target_size) const;

/// @brief If possible, applies a color filter to this contents inputs on
/// the CPU.
///
/// This method will either fully apply the color filter or
/// perform no action. Partial/incorrect application of the color
/// filter will never occur.
///
/// @param[in] color_filter_proc A function that filters a given
/// unpremultiplied color to produce a new
/// unpremultiplied color.
///
/// @return True if the color filter was able to be fully applied to all
/// all relevant inputs. Otherwise, this operation is a no-op and
/// false is returned.
[[nodiscard]] virtual bool ApplyColorFilter(
const ColorFilterProc& color_filter_proc);

private:
std::optional<Rect> coverage_hint_;
std::optional<Size> color_source_size_;
Expand Down
8 changes: 8 additions & 0 deletions impeller/entity/contents/linear_gradient_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -184,4 +184,12 @@ bool LinearGradientContents::RenderSSBO(const ContentContext& renderer,
return true;
}

bool LinearGradientContents::ApplyColorFilter(
const ColorFilterProc& color_filter_proc) {
for (Color& color : colors_) {
color = color_filter_proc(color);
}
return true;
}

} // namespace impeller
4 changes: 4 additions & 0 deletions impeller/entity/contents/linear_gradient_contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ class LinearGradientContents final : public ColorSourceContents {
const Entity& entity,
RenderPass& pass) const override;

// |Contents|
[[nodiscard]] bool ApplyColorFilter(
const ColorFilterProc& color_filter_proc) override;

void SetEndPoints(Point start_point, Point end_point);

void SetColors(std::vector<Color> colors);
Expand Down
8 changes: 8 additions & 0 deletions impeller/entity/contents/radial_gradient_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -185,4 +185,12 @@ bool RadialGradientContents::RenderTexture(const ContentContext& renderer,
return true;
}

bool RadialGradientContents::ApplyColorFilter(
const ColorFilterProc& color_filter_proc) {
for (Color& color : colors_) {
color = color_filter_proc(color);
}
return true;
}

} // namespace impeller
4 changes: 4 additions & 0 deletions impeller/entity/contents/radial_gradient_contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ class RadialGradientContents final : public ColorSourceContents {
const Entity& entity,
RenderPass& pass) const override;

// |Contents|
[[nodiscard]] bool ApplyColorFilter(
const ColorFilterProc& color_filter_proc) override;

void SetCenterAndRadius(Point center, Scalar radius);

void SetColors(std::vector<Color> colors);
Expand Down
6 changes: 6 additions & 0 deletions impeller/entity/contents/solid_color_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -110,4 +110,10 @@ std::optional<Color> SolidColorContents::AsBackgroundColor(
: std::optional<Color>();
}

bool SolidColorContents::ApplyColorFilter(
const ColorFilterProc& color_filter_proc) {
color_ = color_filter_proc(color_);
return true;
}

} // namespace impeller
4 changes: 4 additions & 0 deletions impeller/entity/contents/solid_color_contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ class SolidColorContents final : public ColorSourceContents {
std::optional<Color> AsBackgroundColor(const Entity& entity,
ISize target_size) const override;

// |Contents|
[[nodiscard]] bool ApplyColorFilter(
const ColorFilterProc& color_filter_proc) override;

private:
Color color_;

Expand Down
8 changes: 8 additions & 0 deletions impeller/entity/contents/sweep_gradient_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -192,4 +192,12 @@ bool SweepGradientContents::RenderTexture(const ContentContext& renderer,
return true;
}

bool SweepGradientContents::ApplyColorFilter(
const ColorFilterProc& color_filter_proc) {
for (Color& color : colors_) {
color = color_filter_proc(color);
}
return true;
}

} // namespace impeller
4 changes: 4 additions & 0 deletions impeller/entity/contents/sweep_gradient_contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ class SweepGradientContents final : public ColorSourceContents {
const Entity& entity,
RenderPass& pass) const override;

// |Contents|
[[nodiscard]] bool ApplyColorFilter(
const ColorFilterProc& color_filter_proc) override;

void SetCenterAndAngles(Point center, Degrees start_angle, Degrees end_angle);

void SetColors(std::vector<Color> colors);
Expand Down