Skip to content

Commit b9e7ba3

Browse files
authored
[Impeller] Avoid allocating path for dashed lines (#169881)
We use the new algorithmically generated `PathSource` mechanism for generating dashed lines to avoid allocating a growable path object.
1 parent 60cbfb7 commit b9e7ba3

File tree

10 files changed

+286
-35
lines changed

10 files changed

+286
-35
lines changed

engine/src/flutter/ci/licenses_golden/licenses_flutter

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51472,6 +51472,8 @@ ORIGIN: ../../../flutter/impeller/geometry/color.cc + ../../../flutter/LICENSE
5147251472
ORIGIN: ../../../flutter/impeller/geometry/color.h + ../../../flutter/LICENSE
5147351473
ORIGIN: ../../../flutter/impeller/geometry/constants.cc + ../../../flutter/LICENSE
5147451474
ORIGIN: ../../../flutter/impeller/geometry/constants.h + ../../../flutter/LICENSE
51475+
ORIGIN: ../../../flutter/impeller/geometry/dashed_line_path_source.cc + ../../../flutter/LICENSE
51476+
ORIGIN: ../../../flutter/impeller/geometry/dashed_line_path_source.h + ../../../flutter/LICENSE
5147551477
ORIGIN: ../../../flutter/impeller/geometry/geometry_asserts.h + ../../../flutter/LICENSE
5147651478
ORIGIN: ../../../flutter/impeller/geometry/geometry_benchmarks.cc + ../../../flutter/LICENSE
5147751479
ORIGIN: ../../../flutter/impeller/geometry/gradient.cc + ../../../flutter/LICENSE
@@ -54496,6 +54498,8 @@ FILE: ../../../flutter/impeller/geometry/color.cc
5449654498
FILE: ../../../flutter/impeller/geometry/color.h
5449754499
FILE: ../../../flutter/impeller/geometry/constants.cc
5449854500
FILE: ../../../flutter/impeller/geometry/constants.h
54501+
FILE: ../../../flutter/impeller/geometry/dashed_line_path_source.cc
54502+
FILE: ../../../flutter/impeller/geometry/dashed_line_path_source.h
5449954503
FILE: ../../../flutter/impeller/geometry/geometry_asserts.h
5450054504
FILE: ../../../flutter/impeller/geometry/geometry_benchmarks.cc
5450154505
FILE: ../../../flutter/impeller/geometry/gradient.cc

engine/src/flutter/impeller/display_list/canvas.cc

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,32 @@ void Canvas::DrawLine(const Point& p0,
603603
}
604604
}
605605

606+
void Canvas::DrawDashedLine(const Point& p0,
607+
const Point& p1,
608+
Scalar on_length,
609+
Scalar off_length,
610+
const Paint& paint) {
611+
// Reasons to defer to regular DrawLine:
612+
// - performance for degenerate and "regular line" cases
613+
// - length is non-positive - DrawLine will draw appropriate "dot"
614+
// - off_length is non-positive - no gaps, DrawLine will draw it solid
615+
// - on_length is negative - invalid dashing
616+
//
617+
// Note that a 0 length "on" dash will draw "dot"s every "off" distance
618+
// apart so we proceed with the dashing process in that case.
619+
Scalar length = p0.GetDistance(p1);
620+
if (length > 0.0f && on_length >= 0.0f && off_length > 0.0f) {
621+
Entity entity;
622+
entity.SetTransform(GetCurrentTransform());
623+
entity.SetBlendMode(paint.blend_mode);
624+
625+
StrokeDashedLineGeometry geom(p0, p1, on_length, off_length, paint.stroke);
626+
AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
627+
} else {
628+
DrawLine(p0, p1, paint);
629+
}
630+
}
631+
606632
void Canvas::DrawRect(const Rect& rect, const Paint& paint) {
607633
if (AttemptDrawBlurredRRect(rect, {}, paint)) {
608634
return;

engine/src/flutter/impeller/display_list/canvas.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,12 @@ class Canvas {
199199
const Paint& paint,
200200
bool reuse_depth = false);
201201

202+
void DrawDashedLine(const Point& p0,
203+
const Point& p1,
204+
Scalar on_length,
205+
Scalar off_length,
206+
const Paint& paint);
207+
202208
void DrawRect(const Rect& rect, const Paint& paint);
203209

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

engine/src/flutter/impeller/display_list/dl_dispatcher.cc

Lines changed: 2 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212

1313
#include "display_list/dl_sampling_options.h"
1414
#include "display_list/effects/dl_image_filter.h"
15-
#include "display_list/geometry/dl_path_builder.h"
1615
#include "flutter/fml/logging.h"
1716
#include "fml/closure.h"
1817
#include "impeller/core/formats.h"
@@ -547,46 +546,14 @@ void DlDispatcherBase::drawLine(const DlPoint& p0, const DlPoint& p1) {
547546
GetCanvas().DrawLine(p0, p1, paint_);
548547
}
549548

549+
// |flutter::DlOpReceiver|
550550
void DlDispatcherBase::drawDashedLine(const DlPoint& p0,
551551
const DlPoint& p1,
552552
DlScalar on_length,
553553
DlScalar off_length) {
554554
AUTO_DEPTH_WATCHER(1u);
555555

556-
Scalar length = p0.GetDistance(p1);
557-
// Reasons to defer to regular DrawLine:
558-
// length is non-positive - drawLine will draw appropriate "dot"
559-
// off_length is non-positive - no gaps, drawLine will draw it solid
560-
// on_length is negative - invalid dashing
561-
// Note that a 0 length "on" dash will draw "dot"s every "off" distance
562-
// apart
563-
if (length > 0.0f && on_length >= 0.0f && off_length > 0.0f) {
564-
Point delta = (p1 - p0) / length; // length > 0 already tested
565-
flutter::DlPathBuilder builder;
566-
567-
Scalar consumed = 0.0f;
568-
while (consumed < length) {
569-
builder.MoveTo(p0 + delta * consumed);
570-
571-
Scalar dash_end = consumed + on_length;
572-
if (dash_end < length) {
573-
builder.LineTo(p0 + delta * dash_end);
574-
} else {
575-
builder.LineTo(p1);
576-
// Should happen anyway due to the math, but let's make it explicit
577-
// in case of bit errors. We're done with this line.
578-
break;
579-
}
580-
581-
consumed = dash_end + off_length;
582-
}
583-
584-
Paint stroke_paint = paint_;
585-
stroke_paint.style = Paint::Style::kStroke;
586-
GetCanvas().DrawPath(builder.TakePath(), stroke_paint);
587-
} else {
588-
drawLine(p0, p1);
589-
}
556+
GetCanvas().DrawDashedLine(p0, p1, on_length, off_length, paint_);
590557
}
591558

592559
// |flutter::DlOpReceiver|

engine/src/flutter/impeller/entity/geometry/stroke_path_geometry.cc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -846,4 +846,17 @@ const PathSource& StrokeDiffRoundRectGeometry::GetSource() const {
846846
return source_;
847847
}
848848

849+
StrokeDashedLineGeometry::StrokeDashedLineGeometry(
850+
Point p0,
851+
Point p1,
852+
Scalar on_length,
853+
Scalar off_length,
854+
const StrokeParameters& parameters)
855+
: StrokePathSourceGeometry(parameters),
856+
source_(p0, p1, on_length, off_length) {}
857+
858+
const PathSource& StrokeDashedLineGeometry::GetSource() const {
859+
return source_;
860+
}
861+
849862
} // namespace impeller

engine/src/flutter/impeller/entity/geometry/stroke_path_geometry.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#define FLUTTER_IMPELLER_ENTITY_GEOMETRY_STROKE_PATH_GEOMETRY_H_
77

88
#include "impeller/entity/geometry/geometry.h"
9+
#include "impeller/geometry/dashed_line_path_source.h"
910
#include "impeller/geometry/matrix.h"
1011
#include "impeller/geometry/path_source.h"
1112
#include "impeller/geometry/stroke_parameters.h"
@@ -126,6 +127,25 @@ class StrokeDiffRoundRectGeometry final : public StrokePathSourceGeometry {
126127
const DiffRoundRectPathSource source_;
127128
};
128129

130+
/// @brief A Geometry that produces fillable vertices representing the
131+
/// stroked outline of a |DlPath| object using the
132+
/// |StrokePathSourceGeometry| base class and a |DlPath| object
133+
/// to perform path iteration.
134+
class StrokeDashedLineGeometry final : public StrokePathSourceGeometry {
135+
public:
136+
StrokeDashedLineGeometry(Point p0,
137+
Point p1,
138+
Scalar on_length,
139+
Scalar off_length,
140+
const StrokeParameters& parameters);
141+
142+
protected:
143+
const PathSource& GetSource() const override;
144+
145+
private:
146+
const DashedLinePathSource source_;
147+
};
148+
129149
} // namespace impeller
130150

