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

Commit 4c04abe

Browse files
committed
[Impeller] Defer applying opacity when saving layer
1 parent 8ef540f commit 4c04abe

21 files changed

+205
-60
lines changed

impeller/aiks/paint_pass_delegate.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ std::shared_ptr<Contents> PaintPassDelegate::CreateContentsForSubpassTarget(
3939
contents->SetTexture(target);
4040
contents->SetSourceRect(Rect::MakeSize(target->GetSize()));
4141
contents->SetOpacity(paint_.color.alpha);
42+
contents->SetDeferApplyingOpacity(true);
4243

4344
return paint_.WithFilters(std::move(contents), false, effect_transform);
4445
}

impeller/display_list/display_list_dispatcher.cc

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,8 @@ void DisplayListDispatcher::setColorSource(
419419
}
420420

421421
static std::optional<Paint::ColorFilterProc> ToColorFilterProc(
422-
const flutter::DlColorFilter* filter) {
422+
const flutter::DlColorFilter* filter,
423+
bool need_absorb_opacity = true) {
423424
if (filter == nullptr) {
424425
return std::nullopt;
425426
}
@@ -428,25 +429,29 @@ static std::optional<Paint::ColorFilterProc> ToColorFilterProc(
428429
auto dl_blend = filter->asBlend();
429430
auto blend_mode = ToBlendMode(dl_blend->mode());
430431
auto color = ToColor(dl_blend->color());
431-
return [blend_mode, color](FilterInput::Ref input) {
432-
return FilterContents::MakeBlend(blend_mode, {input}, color);
432+
return [blend_mode, color, need_absorb_opacity](FilterInput::Ref input) {
433+
return FilterContents::MakeBlend(blend_mode, {input}, color,
434+
need_absorb_opacity);
433435
};
434436
}
435437
case flutter::DlColorFilterType::kMatrix: {
436438
const flutter::DlMatrixColorFilter* dl_matrix = filter->asMatrix();
437439
impeller::FilterContents::ColorMatrix color_matrix;
438440
dl_matrix->get_matrix(color_matrix.array);
439-
return [color_matrix](FilterInput::Ref input) {
440-
return FilterContents::MakeColorMatrix({input}, color_matrix);
441+
return [color_matrix, need_absorb_opacity](FilterInput::Ref input) {
442+
return FilterContents::MakeColorMatrix({input}, color_matrix,
443+
need_absorb_opacity);
441444
};
442445
}
443446
case flutter::DlColorFilterType::kSrgbToLinearGamma:
444-
return [](FilterInput::Ref input) {
445-
return FilterContents::MakeSrgbToLinearFilter({input});
447+
return [need_absorb_opacity](FilterInput::Ref input) {
448+
return FilterContents::MakeSrgbToLinearFilter({input},
449+
need_absorb_opacity);
446450
};
447451
case flutter::DlColorFilterType::kLinearToSrgbGamma:
448-
return [](FilterInput::Ref input) {
449-
return FilterContents::MakeLinearToSrgbFilter({input});
452+
return [need_absorb_opacity](FilterInput::Ref input) {
453+
return FilterContents::MakeLinearToSrgbFilter({input},
454+
need_absorb_opacity);
450455
};
451456
case flutter::DlColorFilterType::kUnknown:
452457
FML_LOG(ERROR) << "requested DlColorFilterType::kUnknown";
@@ -612,7 +617,8 @@ static std::optional<Paint::ImageFilterProc> ToImageFilterProc(
612617
auto color_filter_image_filter = filter->asColorFilter();
613618
FML_DCHECK(color_filter_image_filter);
614619
auto color_filter_proc =
615-
ToColorFilterProc(color_filter_image_filter->color_filter().get());
620+
ToColorFilterProc(color_filter_image_filter->color_filter().get(),
621+
/*need_absorb_opacity=*/false);
616622
if (!color_filter_proc.has_value()) {
617623
return std::nullopt;
618624
}

impeller/display_list/display_list_unittests.cc

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -815,5 +815,70 @@ TEST_P(DisplayListTest, CanDrawPaintWithColorSource) {
815815
ASSERT_TRUE(OpenPlaygroundHere(builder.Build()));
816816
}
817817

818+
TEST_P(DisplayListTest, SaveLayerWithFiltersAndAlphaDrawCorrectly) {
819+
auto texture = CreateTextureForFixture("boston.jpg");
820+
bool first_frame = true;
821+
enum class Type { kUseAsImageFilter, kUseAsColorFilter, kDisableFilter };
822+
auto callback = [&]() {
823+
if (first_frame) {
824+
first_frame = false;
825+
ImGui::SetNextWindowPos({10, 10});
826+
}
827+
828+
static float alpha = 0.5;
829+
static int selected_type = 0;
830+
const char* names[] = {"Use as image filter", "Use as color filter",
831+
"Disable filter"};
832+
833+
static float color_matrix[20] = {
834+
1, 0, 0, 0, 0, //
835+
0, 1, 0, 0, 0, //
836+
0, 0, 1, 0, 0, //
837+
0, 0, 0, 2, 0, //
838+
};
839+
840+
ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
841+
ImGui::SliderFloat("Alpha", &alpha, 0, 1);
842+
843+
ImGui::Combo("Type", &selected_type, names, sizeof(names) / sizeof(char*));
844+
std::string label = "##1";
845+
for (int i = 0; i < 20; i += 5) {
846+
ImGui::InputScalarN(label.c_str(), ImGuiDataType_Float,
847+
&(color_matrix[i]), 5, nullptr, nullptr, "%.2f", 0);
848+
label[2]++;
849+
}
850+
ImGui::End();
851+
852+
flutter::DisplayListBuilder builder;
853+
flutter::DlPaint save_paint;
854+
save_paint.setAlpha(static_cast<uint8_t>(255 * alpha));
855+
auto color_filter =
856+
std::make_shared<flutter::DlMatrixColorFilter>(color_matrix);
857+
Type type = static_cast<Type>(selected_type);
858+
switch (type) {
859+
case Type::kUseAsImageFilter: {
860+
auto image_filter =
861+
std::make_shared<flutter::DlColorFilterImageFilter>(color_filter);
862+
save_paint.setImageFilter(image_filter);
863+
break;
864+
}
865+
case Type::kUseAsColorFilter: {
866+
save_paint.setColorFilter(color_filter);
867+
break;
868+
}
869+
case Type::kDisableFilter:
870+
break;
871+
}
872+
builder.saveLayer(nullptr, &save_paint);
873+
flutter::DlPaint draw_paint;
874+
builder.drawImage(DlImageImpeller::Make(texture), SkPoint::Make(100, 100),
875+
flutter::DlImageSampling::kNearestNeighbor, &draw_paint);
876+
builder.restore();
877+
return builder.Build();
878+
};
879+
880+
ASSERT_TRUE(OpenPlaygroundHere(callback));
881+
}
882+
818883
} // namespace testing
819884
} // namespace impeller

impeller/entity/contents/filters/blend_filter_contents.cc

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ static std::optional<Snapshot> AdvancedBlend(
3535
const Entity& entity,
3636
const Rect& coverage,
3737
std::optional<Color> foreground_color,
38+
bool need_absorb_opacity,
3839
PipelineProc pipeline_proc) {
3940
using VS = typename TPipeline::VertexShader;
4041
using FS = typename TPipeline::FragmentShader;
@@ -107,6 +108,8 @@ static std::optional<Snapshot> AdvancedBlend(
107108
auto sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler({});
108109
FS::BindTextureSamplerDst(cmd, dst_snapshot->texture, sampler);
109110
blend_info.dst_y_coord_scale = dst_snapshot->texture->GetYCoordScale();
111+
blend_info.dst_input_alpha =
112+
need_absorb_opacity ? dst_snapshot->opacity : 1.0f;
110113

111114
if (foreground_color.has_value()) {
112115
blend_info.color_factor = 1;
@@ -139,9 +142,11 @@ static std::optional<Snapshot> AdvancedBlend(
139142
}
140143
out_texture->SetLabel("Advanced Blend Filter Texture");
141144

142-
return Snapshot{.texture = out_texture,
143-
.transform = Matrix::MakeTranslation(coverage.origin),
144-
.sampler_descriptor = dst_snapshot->sampler_descriptor};
145+
return Snapshot{
146+
.texture = out_texture,
147+
.transform = Matrix::MakeTranslation(coverage.origin),
148+
.sampler_descriptor = dst_snapshot->sampler_descriptor,
149+
.opacity = need_absorb_opacity ? 1.0f : dst_snapshot->opacity};
145150
}
146151

147152
static std::optional<Snapshot> PipelineBlend(
@@ -150,10 +155,13 @@ static std::optional<Snapshot> PipelineBlend(
150155
const Entity& entity,
151156
const Rect& coverage,
152157
BlendMode pipeline_blend,
153-
std::optional<Color> foreground_color) {
158+
std::optional<Color> foreground_color,
159+
bool need_absorb_opacity) {
154160
using VS = BlendPipeline::VertexShader;
155161
using FS = BlendPipeline::FragmentShader;
156162

163+
auto input_snapshot = inputs[0]->GetSnapshot(renderer, entity);
164+
157165
ContentContext::SubpassCallback callback = [&](const ContentContext& renderer,
158166
RenderPass& pass) {
159167
auto& host_buffer = pass.GetTransientsBuffer();
@@ -195,6 +203,7 @@ static std::optional<Snapshot> PipelineBlend(
195203
FS::FragInfo frag_info;
196204
frag_info.texture_sampler_y_coord_scale =
197205
input->texture->GetYCoordScale();
206+
frag_info.input_alpha = need_absorb_opacity ? input->opacity : 1.0f;
198207
FS::BindFragInfo(cmd, host_buffer.EmplaceUniform(frag_info));
199208
VS::BindFrameInfo(cmd, host_buffer.EmplaceUniform(frame_info));
200209

@@ -203,10 +212,9 @@ static std::optional<Snapshot> PipelineBlend(
203212
};
204213

205214
// Draw the first texture using kSource.
206-
207215
options.blend_mode = BlendMode::kSource;
208216
cmd.pipeline = renderer.GetBlendPipeline(options);
209-
if (!add_blend_command(inputs[0]->GetSnapshot(renderer, entity))) {
217+
if (!add_blend_command(input_snapshot)) {
210218
return true;
211219
}
212220

@@ -255,19 +263,21 @@ static std::optional<Snapshot> PipelineBlend(
255263
.texture = out_texture,
256264
.transform = Matrix::MakeTranslation(coverage.origin),
257265
.sampler_descriptor =
258-
inputs[0]->GetSnapshot(renderer, entity)->sampler_descriptor};
266+
inputs[0]->GetSnapshot(renderer, entity)->sampler_descriptor,
267+
.opacity = need_absorb_opacity ? 1.0f : input_snapshot->opacity};
259268
}
260269

261-
#define BLEND_CASE(mode) \
262-
case BlendMode::k##mode: \
263-
advanced_blend_proc_ = [](const FilterInput::Vector& inputs, \
264-
const ContentContext& renderer, \
265-
const Entity& entity, const Rect& coverage, \
266-
std::optional<Color> fg_color) { \
267-
PipelineProc p = &ContentContext::GetBlend##mode##Pipeline; \
268-
return AdvancedBlend<BlendScreenPipeline>(inputs, renderer, entity, \
269-
coverage, fg_color, p); \
270-
}; \
270+
#define BLEND_CASE(mode) \
271+
case BlendMode::k##mode: \
272+
advanced_blend_proc_ = \
273+
[](const FilterInput::Vector& inputs, const ContentContext& renderer, \
274+
const Entity& entity, const Rect& coverage, \
275+
std::optional<Color> fg_color, bool need_absorb_opacity) { \
276+
PipelineProc p = &ContentContext::GetBlend##mode##Pipeline; \
277+
return AdvancedBlend<BlendScreenPipeline>(inputs, renderer, entity, \
278+
coverage, fg_color, \
279+
need_absorb_opacity, p); \
280+
}; \
271281
break;
272282

273283
void BlendFilterContents::SetBlendMode(BlendMode blend_mode) {
@@ -318,17 +328,17 @@ std::optional<Snapshot> BlendFilterContents::RenderFilter(
318328
if (inputs.size() == 1 && !foreground_color_.has_value()) {
319329
// Nothing to blend.
320330
return PipelineBlend(inputs, renderer, entity, coverage, BlendMode::kSource,
321-
std::nullopt);
331+
std::nullopt, GetNeedAbsorbOpacity());
322332
}
323333

324334
if (blend_mode_ <= Entity::kLastPipelineBlendMode) {
325335
return PipelineBlend(inputs, renderer, entity, coverage, blend_mode_,
326-
foreground_color_);
336+
foreground_color_, GetNeedAbsorbOpacity());
327337
}
328338

329339
if (blend_mode_ <= Entity::kLastAdvancedBlendMode) {
330340
return advanced_blend_proc_(inputs, renderer, entity, coverage,
331-
foreground_color_);
341+
foreground_color_, GetNeedAbsorbOpacity());
332342
}
333343
FML_UNREACHABLE();
334344
}

impeller/entity/contents/filters/blend_filter_contents.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ class BlendFilterContents : public FilterContents {
1616
const ContentContext& renderer,
1717
const Entity& entity,
1818
const Rect& coverage,
19-
std::optional<Color> foreground_color)>;
19+
std::optional<Color> foreground_color,
20+
bool need_absorb_opacity)>;
2021

2122
BlendFilterContents();
2223

impeller/entity/contents/filters/border_mask_blur_filter_contents.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,8 @@ std::optional<Snapshot> BorderMaskBlurFilterContents::RenderFilter(
127127
out_texture->SetLabel("BorderMaskBlurFilter Texture");
128128

129129
return Snapshot{.texture = out_texture,
130-
.transform = Matrix::MakeTranslation(coverage.origin)};
130+
.transform = Matrix::MakeTranslation(coverage.origin),
131+
.opacity = input_snapshot->opacity};
131132
}
132133

133134
std::optional<Rect> BorderMaskBlurFilterContents::GetFilterCoverage(

impeller/entity/contents/filters/color_matrix_filter_contents.cc

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ std::optional<Snapshot> ColorMatrixFilterContents::RenderFilter(
8787
matrix[3], matrix[8], matrix[13], matrix[18]
8888
);
8989
// clang-format on
90+
frag_info.input_alpha =
91+
GetNeedAbsorbOpacity() ? input_snapshot->opacity : 1.0f;
9092
auto sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler({});
9193
FS::BindInputTexture(cmd, input_snapshot->texture, sampler);
9294
FS::BindFragInfo(cmd, host_buffer.EmplaceUniform(frag_info));
@@ -103,9 +105,11 @@ std::optional<Snapshot> ColorMatrixFilterContents::RenderFilter(
103105
}
104106
out_texture->SetLabel("ColorMatrixFilter Texture");
105107

106-
return Snapshot{.texture = out_texture,
107-
.transform = input_snapshot->transform,
108-
.sampler_descriptor = input_snapshot->sampler_descriptor};
108+
return Snapshot{
109+
.texture = out_texture,
110+
.transform = input_snapshot->transform,
111+
.sampler_descriptor = input_snapshot->sampler_descriptor,
112+
.opacity = GetNeedAbsorbOpacity() ? 1.0f : input_snapshot->opacity};
109113
}
110114

111115
} // namespace impeller

impeller/entity/contents/filters/filter_contents.cc

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ namespace impeller {
3636
std::shared_ptr<FilterContents> FilterContents::MakeBlend(
3737
BlendMode blend_mode,
3838
FilterInput::Vector inputs,
39-
std::optional<Color> foreground_color) {
39+
std::optional<Color> foreground_color,
40+
bool need_absorb_opacity) {
4041
if (blend_mode > Entity::kLastAdvancedBlendMode) {
4142
VALIDATION_LOG << "Invalid blend mode " << static_cast<int>(blend_mode)
4243
<< " passed to FilterContents::MakeBlend.";
@@ -49,6 +50,7 @@ std::shared_ptr<FilterContents> FilterContents::MakeBlend(
4950
blend->SetInputs(inputs);
5051
blend->SetBlendMode(blend_mode);
5152
blend->SetForegroundColor(foreground_color);
53+
blend->SetNeedAbsorbOpacity(need_absorb_opacity);
5254
return blend;
5355
}
5456

@@ -58,6 +60,7 @@ std::shared_ptr<FilterContents> FilterContents::MakeBlend(
5860
new_blend = std::make_shared<BlendFilterContents>();
5961
new_blend->SetInputs({*in_i, blend_input});
6062
new_blend->SetBlendMode(blend_mode);
63+
new_blend->SetNeedAbsorbOpacity(need_absorb_opacity);
6164
if (in_i < inputs.end() - 1 || foreground_color.has_value()) {
6265
blend_input = FilterInput::Make(
6366
std::static_pointer_cast<FilterContents>(new_blend));
@@ -69,6 +72,7 @@ std::shared_ptr<FilterContents> FilterContents::MakeBlend(
6972
new_blend->SetInputs({blend_input});
7073
new_blend->SetBlendMode(blend_mode);
7174
new_blend->SetForegroundColor(foreground_color);
75+
new_blend->SetNeedAbsorbOpacity(need_absorb_opacity);
7276
}
7377

7478
return new_blend;
@@ -156,24 +160,30 @@ std::shared_ptr<FilterContents> FilterContents::MakeMorphology(
156160

157161
std::shared_ptr<FilterContents> FilterContents::MakeColorMatrix(
158162
FilterInput::Ref input,
159-
const ColorMatrix& color_matrix) {
163+
const ColorMatrix& color_matrix,
164+
bool need_absorb_opacity) {
160165
auto filter = std::make_shared<ColorMatrixFilterContents>();
161166
filter->SetInputs({input});
162167
filter->SetMatrix(color_matrix);
168+
filter->SetNeedAbsorbOpacity(need_absorb_opacity);
163169
return filter;
164170
}
165171

166172
std::shared_ptr<FilterContents> FilterContents::MakeLinearToSrgbFilter(
167-
FilterInput::Ref input) {
173+
FilterInput::Ref input,
174+
bool need_absorb_opacity) {
168175
auto filter = std::make_shared<LinearToSrgbFilterContents>();
169176
filter->SetInputs({input});
177+
filter->SetNeedAbsorbOpacity(need_absorb_opacity);
170178
return filter;
171179
}
172180

173181
std::shared_ptr<FilterContents> FilterContents::MakeSrgbToLinearFilter(
174-
FilterInput::Ref input) {
182+
FilterInput::Ref input,
183+
bool need_absorb_opacity) {
175184
auto filter = std::make_shared<SrgbToLinearFilterContents>();
176185
filter->SetInputs({input});
186+
filter->SetNeedAbsorbOpacity(need_absorb_opacity);
177187
return filter;
178188
}
179189

@@ -236,6 +246,7 @@ bool FilterContents::Render(const ContentContext& renderer,
236246
contents->SetTexture(snapshot.texture);
237247
contents->SetSamplerDescriptor(snapshot.sampler_descriptor);
238248
contents->SetSourceRect(texture_rect);
249+
contents->SetOpacity(snapshot.opacity);
239250

240251
Entity e;
241252
e.SetBlendMode(entity.GetBlendMode());
@@ -313,4 +324,12 @@ Matrix FilterContents::GetTransform(const Matrix& parent_transform) const {
313324
return parent_transform * GetLocalTransform(parent_transform);
314325
}
315326

327+
void FilterContents::SetNeedAbsorbOpacity(bool need_absorb_opacity) {
328+
need_absorb_opacity_ = need_absorb_opacity;
329+
}
330+
331+
bool FilterContents::GetNeedAbsorbOpacity() const {
332+
return need_absorb_opacity_;
333+
}
334+
316335
} // namespace impeller

0 commit comments

Comments
 (0)