This repository was archived by the owner on Feb 25, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6k
[Impeller] Reduce allocations for polyline generation #47837
Merged
Merged
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
1bc0c4d
1
dnfield ebfaabb
[Impeller] Reduce allocations in polyline generation
dnfield 84d2e20
merge
dnfield a92b757
fixes for tests, minor cleanup/rename
dnfield aa280ec
docs
dnfield cd60b9f
one more reserve
dnfield 07eee60
No TLS, unique_ptr for vector with callback
dnfield 761be29
more review
dnfield 4d9fe4e
merge
dnfield 720a0ee
names
dnfield 615f8fd
tests
dnfield 71afaa0
lint
dnfield da16afe
lint
dnfield d9a0ab9
Merge branch 'main' into alloc
dnfield eaa07be
Merge branch 'main' into alloc
dnfield File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -128,9 +128,9 @@ StrokePathGeometry::JoinProc StrokePathGeometry::GetJoinProc(Join stroke_join) { | |
PathBuilder::kArcApproximationMagic * alignment * | ||
dir; | ||
|
||
auto arc_points = CubicPathComponent(start_offset, start_handle, | ||
middle_handle, middle) | ||
.CreatePolyline(scale); | ||
std::vector<Point> arc_points; | ||
CubicPathComponent(start_offset, start_handle, middle_handle, middle) | ||
.AppendPolylinePoints(scale, arc_points); | ||
|
||
VS::PerVertexData vtx; | ||
for (const auto& point : arc_points) { | ||
|
@@ -192,7 +192,9 @@ StrokePathGeometry::CapProc StrokePathGeometry::GetCapProc(Cap stroke_cap) { | |
vtx_builder.AppendVertex(vtx); | ||
vtx.position = position - orientation; | ||
vtx_builder.AppendVertex(vtx); | ||
for (const auto& point : arc.CreatePolyline(scale)) { | ||
std::vector<Point> arc_points; | ||
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. Or here? 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. Same deal. This shouldn't typically result in a large number of points. |
||
arc.AppendPolylinePoints(scale, arc_points); | ||
for (const auto& point : arc_points) { | ||
vtx.position = position + point; | ||
vtx_builder.AppendVertex(vtx); | ||
vtx.position = position + (-point).Reflect(forward_normal); | ||
|
@@ -234,7 +236,12 @@ StrokePathGeometry::CreateSolidStrokeVertices( | |
const StrokePathGeometry::CapProc& cap_proc, | ||
Scalar scale) { | ||
VertexBufferBuilder<VS::PerVertexData> vtx_builder; | ||
auto polyline = path.CreatePolyline(scale); | ||
auto point_buffer = std::make_unique<std::vector<Point>>(); | ||
// 512 is an arbitrary choice that should be big enough for most paths without | ||
// needing to reallocate. If we have motivating benchmarks we should raise or | ||
// lower this number, cause dnfield just made it up! | ||
point_buffer->reserve(512); | ||
auto polyline = path.CreatePolyline(scale, std::move(point_buffer)); | ||
|
||
VS::PerVertexData vtx; | ||
|
||
|
@@ -256,8 +263,8 @@ StrokePathGeometry::CreateSolidStrokeVertices( | |
} else if (point_i <= contour_start_point_i) { | ||
direction = -contour.start_direction; | ||
} else { | ||
direction = | ||
(polyline.points[point_i] - polyline.points[point_i - 1]).Normalize(); | ||
direction = (polyline.GetPoint(point_i) - polyline.GetPoint(point_i - 1)) | ||
.Normalize(); | ||
} | ||
previous_offset = offset; | ||
offset = Vector2{-direction.y, direction.x} * stroke_width * 0.5; | ||
|
@@ -276,23 +283,23 @@ StrokePathGeometry::CreateSolidStrokeVertices( | |
for (size_t point_i = component_start_index; | ||
point_i < component_end_index; point_i++) { | ||
auto is_end_of_component = point_i == component_end_index - 1; | ||
vtx.position = polyline.points[point_i] + offset; | ||
vtx.position = polyline.GetPoint(point_i) + offset; | ||
vtx_builder.AppendVertex(vtx); | ||
vtx.position = polyline.points[point_i] - offset; | ||
vtx.position = polyline.GetPoint(point_i) - offset; | ||
vtx_builder.AppendVertex(vtx); | ||
|
||
// For line components, two additional points need to be appended | ||
// prior to appending a join connecting the next component. | ||
vtx.position = polyline.points[point_i + 1] + offset; | ||
vtx.position = polyline.GetPoint(point_i + 1) + offset; | ||
vtx_builder.AppendVertex(vtx); | ||
vtx.position = polyline.points[point_i + 1] - offset; | ||
vtx.position = polyline.GetPoint(point_i + 1) - offset; | ||
vtx_builder.AppendVertex(vtx); | ||
|
||
compute_offset(point_i + 2, contour_start_point_i, | ||
contour_end_point_i, contour); | ||
if (!is_last_component && is_end_of_component) { | ||
// Generate join from the current line to the next line. | ||
join_proc(vtx_builder, polyline.points[point_i + 1], | ||
join_proc(vtx_builder, polyline.GetPoint(point_i + 1), | ||
previous_offset, offset, scaled_miter_limit, scale); | ||
} | ||
} | ||
|
@@ -312,23 +319,23 @@ StrokePathGeometry::CreateSolidStrokeVertices( | |
point_i < component_end_index; point_i++) { | ||
auto is_end_of_component = point_i == component_end_index - 1; | ||
|
||
vtx.position = polyline.points[point_i] + offset; | ||
vtx.position = polyline.GetPoint(point_i) + offset; | ||
vtx_builder.AppendVertex(vtx); | ||
vtx.position = polyline.points[point_i] - offset; | ||
vtx.position = polyline.GetPoint(point_i) - offset; | ||
vtx_builder.AppendVertex(vtx); | ||
|
||
compute_offset(point_i + 2, contour_start_point_i, | ||
contour_end_point_i, contour); | ||
// For curve components, the polyline is detailed enough such that | ||
// it can avoid worrying about joins altogether. | ||
if (is_end_of_component) { | ||
vtx.position = polyline.points[point_i + 1] + offset; | ||
vtx.position = polyline.GetPoint(point_i + 1) + offset; | ||
vtx_builder.AppendVertex(vtx); | ||
vtx.position = polyline.points[point_i + 1] - offset; | ||
vtx.position = polyline.GetPoint(point_i + 1) - offset; | ||
vtx_builder.AppendVertex(vtx); | ||
// Generate join from the current line to the next line. | ||
if (!is_last_component) { | ||
join_proc(vtx_builder, polyline.points[point_i + 1], | ||
join_proc(vtx_builder, polyline.GetPoint(point_i + 1), | ||
previous_offset, offset, scaled_miter_limit, scale); | ||
} | ||
} | ||
|
@@ -344,7 +351,7 @@ StrokePathGeometry::CreateSolidStrokeVertices( | |
|
||
switch (contour_end_point_i - contour_start_point_i) { | ||
case 1: { | ||
Point p = polyline.points[contour_start_point_i]; | ||
Point p = polyline.GetPoint(contour_start_point_i); | ||
cap_proc(vtx_builder, p, {-stroke_width * 0.5f, 0}, scale, false); | ||
cap_proc(vtx_builder, p, {stroke_width * 0.5f, 0}, scale, false); | ||
continue; | ||
|
@@ -367,14 +374,14 @@ StrokePathGeometry::CreateSolidStrokeVertices( | |
// vertices at the start of the new contour (thus connecting the two | ||
// contours with two zero volume triangles, which will be discarded by | ||
// the rasterizer). | ||
vtx.position = polyline.points[contour_start_point_i - 1]; | ||
vtx.position = polyline.GetPoint(contour_start_point_i - 1); | ||
// Append two vertices when "picking up" the pen so that the triangle | ||
// drawn when moving to the beginning of the new contour will have zero | ||
// volume. | ||
vtx_builder.AppendVertex(vtx); | ||
vtx_builder.AppendVertex(vtx); | ||
|
||
vtx.position = polyline.points[contour_start_point_i]; | ||
vtx.position = polyline.GetPoint(contour_start_point_i); | ||
// Append two vertices at the beginning of the new contour, which | ||
// appends two triangles of zero area. | ||
vtx_builder.AppendVertex(vtx); | ||
|
@@ -386,8 +393,8 @@ StrokePathGeometry::CreateSolidStrokeVertices( | |
auto cap_offset = | ||
Vector2(-contour.start_direction.y, contour.start_direction.x) * | ||
stroke_width * 0.5; // Counterclockwise normal | ||
cap_proc(vtx_builder, polyline.points[contour_start_point_i], cap_offset, | ||
scale, true); | ||
cap_proc(vtx_builder, polyline.GetPoint(contour_start_point_i), | ||
cap_offset, scale, true); | ||
} | ||
|
||
for (size_t contour_component_i = 0; | ||
|
@@ -418,10 +425,10 @@ StrokePathGeometry::CreateSolidStrokeVertices( | |
auto cap_offset = | ||
Vector2(-contour.end_direction.y, contour.end_direction.x) * | ||
stroke_width * 0.5; // Clockwise normal | ||
cap_proc(vtx_builder, polyline.points[contour_end_point_i - 1], | ||
cap_proc(vtx_builder, polyline.GetPoint(contour_end_point_i - 1), | ||
cap_offset, scale, false); | ||
} else { | ||
join_proc(vtx_builder, polyline.points[contour_start_point_i], offset, | ||
join_proc(vtx_builder, polyline.GetPoint(contour_start_point_i), offset, | ||
contour_first_offset, scaled_miter_limit, scale); | ||
} | ||
} | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Can the reserve size be calculated here?
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.
These are small and shouldn't result in lots of reallocation. I'd feel more comfortable having a benchmark showing this before trying to place a number in it.
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 ask because I'm turning on a linter for this in #47868. I don't think it will flag this though since it can't trivially know what the reserve size is.
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.
Reserving incorrect sizes can make things worse. If we don't know let's use the standard vec reallocation startegy