-
Notifications
You must be signed in to change notification settings - Fork 6k
Set SkPath::setIsVolatile based on whether the path survives at least two frames #22620
Changes from 11 commits
bc78eea
f2867c8
34e2523
100b2ec
6a84f9e
24df8c7
280b3c9
07d2d99
88d4125
62c238f
9fc3504
c8171ad
17eefed
9cd0ac9
e087e3d
50dadd3
38281c2
7767698
b1d122e
847a998
cfaa5b0
71153fe
1eac95f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -67,43 +67,71 @@ void CanvasPath::RegisterNatives(tonic::DartLibraryNatives* natives) { | |
| FOR_EACH_BINDING(DART_REGISTER_NATIVE)}); | ||
| } | ||
|
|
||
| CanvasPath::CanvasPath() {} | ||
| CanvasPath::CanvasPath() | ||
| : path_tracker_(UIDartState::Current()->GetVolatilePathTracker()), | ||
| tracked_path_(std::make_shared<VolatilePathTracker::Path>()) { | ||
| FML_DCHECK(path_tracker_); | ||
| resetVolatility(); | ||
| } | ||
|
|
||
| CanvasPath::~CanvasPath() = default; | ||
|
|
||
| CanvasPath::~CanvasPath() {} | ||
| void CanvasPath::resetVolatility() { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The name
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
| if (!tracked_path_->tracking_volatility) { | ||
| mutable_path().setIsVolatile(true); | ||
| tracked_path_->frame_count = 0; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems redundant.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If this path had previously been marked as non-volatile, but now has been mutated and is volatile again, we have to reset the frame count so that we don't immediately mark it volatile if it is only drawn for e.g. 1 frame. |
||
| tracked_path_->tracking_volatility = true; | ||
| path_tracker_->Insert(tracked_path_); | ||
| } | ||
| } | ||
|
|
||
| void CanvasPath::ReleaseDartWrappableReference() const { | ||
| FML_DCHECK(path_tracker_); | ||
| if (tracked_path_->tracking_volatility) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This can happen on any thread right? For example, the thread on which the GC happens. In that case, isn't there a data race between this and the the setter in
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just tracking volatility from the get go in the constructor and not needing the flag (and its unsafe check) should make it so that you don't need the check.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe this would be safe if the This relies on the contract that There is a race against However, this is confusing and makes it easy to introduce errors. The advantage of the check is avoiding the performance cost of the If the cost is small, another alternative would be to always call
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So my thought is that at best, this will save us taking a lock, and at worst we'll get a data race that causes us to insert this into the collection even though the path has been GC'd, and it will be removed anyway. I guess the risk is that some refactor happens which changes that worst case scenario to something bad. @chinmaygarde - WDYT about making it an
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I was thinking of calls to
IMO, that would be a lot clearer.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. SG, done. We can always come back to this later with a benchmark if it makes a difference. |
||
| path_tracker_->Erase(tracked_path_); | ||
| } | ||
| } | ||
|
|
||
| int CanvasPath::getFillType() { | ||
| return static_cast<int>(path_.getFillType()); | ||
| return static_cast<int>(path().getFillType()); | ||
| } | ||
|
|
||
| void CanvasPath::setFillType(int fill_type) { | ||
| path_.setFillType(static_cast<SkPathFillType>(fill_type)); | ||
| mutable_path().setFillType(static_cast<SkPathFillType>(fill_type)); | ||
| resetVolatility(); | ||
| } | ||
|
|
||
| void CanvasPath::moveTo(float x, float y) { | ||
| path_.moveTo(x, y); | ||
| mutable_path().moveTo(x, y); | ||
| resetVolatility(); | ||
| } | ||
|
|
||
| void CanvasPath::relativeMoveTo(float x, float y) { | ||
| path_.rMoveTo(x, y); | ||
| mutable_path().rMoveTo(x, y); | ||
| resetVolatility(); | ||
| } | ||
|
|
||
| void CanvasPath::lineTo(float x, float y) { | ||
| path_.lineTo(x, y); | ||
| mutable_path().lineTo(x, y); | ||
| resetVolatility(); | ||
| } | ||
|
|
||
| void CanvasPath::relativeLineTo(float x, float y) { | ||
| path_.rLineTo(x, y); | ||
| mutable_path().rLineTo(x, y); | ||
| resetVolatility(); | ||
| } | ||
|
|
||
| void CanvasPath::quadraticBezierTo(float x1, float y1, float x2, float y2) { | ||
| path_.quadTo(x1, y1, x2, y2); | ||
| mutable_path().quadTo(x1, y1, x2, y2); | ||
| resetVolatility(); | ||
| } | ||
|
|
||
| void CanvasPath::relativeQuadraticBezierTo(float x1, | ||
| float y1, | ||
| float x2, | ||
| float y2) { | ||
| path_.rQuadTo(x1, y1, x2, y2); | ||
| mutable_path().rQuadTo(x1, y1, x2, y2); | ||
| resetVolatility(); | ||
| } | ||
|
|
||
| void CanvasPath::cubicTo(float x1, | ||
|
|
@@ -112,7 +140,8 @@ void CanvasPath::cubicTo(float x1, | |
| float y2, | ||
| float x3, | ||
| float y3) { | ||
| path_.cubicTo(x1, y1, x2, y2, x3, y3); | ||
| mutable_path().cubicTo(x1, y1, x2, y2, x3, y3); | ||
| resetVolatility(); | ||
| } | ||
|
|
||
| void CanvasPath::relativeCubicTo(float x1, | ||
|
|
@@ -121,19 +150,22 @@ void CanvasPath::relativeCubicTo(float x1, | |
| float y2, | ||
| float x3, | ||
| float y3) { | ||
| path_.rCubicTo(x1, y1, x2, y2, x3, y3); | ||
| mutable_path().rCubicTo(x1, y1, x2, y2, x3, y3); | ||
| resetVolatility(); | ||
| } | ||
|
|
||
| void CanvasPath::conicTo(float x1, float y1, float x2, float y2, float w) { | ||
| path_.conicTo(x1, y1, x2, y2, w); | ||
| mutable_path().conicTo(x1, y1, x2, y2, w); | ||
| resetVolatility(); | ||
| } | ||
|
|
||
| void CanvasPath::relativeConicTo(float x1, | ||
| float y1, | ||
| float x2, | ||
| float y2, | ||
| float w) { | ||
| path_.rConicTo(x1, y1, x2, y2, w); | ||
| mutable_path().rConicTo(x1, y1, x2, y2, w); | ||
| resetVolatility(); | ||
| } | ||
|
|
||
| void CanvasPath::arcTo(float left, | ||
|
|
@@ -143,9 +175,10 @@ void CanvasPath::arcTo(float left, | |
| float startAngle, | ||
| float sweepAngle, | ||
| bool forceMoveTo) { | ||
| path_.arcTo(SkRect::MakeLTRB(left, top, right, bottom), | ||
| startAngle * 180.0 / M_PI, sweepAngle * 180.0 / M_PI, | ||
| forceMoveTo); | ||
| mutable_path().arcTo(SkRect::MakeLTRB(left, top, right, bottom), | ||
| startAngle * 180.0 / M_PI, sweepAngle * 180.0 / M_PI, | ||
| forceMoveTo); | ||
| resetVolatility(); | ||
| } | ||
|
|
||
| void CanvasPath::arcToPoint(float arcEndX, | ||
|
|
@@ -160,8 +193,9 @@ void CanvasPath::arcToPoint(float arcEndX, | |
| const auto direction = | ||
| isClockwiseDirection ? SkPathDirection::kCW : SkPathDirection::kCCW; | ||
|
|
||
| path_.arcTo(radiusX, radiusY, xAxisRotation, arcSize, direction, arcEndX, | ||
| arcEndY); | ||
| mutable_path().arcTo(radiusX, radiusY, xAxisRotation, arcSize, direction, | ||
| arcEndX, arcEndY); | ||
| resetVolatility(); | ||
| } | ||
|
|
||
| void CanvasPath::relativeArcToPoint(float arcEndDeltaX, | ||
|
|
@@ -175,16 +209,19 @@ void CanvasPath::relativeArcToPoint(float arcEndDeltaX, | |
| : SkPath::ArcSize::kSmall_ArcSize; | ||
| const auto direction = | ||
| isClockwiseDirection ? SkPathDirection::kCW : SkPathDirection::kCCW; | ||
| path_.rArcTo(radiusX, radiusY, xAxisRotation, arcSize, direction, | ||
| arcEndDeltaX, arcEndDeltaY); | ||
| mutable_path().rArcTo(radiusX, radiusY, xAxisRotation, arcSize, direction, | ||
| arcEndDeltaX, arcEndDeltaY); | ||
| resetVolatility(); | ||
| } | ||
|
|
||
| void CanvasPath::addRect(float left, float top, float right, float bottom) { | ||
| path_.addRect(SkRect::MakeLTRB(left, top, right, bottom)); | ||
| mutable_path().addRect(SkRect::MakeLTRB(left, top, right, bottom)); | ||
| resetVolatility(); | ||
| } | ||
|
|
||
| void CanvasPath::addOval(float left, float top, float right, float bottom) { | ||
| path_.addOval(SkRect::MakeLTRB(left, top, right, bottom)); | ||
| mutable_path().addOval(SkRect::MakeLTRB(left, top, right, bottom)); | ||
| resetVolatility(); | ||
| } | ||
|
|
||
| void CanvasPath::addArc(float left, | ||
|
|
@@ -193,25 +230,29 @@ void CanvasPath::addArc(float left, | |
| float bottom, | ||
| float startAngle, | ||
| float sweepAngle) { | ||
| path_.addArc(SkRect::MakeLTRB(left, top, right, bottom), | ||
| startAngle * 180.0 / M_PI, sweepAngle * 180.0 / M_PI); | ||
| mutable_path().addArc(SkRect::MakeLTRB(left, top, right, bottom), | ||
| startAngle * 180.0 / M_PI, sweepAngle * 180.0 / M_PI); | ||
| resetVolatility(); | ||
| } | ||
|
|
||
| void CanvasPath::addPolygon(const tonic::Float32List& points, bool close) { | ||
| path_.addPoly(reinterpret_cast<const SkPoint*>(points.data()), | ||
| points.num_elements() / 2, close); | ||
| mutable_path().addPoly(reinterpret_cast<const SkPoint*>(points.data()), | ||
| points.num_elements() / 2, close); | ||
| resetVolatility(); | ||
| } | ||
|
|
||
| void CanvasPath::addRRect(const RRect& rrect) { | ||
| path_.addRRect(rrect.sk_rrect); | ||
| mutable_path().addRRect(rrect.sk_rrect); | ||
| resetVolatility(); | ||
| } | ||
|
|
||
| void CanvasPath::addPath(CanvasPath* path, double dx, double dy) { | ||
| if (!path) { | ||
| Dart_ThrowException(ToDart("Path.addPath called with non-genuine Path.")); | ||
| return; | ||
| } | ||
| path_.addPath(path->path(), dx, dy, SkPath::kAppend_AddPathMode); | ||
| mutable_path().addPath(path->path(), dx, dy, SkPath::kAppend_AddPathMode); | ||
| resetVolatility(); | ||
| } | ||
|
|
||
| void CanvasPath::addPathWithMatrix(CanvasPath* path, | ||
|
|
@@ -227,8 +268,9 @@ void CanvasPath::addPathWithMatrix(CanvasPath* path, | |
| SkMatrix matrix = ToSkMatrix(matrix4); | ||
| matrix.setTranslateX(matrix.getTranslateX() + dx); | ||
| matrix.setTranslateY(matrix.getTranslateY() + dy); | ||
| path_.addPath(path->path(), matrix, SkPath::kAppend_AddPathMode); | ||
| mutable_path().addPath(path->path(), matrix, SkPath::kAppend_AddPathMode); | ||
| matrix4.Release(); | ||
| resetVolatility(); | ||
| } | ||
|
|
||
| void CanvasPath::extendWithPath(CanvasPath* path, double dx, double dy) { | ||
|
|
@@ -237,7 +279,8 @@ void CanvasPath::extendWithPath(CanvasPath* path, double dx, double dy) { | |
| ToDart("Path.extendWithPath called with non-genuine Path.")); | ||
| return; | ||
| } | ||
| path_.addPath(path->path(), dx, dy, SkPath::kExtend_AddPathMode); | ||
| mutable_path().addPath(path->path(), dx, dy, SkPath::kExtend_AddPathMode); | ||
| resetVolatility(); | ||
| } | ||
|
|
||
| void CanvasPath::extendWithPathAndMatrix(CanvasPath* path, | ||
|
|
@@ -253,37 +296,45 @@ void CanvasPath::extendWithPathAndMatrix(CanvasPath* path, | |
| SkMatrix matrix = ToSkMatrix(matrix4); | ||
| matrix.setTranslateX(matrix.getTranslateX() + dx); | ||
| matrix.setTranslateY(matrix.getTranslateY() + dy); | ||
| path_.addPath(path->path(), matrix, SkPath::kExtend_AddPathMode); | ||
| mutable_path().addPath(path->path(), matrix, SkPath::kExtend_AddPathMode); | ||
| matrix4.Release(); | ||
| resetVolatility(); | ||
| } | ||
|
|
||
| void CanvasPath::close() { | ||
| path_.close(); | ||
| mutable_path().close(); | ||
| resetVolatility(); | ||
| } | ||
|
|
||
| void CanvasPath::reset() { | ||
| path_.reset(); | ||
| mutable_path().reset(); | ||
| resetVolatility(); | ||
| } | ||
|
|
||
| bool CanvasPath::contains(double x, double y) { | ||
| return path_.contains(x, y); | ||
| return path().contains(x, y); | ||
| } | ||
|
|
||
| void CanvasPath::shift(Dart_Handle path_handle, double dx, double dy) { | ||
| fml::RefPtr<CanvasPath> path = CanvasPath::Create(path_handle); | ||
| path_.offset(dx, dy, &path->path_); | ||
| auto other_mutable_path = path->mutable_path(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this should be
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are right - adding a test to cover this |
||
| mutable_path().offset(dx, dy, &other_mutable_path); | ||
| resetVolatility(); | ||
| } | ||
|
|
||
| void CanvasPath::transform(Dart_Handle path_handle, | ||
| tonic::Float64List& matrix4) { | ||
| fml::RefPtr<CanvasPath> path = CanvasPath::Create(path_handle); | ||
| path_.transform(ToSkMatrix(matrix4), &path->path_); | ||
| auto& other_mutable_path = path->mutable_path(); | ||
| mutable_path().transform(ToSkMatrix(matrix4), &other_mutable_path); | ||
| matrix4.Release(); | ||
| } | ||
|
|
||
| tonic::Float32List CanvasPath::getBounds() { | ||
| tonic::Float32List rect(Dart_NewTypedData(Dart_TypedData_kFloat32, 4)); | ||
| const SkRect& bounds = path_.getBounds(); | ||
| const SkRect& bounds = path().getBounds(); | ||
| FML_DLOG(ERROR) << "Bounds " << bounds.left() << " " << bounds.top() << " " | ||
| << bounds.right() << " " << bounds.bottom(); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removing this. Whups. |
||
| rect[0] = bounds.left(); | ||
| rect[1] = bounds.top(); | ||
| rect[2] = bounds.right(); | ||
|
|
@@ -293,21 +344,22 @@ tonic::Float32List CanvasPath::getBounds() { | |
|
|
||
| bool CanvasPath::op(CanvasPath* path1, CanvasPath* path2, int operation) { | ||
| return Op(path1->path(), path2->path(), static_cast<SkPathOp>(operation), | ||
| &path_); | ||
| &tracked_path_->path); | ||
| resetVolatility(); | ||
| } | ||
|
|
||
| void CanvasPath::clone(Dart_Handle path_handle) { | ||
| fml::RefPtr<CanvasPath> path = CanvasPath::Create(path_handle); | ||
| // per Skia docs, this will create a fast copy | ||
| // data is shared until the source path or dest path are mutated | ||
| path->path_ = path_; | ||
| path->mutable_path() = this->path(); | ||
| } | ||
|
|
||
| // This is doomed to be called too early, since Paths are mutable. | ||
| // However, it can help for some of the clone/shift/transform type methods | ||
| // where the resultant path will initially have a meaningful size. | ||
| size_t CanvasPath::GetAllocationSize() const { | ||
| return sizeof(CanvasPath) + path_.approximateBytesUsed(); | ||
| return sizeof(CanvasPath) + path().approximateBytesUsed(); | ||
| } | ||
|
|
||
| } // namespace flutter | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm confused. This seems dead code. Did you forget to check in the test maybe?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I forgot to remove this code when I changed how a test worked.