Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(156)

Unified Diff: src/core/SkScan_Path.cpp

Issue 692583002: WIP: GPU-accelerated trapezoidal path renderer. Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Rename GrTrapezoidalPathRenderer -> GrAAConcavePathRenderer; swap MSAA support for a coverage ramp. Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/core/SkScan_AntiPath.cpp ('k') | src/core/SkStroke.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/core/SkScan_Path.cpp
diff --git a/src/core/SkScan_Path.cpp b/src/core/SkScan_Path.cpp
index fc79fc8537d08fdbff306ee801a2fa66a5a9a6a2..dbe61e13d207e55376140c69fae7e300125dcea3 100644
--- a/src/core/SkScan_Path.cpp
+++ b/src/core/SkScan_Path.cpp
@@ -14,9 +14,14 @@
#include "SkQuadClipper.h"
#include "SkRasterClip.h"
#include "SkRegion.h"
+#include "SkStroke.h"
#include "SkTemplates.h"
#include "SkTSort.h"
+#include <stdio.h> // FIXME
+
+static bool dumping;
+
#define kEDGE_HEAD_Y SK_MinS32
#define kEDGE_TAIL_Y SK_MaxS32
@@ -48,6 +53,105 @@ static inline void insert_edge_after(SkEdge* edge, SkEdge* afterMe) {
afterMe->fNext = edge;
}
+static void emit_wireframe_triangle(SkPoint t[3], SkTDArray<SkPoint>* points) {
+ SkPoint *p = points->append(6);
+ p[0] = t[0];
+ p[1] = t[1];
+ p[2] = t[1];
+ p[3] = t[2];
+ p[4] = t[2];
+ p[5] = t[0];
+}
+
+static void emit_trapezoid(SkEdge* left, SkEdge* right, float top, float bottom, SkTDArray<SkPoint>* points)
+{
+ // If this edge was already neutered by its partner, don't emit.
+ if (top > bottom) {
+ return;
+ }
+
+ if (!left || !right) {
+ return;
+ }
+
+ float top_left = left->fFirstXf;
+ float top_right = right->fFirstXf;
+ float bottom_left = left->fFirstXf + SkFixedToFloat(left->fDX * (bottom - top));
+ float bottom_right = right->fFirstXf + SkFixedToFloat(right->fDX * (bottom - top));
+ if (dumping) {
+ printf("top %g bot %g tl %g tr %g bl %g br %g\n",
+ top, bottom, left->fFirstXf, right->fFirstXf, bottom_left, bottom_right);
+ }
+ if (SkScan::gWireframe) {
+ if (top_left == top_right) {
+ SkPoint p[3];
+ p[0] = SkPoint::Make(top_right, top);
+ p[1] = SkPoint::Make(bottom_right, bottom);
+ p[2] = SkPoint::Make(bottom_left , bottom);
+ emit_wireframe_triangle(p, points);
+ } else if (bottom_left == bottom_right) {
+ SkPoint p[3];
+ p[0] = SkPoint::Make(top_left, top);
+ p[1] = SkPoint::Make(top_right, top);
+ p[2] = SkPoint::Make(bottom_left, bottom);
+ emit_wireframe_triangle(p, points);
+ } else {
+ SkPoint p[3];
+ p[0] = SkPoint::Make(top_left, top);
+ p[1] = SkPoint::Make(top_right, top);
+ p[2] = SkPoint::Make(bottom_left , bottom);
+ emit_wireframe_triangle(p, points);
+ p[0] = SkPoint::Make(top_right, top);
+ p[1] = SkPoint::Make(bottom_right, bottom);
+ p[2] = SkPoint::Make(bottom_left , bottom);
+ emit_wireframe_triangle(p, points);
+ }
+ } else {
+ if (top_left == top_right) {
+ SkPoint *p = points->append(3);
+ p[0] = SkPoint::Make(top_right, top);
+ p[1] = SkPoint::Make(bottom_right, bottom);
+ p[2] = SkPoint::Make(bottom_left , bottom);
+ } else if (bottom_left == bottom_right) {
+ SkPoint *p = points->append(3);
+ p[0] = SkPoint::Make(top_left, top);
+ p[1] = SkPoint::Make(top_right, top);
+ p[2] = SkPoint::Make(bottom_left, bottom);
+ } else {
+ SkPoint *p = points->append(6);
+ p[0] = SkPoint::Make(top_left, top);
+ p[1] = SkPoint::Make(top_right, top);
+ p[2] = SkPoint::Make(bottom_left , bottom);
+ p[3] = SkPoint::Make(top_right, top);
+ p[4] = SkPoint::Make(bottom_right, bottom);
+ p[5] = SkPoint::Make(bottom_left , bottom);
+ }
+ }
+ left->fFirstXf = bottom_left;
+ left->fFirstYf = bottom;
+ right->fFirstXf = bottom_right;
+ right->fFirstYf = bottom;
+}
+
+static void emit_all_trapezoids(SkEdge* start, int windingMask, int curr_y, SkTDArray<SkPoint>* points)
+{
+ int w = 0;
+ SkEdge* left = NULL;
+ for (SkEdge* edge = start; edge != NULL && edge->fFirstY < curr_y && edge->fFirstYf < curr_y; edge = edge->fNext) {
+ w += edge->fWinding;
+ if ((w & windingMask) == 0) {
+ SkASSERT(left);
+ emit_trapezoid(left, edge, left->fFirstYf, curr_y, points);
+ left = NULL;
+ } else if (!left) {
+ left = edge;
+ } else {
+ edge->fFirstXf += SkFixedToFloat(edge->fDX * (curr_y - edge->fFirstYf));
+ edge->fFirstYf = (float) curr_y;
+ }
+ }
+}
+
static void backward_insert_edge_based_on_x(SkEdge* edge SkDECLAREPARAM(int, curr_y)) {
SkFixed x = edge->fX;
@@ -97,8 +201,8 @@ typedef void (*PrePostProc)(SkBlitter* blitter, int y, bool isStartOfScanline);
#define PREPOST_END false
static void walk_edges(SkEdge* prevHead, SkPath::FillType fillType,
- SkBlitter* blitter, int start_y, int stop_y,
- PrePostProc proc, int rightClip) {
+ SkBlitter* blitter, SkTDArray<SkPoint>* points,
+ int start_y, int stop_y, PrePostProc proc, int rightClip) {
validate_sort(prevHead->fNext);
int curr_y = start_y;
@@ -114,7 +218,7 @@ static void walk_edges(SkEdge* prevHead, SkPath::FillType fillType,
validate_edges_for_y(currE, curr_y);
- if (proc) {
+ if (proc && blitter) {
proc(blitter, curr_y, PREPOST_START); // pre-proc
}
@@ -127,8 +231,11 @@ static void walk_edges(SkEdge* prevHead, SkPath::FillType fillType,
SkASSERT(in_interval);
int width = x - left;
SkASSERT(width >= 0);
- if (width)
- blitter->blitH(left, curr_y, width);
+ if (width) {
+ if (blitter) {
+ blitter->blitH(left, curr_y, width);
+ }
+ }
in_interval = false;
} else if (!in_interval) {
left = x;
@@ -139,6 +246,7 @@ static void walk_edges(SkEdge* prevHead, SkPath::FillType fillType,
SkFixed newX;
if (currE->fLastY == curr_y) { // are we done with this edge?
+ if (points) emit_all_trapezoids(prevHead->fNext, windingMask, curr_y + 1, points);
if (currE->fCurveCount < 0) {
if (((SkCubicEdge*)currE)->updateCubic()) {
SkASSERT(currE->fFirstY == curr_y + 1);
@@ -159,6 +267,7 @@ static void walk_edges(SkEdge* prevHead, SkPath::FillType fillType,
currE->fX = newX;
NEXT_X:
if (newX < prevX) { // ripple currE backwards until it is x-sorted
+ if (points) emit_all_trapezoids(prevHead->fNext, windingMask, curr_y + 1, points);
backward_insert_edge_based_on_x(currE SkPARAM(curr_y));
} else {
prevX = newX;
@@ -169,14 +278,14 @@ static void walk_edges(SkEdge* prevHead, SkPath::FillType fillType,
}
// was our right-edge culled away?
- if (in_interval) {
+ if (in_interval && blitter) {
int width = rightClip - left;
if (width > 0) {
blitter->blitH(left, curr_y, width);
}
}
- if (proc) {
+ if (proc && blitter) {
proc(blitter, curr_y, PREPOST_END); // post-proc
}
@@ -184,6 +293,9 @@ static void walk_edges(SkEdge* prevHead, SkPath::FillType fillType,
if (curr_y >= stop_y) {
break;
}
+ if (points && currE->fFirstY == curr_y) {
+ emit_all_trapezoids(prevHead->fNext, windingMask, curr_y, points);
+ }
// now currE points to the first edge with a Yint larger than curr_y
insert_new_edges(currE, curr_y);
}
@@ -210,7 +322,8 @@ static bool update_edge(SkEdge* edge, int last_y) {
}
static void walk_convex_edges(SkEdge* prevHead, SkPath::FillType,
- SkBlitter* blitter, int start_y, int stop_y,
+ SkBlitter* blitter, SkTDArray<SkPoint>* points,
+ int start_y, int stop_y,
PrePostProc proc) {
validate_sort(prevHead->fNext);
@@ -247,12 +360,22 @@ static void walk_convex_edges(SkEdge* prevHead, SkPath::FillType,
SkFixed dRite = riteE->fDX;
int count = local_bot - local_top;
SkASSERT(count >= 0);
- if (0 == (dLeft | dRite)) {
+ if (points) {
+ emit_trapezoid(leftE, riteE, (float) local_top, (float) (local_bot + 1), points);
+ if (left < rite) {
+ count += 1;
+ left += count * dLeft;
+ rite += count * dRite;
+ }
+ local_top = local_bot + 1;
+ } else if (0 == (dLeft | dRite)) {
int L = SkFixedRoundToInt(left);
int R = SkFixedRoundToInt(rite);
if (L < R) {
count += 1;
blitter->blitRect(L, local_top, R - L, count);
+ left += count * dLeft;
+ rite += count * dRite;
}
local_top = local_bot + 1;
} else {
@@ -394,14 +517,16 @@ static SkEdge* sort_edges(SkEdge* list[], int count, SkEdge** last) {
//
// clipRect (if no null) has already been shifted up
//
-void sk_fill_path(const SkPath& path, const SkIRect* clipRect, SkBlitter* blitter,
- int start_y, int stop_y, int shiftEdgesUp, const SkRegion& clipRgn) {
- SkASSERT(blitter);
+void sk_fill_path(const SkPath& path, const SkIRect* clipRect,
+ SkBlitter* blitter, SkTDArray<SkPoint>* points,
+ int start_y, int stop_y, int shiftEdgesUp,
+ const SkRegion& clipRgn) {
+ SkASSERT(blitter || points);
SkEdgeBuilder builder;
// If we're convex, then we need both edges, even the right edge is past the clip
- const bool canCullToTheRight = !path.isConvex();
+ const bool canCullToTheRight = !path.isConvex() && !points;
int count = builder.build(path, clipRect, shiftEdgesUp, canCullToTheRight);
SkASSERT(count >= 0);
@@ -424,18 +549,32 @@ void sk_fill_path(const SkPath& path, const SkIRect* clipRect, SkBlitter* blitte
rect.fBottom = stop_y;
}
if (!rect.isEmpty()) {
- blitter->blitRect(rect.fLeft << shiftEdgesUp,
- rect.fTop << shiftEdgesUp,
- rect.width() << shiftEdgesUp,
- rect.height() << shiftEdgesUp);
+ if (blitter) {
+ blitter->blitRect(rect.fLeft << shiftEdgesUp,
+ rect.fTop << shiftEdgesUp,
+ rect.width() << shiftEdgesUp,
+ rect.height() << shiftEdgesUp);
+ } else {
+ SkRect r = SkRect::Make(rect);
+ r.toQuad(points->append(4));
+ }
}
}
+
return;
}
SkEdge headEdge, tailEdge, *last;
// this returns the first and last edge after they're sorted into a dlink list
SkEdge* edge = sort_edges(list, count, &last);
+ if (dumping) {
+ printf("sorted into %d edges:\n", count);
+ SkEdge* e = edge;
+ for (int i = 0; i < count; i++) {
+ printf("edge %p fFirstXf %g fFirstYf %g fLastY %d fDX %g\n", e, e->fFirstXf, e->fFirstYf, e->fLastY, e->fDX / 65536.0);
+ e = e->fNext;
+ }
+ }
headEdge.fPrev = nullptr;
headEdge.fNext = edge;
@@ -462,15 +601,15 @@ void sk_fill_path(const SkPath& path, const SkIRect* clipRect, SkBlitter* blitte
InverseBlitter ib;
PrePostProc proc = nullptr;
- if (path.isInverseFillType()) {
+ if (path.isInverseFillType() && blitter) {
ib.setBlitter(blitter, clipRgn.getBounds(), shiftEdgesUp);
blitter = &ib;
proc = PrePostInverseBlitterProc;
}
- if (path.isConvex() && (nullptr == proc)) {
+ if (path.isConvex() && (nullptr == proc) && blitter) {
SkASSERT(count >= 2); // convex walker does not handle missing right edges
- walk_convex_edges(&headEdge, path.getFillType(), blitter, start_y, stop_y, nullptr);
+ walk_convex_edges(&headEdge, path.getFillType(), blitter, points, start_y, stop_y, NULL);
} else {
int rightEdge;
if (clipRect) {
@@ -478,8 +617,8 @@ void sk_fill_path(const SkPath& path, const SkIRect* clipRect, SkBlitter* blitte
} else {
rightEdge = SkScalarRoundToInt(path.getBounds().right()) << shiftEdgesUp;
}
-
- walk_edges(&headEdge, path.getFillType(), blitter, start_y, stop_y, proc, rightEdge);
+
+ walk_edges(&headEdge, path.getFillType(), blitter, points, start_y, stop_y, proc, rightEdge);
}
}
@@ -599,7 +738,7 @@ void SkScan::FillPath(const SkPath& path, const SkRegion& origClip,
if (path.isInverseFillType()) {
sk_blit_above(blitter, ir, *clipPtr);
}
- sk_fill_path(path, clipper.getClipRect(), blitter, ir.fTop, ir.fBottom,
+ sk_fill_path(path, clipper.getClipRect(), blitter, NULL, ir.fTop, ir.fBottom,
0, *clipPtr);
if (path.isInverseFillType()) {
sk_blit_below(blitter, ir, *clipPtr);
@@ -673,8 +812,8 @@ static void sk_fill_triangle(const SkPoint pts[], const SkIRect* clipRect,
if (clipRect && start_y < clipRect->fTop) {
start_y = clipRect->fTop;
}
- walk_convex_edges(&headEdge, SkPath::kEvenOdd_FillType, blitter, start_y, stop_y, nullptr);
-// walk_edges(&headEdge, SkPath::kEvenOdd_FillType, blitter, start_y, stop_y, nullptr);
+ walk_convex_edges(&headEdge, SkPath::kEvenOdd_FillType, blitter, nullptr, start_y, stop_y, nullptr);
+// walk_edges(&headEdge, SkPath::kEvenOdd_FillType, blitter, start_y, stop_y, NULL);
}
void SkScan::FillTriangle(const SkPoint pts[], const SkRasterClip& clip,
@@ -707,3 +846,39 @@ void SkScan::FillTriangle(const SkPoint pts[], const SkRasterClip& clip,
sk_fill_triangle(pts, clipper.getClipRect(), blitter, ir);
}
}
+
+void SkScan::PathToTriangles(const SkPath& path, const SkIRect& clipBounds,
+ bool antiAlias, SkTDArray<SkPoint>* points) {
+// dumping = true;
+// printf("*** SkScan::PathToTriangles start\n");
+ points->setReserve(path.countPoints());
+ SkPath localPath = path;
+ SkIRect localClipBounds = clipBounds;
+ if (antiAlias) {
+ // Stroke 1-pix wide around path.
+ SkStroke stroker;
+ stroker.setJoin(SkPaint::kMiter_Join);
+ stroker.setWidth(5);
+ SkPath strokedPath;
+ // We want even open paths to become closed, so we can fill them.
+ stroker.setAutoClose(true);
+ // Don't reverse the inner path direction, since want the interior to be filled.
+ stroker.setReverseInner(false);
+ stroker.strokePath(localPath, &strokedPath);
+ localPath = strokedPath;
+ }
+ SkRect pathBounds = localPath.getBounds();
+ SkRegion clipRgn(localClipBounds);
+ if (localPath.isInverseFillType()) {
+ localPath.addRect(SkRect::Make(localClipBounds), SkPath::kCCW_Direction);
+ sk_fill_path(localPath, &localClipBounds, NULL, points,
+ localClipBounds.top(), localClipBounds.bottom(), 0,
+ clipRgn);
+ } else {
+ sk_fill_path(localPath, &localClipBounds, NULL, points,
+ pathBounds.top() - 1, pathBounds.bottom() + 1, 0,
+ clipRgn);
+ }
+// printf("*** SkScan::PathToTriangles end\n");
+// dumping = false;
+}
« no previous file with comments | « src/core/SkScan_AntiPath.cpp ('k') | src/core/SkStroke.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698