From f29ce2aa7a01fd2cb0c9ee453248331b0e130014 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Fri, 6 Oct 2023 13:49:08 -0700 Subject: [PATCH] [Impeller] Ensure known geometry has simple bounds computation. (flutter/engine#46623) Computing the bounds of an RRect can be really slow if you don't actually know that it is an RRect, and shows up in the traces for flutter gallery on wembly. This change should be semantically equivalent and is only an optimization to avoid recomputing the same value we already know. --- engine/src/flutter/impeller/aiks/canvas.cc | 13 ++-- .../impeller/display_list/dl_unittests.cc | 60 +++++++++++++++++++ 2 files changed, 69 insertions(+), 4 deletions(-) diff --git a/engine/src/flutter/impeller/aiks/canvas.cc b/engine/src/flutter/impeller/aiks/canvas.cc index e8271ca642..d4d3829972 100644 --- a/engine/src/flutter/impeller/aiks/canvas.cc +++ b/engine/src/flutter/impeller/aiks/canvas.cc @@ -252,6 +252,7 @@ void Canvas::DrawRRect(Rect rect, Scalar corner_radius, const Paint& paint) { auto path = PathBuilder{} .SetConvexity(Convexity::kConvex) .AddRoundedRect(rect, corner_radius) + .SetBounds(rect) .TakePath(); if (paint.style == Paint::Style::kFill) { Entity entity; @@ -273,10 +274,13 @@ void Canvas::DrawCircle(Point center, Scalar radius, const Paint& paint) { paint)) { return; } - auto circle_path = PathBuilder{} - .AddCircle(center, radius) - .SetConvexity(Convexity::kConvex) - .TakePath(); + auto circle_path = + PathBuilder{} + .AddCircle(center, radius) + .SetConvexity(Convexity::kConvex) + .SetBounds(Rect::MakeLTRB(center.x - radius, center.y - radius, + center.x + radius, center.y + radius)) + .TakePath(); DrawPath(circle_path, paint); } @@ -317,6 +321,7 @@ void Canvas::ClipRRect(const Rect& rect, auto path = PathBuilder{} .SetConvexity(Convexity::kConvex) .AddRoundedRect(rect, corner_radius) + .SetBounds(rect) .TakePath(); std::optional inner_rect = (corner_radius * 2 < rect.size.width && diff --git a/engine/src/flutter/impeller/display_list/dl_unittests.cc b/engine/src/flutter/impeller/display_list/dl_unittests.cc index 896989c34e..c59ca6b010 100644 --- a/engine/src/flutter/impeller/display_list/dl_unittests.cc +++ b/engine/src/flutter/impeller/display_list/dl_unittests.cc @@ -21,6 +21,7 @@ #include "impeller/display_list/dl_dispatcher.h" #include "impeller/display_list/dl_image_impeller.h" #include "impeller/display_list/dl_playground.h" +#include "impeller/entity/contents/clip_contents.h" #include "impeller/entity/contents/solid_color_contents.h" #include "impeller/entity/contents/solid_rrect_blur_contents.h" #include "impeller/geometry/constants.h" @@ -1681,6 +1682,65 @@ TEST_P(DisplayListTest, DrawVerticesBlendModes) { ASSERT_TRUE(OpenPlaygroundHere(callback)); } +template +static std::optional GetCoverageOfFirstEntity(const Picture& picture) { + std::optional coverage; + picture.pass->IterateAllEntities([&coverage](Entity& entity) { + if (std::static_pointer_cast(entity.GetContents())) { + auto contents = std::static_pointer_cast(entity.GetContents()); + Entity entity; + coverage = contents->GetCoverage(entity); + return false; + } + return true; + }); + return coverage; +} + +TEST(DisplayListTest, RRectBoundsComputation) { + SkRRect rrect = SkRRect::MakeRectXY(SkRect::MakeLTRB(0, 0, 100, 100), 4, 4); + SkPath path = SkPath().addRRect(rrect); + + flutter::DlPaint paint; + flutter::DisplayListBuilder builder; + + builder.DrawPath(path, paint); + auto display_list = builder.Build(); + + DlDispatcher dispatcher; + display_list->Dispatch(dispatcher); + auto picture = dispatcher.EndRecordingAsPicture(); + + std::optional coverage = + GetCoverageOfFirstEntity(picture); + + // Validate that the RRect coverage is _exactly_ the same as the input rect. + ASSERT_TRUE(coverage.has_value()); + ASSERT_EQ(coverage.value_or(Rect::MakeMaximum()), + Rect::MakeLTRB(0, 0, 100, 100)); +} + +TEST(DisplayListTest, CircleBoundsComputation) { + SkPath path = SkPath().addCircle(0, 0, 5); + + flutter::DlPaint paint; + flutter::DisplayListBuilder builder; + + builder.DrawPath(path, paint); + auto display_list = builder.Build(); + + DlDispatcher dispatcher; + display_list->Dispatch(dispatcher); + auto picture = dispatcher.EndRecordingAsPicture(); + + std::optional coverage = + GetCoverageOfFirstEntity(picture); + + ASSERT_TRUE(coverage.has_value()); + ASSERT_EQ(coverage.value_or(Rect::MakeMaximum()), + Rect::MakeLTRB(-5, -5, 5, 5)); +} + #ifdef IMPELLER_ENABLE_3D TEST_P(DisplayListTest, SceneColorSource) { // Load up the scene.