From 84a598832fd4ca3484029a67d58eec834e310ed8 Mon Sep 17 00:00:00 2001 From: magicianA Date: Mon, 8 Aug 2022 10:37:21 +0800 Subject: [PATCH] [Impeller] EntityPass should cover the whole screen for some blend modes (flutter/engine#35157) --- .../flutter/impeller/aiks/aiks_unittests.cc | 25 +++++++++++++++++++ engine/src/flutter/impeller/entity/entity.cc | 20 +++++++++++++++ engine/src/flutter/impeller/entity/entity.h | 2 ++ .../flutter/impeller/entity/entity_pass.cc | 6 ++++- .../src/flutter/impeller/entity/entity_pass.h | 2 +- 5 files changed, 53 insertions(+), 2 deletions(-) diff --git a/engine/src/flutter/impeller/aiks/aiks_unittests.cc b/engine/src/flutter/impeller/aiks/aiks_unittests.cc index 55e5a9f1e6d..edd552f17d8 100644 --- a/engine/src/flutter/impeller/aiks/aiks_unittests.cc +++ b/engine/src/flutter/impeller/aiks/aiks_unittests.cc @@ -252,6 +252,31 @@ TEST_P(AiksTest, CanRenderRadialGradient) { ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); } +TEST_P(AiksTest, BlendModeShouldCoverWholeScreen) { + Canvas canvas; + Paint paint; + + paint.color = Color::Red(); + canvas.DrawPaint(paint); + + paint.blend_mode = Entity::BlendMode::kSourceOver; + canvas.SaveLayer(paint); + + paint.color = Color::White(); + canvas.DrawRect({100, 100, 400, 400}, paint); + + paint.blend_mode = Entity::BlendMode::kSource; + canvas.SaveLayer(paint); + + paint.color = Color::Blue(); + canvas.DrawRect({200, 200, 200, 200}, paint); + + canvas.Restore(); + canvas.Restore(); + + ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture())); +} + TEST_P(AiksTest, CanRenderGroupOpacity) { Canvas canvas; diff --git a/engine/src/flutter/impeller/entity/entity.cc b/engine/src/flutter/impeller/entity/entity.cc index e5695ef8017..56f534a880d 100644 --- a/engine/src/flutter/impeller/entity/entity.cc +++ b/engine/src/flutter/impeller/entity/entity.cc @@ -42,6 +42,9 @@ std::optional Entity::GetCoverage() const { } bool Entity::ShouldRender(const ISize& target_size) const { + if (BlendModeShouldCoverWholeScreen(blend_mode_)) { + return true; + } return contents_->ShouldRender(*this, target_size); } @@ -73,6 +76,23 @@ Entity::BlendMode Entity::GetBlendMode() const { return blend_mode_; } +bool Entity::BlendModeShouldCoverWholeScreen(BlendMode blend_mode) { + switch (blend_mode) { + case BlendMode::kClear: + case BlendMode::kSource: + case BlendMode::kSourceIn: + case BlendMode::kDestinationIn: + case BlendMode::kSourceOut: + case BlendMode::kDestinationOut: + case BlendMode::kDestinationATop: + case BlendMode::kXor: + case BlendMode::kModulate: + return true; + default: + return false; + } +} + bool Entity::Render(const ContentContext& renderer, RenderPass& parent_pass) const { if (!contents_) { diff --git a/engine/src/flutter/impeller/entity/entity.h b/engine/src/flutter/impeller/entity/entity.h index b79ce606992..8c787e2c773 100644 --- a/engine/src/flutter/impeller/entity/entity.h +++ b/engine/src/flutter/impeller/entity/entity.h @@ -121,6 +121,8 @@ class Entity { bool Render(const ContentContext& renderer, RenderPass& parent_pass) const; + static bool BlendModeShouldCoverWholeScreen(BlendMode blend_mode); + private: Matrix transformation_; std::shared_ptr contents_; diff --git a/engine/src/flutter/impeller/entity/entity_pass.cc b/engine/src/flutter/impeller/entity/entity_pass.cc index 5cae1fc91b2..442862a7ac2 100644 --- a/engine/src/flutter/impeller/entity/entity_pass.cc +++ b/engine/src/flutter/impeller/entity/entity_pass.cc @@ -252,7 +252,10 @@ EntityPass::EntityResult EntityPass::GetEntityForElement( auto subpass_coverage = GetSubpassCoverage(*subpass, Rect::MakeSize(root_pass_size)); - + if (subpass->cover_whole_screen) { + subpass_coverage = Rect( + position, Size(pass_context.GetRenderTarget().GetRenderTargetSize())); + } if (backdrop_contents) { auto backdrop_coverage = backdrop_contents->GetCoverage(Entity{}); if (backdrop_coverage.has_value()) { @@ -501,6 +504,7 @@ void EntityPass::SetStencilDepth(size_t stencil_depth) { void EntityPass::SetBlendMode(Entity::BlendMode blend_mode) { blend_mode_ = blend_mode; + cover_whole_screen = Entity::BlendModeShouldCoverWholeScreen(blend_mode); } void EntityPass::SetBackdropFilter(std::optional proc) { diff --git a/engine/src/flutter/impeller/entity/entity_pass.h b/engine/src/flutter/impeller/entity/entity_pass.h index 87c7bddd4cd..7ec177f68f5 100644 --- a/engine/src/flutter/impeller/entity/entity_pass.h +++ b/engine/src/flutter/impeller/entity/entity_pass.h @@ -114,7 +114,7 @@ class EntityPass { Matrix xformation_; size_t stencil_depth_ = 0u; Entity::BlendMode blend_mode_ = Entity::BlendMode::kSourceOver; - + bool cover_whole_screen = false; /// This flag is set to `true` whenever an entity is added to the pass that /// requires reading the pass texture during rendering. This can happen in the /// following scenarios: