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/include/GrPathRenderer.h b/gpu/include/GrPathRenderer.h
index d77aad6..6bc91b5 100644
--- a/gpu/include/GrPathRenderer.h
+++ b/gpu/include/GrPathRenderer.h
@@ -18,57 +18,46 @@
 #define GrPathRenderer_DEFINED
 
 #include "GrDrawTarget.h"
+#include "SkTemplates.h"
 
 class SkPath;
 struct GrPoint;
 
 /**
  *  Base class for drawing paths into a GrDrawTarget.
+ *  Paths may be drawn multiple times as when tiling for supersampling. The 
+ *  calls on GrPathRenderer to draw a path will look like this:
+ *  
+ *  pr->setPath(target, path, fill, translate); // sets the path to draw
+ *      pr->drawPath(...);  // draw the path
+ *      pr->drawPath(...);
+ *      ...
+ *  pr->clearPath();  // finished with the path
  */
 class GR_API GrPathRenderer : public GrRefCnt {
 public:
     GrPathRenderer(void);
-
     /**
      * Returns true if this path renderer is able to render the path.
      * Returning false allows the caller to fallback to another path renderer.
      *
-     * @param target    The target to draw into
      * @param path      The path to draw
      * @param fill      The fill rule to use
      *
      * @return  true if the path can be drawn by this object, false otherwise.
      */
-    virtual bool canDrawPath(const GrDrawTarget* target, const SkPath& path,
-                             GrPathFill fill) const = 0;
-
-    /**
-     * Draws a path into the draw target. The target will already have its draw
-     * state configured for the draw.
-     * @param target                the target to draw into.
-     * @param stages                indicates which stages the are already
-     *                              in use. All enabled stages expect positions
-     *                              as texture coordinates. The path renderer
-     *                              use the remaining stages for its path
-     *                              filling algorithm.
-     * @param path                  the path to draw.
-     * @param fill                  the fill rule to apply.
-     * @param translate             optional additional translation to apply to
-     *                              the path. NULL means (0,0).
-     */
-    virtual void drawPath(GrDrawTarget* target,
-                          GrDrawTarget::StageBitfield stages,
-                          const SkPath& path,
-                          GrPathFill fill,
-                          const GrPoint* translate) = 0;
+    virtual bool canDrawPath(const SkPath& path, GrPathFill fill) const = 0;
 
     /**
      * For complex clips Gr uses the stencil buffer. The path renderer must be
      * able to render paths into the stencil buffer. However, the path renderer
-     * itself may require the stencil buffer to resolve the path fill rule. This
-     * function queries whether the path render needs its own stencil
+     * itself may require the stencil buffer to resolve the path fill rule.
+     * This function queries whether the path render needs its own stencil
      * pass. If this returns false then drawPath() should not modify the
-     * the target's stencil settings but use those already set on target.
+     * the target's stencil settings but use those already set on target. The
+     * target is passed as a param in case the answer depends upon draw state.
+     * The view matrix and render target set on the draw target may change 
+     * before setPath/drawPath is called and so shouldn't be considered.
      *
      * @param target target that the path will be rendered to
      * @param path   the path that will be drawn
@@ -85,7 +74,59 @@
                                      GrPathFill fill) const { return false; }
 
     /**
-     * Draws a path to the stencil buffer. Assume the writable stencil bits
+     * @return true if the path renderer can perform anti-aliasing (aside from
+     * having FSAA enabled for a render target). Target is provided to
+     * communicate the draw state (blend mode, stage settings, etc).
+     */
+    virtual bool supportsAA(GrDrawTarget* target,
+                            const SkPath& path,
+                            GrPathFill fill) { return false; }
+
+    /**
+     * Sets the path to render and target to render into. All calls to drawPath
+     * and drawPathToStencil must occur between setPath and clearPath. The
+     * path cannot be modified externally between setPath and clearPath. The
+     * path may be drawn several times (e.g. tiled supersampler). The target's
+     * state may change between setPath and drawPath* calls. However, if the
+     * path renderer specified vertices/indices during setPath or drawPath*
+     * they will still be set at subsequent drawPath* calls until the next
+     * clearPath. The target's draw state may change between drawPath* calls
+     * so if the subclass does any caching of tesselation, etc. then it must
+     * validate that target parameters that guided the decisions still hold.
+     *
+     * @param target                the target to draw into.
+     * @param path                  the path to draw.
+     * @param fill                  the fill rule to apply.
+     * @param translate             optional additional translation to apply to
+     *                              the path. NULL means (0,0).
+     */
+    void setPath(GrDrawTarget* target,
+                 const SkPath* path,
+                 GrPathFill fill,
+                 const GrPoint* translate);
+
+    /**
+     * Notifies path renderer that path set in setPath is no longer in use.
+     */
+    void clearPath();
+
+    /**
+     * Draws the path into the draw target. If requiresStencilBuffer returned
+     * false then the target may be setup for stencil rendering (since the 
+     * path renderer didn't claim that it needs to use the stencil internally).
+     *
+     * Only called between setPath / clearPath.
+     *
+     * @param stages                bitfield that indicates which stages are
+     *                              in use. All enabled stages expect positions
+     *                              as texture coordinates. The path renderer
+     *                              use the remaining stages for its path
+     *                              filling algorithm.
+     */
+    virtual void drawPath(GrDrawTarget::StageBitfield stages) = 0;
+
+    /**
+     * Draws the path to the stencil buffer. Assume the writable stencil bits
      * are already initialized to zero. Fill will always be either
      * kWinding_PathFill or kEvenOdd_PathFill.
      *
@@ -95,27 +136,11 @@
      * The default implementation assumes the path filling algorithm doesn't
      * require a separate stencil pass and so crashes.
      *
-     *
-     * @param target                the target to draw into.
-     * @param path                  the path to draw.
-     * @param fill                  the fill rule to apply.
-     * @param translate             optional additional translation to apply to
-     *                              the path. NULL means (0,0).
+     * Only called between setPath / clearPath.
      */
-    virtual void drawPathToStencil(GrDrawTarget* target,
-                                   const SkPath& path,
-                                   GrPathFill fill,
-                                   const GrPoint* translate) {
+    virtual void drawPathToStencil() {
         GrCrash("Unexpected call to drawPathToStencil.");
     }
-    
-    /**
-     * @return true if the path renderer can perform anti-aliasing (aside from
-     * having FSAA enabled for a render target)
-     */
-    virtual bool supportsAA(GrDrawTarget* target,
-                            const SkPath& path,
-                            GrPathFill fill) { return false; }
 
     /**
      * This is called to install a custom path renderer in every GrContext at
@@ -134,8 +159,56 @@
         fCurveTolerance = SkScalarMul(fCurveTolerance, multiplier);
     }
 
+    /**
+     * Helper that sets a path and automatically remove it in destructor.
+     */
+    class AutoClearPath {
+    public:
+        AutoClearPath() {
+            fPathRenderer = NULL;
+        }
+        AutoClearPath(GrPathRenderer* pr,
+                       GrDrawTarget* target,
+                       const SkPath* path,
+                       GrPathFill fill,
+                       const GrPoint* translate) {
+            GrAssert(NULL != pr);
+            pr->setPath(target, path, fill, translate);
+            fPathRenderer = pr;
+        }
+        void set(GrPathRenderer* pr,
+                 GrDrawTarget* target,
+                 const SkPath* path,
+                 GrPathFill fill,
+                 const GrPoint* translate) {
+            if (NULL != fPathRenderer) {
+                fPathRenderer->clearPath();
+            }
+            GrAssert(NULL != pr);
+            pr->setPath(target, path, fill, translate);
+            fPathRenderer = pr;
+        }
+        ~AutoClearPath() {
+            if (NULL != fPathRenderer) {
+                fPathRenderer->clearPath();
+            }
+        }
+    private:
+        GrPathRenderer* fPathRenderer;
+    };
+
 protected:
+
+    // subclass can override these to be notified just after a path is set
+    // and just before the path is cleared.
+    virtual void pathWasSet() {}
+    virtual void pathWillClear() {}
+
     GrScalar fCurveTolerance;
+    const SkPath*               fPath;
+    GrDrawTarget*               fTarget;
+    GrPathFill                  fFill;
+    GrPoint                     fTranslate;
 
 private:
 
@@ -151,35 +224,37 @@
     GrDefaultPathRenderer(bool separateStencilSupport,
                           bool stencilWrapOpsSupport);
 
-    virtual bool canDrawPath(const GrDrawTarget* target,
-                             const SkPath& path,
+    virtual bool canDrawPath(const SkPath& path,
                              GrPathFill fill) const { return true; }
 
-    virtual void drawPath(GrDrawTarget* target,
-                          GrDrawTarget::StageBitfield stages,
-                          const SkPath& path,
-                          GrPathFill fill,
-                          const GrPoint* translate);
     virtual bool requiresStencilPass(const GrDrawTarget* target,
                                      const SkPath& path,
                                      GrPathFill fill) const;
-    virtual void drawPathToStencil(GrDrawTarget* target,
-                                   const SkPath& path,
-                                   GrPathFill fill,
-                                   const GrPoint* translate);
+
+    virtual void drawPath(GrDrawTarget::StageBitfield stages);
+    virtual void drawPathToStencil();
+
+protected:
+    virtual void pathWillClear();
+
 private:
 
-    void onDrawPath(GrDrawTarget* target,
-                    GrDrawTarget::StageBitfield stages,
-                    const SkPath& path,
-                    GrPathFill fill,
-                    const GrPoint* translate,
-                    bool stencilOnly);
+    void onDrawPath(GrDrawTarget::StageBitfield stages, bool stencilOnly);
+
+    void createGeom(GrScalar srcSpaceTolSqd,
+                    GrDrawTarget::StageBitfield stages);
 
     bool    fSeparateStencil;
     bool    fStencilWrapOps;
 
+    int                         fSubpathCount;
+    SkAutoSTMalloc<8, uint16_t> fSubpathVertCount;
+    GrScalar                    fPreviousSrcTol;
+    GrDrawTarget::StageBitfield fPreviousStages;
+
+
     typedef GrPathRenderer INHERITED;
 };
 
 #endif
+