Skip to content

Commit 205d2b8

Browse files
authored
Reland path volatility tracker (flutter#23063)
* Revert "Revert "Set SkPath::setIsVolatile based on whether the path survives at least two frames (flutter#22620)" (flutter#23044)" This reverts commit 4f91425. * Fix tracing
1 parent f37c8c5 commit 205d2b8

28 files changed

+606
-121
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,7 @@ FILE: ../../../flutter/lib/ui/painting/path.cc
361361
FILE: ../../../flutter/lib/ui/painting/path.h
362362
FILE: ../../../flutter/lib/ui/painting/path_measure.cc
363363
FILE: ../../../flutter/lib/ui/painting/path_measure.h
364+
FILE: ../../../flutter/lib/ui/painting/path_unittests.cc
364365
FILE: ../../../flutter/lib/ui/painting/picture.cc
365366
FILE: ../../../flutter/lib/ui/painting/picture.h
366367
FILE: ../../../flutter/lib/ui/painting/picture_recorder.cc
@@ -404,6 +405,8 @@ FILE: ../../../flutter/lib/ui/ui.dart
404405
FILE: ../../../flutter/lib/ui/ui_benchmarks.cc
405406
FILE: ../../../flutter/lib/ui/ui_dart_state.cc
406407
FILE: ../../../flutter/lib/ui/ui_dart_state.h
408+
FILE: ../../../flutter/lib/ui/volatile_path_tracker.cc
409+
FILE: ../../../flutter/lib/ui/volatile_path_tracker.h
407410
FILE: ../../../flutter/lib/ui/window.dart
408411
FILE: ../../../flutter/lib/ui/window/platform_configuration.cc
409412
FILE: ../../../flutter/lib/ui/window/platform_configuration.h

fml/trace_event.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,19 @@
6868
::fml::tracing::TraceCounter((category_group), (name), (counter_id), (arg1), \
6969
__VA_ARGS__);
7070

71+
// Avoid using the same `name` and `argX_name` for nested traces, which can
72+
// lead to double free errors. E.g. the following code should be avoided:
73+
//
74+
// ```cpp
75+
// {
76+
// TRACE_EVENT1("flutter", "Foo::Bar", "count", "initial_count_value");
77+
// ...
78+
// TRACE_EVENT_INSTANT1("flutter", "Foo::Bar",
79+
// "count", "updated_count_value");
80+
// }
81+
// ```
82+
//
83+
// Instead, either use different `name` or `arg1` parameter names.
7184
#define FML_TRACE_EVENT(category_group, name, ...) \
7285
::fml::tracing::TraceEvent((category_group), (name), __VA_ARGS__); \
7386
__FML__AUTO_TRACE_END(name)

lib/ui/BUILD.gn

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ source_set("ui") {
9191
"text/text_box.h",
9292
"ui_dart_state.cc",
9393
"ui_dart_state.h",
94+
"volatile_path_tracker.cc",
95+
"volatile_path_tracker.h",
9496
"window/platform_configuration.cc",
9597
"window/platform_configuration.h",
9698
"window/platform_message.cc",
@@ -188,6 +190,7 @@ if (enable_unittests) {
188190
sources = [
189191
"painting/image_dispose_unittests.cc",
190192
"painting/image_encoding_unittests.cc",
193+
"painting/path_unittests.cc",
191194
"painting/vertices_unittests.cc",
192195
"window/platform_configuration_unittests.cc",
193196
"window/pointer_data_packet_converter_unittests.cc",

lib/ui/fixtures/ui_test.dart

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,20 @@ void createVertices() {
3535
);
3636
_validateVertices(vertices);
3737
}
38-
3938
void _validateVertices(Vertices vertices) native 'ValidateVertices';
4039

40+
@pragma('vm:entry-point')
41+
void createPath() {
42+
final Path path = Path()..lineTo(10, 10);
43+
_validatePath(path);
44+
// Arbitrarily hold a reference to the path to make sure it does not get
45+
// garbage collected.
46+
Future<void>.delayed(const Duration(days: 100)).then((_) {
47+
path.lineTo(100, 100);
48+
});
49+
}
50+
void _validatePath(Path path) native 'ValidatePath';
51+
4152
@pragma('vm:entry-point')
4253
void frameCallback(FrameInfo info) {
4354
print('called back');

lib/ui/painting/path.cc

Lines changed: 89 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -67,43 +67,69 @@ void CanvasPath::RegisterNatives(tonic::DartLibraryNatives* natives) {
6767
FOR_EACH_BINDING(DART_REGISTER_NATIVE)});
6868
}
6969

70-
CanvasPath::CanvasPath() {}
70+
CanvasPath::CanvasPath()
71+
: path_tracker_(UIDartState::Current()->GetVolatilePathTracker()),
72+
tracked_path_(std::make_shared<VolatilePathTracker::TrackedPath>()) {
73+
FML_DCHECK(path_tracker_);
74+
resetVolatility();
75+
}
76+
77+
CanvasPath::~CanvasPath() = default;
78+
79+
void CanvasPath::resetVolatility() {
80+
if (!tracked_path_->tracking_volatility) {
81+
mutable_path().setIsVolatile(true);
82+
tracked_path_->frame_count = 0;
83+
tracked_path_->tracking_volatility = true;
84+
path_tracker_->Insert(tracked_path_);
85+
}
86+
}
7187

72-
CanvasPath::~CanvasPath() {}
88+
void CanvasPath::ReleaseDartWrappableReference() const {
89+
FML_DCHECK(path_tracker_);
90+
path_tracker_->Erase(tracked_path_);
91+
}
7392

7493
int CanvasPath::getFillType() {
75-
return static_cast<int>(path_.getFillType());
94+
return static_cast<int>(path().getFillType());
7695
}
7796

7897
void CanvasPath::setFillType(int fill_type) {
79-
path_.setFillType(static_cast<SkPathFillType>(fill_type));
98+
mutable_path().setFillType(static_cast<SkPathFillType>(fill_type));
99+
resetVolatility();
80100
}
81101

82102
void CanvasPath::moveTo(float x, float y) {
83-
path_.moveTo(x, y);
103+
mutable_path().moveTo(x, y);
104+
resetVolatility();
84105
}
85106

86107
void CanvasPath::relativeMoveTo(float x, float y) {
87-
path_.rMoveTo(x, y);
108+
mutable_path().rMoveTo(x, y);
109+
resetVolatility();
88110
}
89111

90112
void CanvasPath::lineTo(float x, float y) {
91-
path_.lineTo(x, y);
113+
mutable_path().lineTo(x, y);
114+
resetVolatility();
92115
}
93116

94117
void CanvasPath::relativeLineTo(float x, float y) {
95-
path_.rLineTo(x, y);
118+
mutable_path().rLineTo(x, y);
119+
resetVolatility();
96120
}
97121

98122
void CanvasPath::quadraticBezierTo(float x1, float y1, float x2, float y2) {
99-
path_.quadTo(x1, y1, x2, y2);
123+
mutable_path().quadTo(x1, y1, x2, y2);
124+
resetVolatility();
100125
}
101126

102127
void CanvasPath::relativeQuadraticBezierTo(float x1,
103128
float y1,
104129
float x2,
105130
float y2) {
106-
path_.rQuadTo(x1, y1, x2, y2);
131+
mutable_path().rQuadTo(x1, y1, x2, y2);
132+
resetVolatility();
107133
}
108134

109135
void CanvasPath::cubicTo(float x1,
@@ -112,7 +138,8 @@ void CanvasPath::cubicTo(float x1,
112138
float y2,
113139
float x3,
114140
float y3) {
115-
path_.cubicTo(x1, y1, x2, y2, x3, y3);
141+
mutable_path().cubicTo(x1, y1, x2, y2, x3, y3);
142+
resetVolatility();
116143
}
117144

118145
void CanvasPath::relativeCubicTo(float x1,
@@ -121,19 +148,22 @@ void CanvasPath::relativeCubicTo(float x1,
121148
float y2,
122149
float x3,
123150
float y3) {
124-
path_.rCubicTo(x1, y1, x2, y2, x3, y3);
151+
mutable_path().rCubicTo(x1, y1, x2, y2, x3, y3);
152+
resetVolatility();
125153
}
126154

127155
void CanvasPath::conicTo(float x1, float y1, float x2, float y2, float w) {
128-
path_.conicTo(x1, y1, x2, y2, w);
156+
mutable_path().conicTo(x1, y1, x2, y2, w);
157+
resetVolatility();
129158
}
130159

131160
void CanvasPath::relativeConicTo(float x1,
132161
float y1,
133162
float x2,
134163
float y2,
135164
float w) {
136-
path_.rConicTo(x1, y1, x2, y2, w);
165+
mutable_path().rConicTo(x1, y1, x2, y2, w);
166+
resetVolatility();
137167
}
138168

139169
void CanvasPath::arcTo(float left,
@@ -143,9 +173,10 @@ void CanvasPath::arcTo(float left,
143173
float startAngle,
144174
float sweepAngle,
145175
bool forceMoveTo) {
146-
path_.arcTo(SkRect::MakeLTRB(left, top, right, bottom),
147-
startAngle * 180.0 / M_PI, sweepAngle * 180.0 / M_PI,
148-
forceMoveTo);
176+
mutable_path().arcTo(SkRect::MakeLTRB(left, top, right, bottom),
177+
startAngle * 180.0 / M_PI, sweepAngle * 180.0 / M_PI,
178+
forceMoveTo);
179+
resetVolatility();
149180
}
150181

151182
void CanvasPath::arcToPoint(float arcEndX,
@@ -160,8 +191,9 @@ void CanvasPath::arcToPoint(float arcEndX,
160191
const auto direction =
161192
isClockwiseDirection ? SkPathDirection::kCW : SkPathDirection::kCCW;
162193

163-
path_.arcTo(radiusX, radiusY, xAxisRotation, arcSize, direction, arcEndX,
164-
arcEndY);
194+
mutable_path().arcTo(radiusX, radiusY, xAxisRotation, arcSize, direction,
195+
arcEndX, arcEndY);
196+
resetVolatility();
165197
}
166198

167199
void CanvasPath::relativeArcToPoint(float arcEndDeltaX,
@@ -175,16 +207,19 @@ void CanvasPath::relativeArcToPoint(float arcEndDeltaX,
175207
: SkPath::ArcSize::kSmall_ArcSize;
176208
const auto direction =
177209
isClockwiseDirection ? SkPathDirection::kCW : SkPathDirection::kCCW;
178-
path_.rArcTo(radiusX, radiusY, xAxisRotation, arcSize, direction,
179-
arcEndDeltaX, arcEndDeltaY);
210+
mutable_path().rArcTo(radiusX, radiusY, xAxisRotation, arcSize, direction,
211+
arcEndDeltaX, arcEndDeltaY);
212+
resetVolatility();
180213
}
181214

182215
void CanvasPath::addRect(float left, float top, float right, float bottom) {
183-
path_.addRect(SkRect::MakeLTRB(left, top, right, bottom));
216+
mutable_path().addRect(SkRect::MakeLTRB(left, top, right, bottom));
217+
resetVolatility();
184218
}
185219

186220
void CanvasPath::addOval(float left, float top, float right, float bottom) {
187-
path_.addOval(SkRect::MakeLTRB(left, top, right, bottom));
221+
mutable_path().addOval(SkRect::MakeLTRB(left, top, right, bottom));
222+
resetVolatility();
188223
}
189224

190225
void CanvasPath::addArc(float left,
@@ -193,25 +228,29 @@ void CanvasPath::addArc(float left,
193228
float bottom,
194229
float startAngle,
195230
float sweepAngle) {
196-
path_.addArc(SkRect::MakeLTRB(left, top, right, bottom),
197-
startAngle * 180.0 / M_PI, sweepAngle * 180.0 / M_PI);
231+
mutable_path().addArc(SkRect::MakeLTRB(left, top, right, bottom),
232+
startAngle * 180.0 / M_PI, sweepAngle * 180.0 / M_PI);
233+
resetVolatility();
198234
}
199235

200236
void CanvasPath::addPolygon(const tonic::Float32List& points, bool close) {
201-
path_.addPoly(reinterpret_cast<const SkPoint*>(points.data()),
202-
points.num_elements() / 2, close);
237+
mutable_path().addPoly(reinterpret_cast<const SkPoint*>(points.data()),
238+
points.num_elements() / 2, close);
239+
resetVolatility();
203240
}
204241

205242
void CanvasPath::addRRect(const RRect& rrect) {
206-
path_.addRRect(rrect.sk_rrect);
243+
mutable_path().addRRect(rrect.sk_rrect);
244+
resetVolatility();
207245
}
208246

209247
void CanvasPath::addPath(CanvasPath* path, double dx, double dy) {
210248
if (!path) {
211249
Dart_ThrowException(ToDart("Path.addPath called with non-genuine Path."));
212250
return;
213251
}
214-
path_.addPath(path->path(), dx, dy, SkPath::kAppend_AddPathMode);
252+
mutable_path().addPath(path->path(), dx, dy, SkPath::kAppend_AddPathMode);
253+
resetVolatility();
215254
}
216255

217256
void CanvasPath::addPathWithMatrix(CanvasPath* path,
@@ -227,8 +266,9 @@ void CanvasPath::addPathWithMatrix(CanvasPath* path,
227266
SkMatrix matrix = ToSkMatrix(matrix4);
228267
matrix.setTranslateX(matrix.getTranslateX() + dx);
229268
matrix.setTranslateY(matrix.getTranslateY() + dy);
230-
path_.addPath(path->path(), matrix, SkPath::kAppend_AddPathMode);
269+
mutable_path().addPath(path->path(), matrix, SkPath::kAppend_AddPathMode);
231270
matrix4.Release();
271+
resetVolatility();
232272
}
233273

234274
void CanvasPath::extendWithPath(CanvasPath* path, double dx, double dy) {
@@ -237,7 +277,8 @@ void CanvasPath::extendWithPath(CanvasPath* path, double dx, double dy) {
237277
ToDart("Path.extendWithPath called with non-genuine Path."));
238278
return;
239279
}
240-
path_.addPath(path->path(), dx, dy, SkPath::kExtend_AddPathMode);
280+
mutable_path().addPath(path->path(), dx, dy, SkPath::kExtend_AddPathMode);
281+
resetVolatility();
241282
}
242283

243284
void CanvasPath::extendWithPathAndMatrix(CanvasPath* path,
@@ -253,37 +294,43 @@ void CanvasPath::extendWithPathAndMatrix(CanvasPath* path,
253294
SkMatrix matrix = ToSkMatrix(matrix4);
254295
matrix.setTranslateX(matrix.getTranslateX() + dx);
255296
matrix.setTranslateY(matrix.getTranslateY() + dy);
256-
path_.addPath(path->path(), matrix, SkPath::kExtend_AddPathMode);
297+
mutable_path().addPath(path->path(), matrix, SkPath::kExtend_AddPathMode);
257298
matrix4.Release();
299+
resetVolatility();
258300
}
259301

260302
void CanvasPath::close() {
261-
path_.close();
303+
mutable_path().close();
304+
resetVolatility();
262305
}
263306

264307
void CanvasPath::reset() {
265-
path_.reset();
308+
mutable_path().reset();
309+
resetVolatility();
266310
}
267311

268312
bool CanvasPath::contains(double x, double y) {
269-
return path_.contains(x, y);
313+
return path().contains(x, y);
270314
}
271315

272316
void CanvasPath::shift(Dart_Handle path_handle, double dx, double dy) {
273317
fml::RefPtr<CanvasPath> path = CanvasPath::Create(path_handle);
274-
path_.offset(dx, dy, &path->path_);
318+
auto& other_mutable_path = path->mutable_path();
319+
mutable_path().offset(dx, dy, &other_mutable_path);
320+
resetVolatility();
275321
}
276322

277323
void CanvasPath::transform(Dart_Handle path_handle,
278324
tonic::Float64List& matrix4) {
279325
fml::RefPtr<CanvasPath> path = CanvasPath::Create(path_handle);
280-
path_.transform(ToSkMatrix(matrix4), &path->path_);
326+
auto& other_mutable_path = path->mutable_path();
327+
mutable_path().transform(ToSkMatrix(matrix4), &other_mutable_path);
281328
matrix4.Release();
282329
}
283330

284331
tonic::Float32List CanvasPath::getBounds() {
285332
tonic::Float32List rect(Dart_NewTypedData(Dart_TypedData_kFloat32, 4));
286-
const SkRect& bounds = path_.getBounds();
333+
const SkRect& bounds = path().getBounds();
287334
rect[0] = bounds.left();
288335
rect[1] = bounds.top();
289336
rect[2] = bounds.right();
@@ -293,21 +340,22 @@ tonic::Float32List CanvasPath::getBounds() {
293340

294341
bool CanvasPath::op(CanvasPath* path1, CanvasPath* path2, int operation) {
295342
return Op(path1->path(), path2->path(), static_cast<SkPathOp>(operation),
296-
&path_);
343+
&tracked_path_->path);
344+
resetVolatility();
297345
}
298346

299347
void CanvasPath::clone(Dart_Handle path_handle) {
300348
fml::RefPtr<CanvasPath> path = CanvasPath::Create(path_handle);
301349
// per Skia docs, this will create a fast copy
302350
// data is shared until the source path or dest path are mutated
303-
path->path_ = path_;
351+
path->mutable_path() = this->path();
304352
}
305353

306354
// This is doomed to be called too early, since Paths are mutable.
307355
// However, it can help for some of the clone/shift/transform type methods
308356
// where the resultant path will initially have a meaningful size.
309357
size_t CanvasPath::GetAllocationSize() const {
310-
return sizeof(CanvasPath) + path_.approximateBytesUsed();
358+
return sizeof(CanvasPath) + path().approximateBytesUsed();
311359
}
312360

313361
} // namespace flutter

0 commit comments

Comments
 (0)