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

Commit 6a687be

Browse files
authored
[Impeller] implements new blur tile mode (#48805)
fixes flutter/flutter#139165 ## before <img width="1027" alt="Screenshot 2023-12-07 at 2 18 42 PM" src="https://github.com/flutter/engine/assets/30870216/606d7203-20d6-4efd-a788-2f539508a280"> ## after <img width="1026" alt="Screenshot 2023-12-07 at 2 14 39 PM" src="https://github.com/flutter/engine/assets/30870216/8209b372-e477-4552-b4d1-2296b1e6d2d8"> ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide] and the [C++, Objective-C, Java style guides]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I added new tests to check the change I am making or feature I am adding, or the PR is [test-exempt]. See [testing the engine] for instructions on writing and running engine tests. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I signed the [CLA]. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style [testing the engine]: https://github.com/flutter/flutter/wiki/Testing-the-engine [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat
1 parent 47d4225 commit 6a687be

File tree

5 files changed

+106
-30
lines changed

5 files changed

+106
-30
lines changed

impeller/aiks/aiks_unittests.cc

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4257,7 +4257,43 @@ TEST_P(AiksTest, AdvancedBlendWithClearColorOptimization) {
42574257
canvas.DrawRect(
42584258
Rect::MakeXYWH(0, 0, 200, 300),
42594259
{.color = {1.0, 0.0, 1.0, 1.0}, .blend_mode = BlendMode::kMultiply});
4260+
}
4261+
4262+
TEST_P(AiksTest, GaussianBlurAtPeripheryVertical) {
4263+
Canvas canvas;
42604264

4265+
canvas.Scale(GetContentScale());
4266+
canvas.DrawRRect(Rect::MakeLTRB(0, 0, GetWindowSize().width, 100),
4267+
Point(10, 10), Paint{.color = Color::LimeGreen()});
4268+
canvas.DrawRRect(Rect::MakeLTRB(0, 110, GetWindowSize().width, 210),
4269+
Point(10, 10), Paint{.color = Color::Magenta()});
4270+
canvas.ClipRect(Rect::MakeLTRB(100, 0, 200, GetWindowSize().height));
4271+
canvas.SaveLayer({.blend_mode = BlendMode::kSource}, std::nullopt,
4272+
ImageFilter::MakeBlur(Sigma(20.0), Sigma(20.0),
4273+
FilterContents::BlurStyle::kNormal,
4274+
Entity::TileMode::kClamp));
4275+
canvas.Restore();
4276+
4277+
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
4278+
}
4279+
4280+
TEST_P(AiksTest, GaussianBlurAtPeripheryHorizontal) {
4281+
Canvas canvas;
4282+
4283+
canvas.Scale(GetContentScale());
4284+
std::shared_ptr<Texture> boston = CreateTextureForFixture("boston.jpg");
4285+
canvas.DrawImageRect(
4286+
std::make_shared<Image>(boston),
4287+
Rect::MakeXYWH(0, 0, boston->GetSize().width, boston->GetSize().height),
4288+
Rect::MakeLTRB(0, 0, GetWindowSize().width, 100), Paint{});
4289+
canvas.DrawRRect(Rect::MakeLTRB(0, 110, GetWindowSize().width, 210),
4290+
Point(10, 10), Paint{.color = Color::Magenta()});
4291+
canvas.ClipRect(Rect::MakeLTRB(0, 50, GetWindowSize().width, 150));
4292+
canvas.SaveLayer({.blend_mode = BlendMode::kSource}, std::nullopt,
4293+
ImageFilter::MakeBlur(Sigma(20.0), Sigma(20.0),
4294+
FilterContents::BlurStyle::kNormal,
4295+
Entity::TileMode::kClamp));
4296+
canvas.Restore();
42614297
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
42624298
}
42634299

impeller/entity/contents/filters/filter_contents.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ std::shared_ptr<FilterContents> FilterContents::MakeGaussianBlur(
6666
// TODO(https://github.com/flutter/flutter/issues/131580): Remove once the new
6767
// blur handles all cases.
6868
if (use_new_filter) {
69-
auto blur = std::make_shared<GaussianBlurFilterContents>(sigma_x.sigma);
69+
auto blur =
70+
std::make_shared<GaussianBlurFilterContents>(sigma_x.sigma, tile_mode);
7071
blur->SetInputs({input});
7172
return blur;
7273
}

impeller/entity/contents/filters/gaussian_blur_filter_contents.cc

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,31 @@ Matrix MakeAnchorScale(const Point& anchor, Vector2 scale) {
5454
Matrix::MakeTranslation({-anchor.x, -anchor.y, 0});
5555
}
5656

57+
void SetTileMode(SamplerDescriptor* descriptor,
58+
const ContentContext& renderer,
59+
Entity::TileMode tile_mode) {
60+
switch (tile_mode) {
61+
case Entity::TileMode::kDecal:
62+
if (renderer.GetDeviceCapabilities().SupportsDecalSamplerAddressMode()) {
63+
descriptor->width_address_mode = SamplerAddressMode::kDecal;
64+
descriptor->height_address_mode = SamplerAddressMode::kDecal;
65+
}
66+
break;
67+
case Entity::TileMode::kClamp:
68+
descriptor->width_address_mode = SamplerAddressMode::kClampToEdge;
69+
descriptor->height_address_mode = SamplerAddressMode::kClampToEdge;
70+
break;
71+
case Entity::TileMode::kMirror:
72+
descriptor->width_address_mode = SamplerAddressMode::kMirror;
73+
descriptor->height_address_mode = SamplerAddressMode::kMirror;
74+
break;
75+
case Entity::TileMode::kRepeat:
76+
descriptor->width_address_mode = SamplerAddressMode::kRepeat;
77+
descriptor->height_address_mode = SamplerAddressMode::kRepeat;
78+
break;
79+
}
80+
}
81+
5782
/// Makes a subpass that will render the scaled down input and add the
5883
/// transparent gutter required for the blur halo.
5984
std::shared_ptr<Texture> MakeDownsampleSubpass(
@@ -62,7 +87,8 @@ std::shared_ptr<Texture> MakeDownsampleSubpass(
6287
const SamplerDescriptor& sampler_descriptor,
6388
const Quad& uvs,
6489
const ISize& subpass_size,
65-
const Vector2 padding) {
90+
const Vector2 padding,
91+
Entity::TileMode tile_mode) {
6692
ContentContext::SubpassCallback subpass_callback =
6793
[&](const ContentContext& renderer, RenderPass& pass) {
6894
HostBuffer& host_buffer = pass.GetTransientsBuffer();
@@ -82,21 +108,22 @@ std::shared_ptr<Texture> MakeDownsampleSubpass(
82108
// creates a halo effect. This compensates for when the expanded clip
83109
// region can't give us the full gutter we want.
84110
Vector2 texture_size = Vector2(input_texture->GetSize());
85-
Quad vertices =
111+
Quad guttered_uvs =
86112
MakeAnchorScale({0.5, 0.5},
87-
texture_size / (texture_size + padding * 2))
88-
.Transform(
89-
{Point(0, 0), Point(1, 0), Point(0, 1), Point(1, 1)});
90-
91-
BindVertices<TextureFillVertexShader>(cmd, host_buffer,
92-
{
93-
{vertices[0], uvs[0]},
94-
{vertices[1], uvs[1]},
95-
{vertices[2], uvs[2]},
96-
{vertices[3], uvs[3]},
97-
});
113+
(texture_size + padding * 2) / texture_size)
114+
.Transform(uvs);
115+
116+
BindVertices<TextureFillVertexShader>(
117+
cmd, host_buffer,
118+
{
119+
{Point(0, 0), guttered_uvs[0]},
120+
{Point(1, 0), guttered_uvs[1]},
121+
{Point(0, 1), guttered_uvs[2]},
122+
{Point(1, 1), guttered_uvs[3]},
123+
});
98124

99125
SamplerDescriptor linear_sampler_descriptor = sampler_descriptor;
126+
SetTileMode(&linear_sampler_descriptor, renderer, tile_mode);
100127
linear_sampler_descriptor.mag_filter = MinMagFilter::kLinear;
101128
linear_sampler_descriptor.min_filter = MinMagFilter::kLinear;
102129
TextureFillVertexShader::BindFrameInfo(
@@ -165,8 +192,10 @@ std::shared_ptr<Texture> MakeBlurSubpass(
165192

166193
} // namespace
167194

168-
GaussianBlurFilterContents::GaussianBlurFilterContents(Scalar sigma)
169-
: sigma_(sigma) {}
195+
GaussianBlurFilterContents::GaussianBlurFilterContents(
196+
Scalar sigma,
197+
Entity::TileMode tile_mode)
198+
: sigma_(sigma), tile_mode_(tile_mode) {}
170199

171200
// This value was extracted from Skia, see:
172201
// * https://github.com/google/skia/blob/d29cc3fe182f6e8a8539004a6a4ee8251677a6fd/src/gpu/ganesh/GrBlurUtils.cpp#L2561-L2576
@@ -264,7 +293,7 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
264293

265294
std::shared_ptr<Texture> pass1_out_texture = MakeDownsampleSubpass(
266295
renderer, input_snapshot->texture, input_snapshot->sampler_descriptor,
267-
uvs, subpass_size, padding);
296+
uvs, subpass_size, padding, tile_mode_);
268297

269298
Vector2 pass1_pixel_size = 1.0 / Vector2(pass1_out_texture->GetSize());
270299

impeller/entity/contents/filters/gaussian_blur_filter_contents.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ namespace impeller {
1515
/// Note: This will replace `DirectionalGaussianBlurFilterContents`.
1616
class GaussianBlurFilterContents final : public FilterContents {
1717
public:
18-
explicit GaussianBlurFilterContents(Scalar sigma = 0.0f);
18+
explicit GaussianBlurFilterContents(Scalar sigma, Entity::TileMode tile_mode);
1919

2020
Scalar GetSigma() const { return sigma_; }
2121

@@ -58,6 +58,7 @@ class GaussianBlurFilterContents final : public FilterContents {
5858
const std::optional<Rect>& coverage_hint) const override;
5959

6060
const Scalar sigma_ = 0.0;
61+
const Entity::TileMode tile_mode_;
6162
};
6263

6364
} // namespace impeller

impeller/entity/contents/filters/gaussian_blur_filter_contents_unittests.cc

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,12 @@ class GaussianBlurFilterContentsTest : public EntityPlayground {
3535
INSTANTIATE_PLAYGROUND_SUITE(GaussianBlurFilterContentsTest);
3636

3737
TEST(GaussianBlurFilterContentsTest, Create) {
38-
GaussianBlurFilterContents contents;
38+
GaussianBlurFilterContents contents(/*sigma=*/0.0, Entity::TileMode::kDecal);
3939
ASSERT_EQ(contents.GetSigma(), 0.0);
4040
}
4141

4242
TEST(GaussianBlurFilterContentsTest, CoverageEmpty) {
43-
GaussianBlurFilterContents contents;
43+
GaussianBlurFilterContents contents(/*sigma=*/0.0, Entity::TileMode::kDecal);
4444
FilterInput::Vector inputs = {};
4545
Entity entity;
4646
std::optional<Rect> coverage =
@@ -49,7 +49,7 @@ TEST(GaussianBlurFilterContentsTest, CoverageEmpty) {
4949
}
5050

5151
TEST(GaussianBlurFilterContentsTest, CoverageSimple) {
52-
GaussianBlurFilterContents contents;
52+
GaussianBlurFilterContents contents(/*sigma=*/0.0, Entity::TileMode::kDecal);
5353
FilterInput::Vector inputs = {
5454
FilterInput::Make(Rect::MakeLTRB(10, 10, 110, 110))};
5555
Entity entity;
@@ -60,7 +60,8 @@ TEST(GaussianBlurFilterContentsTest, CoverageSimple) {
6060

6161
TEST(GaussianBlurFilterContentsTest, CoverageWithSigma) {
6262
Scalar sigma_radius_1 = CalculateSigmaForBlurRadius(1.0);
63-
GaussianBlurFilterContents contents(/*sigma=*/sigma_radius_1);
63+
GaussianBlurFilterContents contents(/*sigma=*/sigma_radius_1,
64+
Entity::TileMode::kDecal);
6465
FilterInput::Vector inputs = {
6566
FilterInput::Make(Rect::MakeLTRB(100, 100, 200, 200))};
6667
Entity entity;
@@ -76,7 +77,8 @@ TEST_P(GaussianBlurFilterContentsTest, CoverageWithTexture) {
7677
.size = ISize(100, 100),
7778
};
7879
Scalar sigma_radius_1 = CalculateSigmaForBlurRadius(1.0);
79-
GaussianBlurFilterContents contents(/*sigma=*/sigma_radius_1);
80+
GaussianBlurFilterContents contents(/*sigma=*/sigma_radius_1,
81+
Entity::TileMode::kDecal);
8082
std::shared_ptr<Texture> texture =
8183
GetContentContext()->GetContext()->GetResourceAllocator()->CreateTexture(
8284
desc);
@@ -95,7 +97,8 @@ TEST_P(GaussianBlurFilterContentsTest, CoverageWithEffectTransform) {
9597
.size = ISize(100, 100),
9698
};
9799
Scalar sigma_radius_1 = CalculateSigmaForBlurRadius(1.0);
98-
GaussianBlurFilterContents contents(/*sigma=*/sigma_radius_1);
100+
GaussianBlurFilterContents contents(/*sigma=*/sigma_radius_1,
101+
Entity::TileMode::kDecal);
99102
std::shared_ptr<Texture> texture =
100103
GetContentContext()->GetContext()->GetResourceAllocator()->CreateTexture(
101104
desc);
@@ -109,7 +112,8 @@ TEST_P(GaussianBlurFilterContentsTest, CoverageWithEffectTransform) {
109112

110113
TEST(GaussianBlurFilterContentsTest, FilterSourceCoverage) {
111114
Scalar sigma_radius_1 = CalculateSigmaForBlurRadius(1.0);
112-
auto contents = std::make_unique<GaussianBlurFilterContents>(sigma_radius_1);
115+
auto contents = std::make_unique<GaussianBlurFilterContents>(
116+
sigma_radius_1, Entity::TileMode::kDecal);
113117
std::optional<Rect> coverage = contents->GetFilterSourceCoverage(
114118
/*effect_transform=*/Matrix::MakeScale({2.0, 2.0, 1.0}),
115119
/*output_limit=*/Rect::MakeLTRB(100, 100, 200, 200));
@@ -133,7 +137,8 @@ TEST_P(GaussianBlurFilterContentsTest, RenderCoverageMatchesGetCoverage) {
133137
};
134138
std::shared_ptr<Texture> texture = MakeTexture(desc);
135139
Scalar sigma_radius_1 = CalculateSigmaForBlurRadius(1.0);
136-
auto contents = std::make_unique<GaussianBlurFilterContents>(sigma_radius_1);
140+
auto contents = std::make_unique<GaussianBlurFilterContents>(
141+
sigma_radius_1, Entity::TileMode::kDecal);
137142
contents->SetInputs({FilterInput::Make(texture)});
138143
std::shared_ptr<ContentContext> renderer = GetContentContext();
139144

@@ -165,7 +170,8 @@ TEST_P(GaussianBlurFilterContentsTest,
165170
};
166171
std::shared_ptr<Texture> texture = MakeTexture(desc);
167172
Scalar sigma_radius_1 = CalculateSigmaForBlurRadius(1.0);
168-
auto contents = std::make_unique<GaussianBlurFilterContents>(sigma_radius_1);
173+
auto contents = std::make_unique<GaussianBlurFilterContents>(
174+
sigma_radius_1, Entity::TileMode::kDecal);
169175
contents->SetInputs({FilterInput::Make(texture)});
170176
std::shared_ptr<ContentContext> renderer = GetContentContext();
171177

@@ -199,7 +205,8 @@ TEST_P(GaussianBlurFilterContentsTest,
199205
};
200206
std::shared_ptr<Texture> texture = MakeTexture(desc);
201207
Scalar sigma_radius_1 = CalculateSigmaForBlurRadius(1.0);
202-
auto contents = std::make_unique<GaussianBlurFilterContents>(sigma_radius_1);
208+
auto contents = std::make_unique<GaussianBlurFilterContents>(
209+
sigma_radius_1, Entity::TileMode::kDecal);
203210
contents->SetInputs({FilterInput::Make(texture)});
204211
std::shared_ptr<ContentContext> renderer = GetContentContext();
205212

@@ -258,7 +265,8 @@ TEST_P(GaussianBlurFilterContentsTest, TextureContentsWithDestinationRect) {
258265
50, 40, texture->GetSize().width, texture->GetSize().height));
259266

260267
Scalar sigma_radius_1 = CalculateSigmaForBlurRadius(1.0);
261-
auto contents = std::make_unique<GaussianBlurFilterContents>(sigma_radius_1);
268+
auto contents = std::make_unique<GaussianBlurFilterContents>(
269+
sigma_radius_1, Entity::TileMode::kDecal);
262270
contents->SetInputs({FilterInput::Make(texture_contents)});
263271
std::shared_ptr<ContentContext> renderer = GetContentContext();
264272

@@ -296,7 +304,8 @@ TEST_P(GaussianBlurFilterContentsTest,
296304
50, 40, texture->GetSize().width, texture->GetSize().height));
297305

298306
Scalar sigma_radius_1 = CalculateSigmaForBlurRadius(1.0);
299-
auto contents = std::make_unique<GaussianBlurFilterContents>(sigma_radius_1);
307+
auto contents = std::make_unique<GaussianBlurFilterContents>(
308+
sigma_radius_1, Entity::TileMode::kDecal);
300309
contents->SetInputs({FilterInput::Make(texture_contents)});
301310
std::shared_ptr<ContentContext> renderer = GetContentContext();
302311

0 commit comments

Comments
 (0)