Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

[Impeller] Add CPU implementations for all color filters #42692

Merged
merged 1 commit into from
Jun 9, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion impeller/aiks/paint.cc
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ std::shared_ptr<Contents> Paint::WithColorFilter(

/// A color matrix which inverts colors.
// clang-format off
constexpr ColorFilterContents::ColorMatrix kColorInversion = {
constexpr ColorMatrix kColorInversion = {
.array = {
-1.0, 0, 0, 1.0, 0, //
0, -1.0, 0, 1.0, 0, //
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 @@ -491,7 +491,7 @@ static std::optional<Paint::ColorFilterProc> ToColorFilterProc(
}
case flutter::DlColorFilterType::kMatrix: {
const flutter::DlMatrixColorFilter* dl_matrix = filter->asMatrix();
impeller::FilterContents::ColorMatrix color_matrix;
impeller::ColorMatrix color_matrix;
dl_matrix->get_matrix(color_matrix.array);
return [color_matrix](FilterInput::Ref input) {
return ColorFilterContents::MakeColorMatrix({std::move(input)},
Expand Down
5 changes: 0 additions & 5 deletions impeller/entity/contents/filters/filter_contents.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,6 @@ class FilterContents : public Contents {
kInner,
};

// Domain is kRGBA, we may decide to support more color modes later.
struct ColorMatrix {
float array[20];
};

enum class MorphType { kDilate, kErode };

static std::shared_ptr<FilterContents> MakeDirectionalGaussianBlur(
Expand Down
236 changes: 2 additions & 234 deletions impeller/entity/entity_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1748,7 +1748,7 @@ TEST_P(EntityTest, ColorMatrixFilterCoverageIsCorrect) {
fill->SetColor(Color::Coral());

// Set the color matrix filter.
FilterContents::ColorMatrix matrix = {
ColorMatrix matrix = {
1, 1, 1, 1, 1, //
1, 1, 1, 1, 1, //
1, 1, 1, 1, 1, //
Expand All @@ -1775,7 +1775,7 @@ TEST_P(EntityTest, ColorMatrixFilterEditable) {

auto callback = [&](ContentContext& context, RenderPass& pass) -> bool {
// UI state.
static FilterContents::ColorMatrix color_matrix = {
static ColorMatrix color_matrix = {
1, 0, 0, 0, 0, //
0, 3, 0, 0, 0, //
0, 0, 1, 0, 0, //
Expand Down Expand Up @@ -1931,238 +1931,6 @@ TEST_P(EntityTest, SrgbToLinearFilter) {
ASSERT_TRUE(OpenPlaygroundHere(callback));
}

TEST_P(EntityTest, TTTBlendColor) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's replacing these tests?

See also flutter/flutter#128606. It's possible some of these tests are encoding bad behavior, but it seems veyr likely to me that if they are not encoding bad behavior they're missing cases where there's bad behavior.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I see below the new tests.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I just moved this existing test into GeometryTest.ColorBlend. And yes, some of them are wrong -- we used to use these for absorbing the DrawPaints, which introduced bugs. Some blends are also missing from the test at the moment.

Copy link
Member Author

@bdero bdero Jun 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test also has too many cases and needs to be rewritten in general, or at least be annotated to state why each cases is useful and not redundant.

{
Color src = {1, 0, 0, 0.5};
Color dst = {1, 0, 1, 1};
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kClear),
Color(0, 0, 0, 0));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kSource),
Color(1, 0, 0, 0.5));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kDestination),
Color(1, 0, 1, 1));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kSourceOver),
Color(1.5, 0, 0.5, 1));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kDestinationOver),
Color(1, 0, 1, 1));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kSourceIn),
Color(1, 0, 0, 0.5));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kDestinationIn),
Color(0.5, 0, 0.5, 0.5));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kSourceOut),
Color(0, 0, 0, 0));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kDestinationOut),
Color(0.5, 0, 0.5, 0.5));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kSourceATop),
Color(1.5, 0, 0.5, 1));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kDestinationATop),
Color(0.5, 0, 0.5, 0.5));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kXor),
Color(0.5, 0, 0.5, 0.5));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kPlus), Color(1, 0, 1, 1));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kModulate),
Color(1, 0, 0, 0.5));
}

