Tesselate path once for tiled offscreen AA

Review URL: http://codereview.appspot.com/4661062/


git-svn-id: http://skia.googlecode.com/svn/trunk@1777 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/src/GrPathRenderer.cpp b/gpu/src/GrPathRenderer.cpp
index 1e3c645..b103880 100644
--- a/gpu/src/GrPathRenderer.cpp
+++ b/gpu/src/GrPathRenderer.cpp
@@ -11,15 +11,49 @@
 #include SK_USER_TRACE_INCLUDE_FILE
 
 GrPathRenderer::GrPathRenderer()
-    : fCurveTolerance (GR_Scalar1) {
-
+    : fCurveTolerance (GR_Scalar1)
+    , fPath(NULL)
+    , fTarget(NULL) {
 }
-   
+
+
+void GrPathRenderer::setPath(GrDrawTarget* target,
+                             const SkPath* path,
+                             GrPathFill fill,
+                             const GrPoint* translate) {
+    GrAssert(NULL == fPath);
+    GrAssert(NULL == fTarget);
+    GrAssert(NULL != target);
+
+    fTarget = target;
+    fPath = path;
+    fFill = fill;
+    if (NULL != translate) {
+        fTranslate = *translate;
+    } else {
+        fTranslate.fX = fTranslate.fY = 0;
+    }
+    this->pathWasSet();
+}
+
+void GrPathRenderer::clearPath() {
+    this->pathWillClear();
+    fTarget->resetVertexSource();
+    fTarget = NULL;
+    fPath = NULL;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
 GrDefaultPathRenderer::GrDefaultPathRenderer(bool separateStencilSupport,
                                              bool stencilWrapOpsSupport)
     : fSeparateStencil(separateStencilSupport)
-    , fStencilWrapOps(stencilWrapOpsSupport) {
-
+    , fStencilWrapOps(stencilWrapOpsSupport)
+    , fSubpathCount(0)
+    , fSubpathVertCount(0)
+    , fPreviousSrcTol(-GR_Scalar1)
+    , fPreviousStages(-1) {
+    fTarget = NULL;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -189,21 +223,105 @@
     return !single_pass_path(*target, path, fill);
 }
 
-void GrDefaultPathRenderer::onDrawPath(GrDrawTarget* target,
-                                       GrDrawTarget::StageBitfield stages,
-                                       const GrPath& path,
-                                       GrPathFill fill,
-                                       const GrPoint* translate,
+void GrDefaultPathRenderer::pathWillClear() {
+    fSubpathVertCount.realloc(0);
+    fTarget->resetVertexSource();
+    fPreviousSrcTol = -GR_Scalar1;
+    fPreviousStages = -1;
+}
+
+void GrDefaultPathRenderer::createGeom(GrScalar srcSpaceTol, 
+                                       GrDrawTarget::StageBitfield stages) {
+    {
+    SK_TRACE_EVENT0("GrDefaultPathRenderer::createGeom");
+
+    fPreviousSrcTol = srcSpaceTol;
+    fPreviousStages = stages;
+
+    GrScalar srcSpaceTolSqd = GrMul(srcSpaceTol, srcSpaceTol);
+    int maxPts = GrPathUtils::worstCasePointCount(*fPath, &fSubpathCount,
+                                                  srcSpaceTol);
+
+    GrVertexLayout layout = 0;
+    for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
+        if ((1 << s) & stages) {
+            layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
+        }
+    }
+
+    // add 4 to hold the bounding rect
+    GrPoint* base;
+    fTarget->reserveVertexSpace(layout, maxPts + 4, (void**)&base);
+
+    GrPoint* vert = base;
+    GrPoint* subpathBase = base;
+
+    fSubpathVertCount.realloc(fSubpathCount);
+
+    GrPoint pts[4];
+
+    bool first = true;
+    int subpath = 0;
+
+    SkPath::Iter iter(*fPath, false);
+
+    for (;;) {
+        GrPathCmd cmd = (GrPathCmd)iter.next(pts);
+        switch (cmd) {
+            case kMove_PathCmd:
+                if (!first) {
+                    fSubpathVertCount[subpath] = vert-subpathBase;
+                    subpathBase = vert;
+                    ++subpath;
+                }
+                *vert = pts[0];
+                vert++;
+                break;
+            case kLine_PathCmd:
+                *vert = pts[1];
+                vert++;
+                break;
+            case kQuadratic_PathCmd: {
+                GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2],
+                                                     srcSpaceTolSqd, &vert,
+                                                     GrPathUtils::quadraticPointCount(pts, srcSpaceTol));
+                break;
+            }
+            case kCubic_PathCmd: {
+                GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3],
+                                                 srcSpaceTolSqd, &vert,
+                                                 GrPathUtils::cubicPointCount(pts, srcSpaceTol));
+                break;
+            }
+            case kClose_PathCmd:
+                break;
+            case kEnd_PathCmd:
+                fSubpathVertCount[subpath] = vert-subpathBase;
+                ++subpath; // this could be only in debug
+                goto FINISHED;
+        }
+        first = false;
+    }
+FINISHED:
+    GrAssert(subpath == fSubpathCount);
+    GrAssert((vert - base) <= maxPts);
+
+    if (fTranslate.fX || fTranslate.fY) {
+        int count = vert - base;
+        for (int i = 0; i < count; i++) {
+            base[i].offset(fTranslate.fX, fTranslate.fY);
+        }
+    }
+    }
+}
+
+void GrDefaultPathRenderer::onDrawPath(GrDrawTarget::StageBitfield stages,
                                        bool stencilOnly) {
+
     SK_TRACE_EVENT1("GrDefaultPathRenderer::onDrawPath",
                     "points", SkStringPrintf("%i", path.countPoints()).c_str());
 
-    GrDrawTarget::AutoStateRestore asr(target);
-    bool colorWritesWereDisabled = target->isColorWriteDisabled();
-    // face culling doesn't make sense here
-    GrAssert(GrDrawTarget::kBoth_DrawFace == target->getDrawFace());
-
-    GrMatrix viewM = target->getViewMatrix();
+    GrMatrix viewM = fTarget->getViewMatrix();
     // In order to tesselate the path we get a bound on how much the matrix can
     // stretch when mapping to screen coordinates.
     GrScalar stretch = viewM.getMaxStretch();
@@ -216,28 +334,25 @@
     } else {
         tol = GrScalarDiv(tol, stretch);
     }
