Make GrAAConvexPathRender support paths with > 64K verts.

R=robertphillips@google.com

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

git-svn-id: http://skia.googlecode.com/svn/trunk@9118 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/GrAAConvexPathRenderer.cpp b/src/gpu/GrAAConvexPathRenderer.cpp
index a0e72e5..fc6cae6 100644
--- a/src/gpu/GrAAConvexPathRenderer.cpp
+++ b/src/gpu/GrAAConvexPathRenderer.cpp
@@ -128,7 +128,7 @@
     *iCount = 0;
     // compute normals at all points
     for (int a = 0; a < count; ++a) {
-        const Segment& sega = (*segments)[a];
+        Segment& sega = (*segments)[a];
         int b = (a + 1) % count;
         Segment& segb = (*segments)[b];
 
@@ -304,12 +304,23 @@
     SkScalar fD1;
 };
 
+struct Draw {
+    Draw() : fVertexCnt(0), fIndexCnt(0) {}
+    int fVertexCnt;
+    int fIndexCnt;
+};
+
+typedef SkTArray<Draw, true> DrawArray;
+
 void create_vertices(const SegmentArray&  segments,
                      const SkPoint& fanPt,
+                     DrawArray*     draws,
                      QuadVertex*    verts,
                      uint16_t*      idxs) {
-    int v = 0;
-    int i = 0;
+    Draw* draw = &draws->push_back();
+    // alias just to make vert/index assignments easier to read.
+    int* v = &draw->fVertexCnt;
+    int* i = &draw->fIndexCnt;
 
     int count = segments.count();
     for (int a = 0; a < count; ++a) {
@@ -317,117 +328,133 @@
         int b = (a + 1) % count;
         const Segment& segb = segments[b];
 
+        // Check whether adding the verts for this segment to the current draw would cause index
+        // values to overflow.
+        int vCount = 4;
+        if (Segment::kLine == segb.fType) {
+            vCount += 5;
+        } else {
+            vCount += 6;
+        }
+        if (draw->fVertexCnt + vCount > (1 << 16)) {
+            verts += *v;
+            idxs += *i;
+            draw = &draws->push_back();
+            v = &draw->fVertexCnt;
+            i = &draw->fIndexCnt;
+        }
+
         // FIXME: These tris are inset in the 1 unit arc around the corner
-        verts[v + 0].fPos = sega.endPt();
-        verts[v + 1].fPos = verts[v + 0].fPos + sega.endNorm();
-        verts[v + 2].fPos = verts[v + 0].fPos + segb.fMid;
-        verts[v + 3].fPos = verts[v + 0].fPos + segb.fNorms[0];
-        verts[v + 0].fUV.set(0,0);
-        verts[v + 1].fUV.set(0,-SK_Scalar1);
-        verts[v + 2].fUV.set(0,-SK_Scalar1);
-        verts[v + 3].fUV.set(0,-SK_Scalar1);
-        verts[v + 0].fD0 = verts[v + 0].fD1 = -SK_Scalar1;
-        verts[v + 1].fD0 = verts[v + 1].fD1 = -SK_Scalar1;
-        verts[v + 2].fD0 = verts[v + 2].fD1 = -SK_Scalar1;
-        verts[v + 3].fD0 = verts[v + 3].fD1 = -SK_Scalar1;
+        verts[*v + 0].fPos = sega.endPt();
+        verts[*v + 1].fPos = verts[*v + 0].fPos + sega.endNorm();
+        verts[*v + 2].fPos = verts[*v + 0].fPos + segb.fMid;
+        verts[*v + 3].fPos = verts[*v + 0].fPos + segb.fNorms[0];
+        verts[*v + 0].fUV.set(0,0);
+        verts[*v + 1].fUV.set(0,-SK_Scalar1);
+        verts[*v + 2].fUV.set(0,-SK_Scalar1);
+        verts[*v + 3].fUV.set(0,-SK_Scalar1);
+        verts[*v + 0].fD0 = verts[*v + 0].fD1 = -SK_Scalar1;
+        verts[*v + 1].fD0 = verts[*v + 1].fD1 = -SK_Scalar1;
+        verts[*v + 2].fD0 = verts[*v + 2].fD1 = -SK_Scalar1;
+        verts[*v + 3].fD0 = verts[*v + 3].fD1 = -SK_Scalar1;
 
-        idxs[i + 0] = v + 0;
-        idxs[i + 1] = v + 2;
-        idxs[i + 2] = v + 1;
-        idxs[i + 3] = v + 0;
-        idxs[i + 4] = v + 3;
-        idxs[i + 5] = v + 2;
+        idxs[*i + 0] = *v + 0;
+        idxs[*i + 1] = *v + 2;
+        idxs[*i + 2] = *v + 1;
+        idxs[*i + 3] = *v + 0;
+        idxs[*i + 4] = *v + 3;
+        idxs[*i + 5] = *v + 2;
 
-        v += 4;
-        i += 6;
+        *v += 4;
+        *i += 6;
 
         if (Segment::kLine == segb.fType) {
-            verts[v + 0].fPos = fanPt;
-            verts[v + 1].fPos = sega.endPt();
-            verts[v + 2].fPos = segb.fPts[0];
+            verts[*v + 0].fPos = fanPt;
+            verts[*v + 1].fPos = sega.endPt();
+            verts[*v + 2].fPos = segb.fPts[0];
 
-            verts[v + 3].fPos = verts[v + 1].fPos + segb.fNorms[0];
-            verts[v + 4].fPos = verts[v + 2].fPos + segb.fNorms[0];
+            verts[*v + 3].fPos = verts[*v + 1].fPos + segb.fNorms[0];
+            verts[*v + 4].fPos = verts[*v + 2].fPos + segb.fNorms[0];
 
             // we draw the line edge as a degenerate quad (u is 0, v is the
             // signed distance to the edge)
-            SkScalar dist = fanPt.distanceToLineBetween(verts[v + 1].fPos,
-                                                        verts[v + 2].fPos);
-            verts[v + 0].fUV.set(0, dist);
-            verts[v + 1].fUV.set(0, 0);
-            verts[v + 2].fUV.set(0, 0);
-            verts[v + 3].fUV.set(0, -SK_Scalar1);
-            verts[v + 4].fUV.set(0, -SK_Scalar1);
+            SkScalar dist = fanPt.distanceToLineBetween(verts[*v + 1].fPos,
+                                                        verts[*v + 2].fPos);
+            verts[*v + 0].fUV.set(0, dist);
+            verts[*v + 1].fUV.set(0, 0);
+            verts[*v + 2].fUV.set(0, 0);
+            verts[*v + 3].fUV.set(0, -SK_Scalar1);
+            verts[*v + 4].fUV.set(0, -SK_Scalar1);
 
-            verts[v + 0].fD0 = verts[v + 0].fD1 = -SK_Scalar1;
-            verts[v + 1].fD0 = verts[v + 1].fD1 = -SK_Scalar1;
-            verts[v + 2].fD0 = verts[v + 2].fD1 = -SK_Scalar1;
-            verts[v + 3].fD0 = verts[v + 3].fD1 = -SK_Scalar1;
-            verts[v + 4].fD0 = verts[v + 4].fD1 = -SK_Scalar1;
+            verts[*v + 0].fD0 = verts[*v + 0].fD1 = -SK_Scalar1;
+            verts[*v + 1].fD0 = verts[*v + 1].fD1 = -SK_Scalar1;
+            verts[*v + 2].fD0 = verts[*v + 2].fD1 = -SK_Scalar1;
+            verts[*v + 3].fD0 = verts[*v + 3].fD1 = -SK_Scalar1;
+            verts[*v + 4].fD0 = verts[*v + 4].fD1 = -SK_Scalar1;
 
-            idxs[i + 0] = v + 0;
-            idxs[i + 1] = v + 2;
-            idxs[i + 2] = v + 1;
+            idxs[*i + 0] = *v + 0;
+            idxs[*i + 1] = *v + 2;
+            idxs[*i + 2] = *v + 1;
 
-            idxs[i + 3] = v + 3;
-            idxs[i + 4] = v + 1;
-            idxs[i + 5] = v + 2;
+            idxs[*i + 3] = *v + 3;
+            idxs[*i + 4] = *v + 1;
+            idxs[*i + 5] = *v + 2;
 
-            idxs[i + 6] = v + 4;
-            idxs[i + 7] = v + 3;
-            idxs[i + 8] = v + 2;
+            idxs[*i + 6] = *v + 4;
+            idxs[*i + 7] = *v + 3;
+            idxs[*i + 8] = *v + 2;
 
-            v += 5;
-            i += 9;
+            *v += 5;
+            *i += 9;
         } else {
             GrPoint qpts[] = {sega.endPt(), segb.fPts[0], segb.fPts[1]};
 
             GrVec midVec = segb.fNorms[0] + segb.fNorms[1];
             midVec.normalize();
 
-            verts[v + 0].fPos = fanPt;
-            verts[v + 1].fPos = qpts[0];
-            verts[v + 2].fPos = qpts[2];
-            verts[v + 3].fPos = qpts[0] + segb.fNorms[0];
-            verts[v + 4].fPos = qpts[2] + segb.fNorms[1];
-            verts[v + 5].fPos = qpts[1] + midVec;
+            verts[*v + 0].fPos = fanPt;
+            verts[*v + 1].fPos = qpts[0];
+            verts[*v + 2].fPos = qpts[2];
+            verts[*v + 3].fPos = qpts[0] + segb.fNorms[0];
+            verts[*v + 4].fPos = qpts[2] + segb.fNorms[1];
+            verts[*v + 5].fPos = qpts[1] + midVec;
 
             SkScalar c = segb.fNorms[0].dot(qpts[0]);
-            verts[v + 0].fD0 =  -segb.fNorms[0].dot(fanPt) + c;
-            verts[v + 1].fD0 =  0.f;
-            verts[v + 2].fD0 =  -segb.fNorms[0].dot(qpts[2]) + c;
-            verts[v + 3].fD0 = -SK_ScalarMax/100;
-            verts[v + 4].fD0 = -SK_ScalarMax/100;
-            verts[v + 5].fD0 = -SK_ScalarMax/100;
+            verts[*v + 0].fD0 =  -segb.fNorms[0].dot(fanPt) + c;
+            verts[*v + 1].fD0 =  0.f;
+            verts[*v + 2].fD0 =  -segb.fNorms[0].dot(qpts[2]) + c;
+            verts[*v + 3].fD0 = -SK_ScalarMax/100;
+            verts[*v + 4].fD0 = -SK_ScalarMax/100;
+            verts[*v + 5].fD0 = -SK_ScalarMax/100;
 
             c = segb.fNorms[1].dot(qpts[2]);
-            verts[v + 0].fD1 =  -segb.fNorms[1].dot(fanPt) + c;
-            verts[v + 1].fD1 =  -segb.fNorms[1].dot(qpts[0]) + c;
-            verts[v + 2].fD1 =  0.f;
-            verts[v + 3].fD1 = -SK_ScalarMax/100;
-            verts[v + 4].fD1 = -SK_ScalarMax/100;
-            verts[v + 5].fD1 = -SK_ScalarMax/100;
+            verts[*v + 0].fD1 =  -segb.fNorms[1].dot(fanPt) + c;
+            verts[*v + 1].fD1 =  -segb.fNorms[1].dot(qpts[0]) + c;
+            verts[*v + 2].fD1 =  0.f;
+            verts[*v + 3].fD1 = -SK_ScalarMax/100;
+            verts[*v + 4].fD1 = -SK_ScalarMax/100;
+            verts[*v + 5].fD1 = -SK_ScalarMax/100;
 
             GrPathUtils::QuadUVMatrix toUV(qpts);
-            toUV.apply<6, sizeof(QuadVertex), sizeof(GrPoint)>(verts + v);
+            toUV.apply<6, sizeof(QuadVertex), sizeof(GrPoint)>(verts + *v);
 
-            idxs[i + 0] = v + 3;
-            idxs[i + 1] = v + 1;
-            idxs[i + 2] = v + 2;
-            idxs[i + 3] = v + 4;
-            idxs[i + 4] = v + 3;
-            idxs[i + 5] = v + 2;
+            idxs[*i + 0] = *v + 3;
+            idxs[*i + 1] = *v + 1;
+            idxs[*i + 2] = *v + 2;
+            idxs[*i + 3] = *v + 4;
+            idxs[*i + 4] = *v + 3;
+            idxs[*i + 5] = *v + 2;
 
-            idxs[i + 6] = v + 5;
-            idxs[i + 7] = v + 3;
-            idxs[i + 8] = v + 4;
+            idxs[*i + 6] = *v + 5;
+            idxs[*i + 7] = *v + 3;
+            idxs[*i + 8] = *v + 4;
 
-            idxs[i +  9] = v + 0;
-            idxs[i + 10] = v + 2;
-            idxs[i + 11] = v + 1;
+            idxs[*i +  9] = *v + 0;
+            idxs[*i + 10] = *v + 2;
+            idxs[*i + 11] = *v + 1;
 
-            v += 6;
-            i += 12;
+            *v += 6;
+            *i += 12;
         }
     }
 }
