Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit b34753b

Browse files
committed
Add PathCache
1 parent c254deb commit b34753b

22 files changed

+746
-259
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1375,6 +1375,8 @@ ORIGIN: ../../../flutter/impeller/geometry/path.cc + ../../../flutter/LICENSE
13751375
ORIGIN: ../../../flutter/impeller/geometry/path.h + ../../../flutter/LICENSE
13761376
ORIGIN: ../../../flutter/impeller/geometry/path_builder.cc + ../../../flutter/LICENSE
13771377
ORIGIN: ../../../flutter/impeller/geometry/path_builder.h + ../../../flutter/LICENSE
1378+
ORIGIN: ../../../flutter/impeller/geometry/path_cache.cc + ../../../flutter/LICENSE
1379+
ORIGIN: ../../../flutter/impeller/geometry/path_cache.h + ../../../flutter/LICENSE
13781380
ORIGIN: ../../../flutter/impeller/geometry/path_component.cc + ../../../flutter/LICENSE
13791381
ORIGIN: ../../../flutter/impeller/geometry/path_component.h + ../../../flutter/LICENSE
13801382
ORIGIN: ../../../flutter/impeller/geometry/point.cc + ../../../flutter/LICENSE
@@ -4089,6 +4091,8 @@ FILE: ../../../flutter/impeller/geometry/path.cc
40894091
FILE: ../../../flutter/impeller/geometry/path.h
40904092
FILE: ../../../flutter/impeller/geometry/path_builder.cc
40914093
FILE: ../../../flutter/impeller/geometry/path_builder.h
4094+
FILE: ../../../flutter/impeller/geometry/path_cache.cc
4095+
FILE: ../../../flutter/impeller/geometry/path_cache.h
40924096
FILE: ../../../flutter/impeller/geometry/path_component.cc
40934097
FILE: ../../../flutter/impeller/geometry/path_component.h
40944098
FILE: ../../../flutter/impeller/geometry/point.cc

impeller/aiks/aiks_context.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ ContentContext& AiksContext::GetContentContext() const {
3636
return *content_context_;
3737
}
3838

