Skip to content

Commit

Permalink
[Impeller] Defer applying opacity when saving layer (flutter#36279)
Browse files Browse the repository at this point in the history
  • Loading branch information
ColdPaleLight authored Oct 11, 2022
1 parent e3f1d89 commit c034c8b
Show file tree
Hide file tree
Showing 32 changed files with 427 additions and 156 deletions.
2 changes: 2 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -1175,6 +1175,8 @@ FILE: ../../../flutter/impeller/entity/contents/filters/blend_filter_contents.cc
FILE: ../../../flutter/impeller/entity/contents/filters/blend_filter_contents.h
FILE: ../../../flutter/impeller/entity/contents/filters/border_mask_blur_filter_contents.cc
FILE: ../../../flutter/impeller/entity/contents/filters/border_mask_blur_filter_contents.h
FILE: ../../../flutter/impeller/entity/contents/filters/color_filter_contents.cc
FILE: ../../../flutter/impeller/entity/contents/filters/color_filter_contents.h
FILE: ../../../flutter/impeller/entity/contents/filters/color_matrix_filter_contents.cc
FILE: ../../../flutter/impeller/entity/contents/filters/color_matrix_filter_contents.h
FILE: ../../../flutter/impeller/entity/contents/filters/filter_contents.cc
Expand Down
37 changes: 34 additions & 3 deletions impeller/aiks/paint.cc
Original file line number Diff line number Diff line change
Expand Up @@ -48,22 +48,53 @@ std::shared_ptr<Contents> Paint::WithFilters(
std::optional<bool> is_solid_color,
const Matrix& effect_transform) const {
bool is_solid_color_val = is_solid_color.value_or(!color_source);
input = WithMaskBlur(input, is_solid_color_val, effect_transform);
input = WithImageFilter(input, effect_transform);
input = WithColorFilter(input);
return input;
}

std::shared_ptr<Contents> Paint::WithFiltersForSubpassTarget(
std::shared_ptr<Contents> input,
const Matrix& effect_transform) const {
input = WithMaskBlur(input, false, effect_transform);
input = WithImageFilter(input, effect_transform);
input = WithColorFilter(input, /**absorb_opacity=*/true);
return input;
}

std::shared_ptr<Contents> Paint::WithMaskBlur(
std::shared_ptr<Contents> input,
bool is_solid_color,
const Matrix& effect_transform) const {
if (mask_blur_descriptor.has_value()) {
input = mask_blur_descriptor->CreateMaskBlur(
FilterInput::Make(input), is_solid_color_val, effect_transform);
FilterInput::Make(input), is_solid_color, effect_transform);
}
return input;
}

std::shared_ptr<Contents> Paint::WithImageFilter(
std::shared_ptr<Contents> input,
const Matrix& effect_transform) const {
if (image_filter.has_value()) {
const ImageFilterProc& filter = image_filter.value();
input = filter(FilterInput::Make(input), effect_transform);
}
return input;
}

std::shared_ptr<Contents> Paint::WithColorFilter(
std::shared_ptr<Contents> input,
bool absorb_opacity) const {
if (color_filter.has_value()) {
const ColorFilterProc& filter = color_filter.value();
input = filter(FilterInput::Make(input));
auto color_filter_contents = filter(FilterInput::Make(input));
if (color_filter_contents) {
color_filter_contents->SetAbsorbOpacity(absorb_opacity);
}
input = color_filter_contents;
}

return input;
}