131151
#endif // FLUTTER_IMPELLER_ENTITY_GEOMETRY_STROKE_PATH_GEOMETRY_H_

engine/src/flutter/impeller/geometry/BUILD.gn

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ impeller_component("geometry") {
1010
"color.h",
1111
"constants.cc",
1212
"constants.h",
13+
"dashed_line_path_source.cc",
14+
"dashed_line_path_source.h",
1315
"gradient.cc",
1416
"gradient.h",
1517
"half.h",
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include "impeller/geometry/dashed_line_path_source.h"
6+
7+
namespace impeller {
8+
9+
DashedLinePathSource::DashedLinePathSource(Point p0,
10+
Point p1,
11+
Scalar on_length,
12+
Scalar off_length)
13+
: p0_(p0), p1_(p1), on_length_(on_length), off_length_(off_length) {}
14+
15+
DashedLinePathSource::~DashedLinePathSource() = default;
16+
17+
FillType DashedLinePathSource::GetFillType() const {
18+
return FillType::kNonZero;
19+
}
20+
21+
Rect DashedLinePathSource::GetBounds() const {
22+
return Rect::MakeLTRB(p0_.x, p0_.y, p1_.x, p1_.y).GetPositive();
23+
}
24+
25+
bool DashedLinePathSource::IsConvex() const {
26+
return false;
27+
}
28+
29+
void DashedLinePathSource::Dispatch(PathReceiver& receiver) const {
30+
// Exceptional conditions:
31+
// - length is non-positive - result will draw only a "dot"
32+
// - off_length is non-positive - no gaps, result is a solid line
33+
// - on_length is negative - invalid dashing
34+
// Note that a 0 length "on" dash will draw "dot"s every "off" distance
35+
// apart so we still generate the dashing for that case.
36+
//
37+
// Note that Canvas will detect these conditions and use its own DrawLine
38+
// method directly for performance reasons for a single line, but in case
39+
// someone uses this PathSource with these exceptional cases, we degenerate
40+
// gracefully into a single line segment path description below.
41+
Scalar length = p0_.GetDistance(p1_);
42+
if (length > 0.0f && on_length_ >= 0.0f && off_length_ > 0.0f) {
43+
Point delta = (p1_ - p0_) / length; // length > 0 already verified
44+
45+
Scalar consumed = 0.0f;
46+
while (consumed < length) {
47+
receiver.MoveTo(p0_ + delta * consumed, false);
48+
49+
Scalar dash_end = consumed + on_length_;
50+
if (dash_end < length) {
51+
receiver.LineTo(p0_ + delta * dash_end);
52+
} else {
53+
receiver.LineTo(p1_);
54+
// Should happen anyway due to the math, but let's make it explicit
55+
// in case of bit errors. We're done with this line.
56+
break;
57+
}
58+
59+
consumed = dash_end + off_length_;
60+
}
61+
} else {
62+
receiver.MoveTo(p0_, false);
63+
receiver.LineTo(p1_);
64+
}
65+
receiver.PathEnd();
66+
}
67+
68+
} // namespace impeller
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#ifndef FLUTTER_IMPELLER_GEOMETRY_DASHED_LINE_PATH_SOURCE_H_
6+
#define FLUTTER_IMPELLER_GEOMETRY_DASHED_LINE_PATH_SOURCE_H_
7+
8+
#include "flutter/impeller/geometry/path_source.h"
9+
#include "flutter/impeller/geometry/point.h"
10+
#include "flutter/impeller/geometry/scalar.h"
11+
12+
namespace impeller {
13+
14+
/// @brief A PathSource that generates the various segments of a dashed line.
15+
class DashedLinePathSource : public PathSource {
16+
public:
17+
DashedLinePathSource(Point p0, Point p1, Scalar on_length, Scalar off_length);
18+
19+
~DashedLinePathSource();
20+
21+
// |PathSource|
22+
FillType GetFillType() const override;
23+
24+
// |PathSource|
25+
Rect GetBounds() const override;
26+
27+
// |PathSource|
28+
bool IsConvex() const override;
29+
30+
// |PathSource|
31+
void Dispatch(PathReceiver& receiver) const override;
32+
33+
private:
34+
const Point p0_;
35+
const Point p1_;
36+
const Scalar on_length_;
37+
const Scalar off_length_;
38+
};
39+
40+
} // namespace impeller
41+
42+
#endif // FLUTTER_IMPELLER_GEOMETRY_DASHED_LINE_PATH_SOURCE_H_

0 commit comments

Comments
 (0)