Move the outer mesh into a member of GrAATriangulator
Bug: skia:10419
Change-Id: I547e7c63b9d7ad9abeb6377f4a31d6d671bb5030
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/350482
Commit-Queue: Chris Dalton <csmartdalton@google.com>
Reviewed-by: Jim Van Verth <jvanverth@google.com>
diff --git a/src/gpu/GrTriangulator.cpp b/src/gpu/GrTriangulator.cpp
index 5d86e4c..916457a 100644
--- a/src/gpu/GrTriangulator.cpp
+++ b/src/gpu/GrTriangulator.cpp
@@ -284,6 +284,7 @@
}
void* GrTriangulator::emitMonotonePoly(const MonotonePoly* monotonePoly, void* data) {
+ SkASSERT(monotonePoly->fWinding != 0);
Edge* e = monotonePoly->fFirstEdge;
VertexList vertices;
vertices.append(e->fTop);
@@ -331,12 +332,12 @@
void* GrTriangulator::emitTriangle(Vertex* prev, Vertex* curr, Vertex* next, int winding,
void* data) const {
- if (winding < 0) {
+ if (winding > 0) {
// Ensure our triangles always wind in the same direction as if the path had been
// triangulated as a simple fan (a la red book).
std::swap(prev, next);
}
- return emit_triangle(next, curr, prev, fEmitCoverage, data);
+ return emit_triangle(prev, curr, next, fEmitCoverage, data);
}
Poly* GrTriangulator::Poly::addEdge(Edge* e, Side side, SkArenaAlloc& alloc) {
@@ -1321,7 +1322,7 @@
// Stage 5: Tessellate the simplified mesh into monotone polygons.
-Poly* GrTriangulator::tessellate(const VertexList& vertices, VertexList*, const Comparator&) {
+Poly* GrTriangulator::tessellate(const VertexList& vertices, const Comparator&) {
TESS_LOG("\ntessellating simple polygons\n");
int maxWindMagnitude = std::numeric_limits<int>::max();
if (fSimpleInnerPolygons && !SkPathFillType_IsEvenOdd(fPath.getFillType())) {
@@ -1704,7 +1705,7 @@
// new antialiased mesh from those vertices.
void GrAATriangulator::strokeBoundary(EdgeList* boundary, VertexList* innerMesh,
- VertexList* outerMesh, const Comparator& c) {
+ const Comparator& c) {
TESS_LOG("\nstroking boundary\n");
// A boundary with fewer than 3 edges is degenerate.
if (!boundary->fHead || !boundary->fHead->fRight || !boundary->fHead->fRight->fRight) {
@@ -1860,7 +1861,7 @@
this->makeConnectingEdge(outerVertices.fTail, outerVertices.fHead, EdgeType::kOuter, c,
outerWinding);
innerMesh->append(innerVertices);
- outerMesh->append(outerVertices);
+ fOuterMesh.append(outerVertices);
}
void GrAATriangulator::extractBoundary(EdgeList* boundary, Edge* e) {
@@ -1900,14 +1901,14 @@
// Stage 5b: Extract boundaries from mesh, simplify and stroke them into a new mesh.
void GrAATriangulator::extractBoundaries(const VertexList& inMesh, VertexList* innerVertices,
- VertexList* outerVertices, const Comparator& c) {
+ const Comparator& c) {
this->removeNonBoundaryEdges(inMesh);
for (Vertex* v = inMesh.fHead; v; v = v->fNext) {
while (v->fFirstEdgeBelow) {
EdgeList boundary;
this->extractBoundary(&boundary, v->fFirstEdgeBelow);
this->simplifyBoundary(&boundary, c);
- this->strokeBoundary(&boundary, innerVertices, outerVertices, c);
+ this->strokeBoundary(&boundary, innerVertices, c);
}
}
}
@@ -1949,7 +1950,7 @@
#endif
}
-Poly* GrTriangulator::contoursToPolys(VertexList* contours, int contourCnt, VertexList* outerMesh) {
+Poly* GrTriangulator::contoursToPolys(VertexList* contours, int contourCnt) {
const SkRect& pathBounds = fPath.getBounds();
Comparator c(pathBounds.width() > pathBounds.height() ? Comparator::Direction::kHorizontal
: Comparator::Direction::kVertical);
@@ -1962,56 +1963,56 @@
}
TESS_LOG("\nsimplified mesh:\n");
DUMP_MESH(mesh);
- return this->tessellate(mesh, outerMesh, c);
+ return this->tessellate(mesh, c);
}
-Poly* GrAATriangulator::tessellate(const VertexList& mesh, VertexList* outerMesh,
- const Comparator& c) {
+Poly* GrAATriangulator::tessellate(const VertexList& mesh, const Comparator& c) {
VertexList innerMesh;
- this->extractBoundaries(mesh, &innerMesh, outerMesh, c);
+ this->extractBoundaries(mesh, &innerMesh, c);
SortMesh(&innerMesh, c);
- SortMesh(outerMesh, c);
+ SortMesh(&fOuterMesh, c);
this->mergeCoincidentVertices(&innerMesh, c);
- bool was_complex = this->mergeCoincidentVertices(outerMesh, c);
+ bool was_complex = this->mergeCoincidentVertices(&fOuterMesh, c);
auto result = this->simplify(&innerMesh, c);
SkASSERT(SimplifyResult::kAbort != result);
was_complex = (SimplifyResult::kFoundSelfIntersection == result) || was_complex;
- result = this->simplify(outerMesh, c);
+ result = this->simplify(&fOuterMesh, c);
SkASSERT(SimplifyResult::kAbort != result);
was_complex = (SimplifyResult::kFoundSelfIntersection == result) || was_complex;
TESS_LOG("\ninner mesh before:\n");
DUMP_MESH(innerMesh);
TESS_LOG("\nouter mesh before:\n");
- DUMP_MESH(*outerMesh);
+ DUMP_MESH(fOuterMesh);
EventComparator eventLT(EventComparator::Op::kLessThan);
EventComparator eventGT(EventComparator::Op::kGreaterThan);
was_complex = this->collapseOverlapRegions(&innerMesh, c, eventLT) || was_complex;
- was_complex = this->collapseOverlapRegions(outerMesh, c, eventGT) || was_complex;
+ was_complex = this->collapseOverlapRegions(&fOuterMesh, c, eventGT) || was_complex;
if (was_complex) {
TESS_LOG("found complex mesh; taking slow path\n");
VertexList aaMesh;
TESS_LOG("\ninner mesh after:\n");
DUMP_MESH(innerMesh);
TESS_LOG("\nouter mesh after:\n");
- DUMP_MESH(*outerMesh);
- this->connectPartners(outerMesh, c);
+ DUMP_MESH(fOuterMesh);
+ this->connectPartners(&fOuterMesh, c);
this->connectPartners(&innerMesh, c);
- sorted_merge(&innerMesh, outerMesh, &aaMesh, c);
+ sorted_merge(&innerMesh, &fOuterMesh, &aaMesh, c);
this->mergeCoincidentVertices(&aaMesh, c);
result = this->simplify(&aaMesh, c);
SkASSERT(SimplifyResult::kAbort != result);
TESS_LOG("combined and simplified mesh:\n");
DUMP_MESH(aaMesh);
- outerMesh->fHead = outerMesh->fTail = nullptr;
- return this->GrTriangulator::tessellate(aaMesh, outerMesh, c);
+ fOuterMesh.fHead = fOuterMesh.fTail = nullptr;
+ return this->GrTriangulator::tessellate(aaMesh, c);
} else {
TESS_LOG("no complex polygons; taking fast path\n");
- return this->GrTriangulator::tessellate(innerMesh, outerMesh, c);
+ return this->GrTriangulator::tessellate(innerMesh, c);
}
}
// Stage 6: Triangulate the monotone polygons into a vertex buffer.
-void* GrTriangulator::polysToTriangles(Poly* polys, void* data, SkPathFillType overrideFillType) {
+void* GrTriangulator::polysToTrianglesImpl(Poly* polys, void* data,
+ SkPathFillType overrideFillType) {
for (Poly* poly = polys; poly; poly = poly->fNext) {
if (apply_fill_type(overrideFillType, poly)) {
data = this->emitPoly(poly, data);
@@ -2020,15 +2021,14 @@
return data;
}
-Poly* GrTriangulator::pathToPolys(float tolerance, const SkRect& clipBounds, int contourCnt,
- VertexList* outerMesh) {
+Poly* GrTriangulator::pathToPolys(float tolerance, const SkRect& clipBounds, int contourCnt) {
if (SkPathFillType_IsInverse(fPath.getFillType())) {
contourCnt++;
}
std::unique_ptr<VertexList[]> contours(new VertexList[contourCnt]);
this->pathToContours(tolerance, clipBounds, contours.get());
- return this->contoursToPolys(contours.get(), contourCnt, outerMesh);
+ return this->contoursToPolys(contours.get(), contourCnt);
}
static int get_contour_count(const SkPath& path, SkScalar tolerance) {
@@ -2065,19 +2065,20 @@
return contourCnt;
}
-static int64_t count_points(Poly* polys, SkPathFillType fillType) {
+int64_t GrTriangulator::countPointsImpl(Poly* polys, SkPathFillType overrideFillType) const {
int64_t count = 0;
for (Poly* poly = polys; poly; poly = poly->fNext) {
- if (apply_fill_type(fillType, poly) && poly->fCount >= 3) {
+ if (apply_fill_type(overrideFillType, poly) && poly->fCount >= 3) {
count += (poly->fCount - 2) * (TRIANGULATOR_WIREFRAME ? 6 : 3);
}
}
return count;
}
-static int64_t count_outer_mesh_points(const VertexList& outerMesh) {
- int64_t count = 0;
- for (Vertex* v = outerMesh.fHead; v; v = v->fNext) {
+int64_t GrAATriangulator::countPoints(Poly* polys) const {
+ int64_t count = this->countPointsImpl(polys, SkPathFillType::kWinding);
+ // Count the points from the outer mesh.
+ for (Vertex* v = fOuterMesh.fHead; v; v = v->fNext) {
for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
count += TRIANGULATOR_WIREFRAME ? 12 : 6;
}
@@ -2085,15 +2086,17 @@
return count;
}
-static void* outer_mesh_to_triangles(const VertexList& outerMesh, bool emitCoverage, void* data) {
- for (Vertex* v = outerMesh.fHead; v; v = v->fNext) {
+void* GrAATriangulator::polysToTriangles(Poly* polys, void* data) {
+ data = this->polysToTrianglesImpl(polys, data, SkPathFillType::kWinding);
+ // Emit the triangles from the outer mesh.
+ for (Vertex* v = fOuterMesh.fHead; v; v = v->fNext) {
for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
Vertex* v0 = e->fTop;
Vertex* v1 = e->fBottom;
Vertex* v2 = e->fBottom->fPartner;
Vertex* v3 = e->fTop->fPartner;
- data = emit_triangle(v0, v1, v2, emitCoverage, data);
- data = emit_triangle(v0, v2, v3, emitCoverage, data);
+ data = this->emitTriangle(v0, v1, v2, 0/*winding*/, data);
+ data = this->emitTriangle(v0, v2, v3, 0/*winding*/, data);
}
}
return data;
@@ -2102,19 +2105,14 @@
// Stage 6: Triangulate the monotone polygons into a vertex buffer.
int GrTriangulator::pathToTriangles(float tolerance, const SkRect& clipBounds,
- GrEagerVertexAllocator* vertexAllocator,
- SkPathFillType overrideFillType) {
+ GrEagerVertexAllocator* vertexAllocator) {
int contourCnt = get_contour_count(fPath, tolerance);
if (contourCnt <= 0) {
fIsLinear = true;
return 0;
}
- VertexList outerMesh;
- Poly* polys = this->pathToPolys(tolerance, clipBounds, contourCnt, &outerMesh);
- int64_t count64 = count_points(polys, overrideFillType);
- if (fEmitCoverage) {
- count64 += count_outer_mesh_points(outerMesh);
- }
+ Poly* polys = this->pathToPolys(tolerance, clipBounds, contourCnt);
+ int64_t count64 = this->countPoints(polys);
if (0 == count64 || count64 > SK_MaxS32) {
return 0;
}
@@ -2131,8 +2129,7 @@
}
TESS_LOG("emitting %d verts\n", count);
- void* end = this->polysToTriangles(polys, verts, overrideFillType);
- end = outer_mesh_to_triangles(outerMesh, true, end);
+ void* end = this->polysToTriangles(polys, verts);
int actualCount = static_cast<int>((static_cast<uint8_t*>(end) - static_cast<uint8_t*>(verts))
/ vertexStride);
@@ -2149,9 +2146,8 @@
return 0;
}
GrTriangulator triangulator(path);
- Poly* polys = triangulator.pathToPolys(tolerance, clipBounds, contourCnt, nullptr);
- SkPathFillType fillType = path.getFillType();
- int64_t count64 = count_points(polys, fillType);
+ Poly* polys = triangulator.pathToPolys(tolerance, clipBounds, contourCnt);
+ int64_t count64 = triangulator.countPoints(polys);
if (0 == count64 || count64 > SK_MaxS32) {
*verts = nullptr;
return 0;
@@ -2163,7 +2159,7 @@
SkPoint* points = new SkPoint[count];
SkPoint* pointsEnd = points;
for (Poly* poly = polys; poly; poly = poly->fNext) {
- if (apply_fill_type(fillType, poly)) {
+ if (apply_fill_type(path.getFillType(), poly)) {
SkPoint* start = pointsEnd;
pointsEnd = static_cast<SkPoint*>(triangulator.emitPoly(poly, pointsEnd));
while (start != pointsEnd) {
diff --git a/src/gpu/GrTriangulator.h b/src/gpu/GrTriangulator.h
index aadc572..97975c2 100644
--- a/src/gpu/GrTriangulator.h
+++ b/src/gpu/GrTriangulator.h
@@ -28,8 +28,7 @@
static int PathToTriangles(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds,
GrEagerVertexAllocator* vertexAllocator, bool* isLinear) {
GrTriangulator triangulator(path);
- int count = triangulator.pathToTriangles(tolerance, clipBounds, vertexAllocator,
- path.getFillType());
+ int count = triangulator.pathToTriangles(tolerance, clipBounds, vertexAllocator);
*isLinear = triangulator.fIsLinear;
return count;
}
@@ -40,8 +39,7 @@
GrTriangulator triangulator(path);
triangulator.fCullCollinearVertices = false;
triangulator.fSimpleInnerPolygons = true;
- int count = triangulator.pathToTriangles(0, SkRect::MakeEmpty(), vertexAllocator,
- path.getFillType());
+ int count = triangulator.pathToTriangles(0, SkRect::MakeEmpty(), vertexAllocator);
*isLinear = triangulator.fIsLinear;
return count;
}
@@ -100,10 +98,15 @@
SimplifyResult simplify(VertexList* mesh, const Comparator&);
// 5) Tessellate the simplified mesh into monotone polygons:
- virtual Poly* tessellate(const VertexList& vertices, VertexList* outerMesh, const Comparator&);
+ virtual Poly* tessellate(const VertexList& vertices, const Comparator&);
// 6) Triangulate the monotone polygons directly into a vertex buffer:
- void* polysToTriangles(Poly* polys, void* data, SkPathFillType overrideFillType);
+ virtual int64_t countPoints(Poly* polys) const {
+ return this->countPointsImpl(polys, fPath.getFillType());
+ }
+ virtual void* polysToTriangles(Poly* polys, void* data) {
+ return this->polysToTrianglesImpl(polys, data, fPath.getFillType());
+ }
// The vertex sorting in step (3) is a merge sort, since it plays well with the linked list
// of vertices (and the necessity of inserting new vertices on intersection).
@@ -172,11 +175,11 @@
void sanitizeContours(VertexList* contours, int contourCnt);
bool mergeCoincidentVertices(VertexList* mesh, const Comparator&);
void buildEdges(VertexList* contours, int contourCnt, VertexList* mesh, const Comparator&);
- Poly* contoursToPolys(VertexList* contours, int contourCnt, VertexList* outerMesh);
- Poly* pathToPolys(float tolerance, const SkRect& clipBounds, int contourCnt,
- VertexList* outerMesh);
- int pathToTriangles(float tolerance, const SkRect& clipBounds, GrEagerVertexAllocator*,
- SkPathFillType overrideFillType);
+ Poly* contoursToPolys(VertexList* contours, int contourCnt);
+ Poly* pathToPolys(float tolerance, const SkRect& clipBounds, int contourCnt);
+ int64_t countPointsImpl(Poly* polys, SkPathFillType overrideFillType) const;
+ void* polysToTrianglesImpl(Poly* polys, void* data, SkPathFillType overrideFillType);
+ int pathToTriangles(float tolerance, const SkRect& clipBounds, GrEagerVertexAllocator*);
constexpr static int kArenaChunkSize = 16 * 1024;
SkArenaAlloc fAlloc{kArenaChunkSize};
@@ -446,8 +449,7 @@
GrAATriangulator aaTriangulator(path);
aaTriangulator.fRoundVerticesToQuarterPixel = true;
aaTriangulator.fEmitCoverage = true;
- return aaTriangulator.pathToTriangles(tolerance, clipBounds, vertexAllocator,
- SkPathFillType::kWinding);
+ return aaTriangulator.pathToTriangles(tolerance, clipBounds, vertexAllocator);
}
// Structs used by GrAATriangulator internals.
@@ -479,8 +481,7 @@
// Run steps 1-5 above to produce polygons.
// 5b) Apply fill rules to extract boundary contours from the polygons:
void extractBoundary(EdgeList* boundary, Edge* e);
- void extractBoundaries(const VertexList& inMesh, VertexList* innerVertices,
- VertexList* outerMesh, const Comparator&);
+ void extractBoundaries(const VertexList& inMesh, VertexList* innerVertices, const Comparator&);
// 5c) Simplify boundaries to remove "pointy" vertices that cause inversions:
void simplifyBoundary(EdgeList* boundary, const Comparator&);
@@ -488,11 +489,12 @@
// 5d) Displace edges by half a pixel inward and outward along their normals. Intersect to find
// new vertices, and set zero alpha on the exterior and one alpha on the interior. Build a
// new antialiased mesh from those vertices:
- void strokeBoundary(EdgeList* boundary, VertexList* innerMesh, VertexList* outerMesh,
- const Comparator&);
+ void strokeBoundary(EdgeList* boundary, VertexList* innerMesh, const Comparator&);
// Run steps 3-6 above on the new mesh, and produce antialiased triangles.
- Poly* tessellate(const VertexList& mesh, VertexList* outerMesh, const Comparator&) override;
+ Poly* tessellate(const VertexList& mesh, const Comparator&) override;
+ int64_t countPoints(Poly* polys) const override;
+ void* polysToTriangles(Poly* polys, void* data) override;
// Additional helpers and driver functions.
void makeEvent(SSEdge*, EventList* events);
@@ -502,6 +504,8 @@
void removeNonBoundaryEdges(const VertexList& mesh);
void connectSSEdge(Vertex* v, Vertex* dest, const Comparator&);
bool collapseOverlapRegions(VertexList* mesh, const Comparator&, EventComparator comp);
+
+ VertexList fOuterMesh;
};
#endif