Expand Down
27 changes: 26 additions & 1 deletion impeller/aiks/paint.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "flutter/fml/macros.h"
#include "impeller/entity/contents/contents.h"
#include "impeller/entity/contents/filters/color_filter_contents.h"
#include "impeller/entity/contents/filters/filter_contents.h"
#include "impeller/entity/contents/linear_gradient_contents.h"
#include "impeller/entity/contents/radial_gradient_contents.h"
Expand All @@ -23,7 +24,7 @@ struct Paint {
FilterInput::Ref,
const Matrix& effect_transform)>;
using ColorFilterProc =
std::function<std::shared_ptr<FilterContents>(FilterInput::Ref)>;
std::function<std::shared_ptr<ColorFilterContents>(FilterInput::Ref)>;
using MaskFilterProc = std::function<std::shared_ptr<FilterContents>(
FilterInput::Ref,
bool is_solid_color,
Expand Down Expand Up @@ -75,8 +76,32 @@ struct Paint {
std::optional<bool> is_solid_color = std::nullopt,
const Matrix& effect_transform = Matrix()) const;

/// @brief Wrap this paint's configured filters to the given contents of
/// subpass target.
/// @param[in] input The contents of subpass target to wrap with paint's
/// filters.
///
/// @return The filter-wrapped contents. If there are no filters that need
/// to be wrapped for the current paint configuration, the
/// original contents is returned.
std::shared_ptr<Contents> WithFiltersForSubpassTarget(
std::shared_ptr<Contents> input,
const Matrix& effect_transform = Matrix()) const;

std::shared_ptr<Contents> CreateContentsForEntity(Path path = {},
bool cover = false) const;

private:
std::shared_ptr<Contents> WithMaskBlur(std::shared_ptr<Contents> input,
bool is_solid_color,
const Matrix& effect_transform) const;

std::shared_ptr<Contents> WithImageFilter(
std::shared_ptr<Contents> input,
const Matrix& effect_transform) const;

std::shared_ptr<Contents> WithColorFilter(std::shared_ptr<Contents> input,
bool absorb_opacity = false) const;
};

} // namespace impeller
5 changes: 3 additions & 2 deletions impeller/aiks/paint_pass_delegate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,9 @@ std::shared_ptr<Contents> PaintPassDelegate::CreateContentsForSubpassTarget(
contents->SetTexture(target);
contents->SetSourceRect(Rect::MakeSize(target->GetSize()));
contents->SetOpacity(paint_.color.alpha);

return paint_.WithFilters(std::move(contents), false, effect_transform);
contents->SetDeferApplyingOpacity(true);
return paint_.WithFiltersForSubpassTarget(std::move(contents),
effect_transform);
}

} // namespace impeller
8 changes: 4 additions & 4 deletions impeller/display_list/display_list_dispatcher.cc
Original file line number Diff line number Diff line change
Expand Up @@ -447,24 +447,24 @@ static std::optional<Paint::ColorFilterProc> ToColorFilterProc(
auto blend_mode = ToBlendMode(dl_blend->mode());
auto color = ToColor(dl_blend->color());
return [blend_mode, color](FilterInput::Ref input) {
return FilterContents::MakeBlend(blend_mode, {input}, color);
return ColorFilterContents::MakeBlend(blend_mode, {input}, color);
};
}
case flutter::DlColorFilterType::kMatrix: {
const flutter::DlMatrixColorFilter* dl_matrix = filter->asMatrix();
impeller::FilterContents::ColorMatrix color_matrix;
dl_matrix->get_matrix(color_matrix.array);
return [color_matrix](FilterInput::Ref input) {
return FilterContents::MakeColorMatrix({input}, color_matrix);
return ColorFilterContents::MakeColorMatrix({input}, color_matrix);
};
}
case flutter::DlColorFilterType::kSrgbToLinearGamma:
return [](FilterInput::Ref input) {
return FilterContents::MakeSrgbToLinearFilter({input});
return ColorFilterContents::MakeSrgbToLinearFilter({input});
};
case flutter::DlColorFilterType::kLinearToSrgbGamma:
return [](FilterInput::Ref input) {
return FilterContents::MakeLinearToSrgbFilter({input});
return ColorFilterContents::MakeLinearToSrgbFilter({input});
};
case flutter::DlColorFilterType::kUnknown:
FML_LOG(ERROR) << "requested DlColorFilterType::kUnknown";
Expand Down
117 changes: 117 additions & 0 deletions impeller/display_list/display_list_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,123 @@ TEST_P(DisplayListTest, CanClampTheResultingColorOfColorMatrixFilter) {
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
}

