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

Commit 5335c87

Browse files
[Impeller] reduce advanced blend subpass count for single input with foreground color (#40886)
[Impeller] reduce advanced blend subpass count for single input with foreground color
1 parent 6a6d8cc commit 5335c87

File tree

6 files changed

+246
-0
lines changed

6 files changed

+246
-0
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1200,6 +1200,8 @@ ORIGIN: ../../../flutter/impeller/entity/contents/filters/srgb_to_linear_filter_
12001200
ORIGIN: ../../../flutter/impeller/entity/contents/filters/srgb_to_linear_filter_contents.h + ../../../flutter/LICENSE
12011201
ORIGIN: ../../../flutter/impeller/entity/contents/filters/yuv_to_rgb_filter_contents.cc + ../../../flutter/LICENSE
12021202
ORIGIN: ../../../flutter/impeller/entity/contents/filters/yuv_to_rgb_filter_contents.h + ../../../flutter/LICENSE
1203+
ORIGIN: ../../../flutter/impeller/entity/contents/foreground_blend_contents.cc + ../../../flutter/LICENSE
1204+
ORIGIN: ../../../flutter/impeller/entity/contents/foreground_blend_contents.h + ../../../flutter/LICENSE
12031205
ORIGIN: ../../../flutter/impeller/entity/contents/framebuffer_blend_contents.cc + ../../../flutter/LICENSE
12041206
ORIGIN: ../../../flutter/impeller/entity/contents/framebuffer_blend_contents.h + ../../../flutter/LICENSE
12051207
ORIGIN: ../../../flutter/impeller/entity/contents/gradient_generator.cc + ../../../flutter/LICENSE
@@ -3782,6 +3784,8 @@ FILE: ../../../flutter/impeller/entity/contents/filters/srgb_to_linear_filter_co
37823784
FILE: ../../../flutter/impeller/entity/contents/filters/srgb_to_linear_filter_contents.h
37833785
FILE: ../../../flutter/impeller/entity/contents/filters/yuv_to_rgb_filter_contents.cc
37843786
FILE: ../../../flutter/impeller/entity/contents/filters/yuv_to_rgb_filter_contents.h
3787+
FILE: ../../../flutter/impeller/entity/contents/foreground_blend_contents.cc
3788+
FILE: ../../../flutter/impeller/entity/contents/foreground_blend_contents.h
37853789
FILE: ../../../flutter/impeller/entity/contents/framebuffer_blend_contents.cc
37863790
FILE: ../../../flutter/impeller/entity/contents/framebuffer_blend_contents.h
37873791
FILE: ../../../flutter/impeller/entity/contents/gradient_generator.cc

impeller/entity/BUILD.gn

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ impeller_component("entity") {
180180
"contents/filters/srgb_to_linear_filter_contents.h",
181181
"contents/filters/yuv_to_rgb_filter_contents.cc",
182182
"contents/filters/yuv_to_rgb_filter_contents.h",
183+
"contents/foreground_blend_contents.cc",
184+
"contents/foreground_blend_contents.h",
183185
"contents/framebuffer_blend_contents.cc",
184186
"contents/framebuffer_blend_contents.h",
185187
"contents/gradient_generator.cc",

impeller/entity/contents/filters/blend_filter_contents.cc

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "impeller/entity/contents/content_context.h"
1313
#include "impeller/entity/contents/contents.h"
1414
#include "impeller/entity/contents/filters/inputs/filter_input.h"
15+
#include "impeller/entity/contents/foreground_blend_contents.h"
1516
#include "impeller/entity/contents/solid_color_contents.h"
1617
#include "impeller/entity/entity.h"
1718
#include "impeller/geometry/path_builder.h"
@@ -373,6 +374,20 @@ std::optional<Entity> BlendFilterContents::RenderFilter(
373374
}
374375

375376
if (blend_mode_ <= Entity::kLastAdvancedBlendMode) {
377+
auto potential_alpha = GetAlpha().value_or(1.0);
378+
if (inputs.size() == 1 && foreground_color_.has_value() &&
379+
potential_alpha >= 1.0 - kEhCloseEnough) {
380+
auto contents = std::make_shared<AdvancedForegroundBlendContents>();
381+
contents->SetBlendMode(blend_mode_);
382+
contents->SetCoverage(coverage);
383+
contents->SetSrcInput(inputs[0]);
384+
contents->SetForegroundColor(foreground_color_.value());
385+
Entity entity;
386+
entity.SetTransformation(Matrix::MakeTranslation(coverage.origin));
387+
entity.SetContents(std::move(contents));
388+
return entity;
389+
}
390+
376391
return advanced_blend_proc_(inputs, renderer, entity, coverage,
377392
foreground_color_, GetAbsorbOpacity(),
378393
GetAlpha());
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include "foreground_blend_contents.h"
6+
7+
#include "flutter/impeller/entity/contents/content_context.h"
8+
#include "flutter/impeller/renderer/render_pass.h"
9+
#include "flutter/impeller/renderer/sampler_library.h"
10+
11+
namespace impeller {
12+
13+
AdvancedForegroundBlendContents::AdvancedForegroundBlendContents() {}
14+
15+
AdvancedForegroundBlendContents::~AdvancedForegroundBlendContents() {}
16+
17+
void AdvancedForegroundBlendContents::SetBlendMode(BlendMode blend_mode) {
18+
FML_DCHECK(blend_mode > Entity::kLastPipelineBlendMode);
19+
blend_mode_ = blend_mode;
20+
}
21+
22+
void AdvancedForegroundBlendContents::SetSrcInput(
23+
std::shared_ptr<FilterInput> input) {
24+
input_ = std::move(input);
25+
}
26+
27+
void AdvancedForegroundBlendContents::SetForegroundColor(Color color) {
28+
foreground_color_ = color;
29+
}
30+
31+
void AdvancedForegroundBlendContents::SetCoverage(Rect rect) {
32+
rect_ = rect;
33+
}
34+
35+
std::optional<Rect> AdvancedForegroundBlendContents::GetCoverage(
36+
const Entity& entity) const {
37+
return rect_.TransformBounds(entity.GetTransformation());
38+
}
39+
40+
bool AdvancedForegroundBlendContents::Render(const ContentContext& renderer,
41+
const Entity& entity,
42+
RenderPass& pass) const {
43+
using VS = BlendScreenPipeline::VertexShader;
44+
using FS = BlendScreenPipeline::FragmentShader;
45+
46+
auto& host_buffer = pass.GetTransientsBuffer();
47+
48+
auto dst_snapshot = input_->GetSnapshot(renderer, entity);
49+
if (!dst_snapshot.has_value()) {
50+
return false;
51+
}
52+
auto maybe_dst_uvs = dst_snapshot->GetCoverageUVs(rect_);
53+
if (!maybe_dst_uvs.has_value()) {
54+
return false;
55+
}
56+
auto dst_uvs = maybe_dst_uvs.value();
57+
58+
auto size = rect_.size;
59+
VertexBufferBuilder<VS::PerVertexData> vtx_builder;
60+
vtx_builder.AddVertices({
61+
{Point(0, 0), dst_uvs[0], dst_uvs[0]},
62+
{Point(size.width, 0), dst_uvs[1], dst_uvs[1]},
63+
{Point(size.width, size.height), dst_uvs[3], dst_uvs[3]},
64+
{Point(0, 0), dst_uvs[0], dst_uvs[0]},
65+
{Point(size.width, size.height), dst_uvs[3], dst_uvs[3]},
66+
{Point(0, size.height), dst_uvs[2], dst_uvs[2]},
67+
});
68+
auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer);
69+
70+
Command cmd;
71+
cmd.label = "Foreground Advanced Blend Filter";
72+
cmd.BindVertices(vtx_buffer);
73+
cmd.stencil_reference = entity.GetStencilDepth();
74+
auto options = OptionsFromPass(pass);
75+
76+
switch (blend_mode_) {
77+
case BlendMode::kScreen:
78+
cmd.pipeline = renderer.GetBlendScreenPipeline(options);
79+
break;
80+
case BlendMode::kOverlay:
81+
cmd.pipeline = renderer.GetBlendOverlayPipeline(options);
82+
break;
83+
case BlendMode::kDarken:
84+
cmd.pipeline = renderer.GetBlendDarkenPipeline(options);
85+
break;
86+
case BlendMode::kLighten:
87+
cmd.pipeline = renderer.GetBlendLightenPipeline(options);
88+
break;
89+
case BlendMode::kColorDodge:
90+
cmd.pipeline = renderer.GetBlendColorDodgePipeline(options);
91+
break;
92+
case BlendMode::kColorBurn:
93+
cmd.pipeline = renderer.GetBlendColorBurnPipeline(options);
94+
break;
95+
case BlendMode::kHardLight:
96+
cmd.pipeline = renderer.GetBlendHardLightPipeline(options);
97+
break;
98+
case BlendMode::kSoftLight:
99+
cmd.pipeline = renderer.GetBlendSoftLightPipeline(options);
100+
break;
101+
case BlendMode::kDifference:
102+
cmd.pipeline = renderer.GetBlendDifferencePipeline(options);
103+
break;
104+
case BlendMode::kExclusion:
105+
cmd.pipeline = renderer.GetBlendExclusionPipeline(options);
106+
break;
107+
case BlendMode::kMultiply:
108+
cmd.pipeline = renderer.GetBlendMultiplyPipeline(options);
109+
break;
110+
case BlendMode::kHue:
111+
cmd.pipeline = renderer.GetBlendHuePipeline(options);
112+
break;
113+
case BlendMode::kSaturation:
114+
cmd.pipeline = renderer.GetBlendSaturationPipeline(options);
115+
break;
116+
case BlendMode::kColor:
117+
cmd.pipeline = renderer.GetBlendColorPipeline(options);
118+
break;
119+
case BlendMode::kLuminosity:
120+
cmd.pipeline = renderer.GetBlendLuminosityPipeline(options);
121+
break;
122+
default:
123+
return false;
124+
}
125+
126+
FS::BlendInfo blend_info;
127+
VS::FrameInfo frame_info;
128+
129+
auto dst_sampler_descriptor = dst_snapshot->sampler_descriptor;
130+
if (renderer.GetDeviceCapabilities().SupportsDecalTileMode()) {
131+
dst_sampler_descriptor.width_address_mode = SamplerAddressMode::kDecal;
132+
dst_sampler_descriptor.height_address_mode = SamplerAddressMode::kDecal;
133+
}
134+
auto dst_sampler = renderer.GetContext()->GetSamplerLibrary()->GetSampler(
135+
dst_sampler_descriptor);
136+
FS::BindTextureSamplerDst(cmd, dst_snapshot->texture, dst_sampler);
137+
frame_info.dst_y_coord_scale = dst_snapshot->texture->GetYCoordScale();
138+
blend_info.dst_input_alpha = dst_snapshot->opacity;
139+
140+
blend_info.color_factor = 1;
141+
blend_info.color = foreground_color_;
142+
// This texture will not be sampled from due to the color factor. But
143+
// this is present so that validation doesn't trip on a missing
144+
// binding.
145+
FS::BindTextureSamplerSrc(cmd, dst_snapshot->texture, dst_sampler);
146+
147+
auto blend_uniform = host_buffer.EmplaceUniform(blend_info);
148+
FS::BindBlendInfo(cmd, blend_uniform);
149+
150+
frame_info.mvp = Matrix::MakeOrthographic(pass.GetRenderTargetSize()) *
151+
entity.GetTransformation();
152+
153+
auto uniform_view = host_buffer.EmplaceUniform(frame_info);
154+
VS::BindFrameInfo(cmd, uniform_view);
155+
156+
return pass.AddCommand(cmd);
157+
}
158+
159+
} // namespace impeller
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#pragma once
6+
7+
#include "flutter/fml/macros.h"
8+
#include "flutter/impeller/core/texture.h"
9+
#include "flutter/impeller/entity/contents/color_source_contents.h"
10+
#include "flutter/impeller/entity/contents/filters/inputs/filter_input.h"
11+
#include "flutter/impeller/entity/entity.h"
12+
13+
namespace impeller {
14+
15+
/// @brief Optimized advanced blend that avoids a second subpass when there is
16+
/// only a single input and a foreground color.
17+
///
18+
/// These contents cannot absorb opacity.
19+
class AdvancedForegroundBlendContents : public Contents {
20+
public:
21+
AdvancedForegroundBlendContents();
22+
23+
~AdvancedForegroundBlendContents();
24+
25+
void SetBlendMode(BlendMode blend_mode);
26+
27+
void SetSrcInput(std::shared_ptr<FilterInput> input);
28+
29+
void SetForegroundColor(Color color);
30+
31+
void SetCoverage(Rect rect);
32+
33+
private:
34+
// |Contents|
35+
std::optional<Rect> GetCoverage(const Entity& entity) const override;
36+
37+
// |Contents|
38+
bool Render(const ContentContext& renderer,
39+
const Entity& entity,
40+
RenderPass& pass) const override;
41+
42+
Color foreground_color_;
43+
BlendMode blend_mode_;
44+
std::shared_ptr<FilterInput> input_;
45+
Rect rect_;
46+
47+
FML_DISALLOW_COPY_AND_ASSIGN(AdvancedForegroundBlendContents);
48+
};
49+
50+
} // namespace impeller

impeller/entity/entity_unittests.cc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2451,5 +2451,21 @@ TEST_P(EntityTest, InheritOpacityTest) {
24512451
ASSERT_FALSE(runtime_effect->CanInheritOpacity(entity));
24522452
}
24532453

2454+
TEST_P(EntityTest, ColorFilterWithForegroundColorAdvancedBlend) {
2455+
auto image = CreateTextureForFixture("boston.jpg");
2456+
auto filter = ColorFilterContents::MakeBlend(
2457+
BlendMode::kColorBurn, FilterInput::Make({image}), Color::Red());
2458+
2459+
auto callback = [&](ContentContext& context, RenderPass& pass) -> bool {
2460+
Entity entity;
2461+
entity.SetTransformation(Matrix::MakeScale(GetContentScale()) *
2462+
Matrix::MakeTranslation({500, 300}) *
2463+
Matrix::MakeScale(Vector2{0.5, 0.5}));
2464+
entity.SetContents(filter);
2465+
return entity.Render(context, pass);
2466+
};
2467+
ASSERT_TRUE(OpenPlaygroundHere(callback));
2468+
}
2469+
24542470
} // namespace testing
24552471
} // namespace impeller

0 commit comments

Comments
 (0)