From 6828abffee20f291b91fa166591dd06580e312e0 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Tue, 23 May 2023 19:06:19 -0700 Subject: [PATCH] [Impeller] Set the coverage hint on everything (flutter/engine#42264) Attaches a minimum coverage hint to all rendered entities. This makes ImageFilter blurs do less work when clipped. We can utilize this in a number of other filters as well. ![Screenshot 2023-05-23 at 3 16 49 PM](https://github.com/flutter/engine/assets/919017/5b7182c8-e704-4c4a-bb71-fdf226a60f4e) The test I added also demonstrates a sampling issue in the gaussian blur that I'm trying to work out. Here it is without any clipping. This coverage hint change does not introduce the issue: ![Screenshot 2023-05-23 at 3 08 15 PM](https://github.com/flutter/engine/assets/919017/524c2fb1-3b58-4589-824b-0794c2bd5ea2) --- .../flutter/impeller/aiks/aiks_unittests.cc | 21 +++++++++++++++++++ .../flutter/impeller/entity/entity_pass.cc | 17 ++++++--------- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/engine/src/flutter/impeller/aiks/aiks_unittests.cc b/engine/src/flutter/impeller/aiks/aiks_unittests.cc index 32e9bfc7f07..a34a9892387 100644 --- a/engine/src/flutter/impeller/aiks/aiks_unittests.cc +++ b/engine/src/flutter/impeller/aiks/aiks_unittests.cc @@ -2322,6 +2322,27 @@ TEST_P(AiksTest, CanRenderBackdropBlurHugeSigma) { ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); } +TEST_P(AiksTest, CanRenderClippedBlur) { + Canvas canvas; + canvas.ClipRect(Rect::MakeXYWH(100, 150, 400, 400)); + canvas.DrawCircle( + {400, 400}, 200, + { + .color = Color::Green(), + .image_filter = + [](const FilterInput::Ref& input, const Matrix& effect_transform, + bool is_subpass) { + return FilterContents::MakeGaussianBlur( + input, Sigma(20), Sigma(20), + FilterContents::BlurStyle::kNormal, + Entity::TileMode::kClamp, effect_transform); + }, + }); + canvas.Restore(); + + ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} + // Regression test for https://github.com/flutter/flutter/issues/126701 . TEST_P(AiksTest, CanRenderClippedRuntimeEffects) { if (GetParam() != PlaygroundBackend::kMetal) { diff --git a/engine/src/flutter/impeller/entity/entity_pass.cc b/engine/src/flutter/impeller/entity/entity_pass.cc index 88622975f02..b929ab54d52 100644 --- a/engine/src/flutter/impeller/entity/entity_pass.cc +++ b/engine/src/flutter/impeller/entity/entity_pass.cc @@ -615,6 +615,12 @@ bool EntityPass::OnRender( stencil_coverage.coverage->origin += global_pass_position; } + // The coverage hint tells the rendered Contents which portion of the + // rendered output will actually be used, and so we set this to the current + // stencil coverage (which is the max clip bounds). The contents may + // optionally use this hint to avoid unnecessary rendering work. + element_entity.GetContents()->SetCoverageHint(current_stencil_coverage); + switch (stencil_coverage.type) { case Contents::StencilCoverage::Type::kNoChange: break; @@ -685,17 +691,6 @@ bool EntityPass::OnRender( return false; } - // Tell the backdrop contents which portion of the rendered output will - // actually be used. The contents may optionally use this hint to avoid - // unnecessary rendering work. - if (!stencil_coverage_stack.empty() && - stencil_coverage_stack.back().coverage.has_value()) { - auto coverage_hint = Rect( - stencil_coverage_stack.back().coverage->origin - global_pass_position, - stencil_coverage_stack.back().coverage->size); - backdrop_filter_contents->SetCoverageHint(coverage_hint); - } - Entity backdrop_entity; backdrop_entity.SetContents(std::move(backdrop_filter_contents)); backdrop_entity.SetTransformation(