TEST_P(DisplayListTest, SaveLayerWithColorMatrixFiltersAndAlphaDrawCorrectly) {
auto texture = CreateTextureForFixture("boston.jpg");
bool first_frame = true;
enum class Type { kUseAsImageFilter, kUseAsColorFilter, kDisableFilter };
auto callback = [&]() {
if (first_frame) {
first_frame = false;
ImGui::SetNextWindowPos({10, 10});
}

static float alpha = 0.5;
static int selected_type = 0;
const char* names[] = {"Use as image filter", "Use as color filter",
"Disable filter"};

static float color_matrix[20] = {
1, 0, 0, 0, 0, //
0, 1, 0, 0, 0, //
0, 0, 1, 0, 0, //
0, 0, 0, 2, 0, //
};

ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
ImGui::SliderFloat("Alpha", &alpha, 0, 1);

ImGui::Combo("Type", &selected_type, names, sizeof(names) / sizeof(char*));
std::string label = "##1";
for (int i = 0; i < 20; i += 5) {
ImGui::InputScalarN(label.c_str(), ImGuiDataType_Float,
&(color_matrix[i]), 5, nullptr, nullptr, "%.2f", 0);
label[2]++;
}
ImGui::End();

flutter::DisplayListBuilder builder;
flutter::DlPaint save_paint;
save_paint.setAlpha(static_cast<uint8_t>(255 * alpha));
auto color_filter =
std::make_shared<flutter::DlMatrixColorFilter>(color_matrix);
Type type = static_cast<Type>(selected_type);
switch (type) {
case Type::kUseAsImageFilter: {
auto image_filter =
std::make_shared<flutter::DlColorFilterImageFilter>(color_filter);
save_paint.setImageFilter(image_filter);
break;
}
case Type::kUseAsColorFilter: {
save_paint.setColorFilter(color_filter);
break;
}
case Type::kDisableFilter:
break;
}
builder.saveLayer(nullptr, &save_paint);
flutter::DlPaint draw_paint;
builder.drawImage(DlImageImpeller::Make(texture), SkPoint::Make(100, 100),
flutter::DlImageSampling::kNearestNeighbor, &draw_paint);
builder.restore();
return builder.Build();
};

ASSERT_TRUE(OpenPlaygroundHere(callback));
}

TEST_P(DisplayListTest, SaveLayerWithBlendFiltersAndAlphaDrawCorrectly) {
auto texture = CreateTextureForFixture("boston.jpg");
bool first_frame = true;
enum class Type { kUseAsImageFilter, kUseAsColorFilter, kDisableFilter };
auto callback = [&]() {
if (first_frame) {
first_frame = false;
ImGui::SetNextWindowPos({10, 10});
}

static float alpha = 0.5;
static int selected_type = 0;
const char* names[] = {"Use as image filter", "Use as color filter",
"Disable filter"};

ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
ImGui::SliderFloat("Alpha", &alpha, 0, 1);

ImGui::Combo("Type", &selected_type, names, sizeof(names) / sizeof(char*));
ImGui::End();

flutter::DisplayListBuilder builder;
flutter::DlPaint save_paint;
save_paint.setAlpha(static_cast<uint8_t>(255 * alpha));
auto color_filter = std::make_shared<flutter::DlBlendColorFilter>(
flutter::DlColor::kRed(), flutter::DlBlendMode::kDstOver);
Type type = static_cast<Type>(selected_type);
switch (type) {
case Type::kUseAsImageFilter: {
auto image_filter =
std::make_shared<flutter::DlColorFilterImageFilter>(color_filter);
save_paint.setImageFilter(image_filter);
break;
}
case Type::kUseAsColorFilter: {
save_paint.setColorFilter(color_filter);
break;
}
case Type::kDisableFilter:
break;
}
builder.saveLayer(nullptr, &save_paint);
flutter::DlPaint draw_paint;
draw_paint.setColor(flutter::DlColor::kBlue());
builder.drawRect(SkRect::MakeLTRB(100, 100, 400, 400), draw_paint);
builder.restore();
return builder.Build();
};

ASSERT_TRUE(OpenPlaygroundHere(callback));
}

TEST_P(DisplayListTest, CanDrawBackdropFilter) {
auto texture = CreateTextureForFixture("embarcadero.jpg");

Expand Down
2 changes: 2 additions & 0 deletions impeller/entity/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ impeller_component("entity") {
"contents/filters/blend_filter_contents.h",
"contents/filters/border_mask_blur_filter_contents.cc",
"contents/filters/border_mask_blur_filter_contents.h",
"contents/filters/color_filter_contents.cc",
"contents/filters/color_filter_contents.h",
"contents/filters/color_matrix_filter_contents.cc",
"contents/filters/color_matrix_filter_contents.h",
"contents/filters/filter_contents.cc",
Expand Down
Loading

0 comments on commit c034c8b

Please sign in to comment.