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

Commit c03e698

Browse files
SenorBlancoSkia Commit-Bot
authored andcommitted
GrTessellator: fix for performance issue on many intersections.
On some paths with many self-intersections, performance can approach O(N^2) in intersections, due to "GrTessellator: always rewind to edge top when splitting", aka b67b235. This patch reverts that change, brings back rewind_if_necessary(), and fixes the underlying issue by continuing to rewind past any AEL violations. Bug: 1030306 Change-Id: I64cea1d09bf383c245a5fd2ddb6569b4041b6638 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/269238 Reviewed-by: Chris Dalton <[email protected]> Commit-Queue: Stephen White <[email protected]>
1 parent 8c80b19 commit c03e698

File tree

1 file changed

+53
-8
lines changed

1 file changed

+53
-8
lines changed

src/gpu/GrTessellator.cpp

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,9 @@
6363
* neighbouring edges at the top or bottom vertex. This is handled by merging the
6464
* edges (merge_collinear_edges()).
6565
* B) Intersections may cause an edge to violate the left-to-right ordering of the
66-
* active edge list. This is handled during merging or splitting by rewind()ing the
67-
* active edge list to the vertex before potential violations occur.
66+
* active edge list. This is handled by detecting potential violations and rewinding
67+
* the active edge list to the vertex before they occur (rewind() during merging,
68+
* rewind_if_necessary() during splitting).
6869
*
6970
* The tessellation steps (5) and (6) are based on "Triangulating Simple Polygons and
7071
* Equivalent Problems" (Fournier and Montuno); also a line-sweep algorithm. Note that it
@@ -328,10 +329,11 @@ struct Line {
328329
* An Edge joins a top Vertex to a bottom Vertex. Edge ordering for the list of "edges above" and
329330
* "edge below" a vertex as well as for the active edge list is handled by isLeftOf()/isRightOf().
330331
* Note that an Edge will give occasionally dist() != 0 for its own endpoints (because floating
331-
* point). For speed, that case is only tested by the callers that require it. Edges also handle
332-
* checking for intersection with other edges. Currently, this converts the edges to the
333-
* parametric form, in order to avoid doing a division until an intersection has been confirmed.
334-
* This is slightly slower in the "found" case, but a lot faster in the "not found" case.
332+
* point). For speed, that case is only tested by the callers that require it (e.g.,
333+
* rewind_if_necessary()). Edges also handle checking for intersection with other edges.
334+
* Currently, this converts the edges to the parametric form, in order to avoid doing a division
335+
* until an intersection has been confirmed. This is slightly slower in the "found" case, but
336+
* a lot faster in the "not found" case.
335337
*
336338
* The coefficients of the line equation stored in double precision to avoid catastrphic
337339
* cancellation in the isLeftOf() and isRightOf() checks. Using doubles ensures that the result is
@@ -1023,17 +1025,60 @@ void rewind(EdgeList* activeEdges, Vertex** current, Vertex* dst, Comparator& c)
10231025
for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
10241026
insert_edge(e, leftEdge, activeEdges);
10251027
leftEdge = e;
1028+
Vertex* top = e->fTop;
1029+
if (c.sweep_lt(top->fPoint, dst->fPoint) &&
1030+
((top->fLeftEnclosingEdge && !top->fLeftEnclosingEdge->isLeftOf(e->fTop)) ||
1031+
(top->fRightEnclosingEdge && !top->fRightEnclosingEdge->isRightOf(e->fTop)))) {
1032+
dst = top;
1033+
}
10261034
}
10271035
}
10281036
*current = v;
10291037
}
10301038

1039+
void rewind_if_necessary(Edge* edge, EdgeList* activeEdges, Vertex** current, Comparator& c) {
1040+
if (!activeEdges || !current) {
1041+
return;
1042+
}
1043+
Vertex* top = edge->fTop;
1044+
Vertex* bottom = edge->fBottom;
1045+
if (edge->fLeft) {
1046+
Vertex* leftTop = edge->fLeft->fTop;
1047+
Vertex* leftBottom = edge->fLeft->fBottom;
1048+
if (c.sweep_lt(leftTop->fPoint, top->fPoint) && !edge->fLeft->isLeftOf(top)) {
1049+
rewind(activeEdges, current, leftTop, c);
1050+
} else if (c.sweep_lt(top->fPoint, leftTop->fPoint) && !edge->isRightOf(leftTop)) {
1051+
rewind(activeEdges, current, top, c);
1052+
} else if (c.sweep_lt(bottom->fPoint, leftBottom->fPoint) &&
1053+
!edge->fLeft->isLeftOf(bottom)) {
1054+
rewind(activeEdges, current, leftTop, c);
1055+
} else if (c.sweep_lt(leftBottom->fPoint, bottom->fPoint) && !edge->isRightOf(leftBottom)) {
1056+
rewind(activeEdges, current, top, c);
1057+
}
1058+
}
1059+
if (edge->fRight) {
1060+
Vertex* rightTop = edge->fRight->fTop;
1061+
Vertex* rightBottom = edge->fRight->fBottom;
1062+
if (c.sweep_lt(rightTop->fPoint, top->fPoint) && !edge->fRight->isRightOf(top)) {
1063+
rewind(activeEdges, current, rightTop, c);
1064+
} else if (c.sweep_lt(top->fPoint, rightTop->fPoint) && !edge->isLeftOf(rightTop)) {
1065+
rewind(activeEdges, current, top, c);
1066+
} else if (c.sweep_lt(bottom->fPoint, rightBottom->fPoint) &&
1067+
!edge->fRight->isRightOf(bottom)) {
1068+
rewind(activeEdges, current, rightTop, c);
1069+
} else if (c.sweep_lt(rightBottom->fPoint, bottom->fPoint) &&
1070+
!edge->isLeftOf(rightBottom)) {
1071+
rewind(activeEdges, current, top, c);
1072+
}
1073+
}
1074+
}
1075+
10311076
void set_top(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current, Comparator& c) {
10321077
remove_edge_below(edge);
10331078
edge->fTop = v;
10341079
edge->recompute();
10351080
insert_edge_below(edge, v, c);
1036-
rewind(activeEdges, current, edge->fTop, c);
1081+
rewind_if_necessary(edge, activeEdges, current, c);
10371082
merge_collinear_edges(edge, activeEdges, current, c);
10381083
}
10391084

@@ -1042,7 +1087,7 @@ void set_bottom(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current,
10421087
edge->fBottom = v;
10431088
edge->recompute();
10441089
insert_edge_above(edge, v, c);
1045-
rewind(activeEdges, current, edge->fTop, c);
1090+
rewind_if_necessary(edge, activeEdges, current, c);
10461091
merge_collinear_edges(edge, activeEdges, current, c);
10471092
}
10481093

0 commit comments

Comments
 (0)