39+
PathCache& AiksContext::GetPathCache() {
40+
return path_cache_;
41+
}
42+
3943
bool AiksContext::Render(const Picture& picture, RenderTarget& render_target) {
4044
if (!IsValid()) {
4145
return false;

impeller/aiks/aiks_context.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "flutter/fml/macros.h"
1010
#include "impeller/entity/contents/content_context.h"
11+
#include "impeller/geometry/path_cache.h"
1112
#include "impeller/renderer/context.h"
1213
#include "impeller/renderer/render_target.h"
1314

@@ -30,10 +31,13 @@ class AiksContext {
3031

3132
bool Render(const Picture& picture, RenderTarget& render_target);
3233

34+
PathCache& GetPathCache();
35+
3336
private:
3437
std::shared_ptr<Context> context_;
3538
std::unique_ptr<ContentContext> content_context_;
3639
bool is_valid_ = false;
40+
PathCache path_cache_;
3741

3842
FML_DISALLOW_COPY_AND_ASSIGN(AiksContext);
3943
};

impeller/aiks/canvas.cc

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,16 @@
2020
#include "impeller/entity/contents/vertices_contents.h"
2121
#include "impeller/entity/geometry/geometry.h"
2222
#include "impeller/geometry/path_builder.h"
23+
#include "impeller/geometry/path_cache.h"
2324
#include "include/core/SkRect.h"
2425

2526
namespace impeller {
2627

28+
namespace {
29+
const uint32_t kTagDlRRect = 'dlrr';
30+
const uint32_t kTagDlCircle = 'dlci';
31+
} // namespace
32+
2733
Canvas::Canvas() {
2834
Initialize(std::nullopt);
2935
}
@@ -240,10 +246,18 @@ void Canvas::DrawRRect(Rect rect, Scalar corner_radius, const Paint& paint) {
240246
if (AttemptDrawBlurredRRect(rect, corner_radius, paint)) {
241247
return;
242248
}
243-
auto path = PathBuilder{}
244-
.SetConvexity(Convexity::kConvex)
245-
.AddRoundedRect(rect, corner_radius)
246-
.TakePath();
249+
250+
struct {
251+
Rect rect;
252+
Scalar corner_radius;
253+
} identifier = {.rect = rect, .corner_radius = corner_radius};
254+
auto path = PathCache::GetPath(PathCacheKey(kTagDlRRect, identifier), [&] {
255+
return PathBuilder{}
256+
.SetConvexity(Convexity::kConvex)
257+
.AddRoundedRect(rect, corner_radius)
258+
.TakePath();
259+
});
260+
247261
if (paint.style == Paint::Style::kFill) {
248262
Entity entity;
249263
entity.SetTransformation(GetCurrentTransformation());
@@ -264,10 +278,18 @@ void Canvas::DrawCircle(Point center, Scalar radius, const Paint& paint) {
264278
paint)) {
265279
return;
266280
}
267-
auto circle_path = PathBuilder{}
268-
.AddCircle(center, radius)
269-
.SetConvexity(Convexity::kConvex)
270-
.TakePath();
281+
struct {
282+
Point center;
283+
Scalar radius;
284+
} identifier = {.center = center, .radius = radius};
285+
auto circle_path =
286+
PathCache::GetPath(PathCacheKey(kTagDlCircle, identifier), [&] {
287+
return PathBuilder{}
288+
.AddCircle(center, radius)
289+
.SetConvexity(Convexity::kConvex)
290+
.TakePath();
291+
});
292+
271293
DrawPath(circle_path, paint);
272294
}
273295

impeller/display_list/dl_dispatcher.cc

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -889,10 +889,7 @@ void DlDispatcher::drawRRect(const SkRRect& rrect) {
889889

890890
// |flutter::DlOpReceiver|
891891
void DlDispatcher::drawDRRect(const SkRRect& outer, const SkRRect& inner) {
892-
PathBuilder builder;
893-
builder.AddPath(skia_conversions::ToPath(outer));
894-
builder.AddPath(skia_conversions::ToPath(inner));
895-
canvas_.DrawPath(builder.TakePath(FillType::kOdd), paint_);
892+
canvas_.DrawPath(skia_conversions::ToPath(outer, inner), paint_);
896893
}
897894

898895
// |flutter::DlOpReceiver|

impeller/display_list/skia_conversions.cc

Lines changed: 107 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,18 @@
44

55
#include "impeller/display_list/skia_conversions.h"
66
#include "display_list/dl_color.h"
7+
#include "impeller/geometry/path_cache.h"
78
#include "third_party/skia/modules/skparagraph/include/Paragraph.h"
89

910
namespace impeller {
1011
namespace skia_conversions {
1112

13+
namespace {
14+
const uint32_t kTagSkiaPath = 'skpa';
15+
const uint32_t kTagSkiaRRect = 'skrr';
16+
const uint32_t kTagSkiaDRRect = 'skdr';
17+
} // namespace
18+
1219
Rect ToRect(const SkRect& rect) {
1320
return Rect::MakeLTRB(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
1421
}
@@ -47,63 +54,6 @@ PathBuilder::RoundingRadii ToRoundingRadii(const SkRRect& rrect) {
4754
}
4855

4956
Path ToPath(const SkPath& path) {
50-
auto iterator = SkPath::Iter(path, false);
51-
52-
struct PathData {
53-
union {
54-
SkPoint points[4];
55-
};
56-
};
57-
58-
PathBuilder builder;
59-
PathData data;
60-
auto verb = SkPath::Verb::kDone_Verb;
61-
do {
62-
verb = iterator.next(data.points);
63-
switch (verb) {
64-
case SkPath::kMove_Verb:
65-
builder.MoveTo(ToPoint(data.points[0]));
66-
break;
67-
case SkPath::kLine_Verb:
68-
builder.LineTo(ToPoint(data.points[1]));
69-
break;
70-
case SkPath::kQuad_Verb:
71-
builder.QuadraticCurveTo(ToPoint(data.points[1]),
72-
ToPoint(data.points[2]));
73-
break;
74-
case SkPath::kConic_Verb: {
75-
constexpr auto kPow2 = 1; // Only works for sweeps up to 90 degrees.
76-
constexpr auto kQuadCount = 1 + (2 * (1 << kPow2));
77-
SkPoint points[kQuadCount];
78-
const auto curve_count =
79-
SkPath::ConvertConicToQuads(data.points[0], //
80-
data.points[1], //
81-
data.points[2], //
82-
iterator.conicWeight(), //
83-
points, //
84-
kPow2 //
85-
);
86-
87-
for (int curve_index = 0, point_index = 0; //
88-
curve_index < curve_count; //
89-
curve_index++, point_index += 2 //
90-
) {
91-
builder.QuadraticCurveTo(ToPoint(points[point_index + 1]),
92-
ToPoint(points[point_index + 2]));
93-
}
94-
} break;
95-
case SkPath::kCubic_Verb:
96-
builder.CubicCurveTo(ToPoint(data.points[1]), ToPoint(data.points[2]),
97-
ToPoint(data.points[3]));
98-
break;
99-
case SkPath::kClose_Verb:
100-
builder.Close();
101-
break;
102-
case SkPath::kDone_Verb:
103-
break;
104-
}
105-
} while (verb != SkPath::Verb::kDone_Verb);
106-
10757
FillType fill_type;
10858
switch (path.getFillType()) {
10959
case SkPathFillType::kWinding:
@@ -119,16 +69,109 @@ Path ToPath(const SkPath& path) {
11969
fill_type = FillType::kNonZero;
12070
break;
12171
}
122-
builder.SetConvexity(path.isConvex() ? Convexity::kConvex
123-
: Convexity::kUnknown);
124-
return builder.TakePath(fill_type);
72+
auto create_path = [&] {
73+
auto iterator = SkPath::Iter(path, false);
74+
75+
struct PathData {
76+
union {
77+
SkPoint points[4];
78+
};
79+
};
80+
81+
PathBuilder builder;
82+
PathData data;
83+
auto verb = SkPath::Verb::kDone_Verb;
84+
do {
85+
verb = iterator.next(data.points);
86+
switch (verb) {
87+
case SkPath::kMove_Verb:
88+
builder.MoveTo(ToPoint(data.points[0]));
89+
break;
90+
case SkPath::kLine_Verb:
91+
builder.LineTo(ToPoint(data.points[1]));
92+
break;
93+
case SkPath::kQuad_Verb:
94+
builder.QuadraticCurveTo(ToPoint(data.points[1]),
95+
ToPoint(data.points[2]));
96+
break;
97+
case SkPath::kConic_Verb: {
98+
constexpr auto kPow2 = 1; // Only works for sweeps up to 90 degrees.
99+
constexpr auto kQuadCount = 1 + (2 * (1 << kPow2));
100+
SkPoint points[kQuadCount];
101+
const auto curve_count =
102+
SkPath::ConvertConicToQuads(data.points[0], //
103+
data.points[1], //
104+
data.points[2], //
105+
iterator.conicWeight(), //
106+
points, //
107+
kPow2 //
108+
);
109+
110+
for (int curve_index = 0, point_index = 0; //
111+
curve_index < curve_count; //
112+
curve_index++, point_index += 2 //
113+
) {
114+
builder.QuadraticCurveTo(ToPoint(points[point_index + 1]),
115+
ToPoint(points[point_index + 2]));
116+
}
117+
} break;
118+
case SkPath::kCubic_Verb:
119+
builder.CubicCurveTo(ToPoint(data.points[1]), ToPoint(data.points[2]),
120+
ToPoint(data.points[3]));
121+
break;
122+
case SkPath::kClose_Verb:
123+
builder.Close();
124+
break;
125+
case SkPath::kDone_Verb:
126+
break;
127+
}
128+
} while (verb != SkPath::Verb::kDone_Verb);
129+
130+
builder.SetConvexity(path.isConvex() ? Convexity::kConvex
131+
: Convexity::kUnknown);
132+
return builder.TakePath(fill_type);
133+
};
134+
struct {
135+
uint32_t generation_id;
136+
FillType fill_type;
137+
} identifier = {
138+
.generation_id = path.getGenerationID(),
139+
.fill_type = fill_type,
140+
};
141+
return PathCache::GetPath(PathCacheKey(kTagSkiaPath, identifier),
142+
create_path);
125143
}
126144

127145
Path ToPath(const SkRRect& rrect) {
128-
return PathBuilder{}
129-
.AddRoundedRect(ToRect(rrect.getBounds()), ToRoundingRadii(rrect))
130-
.SetConvexity(Convexity::kConvex)
131-
.TakePath();
146+
// SkRRect may have random padding bytes, so first zero initialize the struct
147+
// and then copy the RRect into it.
148+
struct {
149+
SkRRect rrect;
150+
} identifier = {};
151+
identifier.rrect = rrect;
152+
return PathCache::GetPath(PathCacheKey(kTagSkiaRRect, identifier), [&] {
153+
return PathBuilder{}
154+
.AddRoundedRect(ToRect(rrect.getBounds()), ToRoundingRadii(rrect))
155+
.SetConvexity(Convexity::kConvex)
156+
.TakePath();
157+
});
158+
}
159+
160+
Path ToPath(const SkRRect& outer, const SkRRect& inner) {
161+
// SkRRect may have random padding bytes, so first zero initialize the struct
162+
// and then copy the RRect into it.
163+
struct {
164+
SkRRect outer;
165+
SkRRect inner;
166+
} identifier = {};
167+
identifier.outer = outer;
168+
identifier.inner = inner;
169+
return PathCache::GetPath(PathCacheKey(kTagSkiaDRRect, identifier), [&] {
170+
PathBuilder builder;
171+
builder.AddPath(ToPath(outer));
172+
builder.AddPath(ToPath(inner));
173+
return builder.TakePath(FillType::kOdd);
174+
});
132175
}
133176

134177
Point ToPoint(const SkPoint& point) {

impeller/display_list/skia_conversions.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ Path ToPath(const SkPath& path);
4545

4646
Path ToPath(const SkRRect& rrect);
4747

48+
Path ToPath(const SkRRect& outer, const SkRRect& inner);
49+
4850
Path PathDataFromTextBlob(const sk_sp<SkTextBlob>& blob);
4951

5052
std::optional<impeller::PixelFormat> ToPixelFormat(SkColorType type);

impeller/entity/geometry/geometry.cc

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,27 @@ namespace impeller {
1717

1818
/// Given a convex polyline, create a triangle fan structure.
1919
std::pair<std::vector<Point>, std::vector<uint16_t>> TessellateConvex(
20-
Path::Polyline polyline) {
20+
const Path::Polyline& polyline) {
2121
std::vector<Point> output;
2222
std::vector<uint16_t> indices;
2323

24-
for (auto j = 0u; j < polyline.contours.size(); j++) {
24+
const auto& points = polyline.points();
25+
26+
for (auto j = 0u; j < polyline.contours().size(); j++) {
2527
auto [start, end] = polyline.GetContourPointBounds(j);
26-
auto center = polyline.points[start];
28+
auto center = points[start];
2729

2830
// Some polygons will not self close and an additional triangle
2931
// must be inserted, others will self close and we need to avoid
3032
// inserting an extra triangle.
31-
if (polyline.points[end - 1] == polyline.points[start]) {
33+
if (points[end - 1] == points[start]) {
3234
end--;
3335
}
3436
output.emplace_back(center);
35-
output.emplace_back(polyline.points[start + 1]);
37+
output.emplace_back(points[start + 1]);
3638

3739
for (auto i = start + 2; i < end; i++) {
38-
const auto& point_b = polyline.points[i];
40+
const auto& point_b = points[i];
3941
output.emplace_back(point_b);
4042

4143
indices.emplace_back(0);

impeller/entity/geometry/geometry.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ GeometryResult ComputeUVGeometryForRect(Rect source_rect,
4949
/// @brief Given a polyline created from a convex filled path, perform a
5050
/// tessellation.
5151
std::pair<std::vector<Point>, std::vector<uint16_t>> TessellateConvex(
52-
Path::Polyline polyline);
52+
const Path::Polyline& polyline);
5353

5454
class Geometry {
5555
public:

0 commit comments

Comments
 (0)