Implement filling a path with nv_path_rendering cover

Implement filling a path with nv_path_rendering cover functionality.

The nv_path_rendering cover can be used if the fill is non-inverted
and the draw operation does not require use of vertex shaders.

Moves code for the inverted fill from GrStencilAndCoverPathRenderer
down to GrGpuGL.

R=bsalomon@google.com, markkilgard@gmail.com, cdalton@nvidia.com

Author: kkinnunen@nvidia.com

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

git-svn-id: http://skia.googlecode.com/svn/trunk@11667 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp
index 58b6a4b..1a10336 100644
--- a/src/gpu/GrClipMaskManager.cpp
+++ b/src/gpu/GrClipMaskManager.cpp
@@ -1012,3 +1012,29 @@
     fGpu = gpu;
     fAACache.setContext(gpu->getContext());
 }
+
+void GrClipMaskManager::adjustPathStencilParams(GrStencilSettings* settings) {
+    const GrDrawState& drawState = fGpu->getDrawState();
+    GrClipMaskManager::StencilClipMode clipMode;
+    if (this->isClipInStencil() && drawState.isClipState()) {
+        clipMode = GrClipMaskManager::kRespectClip_StencilClipMode;
+        // We can't be modifying the clip and respecting it at the same time.
+        SkASSERT(!drawState.isStateFlagEnabled(
+                    GrGpu::kModifyStencilClip_StateBit));
+    } else if (drawState.isStateFlagEnabled(
+                    GrGpu::kModifyStencilClip_StateBit)) {
+        clipMode = GrClipMaskManager::kModifyClip_StencilClipMode;
+    } else {
+        clipMode = GrClipMaskManager::kIgnoreClip_StencilClipMode;
+    }
+
+    // TODO: dynamically attach a stencil buffer
+    int stencilBits = 0;
+    GrStencilBuffer* stencilBuffer =
+        drawState.getRenderTarget()->getStencilBuffer();
+    if (NULL != stencilBuffer) {
+        stencilBits = stencilBuffer->bits();
+        this->adjustStencilParams(settings, clipMode, stencilBits);
+    }
+}
+
diff --git a/src/gpu/GrClipMaskManager.h b/src/gpu/GrClipMaskManager.h
index 54b7892..fa93987 100644
--- a/src/gpu/GrClipMaskManager.h
+++ b/src/gpu/GrClipMaskManager.h
@@ -70,6 +70,8 @@
     }
 
     void setGpu(GrGpu* gpu);
+
+    void adjustPathStencilParams(GrStencilSettings* settings);
 private:
     /**
      * Informs the helper function adjustStencilParams() about how the stencil
diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp
index c2256a8..64eedfb 100644
--- a/src/gpu/GrDrawTarget.cpp
+++ b/src/gpu/GrDrawTarget.cpp
@@ -11,6 +11,7 @@
 #include "GrDrawTarget.h"
 #include "GrContext.h"
 #include "GrDrawTargetCaps.h"
+#include "GrPath.h"
 #include "GrRenderTarget.h"
 #include "GrTexture.h"
 #include "GrVertexBuffer.h"
@@ -413,17 +414,18 @@
     return true;
 }
 
-bool GrDrawTarget::setupDstReadIfNecessary(DrawInfo* info) {
+bool GrDrawTarget::setupDstReadIfNecessary(GrDeviceCoordTexture* dstCopy, const SkRect* drawBounds) {
     if (this->caps()->dstReadInShaderSupport() || !this->getDrawState().willEffectReadDstColor()) {
         return true;
     }
     GrRenderTarget* rt = this->drawState()->getRenderTarget();
-
-    const GrClipData* clip = this->getClip();
     SkIRect copyRect;
-    clip->getConservativeBounds(this->getDrawState().getRenderTarget(), &copyRect);
-    SkIRect drawIBounds;
-    if (info->getDevIBounds(&drawIBounds)) {
+    const GrClipData* clip = this->getClip();
+    clip->getConservativeBounds(rt, &copyRect);
+
+    if (NULL != drawBounds) {
+        SkIRect drawIBounds;
+        drawBounds->roundOut(&drawIBounds);
         if (!copyRect.intersect(drawIBounds)) {
 #ifdef SK_DEBUG
             GrPrintf("Missed an early reject. Bailing on draw from setupDstReadIfNecessary.\n");
@@ -451,8 +453,8 @@
     }
     SkIPoint dstPoint = {0, 0};
     if (this->copySurface(ast.texture(), rt, copyRect, dstPoint)) {
-        info->fDstCopy.setTexture(ast.texture());
-        info->fDstCopy.setOffset(copyRect.fLeft, copyRect.fTop);
+        dstCopy->setTexture(ast.texture());
+        dstCopy->setOffset(copyRect.fLeft, copyRect.fTop);
         return true;
     } else {
         return false;
@@ -518,12 +520,37 @@
 void GrDrawTarget::stencilPath(const GrPath* path, const SkStrokeRec& stroke, SkPath::FillType fill) {
     // TODO: extract portions of checkDraw that are relevant to path stenciling.
     SkASSERT(NULL != path);
-    SkASSERT(this->caps()->pathStencilingSupport());
+    SkASSERT(this->caps()->pathRenderingSupport());
     SkASSERT(!stroke.isHairlineStyle());
     SkASSERT(!SkPath::IsInverseFillType(fill));
     this->onStencilPath(path, stroke, fill);
 }
 
+void GrDrawTarget::fillPath(const GrPath* path, const SkStrokeRec& stroke, SkPath::FillType fill) {
+    // TODO: extract portions of checkDraw that are relevant to path rendering.
+    SkASSERT(NULL != path);
+    SkASSERT(this->caps()->pathRenderingSupport());
+    SkASSERT(!stroke.isHairlineStyle());
+    const GrDrawState* drawState = &getDrawState();
+
+    SkRect devBounds;
+    if (SkPath::IsInverseFillType(fill)) {
+        devBounds = SkRect::MakeWH(SkIntToScalar(drawState->getRenderTarget()->width()),
+                                   SkIntToScalar(drawState->getRenderTarget()->height()));
+    } else {
+        devBounds = path->getBounds();
+    }
+    SkMatrix viewM = drawState->getViewMatrix();
+    viewM.mapRect(&devBounds);
+
+    GrDeviceCoordTexture dstCopy;
+    if (!this->setupDstReadIfNecessary(&dstCopy, &devBounds)) {
+        return;
+    }
+
+    this->onFillPath(path, stroke, fill, dstCopy.texture() ? &dstCopy : NULL);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 bool GrDrawTarget::willUseHWAALines() const {
@@ -949,7 +976,7 @@
     fGeometryShaderSupport = false;
     fDualSourceBlendingSupport = false;
     fBufferLockSupport = false;
-    fPathStencilingSupport = false;
+    fPathRenderingSupport = false;
     fDstReadInShaderSupport = false;
     fReuseScratchTextures = true;
 
@@ -968,7 +995,7 @@
     fGeometryShaderSupport = other.fGeometryShaderSupport;
     fDualSourceBlendingSupport = other.fDualSourceBlendingSupport;
     fBufferLockSupport = other.fBufferLockSupport;
-    fPathStencilingSupport = other.fPathStencilingSupport;
+    fPathRenderingSupport = other.fPathRenderingSupport;
     fDstReadInShaderSupport = other.fDstReadInShaderSupport;
     fReuseScratchTextures = other.fReuseScratchTextures;
 
@@ -990,7 +1017,7 @@
     GrPrintf("Geometry Shader Support     : %s\n", gNY[fGeometryShaderSupport]);
     GrPrintf("Dual Source Blending Support: %s\n", gNY[fDualSourceBlendingSupport]);
     GrPrintf("Buffer Lock Support         : %s\n", gNY[fBufferLockSupport]);
-    GrPrintf("Path Stenciling Support     : %s\n", gNY[fPathStencilingSupport]);
+    GrPrintf("Path Rendering Support      : %s\n", gNY[fPathRenderingSupport]);
     GrPrintf("Dst Read In Shader Support  : %s\n", gNY[fDstReadInShaderSupport]);
     GrPrintf("Reuse Scratch Textures      : %s\n", gNY[fReuseScratchTextures]);
     GrPrintf("Max Texture Size            : %d\n", fMaxTextureSize);
diff --git a/src/gpu/GrDrawTarget.h b/src/gpu/GrDrawTarget.h
index 47460ac..49dd388 100644
--- a/src/gpu/GrDrawTarget.h
+++ b/src/gpu/GrDrawTarget.h
@@ -329,6 +329,12 @@
     void stencilPath(const GrPath*, const SkStrokeRec& stroke, SkPath::FillType fill);
 
     /**
+     * Fills a path. Fill must not be a hairline. It will respect the HW
+     * antialias flag on the draw state (if possible in the 3D API).
+     */
+    void fillPath(const GrPath*, const SkStrokeRec& stroke, SkPath::FillType fill);
+
+    /**
      * Helper function for drawing rects. It performs a geometry src push and pop
      * and thus will finalize any reserved geometry.
      *
@@ -448,6 +454,14 @@
      */
     void executeDraw(const DrawInfo& info) { this->onDraw(info); }
 