-    GrScalar tolSqd = GrMul(tol, tol);
-
-    int subpathCnt;
-    int maxPts = GrPathUtils::worstCasePointCount(path, &subpathCnt, tol);
-
-    GrVertexLayout layout = 0;
-    for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
-        if ((1 << s) & stages) {
-            layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
-        }
+    // FIXME: It's really dumb that we recreate the verts for a new vertex
+    // layout. We only do that because the GrDrawTarget API doesn't allow
+    // us to change the vertex layout after reserveVertexSpace(). We won't
+    // actually change the vertex data when the layout changes since all the
+    // stages reference the positions (rather than having separate tex coords)
+    // and we don't ever have per-vert colors. In practice our call sites
+    // won't change the stages in use inside a setPath / removePath pair. But
+    // it is a silly limitation of the GrDrawTarget design that should be fixed.
+    if (tol != fPreviousSrcTol ||
+        stages != fPreviousStages) {
+        this->createGeom(tol, stages);
     }
 
-    // add 4 to hold the bounding rect
-    GrDrawTarget::AutoReleaseGeometry arg(target, layout, maxPts + 4, 0);
+    GrAssert(NULL != fTarget);
+    GrDrawTarget::AutoStateRestore asr(fTarget);
+    bool colorWritesWereDisabled = fTarget->isColorWriteDisabled();
+    // face culling doesn't make sense here
+    GrAssert(GrDrawTarget::kBoth_DrawFace == fTarget->getDrawFace());
 