@@ -601,6 +628,7 @@
     int iCount;
     enum {
         kPreallocSegmentCnt = 512 / sizeof(Segment),
+        kPreallocDrawCnt = 4,
     };
     SkSTArray<kPreallocSegmentCnt, Segment, true> segments;
     SkPoint fanPt;
@@ -629,13 +657,19 @@
     verts = reinterpret_cast<QuadVertex*>(arg.vertices());
     idxs = reinterpret_cast<uint16_t*>(arg.indices());
 
-    create_vertices(segments, fanPt, verts, idxs);
+    SkSTArray<kPreallocDrawCnt, Draw, true> draws;
+    create_vertices(segments, fanPt, &draws, verts, idxs);
 
-    target->drawIndexed(kTriangles_GrPrimitiveType,
-                        0,        // start vertex
-                        0,        // start index
-                        vCount,
-                        iCount);
+    int vOffset = 0;
+    for (int i = 0; i < draws.count(); ++i) {
+        const Draw& draw = draws[i];
+        target->drawIndexed(kTriangles_GrPrimitiveType,
+                            vOffset,  // start vertex
+                            0,        // start index
+                            draw.fVertexCnt,
+                            draw.fIndexCnt);
+        vOffset += draw.fVertexCnt;
+    }
 
     return true;
 }