Revert "Quality and performance fixes for AA tessellating path renderer."

This reverts commit d4b2155248.

Reason for revert: accidentally added some unwanted changes

Original change's description:
> Quality and performance fixes for AA tessellating path renderer.
> 
> Use quads rather than triangles for the edge geometry. This allows
> us to perform a simpler edge categorization (see below). It also
> improves performance by reducing the number of edges processed during
> the simplify and tessellate steps.
> 
> Label AA edges as three types: inner, outer, and connector. This
> results in correct alpha values for intersected edges, even when
> the top or bottom vertex has been merged with a vertex on edges
> of different types.
> 
> Changed the "collinear edges" sample from the concavepaths GM for a
> "fast-foward" shape, which more clearly shows the problem being fixed
> here. (The collinearity from the "collinear edges" was actually being
> removed earlier up the stack, causing the path to become convex and
> not exercise the concave path renderers anyway.)
> 
> NOTE: this will cause changes in the "concavepaths" GM results, and
> minor pixel diffs in a number of other tests.
> 
> BUG=660893
> 
> Change-Id: Ide49374d6d173404c7223f7316dd439df1435787
> Reviewed-on: https://skia-review.googlesource.com/6427
> Commit-Queue: Stephan White <senorblanco@chromium.org>
> Reviewed-by: Brian Salomon <bsalomon@google.com>
> 

TBR=bsalomon@google.com,senorblanco@chromium.org,reviews@skia.org
BUG=660893
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true

Change-Id: I06a36e397645bfc42442a5a9e7c27328f6048ab9
Reviewed-on: https://skia-review.googlesource.com/6428
Commit-Queue: Stephan White <senorblanco@chromium.org>
Reviewed-by: Stephan White <senorblanco@chromium.org>
This commit is contained in:
Stephan White 2017-01-03 21:06:16 +00:00 committed by Skia Commit-Bot
parent d4b2155248
commit 021f927e4c
4 changed files with 48 additions and 67 deletions

View File

@ -80,18 +80,15 @@ void test_fish(SkCanvas* canvas, const SkPaint& paint) {
canvas->restore(); canvas->restore();
} }
// Overlapping "Fast-forward" icon: tests coincidence of inner and outer // Collinear edges
// vertices generated by intersection. void test_collinear_edges(SkCanvas* canvas, const SkPaint& paint) {
void test_fast_forward(SkCanvas* canvas, const SkPaint& paint) {
SkPath path; SkPath path;
canvas->save(); canvas->save();
canvas->translate(100, 100); canvas->translate(100, 100);
path.moveTo(SkIntToScalar(20), SkIntToScalar(20)); path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
path.lineTo(SkIntToScalar(60), SkIntToScalar(50)); path.lineTo(SkIntToScalar(50), SkIntToScalar(20));
path.lineTo(SkIntToScalar(20), SkIntToScalar(80)); path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
path.moveTo(SkIntToScalar(40), SkIntToScalar(20)); path.lineTo(SkIntToScalar(50), SkIntToScalar(80));
path.lineTo(SkIntToScalar(40), SkIntToScalar(80));
path.lineTo(SkIntToScalar(80), SkIntToScalar(50));
canvas->drawPath(path, paint); canvas->drawPath(path, paint);
canvas->restore(); canvas->restore();
} }
@ -387,7 +384,7 @@ protected:
test_bowtie(canvas, paint); test_bowtie(canvas, paint);
test_fake_bowtie(canvas, paint); test_fake_bowtie(canvas, paint);
test_fish(canvas, paint); test_fish(canvas, paint);
test_fast_forward(canvas, paint); test_collinear_edges(canvas, paint);
test_hole(canvas, paint); test_hole(canvas, paint);
test_star(canvas, paint); test_star(canvas, paint);
test_stairstep(canvas, paint); test_stairstep(canvas, paint);

View File