-    GrPoint* base = (GrPoint*) arg.vertices();
-    GrPoint* vert = base;
-    GrPoint* subpathBase = base;
-
-    SkAutoSTMalloc<8, uint16_t> subpathVertCount(subpathCnt);
-
-    // TODO: use primitve restart if available rather than multiple draws
     GrPrimitiveType             type;
     int                         passCount = 0;
     const GrStencilSettings*    passes[3];
@@ -245,7 +360,7 @@
     bool                        reverse = false;
     bool                        lastPassIsBounds;
 
-    if (kHairLine_PathFill == fill) {
+    if (kHairLine_PathFill == fFill) {
         type = kLineStrip_PrimitiveType;
         passCount = 1;
         if (stencilOnly) {
@@ -257,7 +372,7 @@
         drawFace[0] = GrDrawTarget::kBoth_DrawFace;
     } else {
         type = kTriangleFan_PrimitiveType;
-        if (single_pass_path(*target, path, fill)) {
+        if (single_pass_path(*fTarget, *fPath, fFill)) {
             passCount = 1;
             if (stencilOnly) {
                 passes[0] = &gDirectToStencil;
@@ -267,7 +382,7 @@
             drawFace[0] = GrDrawTarget::kBoth_DrawFace;
             lastPassIsBounds = false;
         } else {
-            switch (fill) {
+            switch (fFill) {
                 case kInverseEvenOdd_PathFill:
                     reverse = true;
                     // fallthrough
@@ -327,140 +442,62 @@
                     }
                     break;
                 default:
-                    GrAssert(!"Unknown path fill!");
+                    GrAssert(!"Unknown path fFill!");
                     return;
             }
         }
     }
 
-    GrPoint pts[4];
-
-    bool first = true;
-    int subpath = 0;
-
-    SkPath::Iter iter(path, false);
-
-    {
-    SK_TRACE_EVENT0("GrDefaultPathRenderer::onDrawPath::assembleVerts");
-    for (;;) {
-
-        GrPathCmd cmd = (GrPathCmd)iter.next(pts);
-        switch (cmd) {
-            case kMove_PathCmd:
-                if (!first) {
-                    subpathVertCount[subpath] = vert-subpathBase;
-                    subpathBase = vert;
-                    ++subpath;
-                }
-                *vert = pts[0];
-                vert++;
-                break;
-            case kLine_PathCmd:
-                *vert = pts[1];
-                vert++;
-                break;
-            case kQuadratic_PathCmd: {
-                GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2],
-                                                     tolSqd, &vert,
-                                                     GrPathUtils::quadraticPointCount(pts, tol));
-                break;
-            }
-            case kCubic_PathCmd: {
-                GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3],
-                                                 tolSqd, &vert,
-                                                 GrPathUtils::cubicPointCount(pts, tol));
-                break;
-            }
-            case kClose_PathCmd:
-                break;
-            case kEnd_PathCmd:
-                subpathVertCount[subpath] = vert-subpathBase;
-                ++subpath; // this could be only in debug
-                goto FINISHED;
-        }
-        first = false;
-    }
-    }
-FINISHED:
-    GrAssert(subpath == subpathCnt);
-    GrAssert((vert - base) <= maxPts);
-
-    if (translate) {
-        int count = vert - base;
-        for (int i = 0; i < count; i++) {
-            base[i].offset(translate->fX, translate->fY);
-        }
-    }
-
-    // if we're stenciling we will follow with a pass that draws
-    // a bounding rect to set the color. We're stenciling when
-    // passCount > 1.
-    const int& boundVertexStart = maxPts;
-    GrPoint* boundsVerts = base + boundVertexStart;
-    if (lastPassIsBounds) {
-        GrRect bounds;
-        if (reverse) {
-            GrAssert(NULL != target->getRenderTarget());
-            // draw over the whole world.
-            bounds.setLTRB(0, 0,
-                           GrIntToScalar(target->getRenderTarget()->width()),
-                           GrIntToScalar(target->getRenderTarget()->height()));
-            GrMatrix vmi;
-            if (target->getViewInverse(&vmi)) {
-                vmi.mapRect(&bounds);
-            }
-        } else {
-            bounds.setBounds((GrPoint*)base, vert - base);
-        }
-        boundsVerts[0].setRectFan(bounds.fLeft, bounds.fTop, bounds.fRight,
-                                  bounds.fBottom);
-    }
-
     {
     SK_TRACE_EVENT1("GrDefaultPathRenderer::onDrawPath::renderPasses",
                     "verts", SkStringPrintf("%i", vert - base).c_str());
     for (int p = 0; p < passCount; ++p) {
-        target->setDrawFace(drawFace[p]);
+        fTarget->setDrawFace(drawFace[p]);
         if (NULL != passes[p]) {
-            target->setStencil(*passes[p]);
+            fTarget->setStencil(*passes[p]);
         }
 
         if (lastPassIsBounds && (p == passCount-1)) {
             if (!colorWritesWereDisabled) {
-                target->disableState(GrDrawTarget::kNoColorWrites_StateBit);
+                fTarget->disableState(GrDrawTarget::kNoColorWrites_StateBit);
             }
-            target->drawNonIndexed(kTriangleFan_PrimitiveType,
-                                   boundVertexStart, 4);
-
+            GrRect bounds;
+            if (reverse) {
+                GrAssert(NULL != fTarget->getRenderTarget());
+                // draw over the whole world.
+                bounds.setLTRB(0, 0,
+                               GrIntToScalar(fTarget->getRenderTarget()->width()),
+                               GrIntToScalar(fTarget->getRenderTarget()->height()));
+                GrMatrix vmi;
+                if (fTarget->getViewInverse(&vmi)) {
+                    vmi.mapRect(&bounds);
+                }
+            } else {
+                bounds = fPath->getBounds();
+            }
+            GrDrawTarget::AutoGeometryPush agp(fTarget);
+            fTarget->drawSimpleRect(bounds, NULL, stages);
         } else {
             if (passCount > 1) {
-                target->enableState(GrDrawTarget::kNoColorWrites_StateBit);
+                fTarget->enableState(GrDrawTarget::kNoColorWrites_StateBit);
             }
             int baseVertex = 0;
-            for (int sp = 0; sp < subpathCnt; ++sp) {
-                target->drawNonIndexed(type,
-                                      baseVertex,
-                                      subpathVertCount[sp]);
-                baseVertex += subpathVertCount[sp];
+            for (int sp = 0; sp < fSubpathCount; ++sp) {
+                fTarget->drawNonIndexed(type, baseVertex, 
+                                        fSubpathVertCount[sp]);
+                baseVertex += fSubpathVertCount[sp];
             }
         }
     }
     }
 }
 
-void GrDefaultPathRenderer::drawPath(GrDrawTarget* target,
-                                     GrDrawTarget::StageBitfield stages,
-                                     const GrPath& path,
-                                     GrPathFill fill,
-                                     const GrPoint* translate) {
-    this->onDrawPath(target, stages, path, fill, translate, false);
+void GrDefaultPathRenderer::drawPath(GrDrawTarget::StageBitfield stages) {
+    this->onDrawPath(stages, false);
 }
 
-void GrDefaultPathRenderer::drawPathToStencil(GrDrawTarget* target,
-                                              const GrPath& path,
-                                              GrPathFill fill,
-                                              const GrPoint* translate) {
-    GrAssert(kInverseEvenOdd_PathFill != fill);
-    GrAssert(kInverseWinding_PathFill != fill);
-    this->onDrawPath(target, 0, path, fill, translate, true);
+void GrDefaultPathRenderer::drawPathToStencil() {
+    GrAssert(kInverseEvenOdd_PathFill != fFill);
+    GrAssert(kInverseWinding_PathFill != fFill);
+    this->onDrawPath(0, true);
 }