[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.
This commit is contained in:
Jonah Williams
2023-10-06 13:49:08 -07:00
committed by GitHub
parent fe78d18716
commit f29ce2aa7a
2 changed files with 69 additions and 4 deletions

View File

@@ -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<Rect> inner_rect = (corner_radius * 2 < rect.size.width &&

View File

@@ -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 <typename Contents>
static std::optional<Rect> GetCoverageOfFirstEntity(const Picture& picture) {
std::optional<Rect> coverage;
picture.pass->IterateAllEntities([&coverage](Entity& entity) {
if (std::static_pointer_cast<Contents>(entity.GetContents())) {
auto contents = std::static_pointer_cast<Contents>(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<Rect> coverage =
GetCoverageOfFirstEntity<SolidColorContents>(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<Rect> coverage =
GetCoverageOfFirstEntity<SolidColorContents>(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.