Skip to content

Commit dabf364

Browse files
authored
[Impeller] Direct tessellation of simple filled round rects (flutter#48919)
Simple round rects with the same width and height at each corner are tessellated directly for fill operations, but not yet for stroke operations.
1 parent 53a4d7c commit dabf364

24 files changed

+423
-29
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5115,6 +5115,8 @@ ORIGIN: ../../../flutter/impeller/entity/geometry/point_field_geometry.cc + ../.
51155115
ORIGIN: ../../../flutter/impeller/entity/geometry/point_field_geometry.h + ../../../flutter/LICENSE
51165116
ORIGIN: ../../../flutter/impeller/entity/geometry/rect_geometry.cc + ../../../flutter/LICENSE
51175117
ORIGIN: ../../../flutter/impeller/entity/geometry/rect_geometry.h + ../../../flutter/LICENSE
5118+
ORIGIN: ../../../flutter/impeller/entity/geometry/round_rect_geometry.cc + ../../../flutter/LICENSE
5119+
ORIGIN: ../../../flutter/impeller/entity/geometry/round_rect_geometry.h + ../../../flutter/LICENSE
51185120
ORIGIN: ../../../flutter/impeller/entity/geometry/stroke_path_geometry.cc + ../../../flutter/LICENSE
51195121
ORIGIN: ../../../flutter/impeller/entity/geometry/stroke_path_geometry.h + ../../../flutter/LICENSE
51205122
ORIGIN: ../../../flutter/impeller/entity/geometry/vertices_geometry.cc + ../../../flutter/LICENSE
@@ -7916,6 +7918,8 @@ FILE: ../../../flutter/impeller/entity/geometry/point_field_geometry.cc
79167918
FILE: ../../../flutter/impeller/entity/geometry/point_field_geometry.h
79177919
FILE: ../../../flutter/impeller/entity/geometry/rect_geometry.cc
79187920
FILE: ../../../flutter/impeller/entity/geometry/rect_geometry.h
7921+
FILE: ../../../flutter/impeller/entity/geometry/round_rect_geometry.cc
7922+
FILE: ../../../flutter/impeller/entity/geometry/round_rect_geometry.h
79197923
FILE: ../../../flutter/impeller/entity/geometry/stroke_path_geometry.cc
79207924
FILE: ../../../flutter/impeller/entity/geometry/stroke_path_geometry.h
79217925
FILE: ../../../flutter/impeller/entity/geometry/vertices_geometry.cc

impeller/aiks/aiks_unittests.cc

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2264,6 +2264,74 @@ TEST_P(AiksTest, FilledEllipsesRenderCorrectly) {
22642264
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
22652265
}
22662266

2267+
TEST_P(AiksTest, FilledRoundRectsRenderCorrectly) {
2268+
Canvas canvas;
2269+
canvas.Scale(GetContentScale());
2270+
Paint paint;
2271+
const int color_count = 3;
2272+
Color colors[color_count] = {
2273+
Color::Blue(),
2274+
Color::Green(),
2275+
Color::Crimson(),
2276+
};
2277+
2278+
paint.color = Color::White();
2279+
canvas.DrawPaint(paint);
2280+
2281+
int c_index = 0;
2282+
for (int i = 0; i < 4; i++) {
2283+
for (int j = 0; j < 4; j++) {
2284+
paint.color = colors[(c_index++) % color_count];
2285+
canvas.DrawRRect(Rect::MakeXYWH(i * 100 + 10, j * 100 + 20, 80, 80),
2286+
Size(i * 5 + 10, j * 5 + 10), paint);
2287+
}
2288+
}
2289+
2290+
std::vector<Color> gradient_colors = {
2291+
Color{0x1f / 255.0, 0.0, 0x5c / 255.0, 1.0},
2292+
Color{0x5b / 255.0, 0.0, 0x60 / 255.0, 1.0},
2293+
Color{0x87 / 255.0, 0x01 / 255.0, 0x60 / 255.0, 1.0},
2294+
Color{0xac / 255.0, 0x25 / 255.0, 0x53 / 255.0, 1.0},
2295+
Color{0xe1 / 255.0, 0x6b / 255.0, 0x5c / 255.0, 1.0},
2296+
Color{0xf3 / 255.0, 0x90 / 255.0, 0x60 / 255.0, 1.0},
2297+
Color{0xff / 255.0, 0xb5 / 255.0, 0x6b / 250.0, 1.0}};
2298+
std::vector<Scalar> stops = {
2299+
0.0,
2300+
(1.0 / 6.0) * 1,
2301+
(1.0 / 6.0) * 2,
2302+
(1.0 / 6.0) * 3,
2303+
(1.0 / 6.0) * 4,
2304+
(1.0 / 6.0) * 5,
2305+
1.0,
2306+
};
2307+
auto texture = CreateTextureForFixture("airplane.jpg",
2308+
/*enable_mipmapping=*/true);
2309+
2310+
paint.color = Color::White().WithAlpha(0.1);
2311+
2312+
paint.color_source = ColorSource::MakeRadialGradient(
2313+
{500, 550}, 75, std::move(gradient_colors), std::move(stops),
2314+
Entity::TileMode::kMirror, {});
2315+
for (int i = 1; i <= 10; i++) {
2316+
int j = 11 - i;
2317+
canvas.DrawRRect(Rect::MakeLTRB(500 - i * 20, 550 - j * 20, //
2318+
500 + i * 20, 550 + j * 20),
2319+
Size(i * 10, j * 10), paint);
2320+
}
2321+
2322+
paint.color_source = ColorSource::MakeImage(
2323+
texture, Entity::TileMode::kRepeat, Entity::TileMode::kRepeat, {},
2324+
Matrix::MakeTranslation({500, 20}));
2325+
for (int i = 1; i <= 10; i++) {
2326+
int j = 11 - i;
2327+
canvas.DrawRRect(Rect::MakeLTRB(700 - i * 20, 220 - j * 20, //
2328+
700 + i * 20, 220 + j * 20),
2329+
Size(i * 10, j * 10), paint);
2330+
}
2331+
2332+
ASSERT_TRUE(OpenPlaygroundHere(canvas.EndRecordingAsPicture()));
2333+
}
2334+
22672335
TEST_P(AiksTest, GradientStrokesRenderCorrectly) {
22682336
// Compare with https://fiddle.skia.org/c/027392122bec8ac2b5d5de00a4b9bbe2
22692337
auto callback = [&](AiksContext& renderer) -> std::optional<Picture> {
@@ -4335,9 +4403,9 @@ TEST_P(AiksTest, GaussianBlurAtPeripheryVertical) {
43354403

43364404
canvas.Scale(GetContentScale());
43374405
canvas.DrawRRect(Rect::MakeLTRB(0, 0, GetWindowSize().width, 100),
4338-
Point(10, 10), Paint{.color = Color::LimeGreen()});
4406+
Size(10, 10), Paint{.color = Color::LimeGreen()});
43394407
canvas.DrawRRect(Rect::MakeLTRB(0, 110, GetWindowSize().width, 210),
4340-
Point(10, 10), Paint{.color = Color::Magenta()});
4408+
Size(10, 10), Paint{.color = Color::Magenta()});
43414409
canvas.ClipRect(Rect::MakeLTRB(100, 0, 200, GetWindowSize().height));
43424410
canvas.SaveLayer({.blend_mode = BlendMode::kSource}, std::nullopt,
43434411
ImageFilter::MakeBlur(Sigma(20.0), Sigma(20.0),
@@ -4358,7 +4426,7 @@ TEST_P(AiksTest, GaussianBlurAtPeripheryHorizontal) {
43584426
Rect::MakeXYWH(0, 0, boston->GetSize().width, boston->GetSize().height),
43594427
Rect::MakeLTRB(0, 0, GetWindowSize().width, 100), Paint{});
43604428
canvas.DrawRRect(Rect::MakeLTRB(0, 110, GetWindowSize().width, 210),
4361-
Point(10, 10), Paint{.color = Color::Magenta()});
4429+
Size(10, 10), Paint{.color = Color::Magenta()});
43624430
canvas.ClipRect(Rect::MakeLTRB(0, 50, GetWindowSize().width, 150));
43634431
canvas.SaveLayer({.blend_mode = BlendMode::kSource}, std::nullopt,
43644432
ImageFilter::MakeBlur(Sigma(20.0), Sigma(20.0),

impeller/aiks/canvas.cc

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -365,27 +365,31 @@ void Canvas::DrawOval(const Rect& rect, const Paint& paint) {
365365
GetCurrentPass().AddEntity(std::move(entity));
366366
}
367367

368-
void Canvas::DrawRRect(Rect rect, Point corner_radii, const Paint& paint) {
369-
if (corner_radii.x == corner_radii.y &&
370-
AttemptDrawBlurredRRect(rect, corner_radii.x, paint)) {
368+
void Canvas::DrawRRect(const Rect& rect,
369+
const Size& corner_radii,
370+
const Paint& paint) {
371+
if (corner_radii.IsSquare() &&
372+
AttemptDrawBlurredRRect(rect, corner_radii.width, paint)) {
371373
return;
372374
}
373-
auto path = PathBuilder{}
374-
.SetConvexity(Convexity::kConvex)
375-
.AddRoundedRect(rect, corner_radii)
376-
.SetBounds(rect)
377-
.TakePath();
375+
378376
if (paint.style == Paint::Style::kFill) {
379377
Entity entity;
380378
entity.SetTransform(GetCurrentTransform());
381379
entity.SetClipDepth(GetClipDepth());
382380
entity.SetBlendMode(paint.blend_mode);
383381
entity.SetContents(CreateContentsForGeometryWithFilters(
384-
paint, Geometry::MakeFillPath(std::move(path))));
382+
paint, Geometry::MakeRoundRect(rect, corner_radii)));
385383

386384
GetCurrentPass().AddEntity(std::move(entity));
387385
return;
388386
}
387+
388+
auto path = PathBuilder{}
389+
.SetConvexity(Convexity::kConvex)
390+
.AddRoundedRect(rect, corner_radii)
391+
.SetBounds(rect)
392+
.TakePath();
389393
DrawPath(std::move(path), paint);
390394
}
391395

@@ -445,7 +449,7 @@ void Canvas::ClipRect(const Rect& rect, Entity::ClipOperation clip_op) {
445449
}
446450

447451
void Canvas::ClipRRect(const Rect& rect,
448-
Point corner_radii,
452+
const Size& corner_radii,
449453
Entity::ClipOperation clip_op) {
450454
auto path = PathBuilder{}
451455
.SetConvexity(Convexity::kConvex)
@@ -455,8 +459,8 @@ void Canvas::ClipRRect(const Rect& rect,
455459

456460
auto size = rect.GetSize();
457461
// Does the rounded rect have a flat part on the top/bottom or left/right?
458-
bool flat_on_TB = corner_radii.x * 2 < size.width;
459-
bool flat_on_LR = corner_radii.y * 2 < size.height;
462+
bool flat_on_TB = corner_radii.width * 2 < size.width;
463+
bool flat_on_LR = corner_radii.height * 2 < size.height;
460464
std::optional<Rect> inner_rect = (flat_on_LR && flat_on_TB)
461465
? rect.Expand(-corner_radii)
462466
: std::make_optional<Rect>();
@@ -475,7 +479,7 @@ void Canvas::ClipRRect(const Rect& rect,
475479
IntersectCulling(rect);
476480
break;
477481
case Entity::ClipOperation::kDifference:
478-
if (corner_radii.x <= 0.0 || corner_radii.y <= 0) {
482+
if (corner_radii.IsEmpty()) {
479483
SubtractCulling(rect);
480484
} else {
481485
// We subtract the inner "tall" and "wide" rectangle pieces
@@ -484,10 +488,10 @@ void Canvas::ClipRRect(const Rect& rect,
484488
// Since this is a subtract operation, we can subtract each
485489
// rectangle piece individually without fear of interference.
486490
if (flat_on_TB) {
487-
SubtractCulling(rect.Expand({-corner_radii.x, 0.0}));
491+
SubtractCulling(rect.Expand(Size{-corner_radii.width, 0.0}));
488492
}
489493
if (flat_on_LR) {
490-
SubtractCulling(rect.Expand({0.0, -corner_radii.y}));
494+
SubtractCulling(rect.Expand(Size{0.0, -corner_radii.height}));
491495
}
492496
}
493497
break;

impeller/aiks/canvas.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,9 @@ class Canvas {
106106

107107
void DrawOval(const Rect& rect, const Paint& paint);
108108

109-
void DrawRRect(Rect rect, Point corner_radii, const Paint& paint);
109+
void DrawRRect(const Rect& rect,
110+
const Size& corner_radii,
111+
const Paint& paint);
110112

111113
void DrawCircle(const Point& center, Scalar radius, const Paint& paint);
112114

@@ -136,7 +138,7 @@ class Canvas {
136138

137139
void ClipRRect(
138140
const Rect& rect,
139-
Point corner_radii,
141+
const Size& corner_radii,
140142
Entity::ClipOperation clip_op = Entity::ClipOperation::kIntersect);
141143

142144
void DrawPicture(const Picture& picture);

impeller/aiks/canvas_recorder.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,9 @@ class CanvasRecorder {
195195
paint);
196196
}
197197

198-
void DrawRRect(Rect rect, Point corner_radii, const Paint& paint) {
198+
void DrawRRect(const Rect& rect,
199+
const Size& corner_radii,
200+
const Paint& paint) {
199201
return ExecuteAndSerialize(FLT_CANVAS_RECORDER_OP_ARG(DrawRRect), rect,
200202
corner_radii, paint);
201203
}
@@ -248,7 +250,7 @@ class CanvasRecorder {
248250

249251
void ClipRRect(
250252
const Rect& rect,
251-
Point corner_radii,
253+
const Size& corner_radii,
252254
Entity::ClipOperation clip_op = Entity::ClipOperation::kIntersect) {
253255
return ExecuteAndSerialize(FLT_CANVAS_RECORDER_OP_ARG(ClipRRect), rect,
254256
corner_radii, clip_op);

impeller/display_list/dl_dispatcher.cc

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -731,7 +731,7 @@ void DlDispatcher::clipRRect(const SkRRect& rrect, ClipOp clip_op, bool is_aa) {
731731
ToClipOperation(clip_op));
732732
} else if (rrect.isSimple()) {
733733
canvas_.ClipRRect(skia_conversions::ToRect(rrect.rect()),
734-
skia_conversions::ToPoint(rrect.getSimpleRadii()),
734+
skia_conversions::ToSize(rrect.getSimpleRadii()),
735735
ToClipOperation(clip_op));
736736
} else {
737737
canvas_.ClipPath(skia_conversions::ToPath(rrect), ToClipOperation(clip_op));
@@ -782,8 +782,7 @@ void DlDispatcher::drawCircle(const SkPoint& center, SkScalar radius) {
782782
void DlDispatcher::drawRRect(const SkRRect& rrect) {
783783
if (rrect.isSimple()) {
784784
canvas_.DrawRRect(skia_conversions::ToRect(rrect.rect()),
785-
skia_conversions::ToPoint(rrect.getSimpleRadii()),
786-
paint_);
785+
skia_conversions::ToSize(rrect.getSimpleRadii()), paint_);
787786
} else {
788787
canvas_.DrawPath(skia_conversions::ToPath(rrect), paint_);
789788
}
@@ -817,7 +816,7 @@ void DlDispatcher::SimplifyOrDrawPath(CanvasType& canvas,
817816
SkRRect rrect;
818817
if (path.isRRect(&rrect) && rrect.isSimple()) {
819818
canvas.DrawRRect(skia_conversions::ToRect(rrect.rect()),
820-
skia_conversions::ToPoint(rrect.getSimpleRadii()), paint);
819+
skia_conversions::ToSize(rrect.getSimpleRadii()), paint);
821820
return;
822821
}
823822

impeller/display_list/skia_conversions.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,10 @@ Point ToPoint(const SkPoint& point) {
141141
return Point::MakeXY(point.fX, point.fY);
142142
}
143143

144+
Size ToSize(const SkPoint& point) {
145+
return Size(point.fX, point.fY);
146+
}
147+
144148
Color ToColor(const flutter::DlColor& color) {
145149
return {
146150
static_cast<Scalar>(color.getRedF()), //

impeller/display_list/skia_conversions.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ std::vector<Point> ToPoints(const SkPoint points[], int count);
3333

3434
Point ToPoint(const SkPoint& point);
3535

36+
Size ToSize(const SkPoint& point);
37+
3638
Color ToColor(const flutter::DlColor& color);
3739

3840
std::vector<Matrix> ToRSXForms(const SkRSXform xform[], int count);

impeller/display_list/skia_conversions_unittests.cc

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,24 @@
1111
namespace impeller {
1212
namespace testing {
1313

14+
TEST(SkiaConversionsTest, SkPointToPoint) {
15+
for (int x = -100; x < 100; x += 4) {
16+
for (int y = -100; y < 100; y += 4) {
17+
EXPECT_EQ(skia_conversions::ToPoint(SkPoint::Make(x * 0.25f, y * 0.25f)),
18+
Point(x * 0.25f, y * 0.25f));
19+
}
20+
}
21+
}
22+
23+
TEST(SkiaConversionsTest, SkPointToSize) {
24+
for (int x = -100; x < 100; x += 4) {
25+
for (int y = -100; y < 100; y += 4) {
26+
EXPECT_EQ(skia_conversions::ToSize(SkPoint::Make(x * 0.25f, y * 0.25f)),
27+
Size(x * 0.25f, y * 0.25f));
28+
}
29+
}
30+
}
31+
1432
TEST(SkiaConversionsTest, ToColor) {
1533
// Create a color with alpha, red, green, and blue values that are all
1634
// trivially divisible by 255 so that we can test the conversion results in

impeller/entity/BUILD.gn

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,8 @@ impeller_component("entity") {
207207
"geometry/point_field_geometry.h",
208208
"geometry/rect_geometry.cc",
209209
"geometry/rect_geometry.h",
210+
"geometry/round_rect_geometry.cc",
211+
"geometry/round_rect_geometry.h",
210212
"geometry/stroke_path_geometry.cc",
211213
"geometry/stroke_path_geometry.h",
212214
"geometry/vertices_geometry.cc",

0 commit comments

Comments
 (0)