@ -35,9 +35,9 @@ GrPathRendererChain::GrPathRendererChain(GrContext* context, const Options& opti
this->addPathRenderer(pr)->unref(); this->addPathRenderer(pr)->unref();
} }
#ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK #ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
// if (caps.sampleShadingSupport()) { if (caps.sampleShadingSupport()) {
// this->addPathRenderer(new GrMSAAPathRenderer)->unref(); this->addPathRenderer(new GrMSAAPathRenderer)->unref();
// } }
#endif #endif
this->addPathRenderer(new GrAAHairLinePathRenderer)->unref(); this->addPathRenderer(new GrAAHairLinePathRenderer)->unref();
this->addPathRenderer(new GrAAConvexPathRenderer)->unref(); this->addPathRenderer(new GrAAConvexPathRenderer)->unref();
@ -45,9 +45,9 @@ GrPathRendererChain::GrPathRendererChain(GrContext* context, const Options& opti
if (caps.shaderCaps()->plsPathRenderingSupport()) { if (caps.shaderCaps()->plsPathRenderingSupport()) {
this->addPathRenderer(new GrPLSPathRenderer)->unref(); this->addPathRenderer(new GrPLSPathRenderer)->unref();
} }
// if (!options.fDisableDistanceFieldRenderer) { if (!options.fDisableDistanceFieldRenderer) {
// this->addPathRenderer(new GrAADistanceFieldPathRenderer)->unref(); this->addPathRenderer(new GrAADistanceFieldPathRenderer)->unref();
// } }
this->addPathRenderer(new GrTessellatingPathRenderer)->unref(); this->addPathRenderer(new GrTessellatingPathRenderer)->unref();
this->addPathRenderer(new GrDefaultPathRenderer(caps.twoSidedStencilSupport(), this->addPathRenderer(new GrDefaultPathRenderer(caps.twoSidedStencilSupport(),
caps.stencilWrapOpsSupport()))->unref(); caps.stencilWrapOpsSupport()))->unref();

View File

@ -309,12 +309,10 @@ struct Line {
*/ */
struct Edge { struct Edge {
enum class Type { kInner, kOuter, kConnector }; Edge(Vertex* top, Vertex* bottom, int winding)
Edge(Vertex* top, Vertex* bottom, int winding, Type type)
: fWinding(winding) : fWinding(winding)
, fTop(top) , fTop(top)
, fBottom(bottom) , fBottom(bottom)
, fType(type)
, fLeft(nullptr) , fLeft(nullptr)
, fRight(nullptr) , fRight(nullptr)
, fPrevEdgeAbove(nullptr) , fPrevEdgeAbove(nullptr)
@ -334,7 +332,6 @@ struct Edge {
int fWinding; // 1 == edge goes downward; -1 = edge goes upward. int fWinding; // 1 == edge goes downward; -1 = edge goes upward.
Vertex* fTop; // The top vertex in vertex-sort-order (sweep_lt). Vertex* fTop; // The top vertex in vertex-sort-order (sweep_lt).
Vertex* fBottom; // The bottom vertex in vertex-sort-order. Vertex* fBottom; // The bottom vertex in vertex-sort-order.
Type fType;
Edge* fLeft; // The linked list of edges in the active edge list. Edge* fLeft; // The linked list of edges in the active edge list.
Edge* fRight; // " Edge* fRight; // "
Edge* fPrevEdgeAbove; // The linked list of edges in the bottom Vertex's "edges above". Edge* fPrevEdgeAbove; // The linked list of edges in the bottom Vertex's "edges above".
@ -534,8 +531,7 @@ struct Poly {
fTail->addEdge(e); fTail->addEdge(e);
fCount++; fCount++;
} else { } else {
e = ALLOC_NEW(Edge, (fTail->fLastEdge->fBottom, e->fBottom, 1, Edge::Type::kInner), e = ALLOC_NEW(Edge, (fTail->fLastEdge->fBottom, e->fBottom, 1), alloc);
alloc);
fTail->addEdge(e); fTail->addEdge(e);
fCount++; fCount++;
if (partner) { if (partner) {
@ -771,11 +767,12 @@ inline bool apply_fill_type(SkPath::FillType fillType, Poly* poly) {
} }
} }
Edge* new_edge(Vertex* prev, Vertex* next, SkChunkAlloc& alloc, Comparator& c, Edge::Type type) { Edge* new_edge(Vertex* prev, Vertex* next, SkChunkAlloc& alloc, Comparator& c,
int winding = c.sweep_lt(prev->fPoint, next->fPoint) ? 1 : -1; int winding_scale = 1) {
int winding = c.sweep_lt(prev->fPoint, next->fPoint) ? winding_scale : -winding_scale;
Vertex* top = winding < 0 ? next : prev; Vertex* top = winding < 0 ? next : prev;
Vertex* bottom = winding < 0 ? prev : next; Vertex* bottom = winding < 0 ? prev : next;
return ALLOC_NEW(Edge, (top, bottom, winding, type), alloc); return ALLOC_NEW(Edge, (top, bottom, winding), alloc);
} }
void remove_edge(Edge* edge, EdgeList* edges) { void remove_edge(Edge* edge, EdgeList* edges) {
@ -828,10 +825,7 @@ void find_enclosing_edges(Edge* edge, EdgeList* edges, Comparator& c, Edge** lef
} }
void fix_active_state(Edge* edge, EdgeList* activeEdges, Comparator& c) { void fix_active_state(Edge* edge, EdgeList* activeEdges, Comparator& c) {
if (!activeEdges) { if (activeEdges && activeEdges->contains(edge)) {
return;
}
if (activeEdges->contains(edge)) {
if (edge->fBottom->fProcessed || !edge->fTop->fProcessed) { if (edge->fBottom->fProcessed || !edge->fTop->fProcessed) {
remove_edge(edge, activeEdges); remove_edge(edge, activeEdges);
} }
@ -1027,7 +1021,7 @@ void split_edge(Edge* edge, Vertex* v, EdgeList* activeEdges, Comparator& c, SkC
} else if (c.sweep_gt(v->fPoint, edge->fBottom->fPoint)) { } else if (c.sweep_gt(v->fPoint, edge->fBottom->fPoint)) {
set_bottom(edge, v, activeEdges, c); set_bottom(edge, v, activeEdges, c);
} else { } else {
Edge* newEdge = ALLOC_NEW(Edge, (v, edge->fBottom, edge->fWinding, edge->fType), alloc); Edge* newEdge = ALLOC_NEW(Edge, (v, edge->fBottom, edge->fWinding), alloc);
insert_edge_below(newEdge, v, c); insert_edge_below(newEdge, v, c);
insert_edge_above(newEdge, edge->fBottom, c); insert_edge_above(newEdge, edge->fBottom, c);
set_bottom(edge, v, activeEdges, c); set_bottom(edge, v, activeEdges, c);
@ -1037,8 +1031,9 @@ void split_edge(Edge* edge, Vertex* v, EdgeList* activeEdges, Comparator& c, SkC
} }
} }
Edge* connect(Vertex* prev, Vertex* next, SkChunkAlloc& alloc, Comparator c, Edge::Type type) { Edge* connect(Vertex* prev, Vertex* next, SkChunkAlloc& alloc, Comparator c,
Edge* edge = new_edge(prev, next, alloc, c, type); int winding_scale = 1) {
Edge* edge = new_edge(prev, next, alloc, c, winding_scale);
if (edge->fWinding > 0) { if (edge->fWinding > 0) {
insert_edge_below(edge, prev, c); insert_edge_below(edge, prev, c);
insert_edge_above(edge, next, c); insert_edge_above(edge, next, c);
@ -1068,14 +1063,8 @@ void merge_vertices(Vertex* src, Vertex* dst, Vertex** head, Comparator& c, SkCh
} }
uint8_t max_edge_alpha(Edge* a, Edge* b) { uint8_t max_edge_alpha(Edge* a, Edge* b) {
if (a->fType == Edge::Type::kInner && b->fType == Edge::Type::kInner) { return SkTMax(SkTMax(a->fTop->fAlpha, a->fBottom->fAlpha),
return 255; SkTMax(b->fTop->fAlpha, b->fBottom->fAlpha));
} else if (a->fType == Edge::Type::kOuter && b->fType == Edge::Type::kOuter) {
return 0;
} else {
return SkTMax(SkTMax(a->fTop->fAlpha, a->fBottom->fAlpha),
SkTMax(b->fTop->fAlpha, b->fBottom->fAlpha));
}
} }
Vertex* check_for_intersection(Edge* edge, Edge* other, EdgeList* activeEdges, Comparator& c, Vertex* check_for_intersection(Edge* edge, Edge* other, EdgeList* activeEdges, Comparator& c,
@ -1180,7 +1169,7 @@ Vertex* build_edges(Vertex** contours, int contourCnt, Comparator& c, SkChunkAll
for (int i = 0; i < contourCnt; ++i) { for (int i = 0; i < contourCnt; ++i) {
for (Vertex* v = contours[i]; v != nullptr;) { for (Vertex* v = contours[i]; v != nullptr;) {
Vertex* vNext = v->fNext; Vertex* vNext = v->fNext;
connect(v->fPrev, v, alloc, c, Edge::Type::kInner); connect(v->fPrev, v, alloc, c);
if (prev) { if (prev) {
prev->fNext = v; prev->fNext = v;
v->fPrev = prev; v->fPrev = prev;
@ -1306,8 +1295,8 @@ void simplify(Vertex* vertices, Comparator& c, SkChunkAlloc& alloc) {
} }
} while (restartChecks); } while (restartChecks);
if (v->fAlpha == 0) { if (v->fAlpha == 0) {
if ((leftEnclosingEdge && leftEnclosingEdge->fWinding > 0) && if ((leftEnclosingEdge && leftEnclosingEdge->fWinding < 0) &&
(rightEnclosingEdge && rightEnclosingEdge->fWinding < 0)) { (rightEnclosingEdge && rightEnclosingEdge->fWinding > 0)) {
v->fAlpha = max_edge_alpha(leftEnclosingEdge, rightEnclosingEdge); v->fAlpha = max_edge_alpha(leftEnclosingEdge, rightEnclosingEdge);
} }
} }
@ -1402,8 +1391,7 @@ Poly* tessellate(Vertex* vertices, SkChunkAlloc& alloc) {
rightEnclosingEdge->fLeftPoly = rightPoly; rightEnclosingEdge->fLeftPoly = rightPoly;
} }
} }
Edge* join = ALLOC_NEW(Edge, Edge* join = ALLOC_NEW(Edge, (leftPoly->lastVertex(), v, 1), alloc);
(leftPoly->lastVertex(), v, 1, Edge::Type::kInner), alloc);
leftPoly = leftPoly->addEdge(join, Poly::kRight_Side, alloc); leftPoly = leftPoly->addEdge(join, Poly::kRight_Side, alloc);
rightPoly = rightPoly->addEdge(join, Poly::kLeft_Side, alloc); rightPoly = rightPoly->addEdge(join, Poly::kLeft_Side, alloc);
} }
@ -1481,7 +1469,7 @@ void simplify_boundary(EdgeList* boundary, Comparator& c, SkChunkAlloc& alloc) {
get_edge_normal(e, &normal); get_edge_normal(e, &normal);
float denom = 0.25f * static_cast<float>(e->fLine.magSq()); float denom = 0.25f * static_cast<float>(e->fLine.magSq());
if (prevNormal.dot(normal) < 0.0 && (dist * dist) <= denom) { if (prevNormal.dot(normal) < 0.0 && (dist * dist) <= denom) {
Edge* join = new_edge(prev, next, alloc, c, Edge::Type::kInner); Edge* join = new_edge(prev, next, alloc, c);
insert_edge(join, e, boundary); insert_edge(join, e, boundary);
remove_edge(prevEdge, boundary); remove_edge(prevEdge, boundary);
remove_edge(e, boundary); remove_edge(e, boundary);
@ -1529,8 +1517,8 @@ void boundary_to_aa_mesh(EdgeList* boundary, VertexList* mesh, Comparator& c, Sk
Vertex* innerVertex = ALLOC_NEW(Vertex, (innerPoint, 255), alloc); Vertex* innerVertex = ALLOC_NEW(Vertex, (innerPoint, 255), alloc);
Vertex* outerVertex = ALLOC_NEW(Vertex, (outerPoint, 0), alloc); Vertex* outerVertex = ALLOC_NEW(Vertex, (outerPoint, 0), alloc);
if (innerVertices.fTail && outerVertices.fTail) { if (innerVertices.fTail && outerVertices.fTail) {
Edge innerEdge(innerVertices.fTail, innerVertex, 1, Edge::Type::kInner); Edge innerEdge(innerVertices.fTail, innerVertex, 1);
Edge outerEdge(outerVertices.fTail, outerVertex, 1, Edge::Type::kInner); Edge outerEdge(outerVertices.fTail, outerVertex, 1);
SkVector innerNormal; SkVector innerNormal;
get_edge_normal(&innerEdge, &innerNormal); get_edge_normal(&innerEdge, &innerNormal);
SkVector outerNormal; SkVector outerNormal;
@ -1572,9 +1560,10 @@ void boundary_to_aa_mesh(EdgeList* boundary, VertexList* mesh, Comparator& c, Sk
return; return;
} }
do { do {
connect(outerVertex->fPrev, outerVertex, alloc, c, Edge::Type::kOuter); connect(outerVertex->fNext, outerVertex, alloc, c);
connect(innerVertex->fPrev, innerVertex, alloc, c, Edge::Type::kInner); connect(innerVertex->fNext, innerVertex, alloc, c, 2);
connect(outerVertex, innerVertex, alloc, c, Edge::Type::kConnector)->fWinding = 0; connect(innerVertex, outerVertex->fNext, alloc, c, 2);
connect(outerVertex, innerVertex, alloc, c, 2);
Vertex* innerNext = innerVertex->fNext; Vertex* innerNext = innerVertex->fNext;
Vertex* outerNext = outerVertex->fNext; Vertex* outerNext = outerVertex->fNext;
mesh->append(innerVertex); mesh->append(innerVertex);
@ -1648,9 +1637,9 @@ Vertex* contours_to_mesh(Vertex** contours, int contourCnt, bool antialias,
return build_edges(contours, contourCnt, c, alloc); return build_edges(contours, contourCnt, c, alloc);
} }
void sort_and_simplify(Vertex** vertices, Comparator& c, SkChunkAlloc& alloc) { Poly* mesh_to_polys(Vertex** vertices, Comparator& c, SkChunkAlloc& alloc) {
if (!vertices || !*vertices) { if (!vertices || !*vertices) {
return; return nullptr;
} }
// Sort vertices in Y (secondarily in X). // Sort vertices in Y (secondarily in X).
@ -1663,10 +1652,6 @@ void sort_and_simplify(Vertex** vertices, Comparator& c, SkChunkAlloc& alloc) {
} }
#endif #endif
simplify(*vertices, c, alloc); simplify(*vertices, c, alloc);
}
Poly* mesh_to_polys(Vertex** vertices, Comparator& c, SkChunkAlloc& alloc) {
sort_and_simplify(vertices, c, alloc);
return tessellate(*vertices, alloc); return tessellate(*vertices, alloc);
} }
@ -1692,8 +1677,7 @@ Poly* contours_to_polys(Vertex** contours, int contourCnt, SkPath::FillType fill
boundary_to_aa_mesh(boundary, &aaMesh, c, alloc); boundary_to_aa_mesh(boundary, &aaMesh, c, alloc);
} }
} }
sort_and_simplify(&aaMesh.fHead, c, alloc); return mesh_to_polys(&aaMesh.fHead, c, alloc);
return tessellate(aaMesh.fHead, alloc);
} }
return polys; return polys;
} }

View File

@ -141,15 +141,15 @@ bool GrTessellatingPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) cons
return false; return false;
} }
if (GrAAType::kCoverage == args.fAAType) { if (GrAAType::kCoverage == args.fAAType) {
//#ifdef SK_DISABLE_SCREENSPACE_TESS_AA_PATH_RENDERER #ifdef SK_DISABLE_SCREENSPACE_TESS_AA_PATH_RENDERER
// return false; return false;
//#else #else
// SkPath path; SkPath path;
// args.fShape->asPath(&path); args.fShape->asPath(&path);
// if (path.countVerbs() > 10) { if (path.countVerbs() > 10) {
// return false; return false;
// } }
//#endif #endif
} else if (!args.fShape->hasUnstyledKey()) { } else if (!args.fShape->hasUnstyledKey()) {
return false; return false;
} }