+    /**
+     * For subclass internal use to invoke a call to onFillPath().
+     */
+    void executeFillPath(const GrPath* path, const SkStrokeRec& stroke,
+                         SkPath::FillType fill, const GrDeviceCoordTexture* dstCopy) {
+        this->onFillPath(path, stroke, fill, dstCopy);
+    }
+
     ////////////////////////////////////////////////////////////////////////////
 
     /**
@@ -761,15 +775,6 @@
         }
         const SkRect* getDevBounds() const { return fDevBounds; }
 
-        bool getDevIBounds(SkIRect* bounds) const {
-            if (NULL != fDevBounds) {
-                fDevBounds->roundOut(bounds);
-                return true;
-            } else {
-                return false;
-            }
-        }
-
         // NULL if no copy of the dst is needed for the draw.
         const GrDeviceCoordTexture* getDstCopy() const {
             if (NULL != fDstCopy.texture()) {
@@ -834,6 +839,8 @@
                             const SkRect* localRect,
                             const SkMatrix* localMatrix);
     virtual void onStencilPath(const GrPath*, const SkStrokeRec& stroke, SkPath::FillType fill) = 0;
+    virtual void onFillPath(const GrPath*, const SkStrokeRec& stroke, SkPath::FillType fill,
+                            const GrDeviceCoordTexture* dstCopy) = 0;
 
     // helpers for reserving vertex and index space.
     bool reserveVertexSpace(size_t vertexSize,
@@ -852,7 +859,10 @@
 
     // Makes a copy of the dst if it is necessary for the draw. Returns false if a copy is required
     // but couldn't be made. Otherwise, returns true.
-    bool setupDstReadIfNecessary(DrawInfo* info);
+    bool setupDstReadIfNecessary(DrawInfo* info) {
+        return this->setupDstReadIfNecessary(&info->fDstCopy, info->getDevBounds());
+    }
+    bool setupDstReadIfNecessary(GrDeviceCoordTexture* dstCopy, const SkRect* drawBounds);
 
     // Check to see if this set of draw commands has been sent out
     virtual bool       isIssued(uint32_t drawID) { return true; }
diff --git a/src/gpu/GrDrawTargetCaps.h b/src/gpu/GrDrawTargetCaps.h
index 61c9fed..111b35b 100644
--- a/src/gpu/GrDrawTargetCaps.h
+++ b/src/gpu/GrDrawTargetCaps.h
@@ -34,7 +34,7 @@
     bool geometryShaderSupport() const { return fGeometryShaderSupport; }
     bool dualSourceBlendingSupport() const { return fDualSourceBlendingSupport; }
     bool bufferLockSupport() const { return fBufferLockSupport; }
-    bool pathStencilingSupport() const { return fPathStencilingSupport; }
+    bool pathRenderingSupport() const { return fPathRenderingSupport; }
     bool dstReadInShaderSupport() const { return fDstReadInShaderSupport; }
     bool reuseScratchTextures() const { return fReuseScratchTextures; }
 
@@ -53,7 +53,7 @@
     bool fGeometryShaderSupport     : 1;
     bool fDualSourceBlendingSupport : 1;
     bool fBufferLockSupport         : 1;
-    bool fPathStencilingSupport     : 1;
+    bool fPathRenderingSupport      : 1;
     bool fDstReadInShaderSupport    : 1;
     bool fReuseScratchTextures      : 1;
 
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index 910c571..5b1c23a 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -198,7 +198,7 @@
 }
 
 GrPath* GrGpu::createPath(const SkPath& path) {
-    SkASSERT(this->caps()->pathStencilingSupport());
+    SkASSERT(this->caps()->pathRenderingSupport());
     this->handleDirtyContext();
     return this->onCreatePath(path);
 }
@@ -247,6 +247,42 @@
     this->onResolveRenderTarget(target);
 }
 
+static const GrStencilSettings& winding_path_stencil_settings() {
+    GR_STATIC_CONST_SAME_STENCIL_STRUCT(gSettings,
+        kIncClamp_StencilOp,
+        kIncClamp_StencilOp,
+        kAlwaysIfInClip_StencilFunc,
+        0xFFFF, 0xFFFF, 0xFFFF);
+    return *GR_CONST_STENCIL_SETTINGS_PTR_FROM_STRUCT_PTR(&gSettings);
+}
+
+static const GrStencilSettings& even_odd_path_stencil_settings() {
+    GR_STATIC_CONST_SAME_STENCIL_STRUCT(gSettings,
+        kInvert_StencilOp,
+        kInvert_StencilOp,
+        kAlwaysIfInClip_StencilFunc,
+        0xFFFF, 0xFFFF, 0xFFFF);
+    return *GR_CONST_STENCIL_SETTINGS_PTR_FROM_STRUCT_PTR(&gSettings);
+}
+
+void GrGpu::getPathStencilSettingsForFillType(SkPath::FillType fill, GrStencilSettings* outStencilSettings) {
+
+    switch (fill) {
+        default:
+            GrCrash("Unexpected path fill.");
+            /* fallthrough */;
+        case SkPath::kWinding_FillType:
+        case SkPath::kInverseWinding_FillType:
+            *outStencilSettings = winding_path_stencil_settings();
+            break;
+        case SkPath::kEvenOdd_FillType:
+        case SkPath::kInverseEvenOdd_FillType:
+            *outStencilSettings = even_odd_path_stencil_settings();
+            break;
+    }
+    fClipMaskManager.adjustPathStencilParams(outStencilSettings);
+}
+
 
 ////////////////////////////////////////////////////////////////////////////////
 
