diff --git a/impeller/aiks/aiks_blur_unittests.cc b/impeller/aiks/aiks_blur_unittests.cc index b808d4fa3366c..34a7b7c112d10 100644 --- a/impeller/aiks/aiks_blur_unittests.cc +++ b/impeller/aiks/aiks_blur_unittests.cc @@ -839,6 +839,32 @@ TEST_P(AiksTest, GaussianBlurStyleSolid) { ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); } +TEST_P(AiksTest, MaskBlurTexture) { + Scalar sigma = 30; + auto callback = [&](AiksContext& renderer) -> std::optional { + if (AiksTest::ImGuiBegin("Controls", nullptr, + ImGuiWindowFlags_AlwaysAutoResize)) { + ImGui::SliderFloat("Sigma", &sigma, 0, 500); + ImGui::End(); + } + Canvas canvas; + canvas.Scale(GetContentScale()); + Paint paint; + paint.color = Color::Green(); + paint.mask_blur_descriptor = Paint::MaskBlurDescriptor{ + .style = FilterContents::BlurStyle::kNormal, + .sigma = Sigma(sigma), + }; + std::shared_ptr boston = CreateTextureForFixture("boston.jpg"); + canvas.DrawImage(std::make_shared(boston), {200, 200}, paint); + Paint red; + red.color = Color::Red(); + canvas.DrawRect(Rect::MakeXYWH(0, 0, 200, 200), red); + return canvas.EndRecordingAsPicture(); + }; + ASSERT_TRUE(OpenPlaygroundHere(callback)); +} + TEST_P(AiksTest, GuassianBlurUpdatesMipmapContents) { // This makes sure if mip maps are recycled across invocations of blurs the // contents get updated each frame correctly. If they aren't updated the color diff --git a/impeller/aiks/canvas.cc b/impeller/aiks/canvas.cc index 5a0a86faebbf2..57f84496625b3 100644 --- a/impeller/aiks/canvas.cc +++ b/impeller/aiks/canvas.cc @@ -728,14 +728,19 @@ void Canvas::DrawImageRect(const std::shared_ptr& image, return; } - auto contents = TextureContents::MakeRect(dest); - contents->SetTexture(image->GetTexture()); - contents->SetSourceRect(source); - contents->SetStrictSourceRect(src_rect_constraint == - SourceRectConstraint::kStrict); - contents->SetSamplerDescriptor(std::move(sampler)); - contents->SetOpacity(paint.color.alpha); - contents->SetDeferApplyingOpacity(paint.HasColorFilter()); + auto texture_contents = TextureContents::MakeRect(dest); + texture_contents->SetTexture(image->GetTexture()); + texture_contents->SetSourceRect(source); + texture_contents->SetStrictSourceRect(src_rect_constraint == + SourceRectConstraint::kStrict); + texture_contents->SetSamplerDescriptor(std::move(sampler)); + texture_contents->SetOpacity(paint.color.alpha); + texture_contents->SetDeferApplyingOpacity(paint.HasColorFilter()); + + std::shared_ptr contents = texture_contents; + if (paint.mask_blur_descriptor.has_value()) { + contents = paint.mask_blur_descriptor->CreateMaskBlur(texture_contents); + } Entity entity; entity.SetBlendMode(paint.blend_mode); diff --git a/impeller/aiks/paint.cc b/impeller/aiks/paint.cc index 94951236e6650..31043a148550c 100644 --- a/impeller/aiks/paint.cc +++ b/impeller/aiks/paint.cc @@ -9,6 +9,7 @@ #include "impeller/entity/contents/color_source_contents.h" #include "impeller/entity/contents/filters/color_filter_contents.h" #include "impeller/entity/contents/filters/filter_contents.h" +#include "impeller/entity/contents/filters/gaussian_blur_filter_contents.h" #include "impeller/entity/contents/solid_color_contents.h" #include "impeller/entity/geometry/geometry.h" @@ -121,6 +122,34 @@ std::shared_ptr Paint::WithColorFilter( absorb_opacity); } +std::shared_ptr Paint::MaskBlurDescriptor::CreateMaskBlur( + std::shared_ptr texture_contents) const { + Scalar expand_amount = GaussianBlurFilterContents::CalculateBlurRadius( + GaussianBlurFilterContents::ScaleSigma(sigma.sigma)); + texture_contents->SetSourceRect( + texture_contents->GetSourceRect().Expand(expand_amount, expand_amount)); + auto mask = std::make_shared(); + mask->SetColor(Color::White()); + std::optional coverage = texture_contents->GetCoverage({}); + std::shared_ptr geometry; + if (coverage) { + texture_contents->SetDestinationRect( + coverage.value().Expand(expand_amount, expand_amount)); + geometry = Geometry::MakeRect(coverage.value()); + } + mask->SetGeometry(geometry); + auto descriptor = texture_contents->GetSamplerDescriptor(); + texture_contents->SetSamplerDescriptor(descriptor); + std::shared_ptr blurred_mask = + FilterContents::MakeGaussianBlur(FilterInput::Make(mask), sigma, sigma, + Entity::TileMode::kDecal, style, + geometry); + + return ColorFilterContents::MakeBlend( + BlendMode::kSourceIn, + {FilterInput::Make(blurred_mask), FilterInput::Make(texture_contents)}); +} + std::shared_ptr Paint::MaskBlurDescriptor::CreateMaskBlur( std::shared_ptr color_source_contents, const std::shared_ptr& color_filter) const { diff --git a/impeller/aiks/paint.h b/impeller/aiks/paint.h index 126f152dba84c..10b46dc99c05a 100644 --- a/impeller/aiks/paint.h +++ b/impeller/aiks/paint.h @@ -13,6 +13,7 @@ #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/texture_contents.h" #include "impeller/entity/entity.h" #include "impeller/entity/geometry/geometry.h" #include "impeller/geometry/color.h" @@ -43,6 +44,9 @@ struct Paint { std::shared_ptr color_source_contents, const std::shared_ptr& color_filter) const; + std::shared_ptr CreateMaskBlur( + std::shared_ptr texture_contents) const; + std::shared_ptr CreateMaskBlur( const FilterInput::Ref& input, bool is_solid_color) const; diff --git a/testing/impeller_golden_tests_output.txt b/testing/impeller_golden_tests_output.txt index 0a6c28e5bb62d..7da59594a013d 100644 --- a/testing/impeller_golden_tests_output.txt +++ b/testing/impeller_golden_tests_output.txt @@ -516,6 +516,9 @@ impeller_Play_AiksTest_ImageFilteredUnboundedSaveLayerWithUnboundedContents_Vulk impeller_Play_AiksTest_LinearToSrgbFilterSubpassCollapseOptimization_Metal.png impeller_Play_AiksTest_LinearToSrgbFilterSubpassCollapseOptimization_OpenGLES.png impeller_Play_AiksTest_LinearToSrgbFilterSubpassCollapseOptimization_Vulkan.png +impeller_Play_AiksTest_MaskBlurTexture_Metal.png +impeller_Play_AiksTest_MaskBlurTexture_OpenGLES.png +impeller_Play_AiksTest_MaskBlurTexture_Vulkan.png impeller_Play_AiksTest_MaskBlurVariantTestInnerTranslucentWithBlurImageFilter_Metal.png impeller_Play_AiksTest_MaskBlurVariantTestInnerTranslucentWithBlurImageFilter_OpenGLES.png impeller_Play_AiksTest_MaskBlurVariantTestInnerTranslucentWithBlurImageFilter_Vulkan.png