faster edge re-sort, drop trailing edges
authorreed <reed@google.com>
Fri, 6 Feb 2015 22:18:46 +0000 (14:18 -0800)
committerCommit bot <commit-bot@chromium.org>
Fri, 6 Feb 2015 22:18:46 +0000 (14:18 -0800)
1. drop edges that are wholly on the right (in the non-convex walker)
2. scan and swap once, instead of swapping as we go during re-sort

BUG=skia:

Review URL: https://codereview.chromium.org/891613003

src/core/SkEdgeBuilder.cpp
src/core/SkEdgeBuilder.h
src/core/SkLineClipper.cpp
src/core/SkLineClipper.h
src/core/SkScan_Path.cpp

index 8dcc47a..0081120 100644 (file)
@@ -79,8 +79,8 @@ static void setShiftedClip(SkRect* dst, const SkIRect& src, int shift) {
              SkIntToScalar(src.fBottom >> shift));
 }
 
-int SkEdgeBuilder::buildPoly(const SkPath& path, const SkIRect* iclip,
-                             int shiftUp) {
+int SkEdgeBuilder::buildPoly(const SkPath& path, const SkIRect* iclip, int shiftUp,
+                             bool clipToTheRight) {
     SkPath::Iter    iter(path, true);
     SkPoint         pts[4];
     SkPath::Verb    verb;
@@ -115,7 +115,7 @@ int SkEdgeBuilder::buildPoly(const SkPath& path, const SkIRect* iclip,
                     break;
                 case SkPath::kLine_Verb: {
                     SkPoint lines[SkLineClipper::kMaxPoints];
-                    int lineCount = SkLineClipper::ClipLine(pts, clip, lines);
+                    int lineCount = SkLineClipper::ClipLine(pts, clip, lines, clipToTheRight);
                     SkASSERT(lineCount <= SkLineClipper::kMaxClippedLineSegments);
                     for (int i = 0; i < lineCount; i++) {
                         if (edge->setLine(lines[i], lines[i + 1], shiftUp)) {
@@ -161,14 +161,14 @@ static void handle_quad(SkEdgeBuilder* builder, const SkPoint pts[3]) {
     }
 }
 
-int SkEdgeBuilder::build(const SkPath& path, const SkIRect* iclip,
-                         int shiftUp) {
+int SkEdgeBuilder::build(const SkPath& path, const SkIRect* iclip, int shiftUp,
+                         bool clipToTheRight) {
     fAlloc.reset();
     fList.reset();
     fShiftUp = shiftUp;
 
     if (SkPath::kLine_SegmentMask == path.getSegmentMasks()) {
-        return this->buildPoly(path, iclip, shiftUp);
+        return this->buildPoly(path, iclip, shiftUp, clipToTheRight);
     }
 
     SkAutoConicToQuads quadder;
@@ -192,7 +192,7 @@ int SkEdgeBuilder::build(const SkPath& path, const SkIRect* iclip,
                     break;
                 case SkPath::kLine_Verb: {
                     SkPoint lines[SkLineClipper::kMaxPoints];
-                    int lineCount = SkLineClipper::ClipLine(pts, clip, lines);
+                    int lineCount = SkLineClipper::ClipLine(pts, clip, lines, clipToTheRight);
                     for (int i = 0; i < lineCount; i++) {
                         this->addLine(&lines[i]);
                     }
index f9e5976..625465b 100644 (file)
@@ -22,7 +22,7 @@ public:
 
     // returns the number of built edges. The array of those edge pointers
     // is returned from edgeList().
-    int build(const SkPath& path, const SkIRect* clip, int shiftUp);
+    int build(const SkPath& path, const SkIRect* clip, int shiftUp, bool clipToTheRight);
 
     SkEdge** edgeList() { return fEdgeList; }
 
@@ -36,9 +36,9 @@ private:
      *  empty, as we will have preallocated room for the pointers in fAlloc's
      *  block, and fEdgeList will point into that.
      */
-    SkEdge**            fEdgeList;
+    SkEdge**    fEdgeList;
 
-    int                 fShiftUp;
+    int         fShiftUp;
 
 public:
     void addLine(const SkPoint pts[]);
@@ -46,7 +46,7 @@ public:
     void addCubic(const SkPoint pts[]);
     void addClipper(SkEdgeClipper*);
 
-    int buildPoly(const SkPath& path, const SkIRect* clip, int shiftUp);
+    int buildPoly(const SkPath& path, const SkIRect* clip, int shiftUp, bool clipToTheRight);
 };
 
 #endif
index 1645917..9d72ea5 100644 (file)
@@ -173,7 +173,7 @@ static void sect_with_horizontal_test_for_pin_results() {
 #endif
 
 int SkLineClipper::ClipLine(const SkPoint pts[], const SkRect& clip,
-                            SkPoint lines[]) {
+                            SkPoint lines[], bool canClipToTheRight) {
 #ifdef SK_DEBUG
     {
         static bool gOnce;
@@ -241,6 +241,9 @@ int SkLineClipper::ClipLine(const SkPoint pts[], const SkRect& clip,
         result = tmp;
         reverse = false;
     } else if (tmp[index0].fX >= clip.fRight) {    // wholly to the right
+        if (canClipToTheRight) {
+            return 0;
+        }
         tmp[0].fX = tmp[1].fX = clip.fRight;
         result = tmp;
         reverse = false;
index 8026890..d966dbc 100644 (file)
@@ -30,7 +30,7 @@ public:
             3rd segment: lines[2]..lines[3]
      */
     static int ClipLine(const SkPoint pts[2], const SkRect& clip,
-                        SkPoint lines[kMaxPoints]);
+                        SkPoint lines[kMaxPoints], bool canClipToTheRight);
 
     /*  Intersect the line segment against the rect. If there is a non-empty
         resulting segment, return true and set dst[] to that segment. If not,
index 5d9e0ca..bf56aca 100644 (file)
@@ -45,34 +45,23 @@ static inline void remove_edge(SkEdge* edge) {
     edge->fNext->fPrev = edge->fPrev;
 }
 
-static inline void swap_edges(SkEdge* prev, SkEdge* next) {
-    SkASSERT(prev->fNext == next && next->fPrev == prev);
-
-    // remove prev from the list
-    prev->fPrev->fNext = next;
-    next->fPrev = prev->fPrev;
-
-    // insert prev after next
-    prev->fNext = next->fNext;
-    next->fNext->fPrev = prev;
-    next->fNext = prev;
-    prev->fPrev = next;
+static inline void insert_edge_after(SkEdge* edge, SkEdge* afterMe) {
+    edge->fPrev = afterMe;
+    edge->fNext = afterMe->fNext;
+    afterMe->fNext->fPrev = edge;
+    afterMe->fNext = edge;
 }
 
 static void backward_insert_edge_based_on_x(SkEdge* edge SkDECLAREPARAM(int, curr_y)) {
     SkFixed x = edge->fX;
 
-    for (;;) {
-        SkEdge* prev = edge->fPrev;
-
-        // add 1 to curr_y since we may have added new edges (built from curves)
-        // that start on the next scanline
-        SkASSERT(prev && prev->fFirstY <= curr_y + 1);
-
-        if (prev->fX <= x) {
-            break;
-        }
-        swap_edges(prev, edge);
+    SkEdge* prev = edge->fPrev;
+    while (prev->fX > x) {
+        prev = prev->fPrev;
+    }
+    if (prev->fNext != edge) {
+        remove_edge(edge);
+        insert_edge_after(edge, prev);
     }
 }
 
@@ -113,7 +102,7 @@ typedef void (*PrePostProc)(SkBlitter* blitter, int y, bool isStartOfScanline);
 
 static void walk_edges(SkEdge* prevHead, SkPath::FillType fillType,
                        SkBlitter* blitter, int start_y, int stop_y,
-                       PrePostProc proc) {
+                       PrePostProc proc, int rightClip) {
     validate_sort(prevHead->fNext);
 
     int curr_y = start_y;
@@ -183,6 +172,14 @@ static void walk_edges(SkEdge* prevHead, SkPath::FillType fillType,
             SkASSERT(currE);
         }
 
+        // was our right-edge culled away?
+        if (in_interval) {
+            int width = rightClip - left;
+            if (width > 0) {
+                blitter->blitH(left, curr_y, width);
+            }
+        }
+
         if (proc) {
             proc(blitter, curr_y, PREPOST_END);    // post-proc
         }
@@ -436,7 +433,10 @@ void sk_fill_path(const SkPath& path, const SkIRect* clipRect, SkBlitter* blitte
 
     SkEdgeBuilder   builder;
 
-    int count = builder.build(path, clipRect, shiftEdgesUp);
+    // If we're convex, then we need both edges, even the right edge is past the clip
+    const bool cullToTheRight = !path.isConvex();
+
+    int count = builder.build(path, clipRect, shiftEdgesUp, cullToTheRight);
     SkEdge**    list = builder.edgeList();
 
     if (count < 2) {
@@ -500,10 +500,17 @@ void sk_fill_path(const SkPath& path, const SkIRect* clipRect, SkBlitter* blitte
         proc = PrePostInverseBlitterProc;
     }
 
+    int rightEdge;
+    if (clipRect) {
+        rightEdge = clipRect->right();
+    } else {
+        rightEdge = SkScalarRoundToInt(path.getBounds().right());
+    }
+
     if (path.isConvex() && (NULL == proc)) {
         walk_convex_edges(&headEdge, path.getFillType(), blitter, start_y, stop_y, NULL);
     } else {
-        walk_edges(&headEdge, path.getFillType(), blitter, start_y, stop_y, proc);
+        walk_edges(&headEdge, path.getFillType(), blitter, start_y, stop_y, proc, rightEdge);
     }
 }