@@ -349,10 +385,6 @@
 void GrGpu::onStencilPath(const GrPath* path, const SkStrokeRec&, SkPath::FillType fill) {
     this->handleDirtyContext();
 
-    // TODO: make this more efficient (don't copy and copy back)
-    GrAutoTRestore<GrStencilSettings> asr(this->drawState()->stencil());
-
-    this->setStencilPathSettings(*path, fill, this->drawState()->stencil());
     GrDrawState::AutoRestoreEffects are;
     if (!this->setupClipAndFlushState(kStencilPath_DrawType, NULL, &are)) {
         return;
@@ -361,6 +393,20 @@
     this->onGpuStencilPath(path, fill);
 }
 
+void GrGpu::onFillPath(const GrPath* path, const SkStrokeRec& stroke, SkPath::FillType fill,
+                       const GrDeviceCoordTexture* dstCopy) {
+    this->handleDirtyContext();
+
+    drawState()->setDefaultVertexAttribs();
+
+    GrDrawState::AutoRestoreEffects are;
+    if (!this->setupClipAndFlushState(kFillPath_DrawType, dstCopy, &are)) {
+        return;
+    }
+
+    this->onGpuFillPath(path, fill);
+}
+
 void GrGpu::finalizeReservedVertices() {
     SkASSERT(NULL != fVertexPool);
     fVertexPool->unlock();
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index 239ae6b..6a9dfa2 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -335,12 +335,15 @@
                                                  // clipping.
     };
 
+    void getPathStencilSettingsForFillType(SkPath::FillType fill, GrStencilSettings* outStencilSettings);
+
 protected:
     enum DrawType {
         kDrawPoints_DrawType,
         kDrawLines_DrawType,
         kDrawTriangles_DrawType,
         kStencilPath_DrawType,
+        kFillPath_DrawType,
     };
 
     DrawType PrimTypeToDrawType(GrPrimitiveType type) {
@@ -440,15 +443,10 @@
 
     // overridden by backend-specific derived class to perform the draw call.
     virtual void onGpuDraw(const DrawInfo&) = 0;
-    // when GrDrawTarget::stencilPath is called the draw state's current stencil
-    // settings are ignored. Instead the GrGpu decides the stencil rules
-    // necessary to stencil the path. These are still subject to filtering by
-    // the clip mask manager.
-    virtual void setStencilPathSettings(const GrPath&,
-                                        SkPath::FillType,
-                                        GrStencilSettings* settings) = 0;
+
     // overridden by backend-specific derived class to perform the path stenciling.
     virtual void onGpuStencilPath(const GrPath*, SkPath::FillType) = 0;
+    virtual void onGpuFillPath(const GrPath*, SkPath::FillType) = 0;
 
     // overridden by backend-specific derived class to perform flush
     virtual void onForceRenderTargetFlush() = 0;
@@ -494,6 +492,9 @@
     virtual void onStencilPath(const GrPath* path, const SkStrokeRec& stroke,
                                SkPath::FillType) SK_OVERRIDE;
 
+    virtual void onFillPath(const GrPath* path, const SkStrokeRec& stroke, SkPath::FillType,
+                            const GrDeviceCoordTexture* dstCopy) SK_OVERRIDE;
+
     // readies the pools to provide vertex/index data.
     void prepareVertexPool();
     void prepareIndexPool();
diff --git a/src/gpu/GrInOrderDrawBuffer.cpp b/src/gpu/GrInOrderDrawBuffer.cpp
index 8c8fbfc..dbbdf16 100644
--- a/src/gpu/GrInOrderDrawBuffer.cpp
+++ b/src/gpu/GrInOrderDrawBuffer.cpp
@@ -385,6 +385,7 @@
 }
 
 GrInOrderDrawBuffer::StencilPath::StencilPath() : fStroke(SkStrokeRec::kFill_InitStyle) {}
+GrInOrderDrawBuffer::FillPath::FillPath() : fStroke(SkStrokeRec::kFill_InitStyle) {}
 
 void GrInOrderDrawBuffer::onStencilPath(const GrPath* path, const SkStrokeRec& stroke,
                                         SkPath::FillType fill) {
@@ -402,6 +403,25 @@
     sp->fStroke = stroke;
 }
 
+void GrInOrderDrawBuffer::onFillPath(const GrPath* path, const SkStrokeRec& stroke,
+                                     SkPath::FillType fill, const GrDeviceCoordTexture* dstCopy) {
+    if (this->needsNewClip()) {
+        this->recordClip();
+    }
+    // TODO: Only compare the subset of GrDrawState relevant to path covering?
+    if (this->needsNewState()) {
+        this->recordState();
+    }
+    FillPath* cp = this->recordFillPath();
+    cp->fPath.reset(path);
+    path->ref();
+    cp->fFill = fill;
+    cp->fStroke = stroke;
+    if (NULL != dstCopy) {
+        cp->fDstCopy = *dstCopy;
+    }
+}
+
 void GrInOrderDrawBuffer::clear(const SkIRect* rect, GrColor color, GrRenderTarget* renderTarget) {
     SkIRect r;
     if (NULL == renderTarget) {
@@ -436,6 +456,7 @@
     fCmds.reset();
     fDraws.reset();
     fStencilPaths.reset();
+    fFillPaths.reset();
     fStates.reset();
     fClears.reset();
     fVertexPool.reset();
@@ -480,6 +501,7 @@
     int currClear       = 0;
     int currDraw        = 0;
     int currStencilPath = 0;
+    int currFillPath    = 0;
     int currCopySurface = 0;
 
     for (int c = 0; c < numCmds; ++c) {
@@ -501,6 +523,13 @@
                 ++currStencilPath;
                 break;
             }
+            case kFillPath_Cmd: {
+                const FillPath& cp = fFillPaths[currFillPath];
+                fDstGpu->executeFillPath(cp.fPath.get(), cp.fStroke, cp.fFill,
+                                         NULL != cp.fDstCopy.texture() ? &cp.fDstCopy : NULL);
+                ++currFillPath;
+                break;
+            }
             case kSetState_Cmd:
                 fStates[currState].restoreTo(&playbackState);
                 ++currState;
@@ -810,6 +839,11 @@
     return &fStencilPaths.push_back();
 }
 
+GrInOrderDrawBuffer::FillPath* GrInOrderDrawBuffer::recordFillPath() {
+    fCmds.push_back(kFillPath_Cmd);
+    return &fFillPaths.push_back();
+}
+
 GrInOrderDrawBuffer::Clear* GrInOrderDrawBuffer::recordClear() {
     fCmds.push_back(kClear_Cmd);
     return &fClears.push_back();
diff --git a/src/gpu/GrInOrderDrawBuffer.h b/src/gpu/GrInOrderDrawBuffer.h
index ca6af3f..b9e5ca8 100644
--- a/src/gpu/GrInOrderDrawBuffer.h
+++ b/src/gpu/GrInOrderDrawBuffer.h
@@ -87,6 +87,7 @@
         kSetClip_Cmd        = 4,
         kClear_Cmd          = 5,
         kCopySurface_Cmd    = 6,
+        kFillPath_Cmd       = 7,
     };
 
     class DrawRecord : public DrawInfo {
@@ -104,6 +105,15 @@
         SkPath::FillType            fFill;
     };
 
+    struct FillPath : public ::SkNoncopyable {
+        FillPath();
+
+        SkAutoTUnref<const GrPath>  fPath;
+        SkStrokeRec                 fStroke;
+        SkPath::FillType            fFill;
+        GrDeviceCoordTexture        fDstCopy;
+    };
+
     struct Clear : public ::SkNoncopyable {
         Clear() : fRenderTarget(NULL) {}
         ~Clear() { SkSafeUnref(fRenderTarget); }
@@ -127,6 +137,8 @@
                             const SkRect* localRect,
                             const SkMatrix* localMatrix) SK_OVERRIDE;
     virtual void onStencilPath(const GrPath*, const SkStrokeRec& stroke, SkPath::FillType) SK_OVERRIDE;
+    virtual void onFillPath(const GrPath*, const SkStrokeRec& stroke, SkPath::FillType,
+                            const GrDeviceCoordTexture* dstCopy) SK_OVERRIDE;
     virtual bool onReserveVertexSpace(size_t vertexSize,
                                       int vertexCount,
                                       void** vertices) SK_OVERRIDE;
@@ -169,6 +181,7 @@
     void            recordClip();
     DrawRecord*     recordDraw(const DrawInfo&);
     StencilPath*    recordStencilPath();
+    FillPath*       recordFillPath();
     Clear*          recordClear();
     CopySurface*    recordCopySurface();
 
@@ -177,6 +190,7 @@
         kCmdPreallocCnt          = 32,
         kDrawPreallocCnt         = 8,
         kStencilPathPreallocCnt  = 8,
+        kFillPathPreallocCnt     = 8,
         kStatePreallocCnt        = 8,
         kClipPreallocCnt         = 8,
         kClearPreallocCnt        = 4,
@@ -187,6 +201,7 @@
     SkSTArray<kCmdPreallocCnt, uint8_t, true>                          fCmds;
     GrSTAllocator<kDrawPreallocCnt, DrawRecord>                        fDraws;
     GrSTAllocator<kStatePreallocCnt, StencilPath>                      fStencilPaths;
+    GrSTAllocator<kStatePreallocCnt, FillPath>                         fFillPaths;
     GrSTAllocator<kStatePreallocCnt, GrDrawState::DeferredState>       fStates;
     GrSTAllocator<kClearPreallocCnt, Clear>                            fClears;
     GrSTAllocator<kCopySurfacePreallocCnt, CopySurface>                fCopySurfaces;
diff --git a/src/gpu/GrStencilAndCoverPathRenderer.cpp b/src/gpu/GrStencilAndCoverPathRenderer.cpp
index f7330a8..ef3b953 100644
--- a/src/gpu/GrStencilAndCoverPathRenderer.cpp
+++ b/src/gpu/GrStencilAndCoverPathRenderer.cpp
@@ -17,7 +17,7 @@
 GrPathRenderer* GrStencilAndCoverPathRenderer::Create(GrContext* context) {
     SkASSERT(NULL != context);
     SkASSERT(NULL != context->getGpu());
-    if (context->getGpu()->caps()->pathStencilingSupport()) {
+    if (context->getGpu()->caps()->pathRenderingSupport()) {
         return SkNEW_ARGS(GrStencilAndCoverPathRenderer, (context->getGpu()));
     } else {
         return NULL;
@@ -25,7 +25,7 @@
 }
 
 GrStencilAndCoverPathRenderer::GrStencilAndCoverPathRenderer(GrGpu* gpu) {
-    SkASSERT(gpu->caps()->pathStencilingSupport());
+    SkASSERT(gpu->caps()->pathRenderingSupport());
     fGpu = gpu;
     gpu->ref();
 }
@@ -40,6 +40,7 @@
                                                 bool antiAlias) const {
     return stroke.isFillStyle() &&
            !antiAlias && // doesn't do per-path AA, relies on the target having MSAA
+           NULL != target->getDrawState().getRenderTarget()->getStencilBuffer() &&
            target->getDrawState().getStencil().isDisabled();
 }
 
@@ -70,27 +71,7 @@
 
     SkAutoTUnref<GrPath> p(fGpu->createPath(path));
 
-    SkPath::FillType nonInvertedFill = SkPath::ConvertToNonInverseFillType(path.getFillType());
-    target->stencilPath(p, stroke, nonInvertedFill);
-
-    // TODO: Use built in cover operation rather than a rect draw. This will require making our
-    // fragment shaders be able to eat varyings generated by a matrix.
-
-    // fill the path, zero out the stencil
-    SkRect bounds = p->getBounds();
-    SkScalar bloat = drawState->getViewMatrix().getMaxStretch() * SK_ScalarHalf;
-    GrDrawState::AutoViewMatrixRestore avmr;
-
-    if (nonInvertedFill == path.getFillType()) {
-        GR_STATIC_CONST_SAME_STENCIL(kStencilPass,
-            kZero_StencilOp,
-            kZero_StencilOp,
-            kNotEqual_StencilFunc,
-            0xffff,
-            0x0000,
-            0xffff);
-        *drawState->stencil() = kStencilPass;
-    } else {
+    if (path.isInverseFillType()) {
         GR_STATIC_CONST_SAME_STENCIL(kInvertedStencilPass,
             kZero_StencilOp,
             kZero_StencilOp,
@@ -101,23 +82,22 @@
             0xffff,
             0x0000,
             0xffff);
-        SkMatrix vmi;
-        bounds.setLTRB(0, 0,
-                       SkIntToScalar(drawState->getRenderTarget()->width()),
-                       SkIntToScalar(drawState->getRenderTarget()->height()));
-        // mapRect through persp matrix may not be correct
-        if (!drawState->getViewMatrix().hasPerspective() && drawState->getViewInverse(&vmi)) {
-            vmi.mapRect(&bounds);
-            // theoretically could set bloat = 0, instead leave it because of matrix inversion
-            // precision.
-        } else {
-            avmr.setIdentity(drawState);
-            bloat = 0;
-        }
+
         *drawState->stencil() = kInvertedStencilPass;
+    } else {
+        GR_STATIC_CONST_SAME_STENCIL(kStencilPass,
+            kZero_StencilOp,
+            kZero_StencilOp,
+            kNotEqual_StencilFunc,
+            0xffff,
+            0x0000,
+            0xffff);
+
+        *drawState->stencil() = kStencilPass;
     }
-    bounds.outset(bloat, bloat);
-    target->drawSimpleRect(bounds, NULL);
+
+    target->fillPath(p, stroke, path.getFillType());
+
     target->drawState()->stencil()->setDisabled();
     return true;
 }
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index aac9736..17a4743 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -302,8 +302,8 @@
     // attachment, hence this min:
     fMaxRenderTargetSize = GrMin(fMaxTextureSize, fMaxRenderTargetSize);
 
-    fPathStencilingSupport = GR_GL_USE_NV_PATH_RENDERING &&
-                             ctxInfo.hasExtension("GL_NV_path_rendering");
+    fPathRenderingSupport = GR_GL_USE_NV_PATH_RENDERING &&
+                            ctxInfo.hasExtension("GL_NV_path_rendering");
 
     fDstReadInShaderSupport = kNone_FBFetchType != fFBFetchType;
 
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index 1ca61e3..a69333f 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -52,7 +52,7 @@
 
     if (fDesc.getHeader().fHasVertexCode ||
         !fGpu->glCaps().fixedFunctionSupport() ||
-        !fGpu->glCaps().pathStencilingSupport()) {
+        !fGpu->glCaps().pathRenderingSupport()) {
 
         GrGLFullShaderBuilder fullBuilder(fGpu, fUniformManager, fDesc);
         if (this->genProgram(&fullBuilder, colorStages, coverageStages)) {
diff --git a/src/gpu/gl/GrGLProgramDesc.cpp b/src/gpu/gl/GrGLProgramDesc.cpp
index 8b731fb..f9728ff 100644
--- a/src/gpu/gl/GrGLProgramDesc.cpp
+++ b/src/gpu/gl/GrGLProgramDesc.cpp
@@ -122,11 +122,13 @@
     header->fExperimentalGS = false;
 #endif
 #endif
+    bool defaultToUniformInputs = GR_GL_NO_CONSTANT_ATTRIBUTES || gpu->caps()->pathRenderingSupport();
+
     if (colorIsTransBlack) {
         header->fColorInput = kTransBlack_ColorInput;
     } else if (colorIsSolidWhite) {
         header->fColorInput = kSolidWhite_ColorInput;
-    } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresColorAttrib) {
+    } else if (defaultToUniformInputs && !requiresColorAttrib) {
         header->fColorInput = kUniform_ColorInput;
     } else {
         header->fColorInput = kAttribute_ColorInput;
@@ -139,7 +141,7 @@
         header->fCoverageInput = kTransBlack_ColorInput;
     } else if (covIsSolidWhite) {
         header->fCoverageInput = kSolidWhite_ColorInput;
-    } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresCoverageAttrib) {
+    } else if (defaultToUniformInputs && !requiresCoverageAttrib) {
         header->fCoverageInput = kUniform_ColorInput;
     } else {
         header->fCoverageInput = kAttribute_ColorInput;
diff --git a/src/gpu/gl/GrGLShaderBuilder.cpp b/src/gpu/gl/GrGLShaderBuilder.cpp
index 00fefe1..eb7cfa7 100644
--- a/src/gpu/gl/GrGLShaderBuilder.cpp
+++ b/src/gpu/gl/GrGLShaderBuilder.cpp
@@ -930,7 +930,7 @@
 
     SkASSERT(!desc.getHeader().fHasVertexCode);
     SkASSERT(gpu->glCaps().fixedFunctionSupport());
-    SkASSERT(gpu->glCaps().pathStencilingSupport());
+    SkASSERT(gpu->glCaps().pathRenderingSupport());
     SkASSERT(GrGLProgramDesc::kAttribute_ColorInput != desc.getHeader().fColorInput);
     SkASSERT(GrGLProgramDesc::kAttribute_ColorInput != desc.getHeader().fCoverageInput);
 }
diff --git a/src/gpu/gl/GrGpuGL.cpp b/src/gpu/gl/GrGpuGL.cpp
index 18165d9..1138667 100644
--- a/src/gpu/gl/GrGpuGL.cpp
+++ b/src/gpu/gl/GrGpuGL.cpp
@@ -365,26 +365,30 @@
         fHWBoundRenderTarget = NULL;
     }
 
-    if (resetBits & kFixedFunction_GrGLBackendState && this->glCaps().fixedFunctionSupport()) {
+    if (resetBits & (kFixedFunction_GrGLBackendState | kPathRendering_GrGLBackendState)) {
+        if (this->glCaps().fixedFunctionSupport()) {
+            fHWProjectionMatrixState.invalidate();
+            // we don't use the model view matrix.
+            GL_CALL(MatrixMode(GR_GL_MODELVIEW));
+            GL_CALL(LoadIdentity());
 
-        fHWProjectionMatrixState.invalidate();
-        // we don't use the model view matrix.
-        GL_CALL(MatrixMode(GR_GL_MODELVIEW));
-        GL_CALL(LoadIdentity());
-
-        for (int i = 0; i < this->glCaps().maxFixedFunctionTextureCoords(); ++i) {
-            GL_CALL(ActiveTexture(GR_GL_TEXTURE0 + i));
-            GL_CALL(Disable(GR_GL_TEXTURE_GEN_S));
-            GL_CALL(Disable(GR_GL_TEXTURE_GEN_T));
-            GL_CALL(Disable(GR_GL_TEXTURE_GEN_Q));
-            GL_CALL(Disable(GR_GL_TEXTURE_GEN_R));
-            if (this->caps()->pathStencilingSupport()) {
-                GL_CALL(PathTexGen(GR_GL_TEXTURE0 + i, GR_GL_NONE, 0, NULL));
+            for (int i = 0; i < this->glCaps().maxFixedFunctionTextureCoords(); ++i) {
+                GL_CALL(ActiveTexture(GR_GL_TEXTURE0 + i));
+                GL_CALL(Disable(GR_GL_TEXTURE_GEN_S));
+                GL_CALL(Disable(GR_GL_TEXTURE_GEN_T));
+                GL_CALL(Disable(GR_GL_TEXTURE_GEN_Q));
+                GL_CALL(Disable(GR_GL_TEXTURE_GEN_R));
+                if (this->caps()->pathRenderingSupport()) {
+                    GL_CALL(PathTexGen(GR_GL_TEXTURE0 + i, GR_GL_NONE, 0, NULL));
+                }
+                fHWTexGenSettings[i].fMode = GR_GL_NONE;
+                fHWTexGenSettings[i].fNumComponents = 0;
             }
-            fHWTexGenSettings[i].fMode = GR_GL_NONE;
-            fHWTexGenSettings[i].fNumComponents = 0;
+            fHWActiveTexGenSets = 0;
         }
-        fHWActiveTexGenSets = 0;
+        if (this->caps()->pathRenderingSupport()) {
+            fHWPathStencilSettings.invalidate();
+        }
     }
 
     // we assume these values
@@ -1273,7 +1277,7 @@
 }
 
 GrPath* GrGpuGL::onCreatePath(const SkPath& inPath) {
-    SkASSERT(this->caps()->pathStencilingSupport());
+    SkASSERT(this->caps()->pathRenderingSupport());
     return SkNEW_ARGS(GrGLPath, (this, inPath));
 }
 
@@ -1666,81 +1670,77 @@
 #endif
 }
 
-namespace {
-
-static const uint16_t kOnes16 = static_cast<uint16_t>(~0);
-const GrStencilSettings& winding_nv_path_stencil_settings() {
-    GR_STATIC_CONST_SAME_STENCIL_STRUCT(gSettings,
-        kIncClamp_StencilOp,
-        kIncClamp_StencilOp,
-        kAlwaysIfInClip_StencilFunc,
-        kOnes16, kOnes16, kOnes16);
-    return *GR_CONST_STENCIL_SETTINGS_PTR_FROM_STRUCT_PTR(&gSettings);
-}
-const GrStencilSettings& even_odd_nv_path_stencil_settings() {
-    GR_STATIC_CONST_SAME_STENCIL_STRUCT(gSettings,
-        kInvert_StencilOp,
-        kInvert_StencilOp,
-        kAlwaysIfInClip_StencilFunc,
-        kOnes16, kOnes16, kOnes16);
-    return *GR_CONST_STENCIL_SETTINGS_PTR_FROM_STRUCT_PTR(&gSettings);
-}
-}
-
-void GrGpuGL::setStencilPathSettings(const GrPath&,
-                                     SkPath::FillType fill,
-                                     GrStencilSettings* settings) {
-    switch (fill) {
-        case SkPath::kEvenOdd_FillType:
-            *settings = even_odd_nv_path_stencil_settings();
-            return;
-        case SkPath::kWinding_FillType:
-            *settings = winding_nv_path_stencil_settings();
-            return;
+static GrGLenum gr_stencil_op_to_gl_path_rendering_fill_mode(GrStencilOp op) {
+    switch (op) {
         default:
             GrCrash("Unexpected path fill.");
+            /* fallthrough */;
+        case kIncClamp_StencilOp:
+            return GR_GL_COUNT_UP;
+        case kInvert_StencilOp:
+            return GR_GL_INVERT;
     }
 }
 
 void GrGpuGL::onGpuStencilPath(const GrPath* path, SkPath::FillType fill) {
-    SkASSERT(this->caps()->pathStencilingSupport());
+    SkASSERT(this->caps()->pathRenderingSupport());
 
     GrGLuint id = static_cast<const GrGLPath*>(path)->pathID();
-    GrDrawState* drawState = this->drawState();
-    SkASSERT(NULL != drawState->getRenderTarget());
-    if (NULL == drawState->getRenderTarget()->getStencilBuffer()) {
-        return;
-    }
+    SkASSERT(NULL != this->drawState()->getRenderTarget());
+    SkASSERT(NULL != this->drawState()->getRenderTarget()->getStencilBuffer());
+
+    flushPathStencilSettings(fill);
 
     // Decide how to manipulate the stencil buffer based on the fill rule.
-    // Also, assert that the stencil settings we set in setStencilPathSettings
-    // are present.
-    SkASSERT(!fStencilSettings.isTwoSided());
-    GrGLenum fillMode;
-    switch (fill) {
-        case SkPath::kWinding_FillType:
-            fillMode = GR_GL_COUNT_UP;
-            SkASSERT(kIncClamp_StencilOp ==
-                     fStencilSettings.passOp(GrStencilSettings::kFront_Face));
-            SkASSERT(kIncClamp_StencilOp ==
-                     fStencilSettings.failOp(GrStencilSettings::kFront_Face));
-            break;
-        case SkPath::kEvenOdd_FillType:
-            fillMode = GR_GL_INVERT;
-            SkASSERT(kInvert_StencilOp ==
-                     fStencilSettings.passOp(GrStencilSettings::kFront_Face));
-            SkASSERT(kInvert_StencilOp ==
-                fStencilSettings.failOp(GrStencilSettings::kFront_Face));
-            break;
-        default:
-            // Only the above two fill rules are allowed.
-            GrCrash("Unexpected path fill.");
-            return; // suppress unused var warning.
-    }
-    GrGLint writeMask = fStencilSettings.writeMask(GrStencilSettings::kFront_Face);
+    SkASSERT(!fHWPathStencilSettings.isTwoSided());
+
+    GrGLenum fillMode =
+        gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
+    GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
     GL_CALL(StencilFillPath(id, fillMode, writeMask));
 }
 
+void GrGpuGL::onGpuFillPath(const GrPath* path, SkPath::FillType fill) {
+    SkASSERT(this->caps()->pathRenderingSupport());
+
+    GrGLuint id = static_cast<const GrGLPath*>(path)->pathID();
+    SkASSERT(NULL != this->drawState()->getRenderTarget());
+    SkASSERT(NULL != this->drawState()->getRenderTarget()->getStencilBuffer());
+    SkASSERT(!fCurrentProgram->hasVertexShader());
+
+    flushPathStencilSettings(fill);
+
+    SkPath::FillType nonInvertedFill = SkPath::ConvertToNonInverseFillType(fill);
+    SkASSERT(!fHWPathStencilSettings.isTwoSided());
+    GrGLenum fillMode =
+        gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
+    GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
+    GL_CALL(StencilFillPath(id, fillMode, writeMask));
+
+    if (nonInvertedFill == fill) {
+        GL_CALL(CoverFillPath(id, GR_GL_BOUNDING_BOX));
+    } else {
+        GrDrawState* drawState = this->drawState();
+        GrDrawState::AutoViewMatrixRestore avmr;
+        SkRect bounds = SkRect::MakeLTRB(0, 0,
+                                         SkIntToScalar(drawState->getRenderTarget()->width()),
+                                         SkIntToScalar(drawState->getRenderTarget()->height()));
+        SkMatrix vmi;
+        // mapRect through persp matrix may not be correct
+        if (!drawState->getViewMatrix().hasPerspective() && drawState->getViewInverse(&vmi)) {
+            vmi.mapRect(&bounds);
+            // theoretically could set bloat = 0, instead leave it because of matrix inversion
+            // precision.
+            SkScalar bloat = drawState->getViewMatrix().getMaxStretch() * SK_ScalarHalf;
+            bounds.outset(bloat, bloat);
+        } else {
+            avmr.setIdentity(drawState);
+        }
+
+        this->drawSimpleRect(bounds, NULL);
+    }
+}
+
 void GrGpuGL::onResolveRenderTarget(GrRenderTarget* target) {
     GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(target);
     if (rt->needsResolve()) {
@@ -1862,16 +1862,7 @@
 }
 
 void GrGpuGL::flushStencil(DrawType type) {
-    if (kStencilPath_DrawType == type) {
-        SkASSERT(!fStencilSettings.isTwoSided());
-        // Just the func, ref, and mask is set here. The op and write mask are params to the call
-        // that draws the path to the SB (glStencilFillPath)
-        GrGLenum func =
-            gr_to_gl_stencil_func(fStencilSettings.func(GrStencilSettings::kFront_Face));
-        GL_CALL(PathStencilFunc(func,
-                                fStencilSettings.funcRef(GrStencilSettings::kFront_Face),
-                                fStencilSettings.funcMask(GrStencilSettings::kFront_Face)));
-    } else if (fHWStencilSettings != fStencilSettings) {
+    if (kStencilPath_DrawType != type && fHWStencilSettings != fStencilSettings) {
         if (fStencilSettings.isDisabled()) {
             if (kNo_TriState != fHWStencilTestEnabled) {
                 GL_CALL(Disable(GR_GL_STENCIL_TEST));
@@ -1961,6 +1952,22 @@
     }
 }
 
+void GrGpuGL::flushPathStencilSettings(SkPath::FillType fill) {
+    GrStencilSettings pathStencilSettings;
+    this->getPathStencilSettingsForFillType(fill, &pathStencilSettings);
+    if (fHWPathStencilSettings != pathStencilSettings) {
+        // Just the func, ref, and mask is set here. The op and write mask are params to the call
+        // that draws the path to the SB (glStencilFillPath)
+        GrGLenum func =
+            gr_to_gl_stencil_func(pathStencilSettings.func(GrStencilSettings::kFront_Face));
+        GL_CALL(PathStencilFunc(func,
+                                pathStencilSettings.funcRef(GrStencilSettings::kFront_Face),
+                                pathStencilSettings.funcMask(GrStencilSettings::kFront_Face)));
+
+        fHWPathStencilSettings = pathStencilSettings;
+    }
+}
+
 void GrGpuGL::flushBlend(bool isLines,
                          GrBlendCoeff srcCoeff,
                          GrBlendCoeff dstCoeff) {
@@ -2148,7 +2155,7 @@
                            const GrGLfloat* coefficients) {
 
     SkASSERT(this->glCaps().fixedFunctionSupport());
-    SkASSERT(this->caps()->pathStencilingSupport());
+    SkASSERT(this->caps()->pathRenderingSupport());
     SkASSERT(components >= kS_TexGenComponents && components <= kSTR_TexGenComponents);
 
     if (GR_GL_OBJECT_LINEAR == fHWTexGenSettings[unitIdx].fMode &&
diff --git a/src/gpu/gl/GrGpuGL.h b/src/gpu/gl/GrGpuGL.h
index a59654a..a945e54 100644
--- a/src/gpu/gl/GrGpuGL.h
+++ b/src/gpu/gl/GrGpuGL.h
@@ -151,11 +151,8 @@
 
     virtual void onGpuDraw(const DrawInfo&) SK_OVERRIDE;
 
-    virtual void setStencilPathSettings(const GrPath&,
-                                        SkPath::FillType,
-                                        GrStencilSettings* settings)
-                                        SK_OVERRIDE;
     virtual void onGpuStencilPath(const GrPath*, SkPath::FillType) SK_OVERRIDE;
+    virtual void onGpuFillPath(const GrPath*, SkPath::FillType) SK_OVERRIDE;
 
     virtual void clearStencil() SK_OVERRIDE;
     virtual void clearStencilClip(const SkIRect& rect,
@@ -245,6 +242,7 @@
     void flushRenderTarget(const SkIRect* bound);
     void flushStencil(DrawType);
     void flushAAState(DrawType);
+    void flushPathStencilSettings(SkPath::FillType fill);
 
     bool configToGLFormats(GrPixelConfig config,
                            bool getSizedInternal,
@@ -434,6 +432,7 @@
 
     GrStencilSettings           fHWStencilSettings;
     TriState                    fHWStencilTestEnabled;
+    GrStencilSettings           fHWPathStencilSettings;
 
     GrDrawState::DrawFace       fHWDrawFace;
     TriState                    fHWWriteToColor;
diff --git a/src/gpu/gl/GrGpuGL_program.cpp b/src/gpu/gl/GrGpuGL_program.cpp
index 92eed8d..f3b566c 100644
--- a/src/gpu/gl/GrGpuGL_program.cpp
+++ b/src/gpu/gl/GrGpuGL_program.cpp
@@ -252,6 +252,9 @@
             SkDEBUGFAIL("Failed to create program!");
             return false;
         }
+
+        SkASSERT(kFillPath_DrawType != type || !fCurrentProgram->hasVertexShader());
+
         fCurrentProgram.get()->ref();
 
         GrGLuint programID = fCurrentProgram->programID();