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

Commit 7541e90

Browse files
authored
[Impeller] implement mask blur for textures (#51183)
fixes flutter/flutter#144266 ## 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 b0d3663 commit 7541e90

File tree

5 files changed

+75
-8
lines changed

5 files changed

+75
-8
lines changed

impeller/aiks/aiks_blur_unittests.cc

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -839,6 +839,32 @@ TEST_P(AiksTest, GaussianBlurStyleSolid) {
839839
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
840840
}
841841

842+
TEST_P(AiksTest, MaskBlurTexture) {
843+
Scalar sigma = 30;
844+
auto callback = [&](AiksContext& renderer) -> std::optional<Picture> {
845+
if (AiksTest::ImGuiBegin("Controls", nullptr,
846+
ImGuiWindowFlags_AlwaysAutoResize)) {
847+
ImGui::SliderFloat("Sigma", &sigma, 0, 500);
848+
ImGui::End();
849+
}
850+
Canvas canvas;
851+
canvas.Scale(GetContentScale());
852+
Paint paint;
853+
paint.color = Color::Green();
854+
paint.mask_blur_descriptor = Paint::MaskBlurDescriptor{
855+
.style = FilterContents::BlurStyle::kNormal,
856+
.sigma = Sigma(sigma),
857+
};
858+
std::shared_ptr<Texture> boston = CreateTextureForFixture("boston.jpg");
859+
canvas.DrawImage(std::make_shared<Image>(boston), {200, 200}, paint);
860+
Paint red;
861+
red.color = Color::Red();
862+
canvas.DrawRect(Rect::MakeXYWH(0, 0, 200, 200), red);
863+
return canvas.EndRecordingAsPicture();
864+
};
865+
ASSERT_TRUE(OpenPlaygroundHere(callback));
866+
}
867+
842868
TEST_P(AiksTest, GuassianBlurUpdatesMipmapContents) {
843869
// This makes sure if mip maps are recycled across invocations of blurs the
844870
// contents get updated each frame correctly. If they aren't updated the color

impeller/aiks/canvas.cc

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -728,14 +728,19 @@ void Canvas::DrawImageRect(const std::shared_ptr<Image>& image,
728728
return;
729729
}
730730

731-
auto contents = TextureContents::MakeRect(dest);
732-
contents->SetTexture(image->GetTexture());
733-
contents->SetSourceRect(source);
734-
contents->SetStrictSourceRect(src_rect_constraint ==
735-
SourceRectConstraint::kStrict);
736-
contents->SetSamplerDescriptor(std::move(sampler));
737-
contents->SetOpacity(paint.color.alpha);
738-
contents->SetDeferApplyingOpacity(paint.HasColorFilter());
731+
auto texture_contents = TextureContents::MakeRect(dest);
732+
texture_contents->SetTexture(image->GetTexture());
733+
texture_contents->SetSourceRect(source);
734+
texture_contents->SetStrictSourceRect(src_rect_constraint ==
735+
SourceRectConstraint::kStrict);
736+
texture_contents->SetSamplerDescriptor(std::move(sampler));
737+
texture_contents->SetOpacity(paint.color.alpha);
738+
texture_contents->SetDeferApplyingOpacity(paint.HasColorFilter());
739+
740+
std::shared_ptr<Contents> contents = texture_contents;
741+
if (paint.mask_blur_descriptor.has_value()) {
742+
contents = paint.mask_blur_descriptor->CreateMaskBlur(texture_contents);
743+
}
739744

740745
Entity entity;
741746
entity.SetBlendMode(paint.blend_mode);

impeller/aiks/paint.cc

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "impeller/entity/contents/color_source_contents.h"
1010
#include "impeller/entity/contents/filters/color_filter_contents.h"
1111
#include "impeller/entity/contents/filters/filter_contents.h"
12+
#include "impeller/entity/contents/filters/gaussian_blur_filter_contents.h"
1213
#include "impeller/entity/contents/solid_color_contents.h"
1314
#include "impeller/entity/geometry/geometry.h"
1415

@@ -121,6 +122,34 @@ std::shared_ptr<Contents> Paint::WithColorFilter(
121122
absorb_opacity);
122123
}
123124

125+
std::shared_ptr<FilterContents> Paint::MaskBlurDescriptor::CreateMaskBlur(
126+
std::shared_ptr<TextureContents> texture_contents) const {
127+
Scalar expand_amount = GaussianBlurFilterContents::CalculateBlurRadius(
128+
GaussianBlurFilterContents::ScaleSigma(sigma.sigma));
129+
texture_contents->SetSourceRect(
130+
texture_contents->GetSourceRect().Expand(expand_amount, expand_amount));
131+
auto mask = std::make_shared<SolidColorContents>();
132+
mask->SetColor(Color::White());
133+
std::optional<Rect> coverage = texture_contents->GetCoverage({});
134+
std::shared_ptr<Geometry> geometry;
135+
if (coverage) {
136+
texture_contents->SetDestinationRect(
137+
coverage.value().Expand(expand_amount, expand_amount));
138+
geometry = Geometry::MakeRect(coverage.value());
139+
}
140+
mask->SetGeometry(geometry);
141+
auto descriptor = texture_contents->GetSamplerDescriptor();
142+
texture_contents->SetSamplerDescriptor(descriptor);
143+
std::shared_ptr<FilterContents> blurred_mask =
144+
FilterContents::MakeGaussianBlur(FilterInput::Make(mask), sigma, sigma,
145+
Entity::TileMode::kDecal, style,
146+
geometry);
147+
148+
return ColorFilterContents::MakeBlend(
149+
BlendMode::kSourceIn,
150+
{FilterInput::Make(blurred_mask), FilterInput::Make(texture_contents)});
151+
}
152+
124153
std::shared_ptr<FilterContents> Paint::MaskBlurDescriptor::CreateMaskBlur(
125154
std::shared_ptr<ColorSourceContents> color_source_contents,
126155
const std::shared_ptr<ColorFilter>& color_filter) const {

impeller/aiks/paint.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "impeller/entity/contents/contents.h"
1414
#include "impeller/entity/contents/filters/color_filter_contents.h"
1515
#include "impeller/entity/contents/filters/filter_contents.h"
16+
#include "impeller/entity/contents/texture_contents.h"
1617
#include "impeller/entity/entity.h"
1718
#include "impeller/entity/geometry/geometry.h"
1819
#include "impeller/geometry/color.h"
@@ -43,6 +44,9 @@ struct Paint {
4344
std::shared_ptr<ColorSourceContents> color_source_contents,
4445
const std::shared_ptr<ColorFilter>& color_filter) const;
4546

47+
std::shared_ptr<FilterContents> CreateMaskBlur(
48+
std::shared_ptr<TextureContents> texture_contents) const;
49+
4650
std::shared_ptr<FilterContents> CreateMaskBlur(
4751
const FilterInput::Ref& input,
4852
bool is_solid_color) const;

testing/impeller_golden_tests_output.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,9 @@ impeller_Play_AiksTest_ImageFilteredUnboundedSaveLayerWithUnboundedContents_Vulk
516516
impeller_Play_AiksTest_LinearToSrgbFilterSubpassCollapseOptimization_Metal.png
517517
impeller_Play_AiksTest_LinearToSrgbFilterSubpassCollapseOptimization_OpenGLES.png
518518
impeller_Play_AiksTest_LinearToSrgbFilterSubpassCollapseOptimization_Vulkan.png
519+
impeller_Play_AiksTest_MaskBlurTexture_Metal.png
520+
impeller_Play_AiksTest_MaskBlurTexture_OpenGLES.png
521+
impeller_Play_AiksTest_MaskBlurTexture_Vulkan.png
519522
impeller_Play_AiksTest_MaskBlurVariantTestInnerTranslucentWithBlurImageFilter_Metal.png
520523
impeller_Play_AiksTest_MaskBlurVariantTestInnerTranslucentWithBlurImageFilter_OpenGLES.png
521524
impeller_Play_AiksTest_MaskBlurVariantTestInnerTranslucentWithBlurImageFilter_Vulkan.png

0 commit comments

Comments
 (0)