From f73ae51144f6cb4dd9c56c2ddce137ea19ff3d3b Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Wed, 19 Apr 2023 18:07:33 -0700 Subject: [PATCH] [impeller] convert src over to src for solid color (flutter/engine#41351) Related to https://github.com/flutter/flutter/issues/114402 At least in the flutter gallery test app, with https://github.com/flutter/gallery/pull/909 reverted - this significantly improves the performance in the Xcode frame debugger. If we wanted to do this for more color sources or filter effects, we need to do much more work to track texture opacity, but this seems like a reasonable and low cost first step. ### Before ![image](https://user-images.githubusercontent.com/8975114/233222371-f33d29ad-c556-4db0-b949-84777bb09307.png) ### After ![image](https://user-images.githubusercontent.com/8975114/233222350-0517d109-cabd-45af-a0af-06b95da2d026.png) --- .../entity/contents/solid_color_contents.cc | 8 ++++++++ .../entity/contents/solid_color_contents.h | 4 ++++ .../impeller/entity/entity_unittests.cc | 20 +++++++++++++++++++ 3 files changed, 32 insertions(+) diff --git a/engine/src/flutter/impeller/entity/contents/solid_color_contents.cc b/engine/src/flutter/impeller/entity/contents/solid_color_contents.cc index 9c14169833..80f7c4cb07 100644 --- a/engine/src/flutter/impeller/entity/contents/solid_color_contents.cc +++ b/engine/src/flutter/impeller/entity/contents/solid_color_contents.cc @@ -46,6 +46,11 @@ bool SolidColorContents::ShouldRender( return Contents::ShouldRender(entity, stencil_coverage); } +bool SolidColorContents::ConvertToSrc(const Entity& entity) const { + return entity.GetBlendMode() == BlendMode::kSourceOver && + GetColor().alpha >= 1.0; +} + bool SolidColorContents::Render(const ContentContext& renderer, const Entity& entity, RenderPass& pass) const { @@ -60,6 +65,9 @@ bool SolidColorContents::Render(const ContentContext& renderer, GetGeometry()->GetPositionBuffer(renderer, entity, pass); auto options = OptionsFromPassAndEntity(pass, entity); + if (ConvertToSrc(entity)) { + options.blend_mode = BlendMode::kSource; + } if (geometry_result.prevent_overdraw) { options.stencil_compare = CompareFunction::kEqual; options.stencil_operation = StencilOperation::kIncrementClamp; diff --git a/engine/src/flutter/impeller/entity/contents/solid_color_contents.h b/engine/src/flutter/impeller/entity/contents/solid_color_contents.h index 5348b906af..9486fc8f0d 100644 --- a/engine/src/flutter/impeller/entity/contents/solid_color_contents.h +++ b/engine/src/flutter/impeller/entity/contents/solid_color_contents.h @@ -46,6 +46,10 @@ class SolidColorContents final : public ColorSourceContents { const Entity& entity, RenderPass& pass) const override; + /// @brief Convert SrcOver blend modes into Src blend modes if the color has + /// no opacity. + bool ConvertToSrc(const Entity& entity) const; + private: Color color_; diff --git a/engine/src/flutter/impeller/entity/entity_unittests.cc b/engine/src/flutter/impeller/entity/entity_unittests.cc index f1285c3393..b34055ba5f 100644 --- a/engine/src/flutter/impeller/entity/entity_unittests.cc +++ b/engine/src/flutter/impeller/entity/entity_unittests.cc @@ -2547,5 +2547,25 @@ TEST_P(EntityTest, CoverageForStrokePathWithNegativeValuesInTransform) { ASSERT_RECT_NEAR(coverage.value(), Rect::MakeXYWH(102.5, 342.5, 85, 155)); } +TEST_P(EntityTest, ConvertToSrcBlend) { + Entity entity; + entity.SetBlendMode(BlendMode::kSourceOver); + + auto contents = SolidColorContents::Make( + PathBuilder{}.AddRect(Rect::MakeSize(Size(100, 100))).TakePath(), + Color::Red()); + + ASSERT_TRUE(contents->ConvertToSrc(entity)); + + // Color with alpha, should return false. + contents->SetInheritedOpacity(0.5); + ASSERT_FALSE(contents->ConvertToSrc(entity)); + + // Non source over blend mode, should return false. + contents->SetInheritedOpacity(1.0); + entity.SetBlendMode(BlendMode::kDestination); + ASSERT_FALSE(contents->ConvertToSrc(entity)); +} + } // namespace testing } // namespace impeller