{
Color src = {1, 1, 0, 1};
Color dst = {1, 0, 1, 1};

ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kClear),
Color(0, 0, 0, 0));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kSource),
Color(1, 1, 0, 1));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kDestination),
Color(1, 0, 1, 1));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kSourceOver),
Color(1, 1, 0, 1));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kDestinationOver),
Color(1, 0, 1, 1));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kSourceIn),
Color(1, 1, 0, 1));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kDestinationIn),
Color(1, 0, 1, 1));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kSourceOut),
Color(0, 0, 0, 0));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kDestinationOut),
Color(0, 0, 0, 0));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kSourceATop),
Color(1, 1, 0, 1));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kDestinationATop),
Color(1, 0, 1, 1));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kXor), Color(0, 0, 0, 0));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kPlus), Color(1, 1, 1, 1));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kModulate),
Color(1, 0, 0, 1));
}

{
Color src = {1, 1, 0, 0.2};
Color dst = {1, 1, 1, 0.5};

ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kClear),
Color(0, 0, 0, 0));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kSource),
Color(1, 1, 0, 0.2));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kDestination),
Color(1, 1, 1, 0.5));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kSourceOver),
Color(1.8, 1.8, 0.8, 0.6));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kDestinationOver),
Color(1.5, 1.5, 1, 0.6));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kSourceIn),
Color(0.5, 0.5, 0, 0.1));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kDestinationIn),
Color(0.2, 0.2, 0.2, 0.1));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kSourceOut),
Color(0.5, 0.5, 0, 0.1));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kDestinationOut),
Color(0.8, 0.8, 0.8, 0.4));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kSourceATop),
Color(1.3, 1.3, 0.8, 0.5));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kDestinationATop),
Color(0.7, 0.7, 0.2, 0.2));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kXor),
Color(1.3, 1.3, 0.8, 0.5));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kPlus),
Color(1, 1, 1, 0.7));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kModulate),
Color(1, 1, 0, 0.1));
}

{
Color src = {1, 0.5, 0, 0.2};
Color dst = {1, 1, 0.5, 0.5};
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kClear),
Color(0, 0, 0, 0));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kSource),
Color(1, 0.5, 0, 0.2));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kDestination),
Color(1, 1, 0.5, 0.5));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kSourceOver),
Color(1.8, 1.3, 0.4, 0.6));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kDestinationOver),
Color(1.5, 1.25, 0.5, 0.6));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kSourceIn),
Color(0.5, 0.25, 0, 0.1));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kDestinationIn),
Color(0.2, 0.2, 0.1, 0.1));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kSourceOut),
Color(0.5, 0.25, 0, 0.1));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kDestinationOut),
Color(0.8, 0.8, 0.4, 0.4));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kSourceATop),
Color(1.3, 1.05, 0.4, 0.5));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kDestinationATop),
Color(0.7, 0.45, 0.1, 0.2));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kXor),
Color(1.3, 1.05, 0.4, 0.5));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kPlus),
Color(1, 1, 0.5, 0.7));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kModulate),
Color(1, 0.5, 0, 0.1));
}

{
Color src = {0.5, 0.5, 0, 0.2};
Color dst = {0, 1, 0.5, 0.5};
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kClear),
Color(0, 0, 0, 0));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kSource),
Color(0.5, 0.5, 0, 0.2));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kDestination),
Color(0, 1, 0.5, 0.5));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kSourceOver),
Color(0.5, 1.3, 0.4, 0.6));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kDestinationOver),
Color(0.25, 1.25, 0.5, 0.6));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kSourceIn),
Color(0.25, 0.25, 0, 0.1));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kDestinationIn),
Color(0, 0.2, 0.1, 0.1));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kSourceOut),
Color(0.25, 0.25, 0, 0.1));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kDestinationOut),
Color(0, 0.8, 0.4, 0.4));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kSourceATop),
Color(0.25, 1.05, 0.4, 0.5));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kDestinationATop),
Color(0.25, 0.45, 0.1, 0.2));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kXor),
Color(0.25, 1.05, 0.4, 0.5));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kPlus),
Color(0.5, 1, 0.5, 0.7));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kModulate),
Color(0, 0.5, 0, 0.1));
}

{
Color src = {0.5, 0.5, 0.2, 0.2};
Color dst = {0.2, 1, 0.5, 0.5};
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kClear),
Color(0, 0, 0, 0));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kSource),
Color(0.5, 0.5, 0.2, 0.2));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kDestination),
Color(0.2, 1, 0.5, 0.5));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kSourceOver),
Color(0.66, 1.3, 0.6, 0.6));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kDestinationOver),
Color(0.45, 1.25, 0.6, 0.6));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kSourceIn),
Color(0.25, 0.25, 0.1, 0.1));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kDestinationIn),
Color(0.04, 0.2, 0.1, 0.1));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kSourceOut),
Color(0.25, 0.25, 0.1, 0.1));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kDestinationOut),
Color(0.16, 0.8, 0.4, 0.4));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kSourceATop),
Color(0.41, 1.05, 0.5, 0.5));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kDestinationATop),
Color(0.29, 0.45, 0.2, 0.2));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kXor),
Color(0.41, 1.05, 0.5, 0.5));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kPlus),
Color(0.7, 1, 0.7, 0.7));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kModulate),
Color(0.1, 0.5, 0.1, 0.1));
}

{
Color src = {0.5, 0.5, 0.2, 0.2};
Color dst = {0.2, 0.2, 0.5, 0.5};
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kClear),
Color(0, 0, 0, 0));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kSource),
Color(0.5, 0.5, 0.2, 0.2));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kDestination),
Color(0.2, 0.2, 0.5, 0.5));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kSourceOver),
Color(0.66, 0.66, 0.6, 0.6));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kDestinationOver),
Color(0.45, 0.45, 0.6, 0.6));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kSourceIn),
Color(0.25, 0.25, 0.1, 0.1));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kDestinationIn),
Color(0.04, 0.04, 0.1, 0.1));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kSourceOut),
Color(0.25, 0.25, 0.1, 0.1));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kDestinationOut),
Color(0.16, 0.16, 0.4, 0.4));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kSourceATop),
Color(0.41, 0.41, 0.5, 0.5));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kDestinationATop),
Color(0.29, 0.29, 0.2, 0.2));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kXor),
Color(0.41, 0.41, 0.5, 0.5));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kPlus),
Color(0.7, 0.7, 0.7, 0.7));
ASSERT_EQ(Color::BlendColor(src, dst, BlendMode::kModulate),
Color(0.1, 0.1, 0.1, 0.1));
}
}

TEST_P(EntityTest, AtlasContentsSubAtlas) {
auto boston = CreateTextureForFixture("boston.jpg");

Expand Down
38 changes: 35 additions & 3 deletions impeller/geometry/color.cc
Original file line number Diff line number Diff line change
Expand Up @@ -199,9 +199,9 @@ static constexpr Color FromRGB(Vector3 color, Scalar alpha) {
return {color.x, color.y, color.z, alpha};
}

Color Color::BlendColor(const Color& src,
const Color& dst,
BlendMode blend_mode) {
Color Color::Blend(const Color& src, BlendMode blend_mode) const {
const Color& dst = *this;

static auto apply_rgb_srcover_alpha = [&](auto f) -> Color {
return Color(f(src.red, dst.red), f(src.green, dst.green),
f(src.blue, dst.blue),
Expand Down Expand Up @@ -372,6 +372,38 @@ Color Color::BlendColor(const Color& src,
}
}

Color Color::ApplyColorMatrix(const ColorMatrix& color_matrix) const {
auto* c = color_matrix.array;
return Color(
c[0] * red + c[1] * green + c[2] * blue + c[3] * alpha + c[4],
c[5] * red + c[6] * green + c[7] * blue + c[8] * alpha + c[9],
c[10] * red + c[11] * green + c[12] * blue + c[13] * alpha + c[14],
c[15] * red + c[16] * green + c[17] * blue + c[18] * alpha + c[19])
.Clamp01();
}

Color Color::LinearToSRGB() const {
static auto conversion = [](Scalar component) {
if (component <= 0.0031308) {
return component * 12.92;
}
return 1.055 * pow(component, (1.0 / 2.4)) - 0.055;
};

return Color(conversion(red), conversion(green), conversion(blue), alpha);
}

Color Color::SRGBToLinear() const {
static auto conversion = [](Scalar component) {
if (component <= 0.04045) {
return component / 12.92;
}
return pow((component + 0.055) / 1.055, 2.4);
};

return Color(conversion(red), conversion(green), conversion(blue), alpha);
}

std::string ColorToString(const Color& color) {
return SPrintF("R=%.1f,G=%.1f,B=%.1f,A=%.1f", //
color.red, //
Expand Down
Loading