Separate GL path rendering state from GrGpuGL to GrGLPathRendering

Separate GL path rendering state from GrGpuGL to GrGLPathRendering. This
makes GrGpuGL code simpler.

The intention is that while GrGpuGL represents the global environment for GL,
the GrGLPathRendering represents the global environment for path rendering
extension.

Add GrPathRendering, a base class for path rendering, and inherit
GrGLPathRendering from that. Move the path rendering virtual functions from
GrGpu to GrPathRendering.

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

Author: kkinnunen@nvidia.com

Review URL: https://codereview.chromium.org/452823002
diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi
index 589cc51..ec2a07f 100644
--- a/gyp/gpu.gypi
+++ b/gyp/gpu.gypi
@@ -97,6 +97,7 @@
       '<(skia_src_path)/gpu/GrPathRendererChain.cpp',
       '<(skia_src_path)/gpu/GrPathRenderer.cpp',
       '<(skia_src_path)/gpu/GrPathRenderer.h',
+      '<(skia_src_path)/gpu/GrPathRendering.h',
       '<(skia_src_path)/gpu/GrPathUtils.cpp',
       '<(skia_src_path)/gpu/GrPathUtils.h',
       '<(skia_src_path)/gpu/GrPictureUtils.h',
diff --git a/src/gpu/GrDrawTarget.h b/src/gpu/GrDrawTarget.h
index d1023d2..998f412 100644
--- a/src/gpu/GrDrawTarget.h
+++ b/src/gpu/GrDrawTarget.h
@@ -12,6 +12,7 @@
 #include "GrContext.h"
 #include "GrDrawState.h"
 #include "GrIndexBuffer.h"
+#include "GrPathRendering.h"
 #include "GrTraceMarker.h"
 
 #include "SkClipStack.h"
@@ -36,6 +37,9 @@
 public:
     SK_DECLARE_INST_COUNT(GrDrawTarget)
 
+
+    typedef GrPathRendering::PathTransformType PathTransformType ;
+
     ///////////////////////////////////////////////////////////////////////////
 
     // The context may not be fully constructed and should not be used during GrDrawTarget
@@ -333,38 +337,11 @@
                               PathTransformSize(transformsType) * count elements
      * @param fill            Fill type for drawing all the paths
      */
-    enum PathTransformType {
-        kNone_PathTransformType,        //!< []
-        kTranslateX_PathTransformType,  //!< [kMTransX]
-        kTranslateY_PathTransformType,  //!< [kMTransY]
-        kTranslate_PathTransformType,   //!< [kMTransX, kMTransY]
-        kAffine_PathTransformType,      //!< [kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY]
-
-        kLast_PathTransformType = kAffine_PathTransformType
-    };
     void drawPaths(const GrPathRange* pathRange,
                    const uint32_t indices[], int count,
                    const float transforms[], PathTransformType transformsType,
                    SkPath::FillType fill);
 
-    static inline int PathTransformSize(PathTransformType type) {
-        switch (type) {
-            case kNone_PathTransformType:
-                return 0;
-            case kTranslateX_PathTransformType:
-            case kTranslateY_PathTransformType:
-                return 1;
-            case kTranslate_PathTransformType:
-                return 2;
-            case kAffine_PathTransformType:
-                return 6;
-
-            default:
-                SkFAIL("Unknown path transform type");
-                return 0;
-        }
-    }
-
     /**
      * Helper function for drawing rects. It performs a geometry src push and pop
      * and thus will finalize any reserved geometry.
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index 0b49e74..74df260 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -215,13 +215,12 @@
 GrPath* GrGpu::createPath(const SkPath& path, const SkStrokeRec& stroke) {
     SkASSERT(this->caps()->pathRenderingSupport());
     this->handleDirtyContext();
-    return this->onCreatePath(path, stroke);
+    return this->pathRendering()->createPath(path, stroke);
 }
 
 GrPathRange* GrGpu::createPathRange(size_t size, const SkStrokeRec& stroke) {
-    SkASSERT(this->caps()->pathRenderingSupport());
     this->handleDirtyContext();
-    return this->onCreatePathRange(size, stroke);
+    return this->pathRendering()->createPathRange(size, stroke);
 }
 
 void GrGpu::clear(const SkIRect* rect,
@@ -407,7 +406,7 @@
         return;
     }
 
-    this->onGpuStencilPath(path, fill);
+    this->pathRendering()->stencilPath(path, fill);
 }
 
 
@@ -422,7 +421,7 @@
         return;
     }
 
-    this->onGpuDrawPath(path, fill);
+    this->pathRendering()->drawPath(path, fill);
 }
 
 void GrGpu::onDrawPaths(const GrPathRange* pathRange,
@@ -438,7 +437,7 @@
         return;
     }
 
-    this->onGpuDrawPaths(pathRange, indices, count, transforms, transformsType, fill);
+    this->pathRendering()->drawPaths(pathRange, indices, count, transforms, transformsType, fill);
 }
 
 void GrGpu::finalizeReservedVertices() {
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index b752f7c..5020bdd 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -10,6 +10,7 @@
 
 #include "GrDrawTarget.h"
 #include "GrClipMaskManager.h"
+#include "GrPathRendering.h"
 #include "SkPath.h"
 
 class GrContext;
@@ -54,6 +55,10 @@
     GrContext* getContext() { return this->INHERITED::getContext(); }
     const GrContext* getContext() const { return this->INHERITED::getContext(); }
 
+    GrPathRendering* pathRendering() {
+        return fPathRendering.get();
+    }
+
     /**
      * The GrGpu object normally assumes that no outsider is setting state
      * within the underlying 3D API's context/device/whatever. This call informs
@@ -410,6 +415,8 @@
     void finalizeReservedVertices();
     void finalizeReservedIndices();
 
+    SkAutoTDelete<GrPathRendering> fPathRendering;
+
 private:
     // GrDrawTarget overrides
     virtual bool onReserveVertexSpace(size_t vertexSize, int vertexCount, void** vertices) SK_OVERRIDE;
@@ -438,8 +445,6 @@
     virtual GrRenderTarget* onWrapBackendRenderTarget(const GrBackendRenderTargetDesc&) = 0;
     virtual GrVertexBuffer* onCreateVertexBuffer(size_t size, bool dynamic) = 0;
     virtual GrIndexBuffer* onCreateIndexBuffer(size_t size, bool dynamic) = 0;
-    virtual GrPath* onCreatePath(const SkPath& path, const SkStrokeRec&) = 0;
-    virtual GrPathRange* onCreatePathRange(size_t size, const SkStrokeRec&) = 0;
 
     // overridden by backend-specific derived class to perform the clear and
     // clearRect. NULL rect means clear whole target. If canIgnoreRect is
@@ -449,14 +454,6 @@
     // overridden by backend-specific derived class to perform the draw call.
     virtual void onGpuDraw(const DrawInfo&) = 0;
 
-    // overridden by backend-specific derived class to perform the path stenciling.
-    virtual void onGpuStencilPath(const GrPath*, SkPath::FillType) = 0;
-    virtual void onGpuDrawPath(const GrPath*, SkPath::FillType) = 0;
-    virtual void onGpuDrawPaths(const GrPathRange*,
-                                const uint32_t indices[], int count,
-                                const float transforms[], PathTransformType,
-                                SkPath::FillType) = 0;
-
     // overridden by backend-specific derived class to perform the read pixels.
     virtual bool onReadPixels(GrRenderTarget* target,
                               int left, int top, int width, int height,
diff --git a/src/gpu/GrInOrderDrawBuffer.cpp b/src/gpu/GrInOrderDrawBuffer.cpp
index 6d0bbd1..9df54a8 100644
--- a/src/gpu/GrInOrderDrawBuffer.cpp
+++ b/src/gpu/GrInOrderDrawBuffer.cpp
@@ -430,7 +430,7 @@
     memcpy(dp->fIndices, indices, sizeof(uint32_t) * count);
     dp->fCount = count;
 
-    const int transformsLength = PathTransformSize(transformsType) * count;
+    const int transformsLength = GrPathRendering::PathTransformSize(transformsType) * count;
     dp->fTransforms = SkNEW_ARRAY(float, transformsLength);
     memcpy(dp->fTransforms, transforms, sizeof(float) * transformsLength);
     dp->fTransformsType = transformsType;
diff --git a/src/gpu/GrPathRendering.h b/src/gpu/GrPathRendering.h
new file mode 100644
index 0000000..863da27
--- /dev/null
+++ b/src/gpu/GrPathRendering.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrPathRendering_DEFINED
+#define GrPathRendering_DEFINED
+
+#include "SkPath.h"
+
+class SkStrokeRec;
+class GrPath;
+class GrPathRange;
+class GrGpu;
+
+/**
+ * Abstract class wrapping HW path rendering API.
+ *
+ * The subclasses of this class use the possible HW API to render paths (as opposed to path
+ * rendering implemented in Skia on top of a "3d" HW API).
+ * The subclasses hold the global state needed to render paths, including shadow of the global HW
+ * API state. Similar to GrGpu.
+ *
+ * It is expected that the lifetimes of GrGpuXX and GrXXPathRendering are the same. The call context
+ * interface (eg.  * the concrete instance of GrGpu subclass) should be provided to the instance
+ * during construction.
+ */
+class GrPathRendering {
+public:
+    virtual ~GrPathRendering() { }
+
+    enum PathTransformType {
+        kNone_PathTransformType,        //!< []
+        kTranslateX_PathTransformType,  //!< [kMTransX]
+        kTranslateY_PathTransformType,  //!< [kMTransY]
+        kTranslate_PathTransformType,   //!< [kMTransX, kMTransY]
+        kAffine_PathTransformType,      //!< [kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY]
+
+        kLast_PathTransformType = kAffine_PathTransformType
+    };
+
+    static inline int PathTransformSize(PathTransformType type) {
+        switch (type) {
+            case kNone_PathTransformType:
+                return 0;
+            case kTranslateX_PathTransformType:
+            case kTranslateY_PathTransformType:
+                return 1;
+            case kTranslate_PathTransformType:
+                return 2;
+            case kAffine_PathTransformType:
+                return 6;
+
+            default:
+                SkFAIL("Unknown path transform type");
+                return 0;
+        }
+    }
+
+    virtual GrPath* createPath(const SkPath&, const SkStrokeRec&) = 0;
+    virtual GrPathRange* createPathRange(size_t size, const SkStrokeRec&) = 0;
+    virtual void stencilPath(const GrPath*, SkPath::FillType) = 0;
+    virtual void drawPath(const GrPath*, SkPath::FillType) = 0;
+    virtual void drawPaths(const GrPathRange*, const uint32_t indices[], int count,
+                           const float transforms[], PathTransformType, SkPath::FillType) = 0;
+protected:
+    GrPathRendering() { }
+
+private:
+    GrPathRendering& operator=(const GrPathRendering&);
+};
+
+#endif
diff --git a/src/gpu/GrStencilAndCoverTextContext.cpp b/src/gpu/GrStencilAndCoverTextContext.cpp
index ff7c23e..af4ba64 100644
--- a/src/gpu/GrStencilAndCoverTextContext.cpp
+++ b/src/gpu/GrStencilAndCoverTextContext.cpp
@@ -155,7 +155,7 @@
     SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, glyphCacheTransform);
     fGlyphCache = autoCache.getCache();
     fGlyphs = GlyphPathRange::Create(fContext, fGlyphCache, fStroke);
-    fTransformType = GrDrawTarget::kTranslate_PathTransformType;
+    fTransformType = GrPathRendering::kTranslate_PathTransformType;
 
     const char* stop = text + byteLength;
 
@@ -243,7 +243,7 @@
 
     if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
         if (1 == scalarsPerPosition) {
-            fTransformType = GrDrawTarget::kTranslateX_PathTransformType;
+            fTransformType = GrPathRendering::kTranslateX_PathTransformType;
             while (text < stop) {
                 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0);
                 if (glyph.fWidth) {
@@ -253,7 +253,7 @@
             }
         } else {
             SkASSERT(2 == scalarsPerPosition);
-            fTransformType = GrDrawTarget::kTranslate_PathTransformType;
+            fTransformType = GrPathRendering::kTranslate_PathTransformType;
             while (text < stop) {
                 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0);
                 if (glyph.fWidth) {
@@ -263,7 +263,7 @@
             }
         }
     } else {
-        fTransformType = GrDrawTarget::kTranslate_PathTransformType;
+        fTransformType = GrPathRendering::kTranslate_PathTransformType;
         SkTextMapStateProc tmsProc(SkMatrix::I(), 0, scalarsPerPosition);
         SkTextAlignProcScalar alignProc(fSkPaint.getTextAlign());
         while (text < stop) {
@@ -396,7 +396,7 @@
 }
 
 inline void GrStencilAndCoverTextContext::appendGlyph(uint16_t glyphID, float x) {
-    SkASSERT(GrDrawTarget::kTranslateX_PathTransformType == fTransformType);
+    SkASSERT(GrPathRendering::kTranslateX_PathTransformType == fTransformType);
 
     if (fPendingGlyphCount >= kGlyphBufferSize) {
         this->flush();
@@ -411,7 +411,7 @@
 }
 
 inline void GrStencilAndCoverTextContext::appendGlyph(uint16_t glyphID, float x, float y) {
-    SkASSERT(GrDrawTarget::kTranslate_PathTransformType == fTransformType);
+    SkASSERT(GrPathRendering::kTranslate_PathTransformType == fTransformType);
 
     if (fPendingGlyphCount >= kGlyphBufferSize) {
         this->flush();
diff --git a/src/gpu/gl/GrGLPath.cpp b/src/gpu/gl/GrGLPath.cpp
index 6f158cd..930ec4a 100644
--- a/src/gpu/gl/GrGLPath.cpp
+++ b/src/gpu/gl/GrGLPath.cpp
@@ -85,7 +85,7 @@
                               GrGLuint pathID,
                               const SkPath& skPath,
                               const SkStrokeRec& stroke) {
-    GrGLPathRendering* pr = gpu->pathRendering();
+    GrGLPathRendering* pr = gpu->glPathRendering();
     SkSTArray<16, GrGLubyte, true> pathCommands;
     SkSTArray<16, SkPoint, true> pathPoints;
 
@@ -121,7 +121,7 @@
 
 GrGLPath::GrGLPath(GrGpuGL* gpu, const SkPath& path, const SkStrokeRec& stroke)
     : INHERITED(gpu, kIsWrapped, path, stroke),
-      fPathID(gpu->pathRendering()->genPaths(1)) {
+      fPathID(gpu->glPathRendering()->genPaths(1)) {
     SkASSERT(!path.isEmpty());
 
     InitPathObject(gpu, fPathID, fSkPath, stroke);
@@ -138,7 +138,7 @@
 
 void GrGLPath::onRelease() {
     if (0 != fPathID && !this->isWrapped()) {
-        static_cast<GrGpuGL*>(this->getGpu())->pathRendering()->deletePaths(fPathID, 1);
+        static_cast<GrGpuGL*>(this->getGpu())->glPathRendering()->deletePaths(fPathID, 1);
         fPathID = 0;
     }
 
diff --git a/src/gpu/gl/GrGLPathRange.cpp b/src/gpu/gl/GrGLPathRange.cpp
index 5e89cb5..9aaf9db 100644
--- a/src/gpu/gl/GrGLPathRange.cpp
+++ b/src/gpu/gl/GrGLPathRange.cpp
@@ -13,7 +13,7 @@
 
 GrGLPathRange::GrGLPathRange(GrGpuGL* gpu, size_t size, const SkStrokeRec& stroke)
     : INHERITED(gpu, size, stroke),
-      fBasePathID(gpu->pathRendering()->genPaths(fSize)),
+      fBasePathID(gpu->glPathRendering()->genPaths(fSize)),
       fNumDefinedPaths(0) {
 }
 
@@ -28,7 +28,7 @@
     }
 
     // Make sure the path at this index hasn't been initted already.
-    SkASSERT(GR_GL_FALSE == gpu->pathRendering()->isPath(fBasePathID + index));
+    SkASSERT(GR_GL_FALSE == gpu->glPathRendering()->isPath(fBasePathID + index));
 
     GrGLPath::InitPathObject(gpu, fBasePathID + index, skPath, fStroke);
     ++fNumDefinedPaths;
@@ -39,7 +39,7 @@
     SkASSERT(NULL != this->getGpu());
 
     if (0 != fBasePathID && !this->isWrapped()) {
-        static_cast<GrGpuGL*>(this->getGpu())->pathRendering()->deletePaths(fBasePathID, fSize);
+        static_cast<GrGpuGL*>(this->getGpu())->glPathRendering()->deletePaths(fBasePathID, fSize);
         fBasePathID = 0;
     }
 
diff --git a/src/gpu/gl/GrGLPathRendering.cpp b/src/gpu/gl/GrGLPathRendering.cpp
index 249d981..53d7cf0 100644
--- a/src/gpu/gl/GrGLPathRendering.cpp
+++ b/src/gpu/gl/GrGLPathRendering.cpp
@@ -6,17 +6,49 @@
  */
 
 #include "gl/GrGLPathRendering.h"
-#include "gl/GrGLInterface.h"
 #include "gl/GrGLNameAllocator.h"
 #include "gl/GrGLUtil.h"
+#include "gl/GrGpuGL.h"
 
-#define GL_CALL(X) GR_GL_CALL(fGLInterface.get(), X)
-#define GL_CALL_RET(RET, X) GR_GL_CALL_RET(fGLInterface.get(), RET, X)
+#include "GrGLPath.h"
+#include "GrGLPathRange.h"
+#include "GrGLPathRendering.h"
+
+#define GL_CALL(X) GR_GL_CALL(fGpu->glInterface(), X)
+#define GL_CALL_RET(RET, X) GR_GL_CALL_RET(fGpu->glInterface(), RET, X)
+
+
+static const GrGLenum gXformType2GLType[] = {
+    GR_GL_NONE,
+    GR_GL_TRANSLATE_X,
+    GR_GL_TRANSLATE_Y,
+    GR_GL_TRANSLATE_2D,
+    GR_GL_TRANSPOSE_AFFINE_2D
+};
+
+GR_STATIC_ASSERT(0 == GrPathRendering::kNone_PathTransformType);
+GR_STATIC_ASSERT(1 == GrPathRendering::kTranslateX_PathTransformType);
+GR_STATIC_ASSERT(2 == GrPathRendering::kTranslateY_PathTransformType);
+GR_STATIC_ASSERT(3 == GrPathRendering::kTranslate_PathTransformType);
+GR_STATIC_ASSERT(4 == GrPathRendering::kAffine_PathTransformType);
+GR_STATIC_ASSERT(GrPathRendering::kAffine_PathTransformType == GrPathRendering::kLast_PathTransformType);
+
+static GrGLenum gr_stencil_op_to_gl_path_rendering_fill_mode(GrStencilOp op) {
+    switch (op) {
+        default:
+            SkFAIL("Unexpected path fill.");
+            /* fallthrough */;
+        case kIncClamp_StencilOp:
+            return GR_GL_COUNT_UP;
+        case kInvert_StencilOp:
+            return GR_GL_INVERT;
+    }
+}
 
 class GrGLPathRenderingV12 : public GrGLPathRendering {
 public:
-    GrGLPathRenderingV12(const GrGLInterface* glInterface)
-        : GrGLPathRendering(glInterface) {
+    GrGLPathRenderingV12(GrGpuGL* gpu)
+        : GrGLPathRendering(gpu) {
     }
 
     virtual GrGLvoid stencilThenCoverFillPath(GrGLuint path, GrGLenum fillMode,
@@ -35,8 +67,8 @@
 
 class GrGLPathRenderingV13 : public GrGLPathRenderingV12 {
 public:
-    GrGLPathRenderingV13(const GrGLInterface* glInterface)
-        : GrGLPathRenderingV12(glInterface) {
+    GrGLPathRenderingV13(GrGpuGL* gpu)
+        : GrGLPathRenderingV12(gpu) {
         fCaps.fragmentInputGenSupport = true;
     }
 
@@ -46,24 +78,26 @@
 };
 
 
-GrGLPathRendering* GrGLPathRendering::Create(const GrGLInterface* glInterface) {
+GrGLPathRendering* GrGLPathRendering::Create(GrGpuGL* gpu) {
+    const GrGLInterface* glInterface = gpu->glInterface();
     if (NULL == glInterface->fFunctions.fStencilThenCoverFillPath ||
         NULL == glInterface->fFunctions.fStencilThenCoverStrokePath ||
         NULL == glInterface->fFunctions.fStencilThenCoverFillPathInstanced ||
         NULL == glInterface->fFunctions.fStencilThenCoverStrokePathInstanced) {
-        return new GrGLPathRendering(glInterface);
+        return new GrGLPathRendering(gpu);
     }
 
     if (NULL == glInterface->fFunctions.fProgramPathFragmentInputGen) {
-        return new GrGLPathRenderingV12(glInterface);
+        return new GrGLPathRenderingV12(gpu);
     }
 
-    return new GrGLPathRenderingV13(glInterface);
+    return new GrGLPathRenderingV13(gpu);
 }
 
-GrGLPathRendering::GrGLPathRendering(const GrGLInterface* glInterface)
-    : fGLInterface(SkRef(glInterface)) {
+GrGLPathRendering::GrGLPathRendering(GrGpuGL* gpu)
+    : fGpu(gpu) {
     memset(&fCaps, 0, sizeof(fCaps));
+    fHWPathTexGenSettings.reset(fGpu->glCaps().maxFixedFunctionTextureCoords());
 }
 
 GrGLPathRendering::~GrGLPathRendering() {
@@ -73,6 +107,281 @@
     fPathNameAllocator.reset(NULL);
 }
 
+void GrGLPathRendering::resetContext() {
+    fHWProjectionMatrixState.invalidate();
+    // we don't use the model view matrix.
+    GL_CALL(MatrixLoadIdentity(GR_GL_MODELVIEW));
+
+    for (int i = 0; i < fGpu->glCaps().maxFixedFunctionTextureCoords(); ++i) {
+        this->pathTexGen(GR_GL_TEXTURE0 + i, GR_GL_NONE, 0, NULL);
+        fHWPathTexGenSettings[i].fMode = GR_GL_NONE;
+        fHWPathTexGenSettings[i].fNumComponents = 0;
+    }
+    fHWActivePathTexGenSets = 0;
+    fHWPathStencilSettings.invalidate();
+}
+
+GrPath* GrGLPathRendering::createPath(const SkPath& inPath, const SkStrokeRec& stroke) {
+    return SkNEW_ARGS(GrGLPath, (fGpu, inPath, stroke));
+}
+
+GrPathRange* GrGLPathRendering::createPathRange(size_t size, const SkStrokeRec& stroke) {
+    return SkNEW_ARGS(GrGLPathRange, (fGpu, size, stroke));
+}
+
+void GrGLPathRendering::enablePathTexGen(int unitIdx, PathTexGenComponents components,
+                                         const GrGLfloat* coefficients) {
+    SkASSERT(components >= kS_PathTexGenComponents &&
+             components <= kSTR_PathTexGenComponents);
+    SkASSERT(fGpu->glCaps().maxFixedFunctionTextureCoords() >= unitIdx);
+
+    if (GR_GL_OBJECT_LINEAR == fHWPathTexGenSettings[unitIdx].fMode &&
+        components == fHWPathTexGenSettings[unitIdx].fNumComponents &&
+        !memcmp(coefficients, fHWPathTexGenSettings[unitIdx].fCoefficients,
+                3 * components * sizeof(GrGLfloat))) {
+        return;
+    }
+
+    fGpu->setTextureUnit(unitIdx);
+
+    fHWPathTexGenSettings[unitIdx].fNumComponents = components;
+    this->pathTexGen(GR_GL_TEXTURE0 + unitIdx, GR_GL_OBJECT_LINEAR, components, coefficients);
+
+    memcpy(fHWPathTexGenSettings[unitIdx].fCoefficients, coefficients,
+           3 * components * sizeof(GrGLfloat));
+}
+
+void GrGLPathRendering::enablePathTexGen(int unitIdx, PathTexGenComponents components,
+                                         const SkMatrix& matrix) {
+    GrGLfloat coefficients[3 * 3];
+    SkASSERT(components >= kS_PathTexGenComponents &&
+             components <= kSTR_PathTexGenComponents);
+
+    coefficients[0] = SkScalarToFloat(matrix[SkMatrix::kMScaleX]);
+    coefficients[1] = SkScalarToFloat(matrix[SkMatrix::kMSkewX]);
+    coefficients[2] = SkScalarToFloat(matrix[SkMatrix::kMTransX]);
+
+    if (components >= kST_PathTexGenComponents) {
+        coefficients[3] = SkScalarToFloat(matrix[SkMatrix::kMSkewY]);
+        coefficients[4] = SkScalarToFloat(matrix[SkMatrix::kMScaleY]);
+        coefficients[5] = SkScalarToFloat(matrix[SkMatrix::kMTransY]);
+    }
+
+    if (components >= kSTR_PathTexGenComponents) {
+        coefficients[6] = SkScalarToFloat(matrix[SkMatrix::kMPersp0]);
+        coefficients[7] = SkScalarToFloat(matrix[SkMatrix::kMPersp1]);
+        coefficients[8] = SkScalarToFloat(matrix[SkMatrix::kMPersp2]);
+    }
+
+    this->enablePathTexGen(unitIdx, components, coefficients);
+}
+
+void GrGLPathRendering::flushPathTexGenSettings(int numUsedTexCoordSets) {
+    SkASSERT(fGpu->glCaps().maxFixedFunctionTextureCoords() >= numUsedTexCoordSets);
+
+    // Only write the inactive path tex gens, since active path tex gens were
+    // written when they were enabled.
+
+    SkDEBUGCODE(
+        for (int i = 0; i < numUsedTexCoordSets; i++) {
+            SkASSERT(0 != fHWPathTexGenSettings[i].fNumComponents);
+        }
+    );
+
+    for (int i = numUsedTexCoordSets; i < fHWActivePathTexGenSets; i++) {
+        SkASSERT(0 != fHWPathTexGenSettings[i].fNumComponents);
+
+        fGpu->setTextureUnit(i);
+        GL_CALL(PathTexGen(GR_GL_TEXTURE0 + i, GR_GL_NONE, 0, NULL));
+        fHWPathTexGenSettings[i].fNumComponents = 0;
+    }
+
+    fHWActivePathTexGenSets = numUsedTexCoordSets;
+}
+
+void GrGLPathRendering::stencilPath(const GrPath* path, SkPath::FillType fill) {
+    GrGLuint id = static_cast<const GrGLPath*>(path)->pathID();
+    SkASSERT(NULL != fGpu->drawState()->getRenderTarget());
+    SkASSERT(NULL != fGpu->drawState()->getRenderTarget()->getStencilBuffer());
+
+    this->flushPathStencilSettings(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);
+    this->stencilFillPath(id, fillMode, writeMask);
+}
+
+void GrGLPathRendering::drawPath(const GrPath* path, SkPath::FillType fill) {
+    GrGLuint id = static_cast<const GrGLPath*>(path)->pathID();
+    SkASSERT(NULL != fGpu->drawState()->getRenderTarget());
+    SkASSERT(NULL != fGpu->drawState()->getRenderTarget()->getStencilBuffer());
+    SkASSERT(!fGpu->fCurrentProgram->hasVertexShader());
+
+    this->flushPathStencilSettings(fill);
+    SkASSERT(!fHWPathStencilSettings.isTwoSided());
+
+    const SkStrokeRec& stroke = path->getStroke();
+
+    SkPath::FillType nonInvertedFill = SkPath::ConvertToNonInverseFillType(fill);
+
+    GrGLenum fillMode =
+        gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
+    GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
+
+    if (nonInvertedFill == fill) {
+        if (stroke.needToApply()) {
+            if (SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
+                this->stencilFillPath(id, fillMode, writeMask);
+            }
+            this->stencilThenCoverStrokePath(id, 0xffff, writeMask, GR_GL_BOUNDING_BOX);
+        } else {
+            this->stencilThenCoverFillPath(id, fillMode, writeMask, GR_GL_BOUNDING_BOX);
+        }
+    } else {
+        if (stroke.isFillStyle() || SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
+            this->stencilFillPath(id, fillMode, writeMask);
+        }
+        if (stroke.needToApply()) {
+            this->stencilStrokePath(id, 0xffff, writeMask);
+        }
+
+        GrDrawState* drawState = fGpu->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().getMaxScale() * SK_ScalarHalf;
+            bounds.outset(bloat, bloat);
+        } else {
+            avmr.setIdentity(drawState);
+        }
+
+        fGpu->drawSimpleRect(bounds);
+    }
+}
+
+void GrGLPathRendering::drawPaths(const GrPathRange* pathRange, const uint32_t indices[], int count,
+                                  const float transforms[], PathTransformType transformsType,
+                                  SkPath::FillType fill) {
+    SkASSERT(fGpu->caps()->pathRenderingSupport());
+    SkASSERT(NULL != fGpu->drawState()->getRenderTarget());
+    SkASSERT(NULL != fGpu->drawState()->getRenderTarget()->getStencilBuffer());
+    SkASSERT(!fGpu->fCurrentProgram->hasVertexShader());
+
+    GrGLuint baseID = static_cast<const GrGLPathRange*>(pathRange)->basePathID();
+
+    this->flushPathStencilSettings(fill);
+    SkASSERT(!fHWPathStencilSettings.isTwoSided());
+
+    const SkStrokeRec& stroke = pathRange->getStroke();
+
+    SkPath::FillType nonInvertedFill =
+        SkPath::ConvertToNonInverseFillType(fill);
+
+    GrGLenum fillMode =
+        gr_stencil_op_to_gl_path_rendering_fill_mode(
+            fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
+    GrGLint writeMask =
+        fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
+
+    if (nonInvertedFill == fill) {
+        if (stroke.needToApply()) {
+            if (SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
+                this->stencilFillPathInstanced(
+                                    count, GR_GL_UNSIGNED_INT, indices, baseID, fillMode,
+                                    writeMask, gXformType2GLType[transformsType],
+                                    transforms);
+            }
+            this->stencilThenCoverStrokePathInstanced(
+                                count, GR_GL_UNSIGNED_INT, indices, baseID, 0xffff, writeMask,
+                                GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES,
+                                gXformType2GLType[transformsType], transforms);
+        } else {
+            this->stencilThenCoverFillPathInstanced(
+                                count, GR_GL_UNSIGNED_INT, indices, baseID, fillMode, writeMask,
+                                GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES,
+                                gXformType2GLType[transformsType], transforms);
+        }
+    } else {
+        if (stroke.isFillStyle() || SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
+            this->stencilFillPathInstanced(
+                                count, GR_GL_UNSIGNED_INT, indices, baseID, fillMode,
+                                writeMask, gXformType2GLType[transformsType],
+                                transforms);
+        }
+        if (stroke.needToApply()) {
+            this->stencilStrokePathInstanced(
+                                count, GR_GL_UNSIGNED_INT, indices, baseID, 0xffff,
+                                writeMask, gXformType2GLType[transformsType],
+                                transforms);
+        }
+
+        GrDrawState* drawState = fGpu->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().getMaxScale() * SK_ScalarHalf;
+            bounds.outset(bloat, bloat);
+        } else {
+            avmr.setIdentity(drawState);
+        }
+
+        fGpu->drawSimpleRect(bounds);
+    }
+}
+
+void GrGLPathRendering::flushPathStencilSettings(SkPath::FillType fill) {
+    GrStencilSettings pathStencilSettings;
+    fGpu->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 =
+            GrToGLStencilFunc(pathStencilSettings.func(GrStencilSettings::kFront_Face));
+        this->pathStencilFunc(func, pathStencilSettings.funcRef(GrStencilSettings::kFront_Face),
+                              pathStencilSettings.funcMask(GrStencilSettings::kFront_Face));
+
+        fHWPathStencilSettings = pathStencilSettings;
+    }
+}
+
+void GrGLPathRendering::setProjectionMatrix(const SkMatrix& matrix,
+                                  const SkISize& renderTargetSize,
+                                  GrSurfaceOrigin renderTargetOrigin) {
+
+    SkASSERT(fGpu->glCaps().pathRenderingSupport());
+
+    if (renderTargetOrigin == fHWProjectionMatrixState.fRenderTargetOrigin &&
+        renderTargetSize == fHWProjectionMatrixState.fRenderTargetSize &&
+        matrix.cheapEqualTo(fHWProjectionMatrixState.fViewMatrix)) {
+        return;
+    }
+
+    fHWProjectionMatrixState.fViewMatrix = matrix;
+    fHWProjectionMatrixState.fRenderTargetSize = renderTargetSize;
+    fHWProjectionMatrixState.fRenderTargetOrigin = renderTargetOrigin;
+
+    GrGLfloat glMatrix[4 * 4];
+    fHWProjectionMatrixState.getRTAdjustedGLMatrix<4>(glMatrix);
+    GL_CALL(MatrixLoadf(GR_GL_PROJECTION, glMatrix));
+}
+
+
 
 // NV_path_rendering
 GrGLuint GrGLPathRendering::genPaths(GrGLsizei range) {
@@ -156,6 +465,7 @@
 }
 
 GrGLvoid GrGLPathRendering::stencilFillPath(GrGLuint path, GrGLenum fillMode, GrGLuint mask) {
+    // Decide how to manipulate the stencil buffer based on the fill rule.
     GL_CALL(StencilFillPath(path, fillMode, mask));
 }
 
diff --git a/src/gpu/gl/GrGLPathRendering.h b/src/gpu/gl/GrGLPathRendering.h
index 53b8750..e16f059 100644
--- a/src/gpu/gl/GrGLPathRendering.h
+++ b/src/gpu/gl/GrGLPathRendering.h
@@ -9,28 +9,40 @@
 #define GrGLPathRendering_DEFINED
 
 #include "SkRefCnt.h"
+#include "GrPathRendering.h"
+#include "GrStencil.h"
 #include "gl/GrGLFunctions.h"
+#include "gl/GrGLProgram.h"
 
 class GrGLNameAllocator;
-struct GrGLInterface;
+class GrGpuGL;
 
 /**
  * This class wraps the NV_path_rendering extension and manages its various
- * API versions. If a method is not present in the GrGLInterface (because the
- * driver version is old), it tries to provide a backup implementation. But if
- * a backup implementation is not practical, it marks the method as not
- * supported.
+ * API versions. If a method is not present in the GrGLInterface of the GrGpuGL
+ * (because the driver version is old), it tries to provide a backup
+ * implementation. But if a backup implementation is not practical, it marks the
+ * method as not supported.
  */
-class GrGLPathRendering {
+class GrGLPathRendering : public GrPathRendering {
 public:
     /**
-     * Create a new GrGLPathRendering object from a given GL interface. Unless
+     * Create a new GrGLPathRendering object from a given GrGpuGL. Unless
      * otherwise specified in the caps, every method will work properly, even
-     * if it did not exist in the GL interface.
+     * if it did not exist in the GL interface of the gpu.
      */
-    static GrGLPathRendering* Create(const GrGLInterface*);
+    static GrGLPathRendering* Create(GrGpuGL* gpu);
     virtual ~GrGLPathRendering();
 
+    // GrPathRendering implementations.
+    virtual GrPath* createPath(const SkPath&, const SkStrokeRec&) SK_OVERRIDE;
+    virtual GrPathRange* createPathRange(size_t size, const SkStrokeRec&) SK_OVERRIDE;
+    virtual void stencilPath(const GrPath*, SkPath::FillType) SK_OVERRIDE;
+    virtual void drawPath(const GrPath*, SkPath::FillType) SK_OVERRIDE;
+    virtual void drawPaths(const GrPathRange*, const uint32_t indices[], int count,
+                           const float transforms[], PathTransformType,
+                           SkPath::FillType) SK_OVERRIDE;
+
     /**
      * Mark certain functionality as not supported if the driver version is too
      * old and a backup implementation is not practical.
@@ -40,12 +52,29 @@
     };
     const Caps& caps() const { return fCaps; }
 
+
+    /* Called when the 3D context state is unknown. */
+    void resetContext();
+
     /**
      * Called when the GPU resources have been lost and need to be abandoned
      * (for example after a context loss).
      */
     void abandonGpuResources();
 
+    enum PathTexGenComponents {
+        kS_PathTexGenComponents = 1,
+        kST_PathTexGenComponents = 2,
+        kSTR_PathTexGenComponents = 3
+    };
+    void enablePathTexGen(int unitIdx, PathTexGenComponents, const GrGLfloat* coefficients);
+    void enablePathTexGen(int unitIdx, PathTexGenComponents, const SkMatrix& matrix);
+    void flushPathTexGenSettings(int numUsedTexCoordSets);
+    void setProjectionMatrix(const SkMatrix& matrix,
+                             const SkISize& renderTargetSize,
+                             GrSurfaceOrigin renderTargetOrigin);
+
+
     // NV_path_rendering
     GrGLuint genPaths(GrGLsizei range);
     GrGLvoid deletePaths(GrGLuint path, GrGLsizei range);
@@ -98,11 +127,24 @@
                                                  const GrGLfloat *coeffs);
 
 protected:
-    GrGLPathRendering(const GrGLInterface*);
+    GrGLPathRendering(GrGpuGL* gpu);
 
-    SkAutoTUnref<const GrGLInterface> fGLInterface;
+    GrGpuGL* fGpu;
     SkAutoTDelete<GrGLNameAllocator> fPathNameAllocator;
     Caps fCaps;
+    GrGLProgram::MatrixState fHWProjectionMatrixState;
+    GrStencilSettings fHWPathStencilSettings;
+    struct PathTexGenData {
+        GrGLenum  fMode;
+        GrGLint   fNumComponents;
+        GrGLfloat fCoefficients[3 * 3];
+    };
+    int fHWActivePathTexGenSets;
+    SkTArray<PathTexGenData, true> fHWPathTexGenSettings;
+
+private:
+    void flushPathStencilSettings(SkPath::FillType fill);
+
 };
 
 #endif
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index 0ad7a18..d8c751d 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -154,7 +154,7 @@
     // custom shaders, it's ignored, so we don't need to change the texgen
     // settings in that case.
     if (!fHasVertexShader) {
-        fGpu->flushPathTexGenSettings(fTexCoordSetCnt);
+        fGpu->glPathRendering()->flushPathTexGenSettings(fTexCoordSetCnt);
     }
 }
 
@@ -247,7 +247,7 @@
     if (!fHasVertexShader) {
         SkASSERT(!fBuiltinUniformHandles.fViewMatrixUni.isValid());
         SkASSERT(!fBuiltinUniformHandles.fRTAdjustmentUni.isValid());
-        fGpu->setProjectionMatrix(drawState.getViewMatrix(), size, rt->origin());
+        fGpu->glPathRendering()->setProjectionMatrix(drawState.getViewMatrix(), size, rt->origin());
     } else if (fMatrixState.fRenderTargetOrigin != rt->origin() ||
                fMatrixState.fRenderTargetSize != size ||
                !fMatrixState.fViewMatrix.cheapEqualTo(drawState.getViewMatrix())) {
diff --git a/src/gpu/gl/GrGLProgramEffects.cpp b/src/gpu/gl/GrGLProgramEffects.cpp
index 3fa4f15..8ea77d0 100644
--- a/src/gpu/gl/GrGLProgramEffects.cpp
+++ b/src/gpu/gl/GrGLProgramEffects.cpp
@@ -478,16 +478,18 @@
         switch (get_matrix_type(totalKey, t)) {
             case kNoPersp_MatrixType: {
                 const SkMatrix& transform = get_transform_matrix(drawEffect, t);
-                gpu->enablePathTexGen(texCoordIndex++,
-                                      GrGpuGL::kST_PathTexGenComponents,
-                                      transform);
+                gpu->glPathRendering()->enablePathTexGen(
+                        texCoordIndex++,
+                        GrGLPathRendering::kST_PathTexGenComponents,
+                        transform);
                 break;
             }
             case kGeneral_MatrixType: {
                 const SkMatrix& transform = get_transform_matrix(drawEffect, t);
-                gpu->enablePathTexGen(texCoordIndex++,
-                                      GrGpuGL::kSTR_PathTexGenComponents,
-                                      transform);
+                gpu->glPathRendering()->enablePathTexGen(
+                        texCoordIndex++,
+                        GrGLPathRendering::kSTR_PathTexGenComponents,
+                        transform);
                 break;
             }
             default:
diff --git a/src/gpu/gl/GrGLUtil.cpp b/src/gpu/gl/GrGLUtil.cpp
index 86a3a59..9bc2c5d 100644
--- a/src/gpu/gl/GrGLUtil.cpp
+++ b/src/gpu/gl/GrGLUtil.cpp
@@ -264,3 +264,28 @@
     dest[14] = 0;
     dest[15] = SkScalarToFloat(src[SkMatrix::kMPersp2]);
 }
+
+GrGLenum GrToGLStencilFunc(GrStencilFunc basicFunc) {
+    static const GrGLenum gTable[] = {
+        GR_GL_ALWAYS,           // kAlways_StencilFunc
+        GR_GL_NEVER,            // kNever_StencilFunc
+        GR_GL_GREATER,          // kGreater_StencilFunc
+        GR_GL_GEQUAL,           // kGEqual_StencilFunc
+        GR_GL_LESS,             // kLess_StencilFunc
+        GR_GL_LEQUAL,           // kLEqual_StencilFunc,
+        GR_GL_EQUAL,            // kEqual_StencilFunc,
+        GR_GL_NOTEQUAL,         // kNotEqual_StencilFunc,
+    };
+    GR_STATIC_ASSERT(SK_ARRAY_COUNT(gTable) == kBasicStencilFuncCount);
+    GR_STATIC_ASSERT(0 == kAlways_StencilFunc);
+    GR_STATIC_ASSERT(1 == kNever_StencilFunc);
+    GR_STATIC_ASSERT(2 == kGreater_StencilFunc);
+    GR_STATIC_ASSERT(3 == kGEqual_StencilFunc);
+    GR_STATIC_ASSERT(4 == kLess_StencilFunc);
+    GR_STATIC_ASSERT(5 == kLEqual_StencilFunc);
+    GR_STATIC_ASSERT(6 == kEqual_StencilFunc);
+    GR_STATIC_ASSERT(7 == kNotEqual_StencilFunc);
+    SkASSERT((unsigned) basicFunc < kBasicStencilFuncCount);
+
+    return gTable[basicFunc];
+}
diff --git a/src/gpu/gl/GrGLUtil.h b/src/gpu/gl/GrGLUtil.h
index 89d8076..06210ee 100644
--- a/src/gpu/gl/GrGLUtil.h
+++ b/src/gpu/gl/GrGLUtil.h
@@ -10,6 +10,7 @@
 
 #include "gl/GrGLInterface.h"
 #include "GrGLDefines.h"
+#include "GrStencil.h"
 
 class SkMatrix;
 
@@ -181,4 +182,7 @@
 // call glGetError without doing a redundant error check or logging.
 #define GR_GL_GET_ERROR(IFACE) (IFACE)->fFunctions.fGetError()
 
+GrGLenum GrToGLStencilFunc(GrStencilFunc basicFunc);
+
+
 #endif
diff --git a/src/gpu/gl/GrGpuGL.cpp b/src/gpu/gl/GrGpuGL.cpp
index 7131cfa..c6bd6bb 100644
--- a/src/gpu/gl/GrGpuGL.cpp
+++ b/src/gpu/gl/GrGpuGL.cpp
@@ -8,9 +8,6 @@
 
 #include "GrGpuGL.h"
 #include "GrGLStencilBuffer.h"
-#include "GrGLPath.h"
-#include "GrGLPathRange.h"
-#include "GrGLPathRendering.h"
 #include "GrGLShaderBuilder.h"
 #include "GrTemplates.h"
 #include "GrTypes.h"
@@ -35,20 +32,6 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-static const GrGLenum gXformType2GLType[] = {
-    GR_GL_NONE,
-    GR_GL_TRANSLATE_X,
-    GR_GL_TRANSLATE_Y,
-    GR_GL_TRANSLATE_2D,
-    GR_GL_TRANSPOSE_AFFINE_2D
-};
-
-GR_STATIC_ASSERT(0 == GrDrawTarget::kNone_PathTransformType);
-GR_STATIC_ASSERT(1 == GrDrawTarget::kTranslateX_PathTransformType);
-GR_STATIC_ASSERT(2 == GrDrawTarget::kTranslateY_PathTransformType);
-GR_STATIC_ASSERT(3 == GrDrawTarget::kTranslate_PathTransformType);
-GR_STATIC_ASSERT(4 == GrDrawTarget::kAffine_PathTransformType);
-GR_STATIC_ASSERT(GrDrawTarget::kAffine_PathTransformType == GrDrawTarget::kLast_PathTransformType);
 
 static const GrGLenum gXfermodeCoeff2Blend[] = {
     GR_GL_ZERO,
@@ -137,7 +120,6 @@
     fCaps.reset(SkRef(ctx.caps()));
 
     fHWBoundTextureUniqueIDs.reset(this->glCaps().maxFragmentTextureUnits());
-    fHWPathTexGenSettings.reset(this->glCaps().maxFixedFunctionTextureCoords());
 
     GrGLClearErr(fGLContext.interface());
     if (gPrintStartupSpew) {
@@ -166,7 +148,7 @@
     fHWProgramID = 0;
 
     if (this->glCaps().pathRenderingSupport()) {
-        fPathRendering.reset(GrGLPathRendering::Create(glInterface()));
+        fPathRendering.reset(GrGLPathRendering::Create(this));
     }
 }
 
@@ -328,18 +310,8 @@
 
     if (resetBits & kPathRendering_GrGLBackendState) {
         if (this->caps()->pathRenderingSupport()) {
-            fHWProjectionMatrixState.invalidate();
-            // we don't use the model view matrix.
-            GL_CALL(MatrixLoadIdentity(GR_GL_MODELVIEW));
-
-            for (int i = 0; i < this->glCaps().maxFixedFunctionTextureCoords(); ++i) {
-                fPathRendering->pathTexGen(GR_GL_TEXTURE0 + i, GR_GL_NONE, 0, NULL);
-                fHWPathTexGenSettings[i].fMode = GR_GL_NONE;
-                fHWPathTexGenSettings[i].fNumComponents = 0;
-            }
-            fHWActivePathTexGenSets = 0;
+            this->glPathRendering()->resetContext();
         }
-        fHWPathStencilSettings.invalidate();
     }
 
     // we assume these values
@@ -1372,16 +1344,6 @@
     }
 }
 
-GrPath* GrGpuGL::onCreatePath(const SkPath& inPath, const SkStrokeRec& stroke) {
-    SkASSERT(this->caps()->pathRenderingSupport());
-    return SkNEW_ARGS(GrGLPath, (this, inPath, stroke));
-}
-
-GrPathRange* GrGpuGL::onCreatePathRange(size_t size, const SkStrokeRec& stroke) {
-    SkASSERT(this->caps()->pathRenderingSupport());
-    return SkNEW_ARGS(GrGLPathRange, (this, size, stroke));
-}
-
 void GrGpuGL::flushScissor() {
     if (fScissorState.fEnabled) {
         // Only access the RT if scissoring is being enabled. We can call this before performing
@@ -1839,168 +1801,6 @@
 #endif
 }
 
-static GrGLenum gr_stencil_op_to_gl_path_rendering_fill_mode(GrStencilOp op) {
-    switch (op) {
-        default:
-            SkFAIL("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()->pathRenderingSupport());
-
-    GrGLuint id = static_cast<const GrGLPath*>(path)->pathID();
-    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.
-    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);
-    fPathRendering->stencilFillPath(id, fillMode, writeMask);
-}
-
-void GrGpuGL::onGpuDrawPath(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);
-    const SkStrokeRec& stroke = path->getStroke();
-
-    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);
-
-    if (nonInvertedFill == fill) {
-        if (stroke.needToApply()) {
-            if (SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
-                fPathRendering->stencilFillPath(id, fillMode, writeMask);
-            }
-            fPathRendering->stencilThenCoverStrokePath(id, 0xffff, writeMask, GR_GL_BOUNDING_BOX);
-        } else {
-            fPathRendering->stencilThenCoverFillPath(id, fillMode, writeMask, GR_GL_BOUNDING_BOX);
-        }
-    } else {
-        if (stroke.isFillStyle() || SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
-            fPathRendering->stencilFillPath(id, fillMode, writeMask);
-        }
-        if (stroke.needToApply()) {
-            fPathRendering->stencilStrokePath(id, 0xffff, writeMask);
-        }
-
-        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().getMaxScale() * SK_ScalarHalf;
-            bounds.outset(bloat, bloat);
-        } else {
-            avmr.setIdentity(drawState);
-        }
-
-        this->drawSimpleRect(bounds);
-    }
-}
-
-void GrGpuGL::onGpuDrawPaths(const GrPathRange* pathRange,
-                             const uint32_t indices[], int count,
-                             const float transforms[], PathTransformType transformsType,
-                             SkPath::FillType fill) {
-    SkASSERT(this->caps()->pathRenderingSupport());
-    SkASSERT(NULL != this->drawState()->getRenderTarget());
-    SkASSERT(NULL != this->drawState()->getRenderTarget()->getStencilBuffer());
-    SkASSERT(!fCurrentProgram->hasVertexShader());
-
-    GrGLuint baseID = static_cast<const GrGLPathRange*>(pathRange)->basePathID();
-
-    flushPathStencilSettings(fill);
-    const SkStrokeRec& stroke = pathRange->getStroke();
-
-    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);
-
-    if (nonInvertedFill == fill) {
-        if (stroke.needToApply()) {
-            if (SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
-                fPathRendering->stencilFillPathInstanced(
-                                    count, GR_GL_UNSIGNED_INT, indices, baseID, fillMode,
-                                    writeMask, gXformType2GLType[transformsType],
-                                    transforms);
-            }
-            fPathRendering->stencilThenCoverStrokePathInstanced(
-                                count, GR_GL_UNSIGNED_INT, indices, baseID, 0xffff, writeMask,
-                                GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES,
-                                gXformType2GLType[transformsType], transforms);
-        } else {
-            fPathRendering->stencilThenCoverFillPathInstanced(
-                                count, GR_GL_UNSIGNED_INT, indices, baseID, fillMode, writeMask,
-                                GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES,
-                                gXformType2GLType[transformsType], transforms);
-        }
-    } else {
-        if (stroke.isFillStyle() || SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
-            fPathRendering->stencilFillPathInstanced(
-                                count, GR_GL_UNSIGNED_INT, indices, baseID, fillMode,
-                                writeMask, gXformType2GLType[transformsType],
-                                transforms);
-        }
-        if (stroke.needToApply()) {
-            fPathRendering->stencilStrokePathInstanced(
-                                count, GR_GL_UNSIGNED_INT, indices, baseID, 0xffff,
-                                writeMask, gXformType2GLType[transformsType],
-                                transforms);
-        }
-
-        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().getMaxScale() * SK_ScalarHalf;
-            bounds.outset(bloat, bloat);
-        } else {
-            avmr.setIdentity(drawState);
-        }
-
-        this->drawSimpleRect(bounds);
-    }
-}
-
 void GrGpuGL::onResolveRenderTarget(GrRenderTarget* target) {
     GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(target);
     if (rt->needsResolve()) {
@@ -2046,30 +1846,6 @@
 
 namespace {
 
-GrGLenum gr_to_gl_stencil_func(GrStencilFunc basicFunc) {
-    static const GrGLenum gTable[] = {
-        GR_GL_ALWAYS,           // kAlways_StencilFunc
-        GR_GL_NEVER,            // kNever_StencilFunc
-        GR_GL_GREATER,          // kGreater_StencilFunc
-        GR_GL_GEQUAL,           // kGEqual_StencilFunc
-        GR_GL_LESS,             // kLess_StencilFunc
-        GR_GL_LEQUAL,           // kLEqual_StencilFunc,
-        GR_GL_EQUAL,            // kEqual_StencilFunc,
-        GR_GL_NOTEQUAL,         // kNotEqual_StencilFunc,
-    };
-    GR_STATIC_ASSERT(SK_ARRAY_COUNT(gTable) == kBasicStencilFuncCount);
-    GR_STATIC_ASSERT(0 == kAlways_StencilFunc);
-    GR_STATIC_ASSERT(1 == kNever_StencilFunc);
-    GR_STATIC_ASSERT(2 == kGreater_StencilFunc);
-    GR_STATIC_ASSERT(3 == kGEqual_StencilFunc);
-    GR_STATIC_ASSERT(4 == kLess_StencilFunc);
-    GR_STATIC_ASSERT(5 == kLEqual_StencilFunc);
-    GR_STATIC_ASSERT(6 == kEqual_StencilFunc);
-    GR_STATIC_ASSERT(7 == kNotEqual_StencilFunc);
-    SkASSERT((unsigned) basicFunc < kBasicStencilFuncCount);
-
-    return gTable[basicFunc];
-}
 
 GrGLenum gr_to_gl_stencil_op(GrStencilOp op) {
     static const GrGLenum gTable[] = {
@@ -2099,7 +1875,7 @@
                     const GrStencilSettings& settings,
                     GrGLenum glFace,
                     GrStencilSettings::Face grFace) {
-    GrGLenum glFunc = gr_to_gl_stencil_func(settings.func(grFace));
+    GrGLenum glFunc = GrToGLStencilFunc(settings.func(grFace));
     GrGLenum glFailOp = gr_to_gl_stencil_op(settings.failOp(grFace));
     GrGLenum glPassOp = gr_to_gl_stencil_op(settings.passOp(grFace));
 
@@ -2187,22 +1963,6 @@
     }
 }
 
-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));
-        fPathRendering->pathStencilFunc(
-                            func, pathStencilSettings.funcRef(GrStencilSettings::kFront_Face),
-                            pathStencilSettings.funcMask(GrStencilSettings::kFront_Face));
-
-        fHWPathStencilSettings = pathStencilSettings;
-    }
-}
-
 void GrGpuGL::flushBlend(bool isLines,
                          GrBlendCoeff srcCoeff,
                          GrBlendCoeff dstCoeff) {
@@ -2349,104 +2109,6 @@
     texture->setCachedTexParams(newTexParams, this->getResetTimestamp());
 }
 
-void GrGpuGL::setProjectionMatrix(const SkMatrix& matrix,
-                                  const SkISize& renderTargetSize,
-                                  GrSurfaceOrigin renderTargetOrigin) {
-
-    SkASSERT(this->glCaps().pathRenderingSupport());
-
-    if (renderTargetOrigin == fHWProjectionMatrixState.fRenderTargetOrigin &&
-        renderTargetSize == fHWProjectionMatrixState.fRenderTargetSize &&
-        matrix.cheapEqualTo(fHWProjectionMatrixState.fViewMatrix)) {
-        return;
-    }
-
-    fHWProjectionMatrixState.fViewMatrix = matrix;
-    fHWProjectionMatrixState.fRenderTargetSize = renderTargetSize;
-    fHWProjectionMatrixState.fRenderTargetOrigin = renderTargetOrigin;
-
-    GrGLfloat glMatrix[4 * 4];
-    fHWProjectionMatrixState.getRTAdjustedGLMatrix<4>(glMatrix);
-    GL_CALL(MatrixLoadf(GR_GL_PROJECTION, glMatrix));
-}
-
-void GrGpuGL::enablePathTexGen(int unitIdx,
-                               PathTexGenComponents components,
-                               const GrGLfloat* coefficients) {
-    SkASSERT(this->glCaps().pathRenderingSupport());
-    SkASSERT(components >= kS_PathTexGenComponents &&
-             components <= kSTR_PathTexGenComponents);
-    SkASSERT(this->glCaps().maxFixedFunctionTextureCoords() >= unitIdx);
-
-    if (GR_GL_OBJECT_LINEAR == fHWPathTexGenSettings[unitIdx].fMode &&
-        components == fHWPathTexGenSettings[unitIdx].fNumComponents &&
-        !memcmp(coefficients, fHWPathTexGenSettings[unitIdx].fCoefficients,
-                3 * components * sizeof(GrGLfloat))) {
-        return;
-    }
-
-    this->setTextureUnit(unitIdx);
-
-    fHWPathTexGenSettings[unitIdx].fNumComponents = components;
-    fPathRendering->pathTexGen(GR_GL_TEXTURE0 + unitIdx,
-                               GR_GL_OBJECT_LINEAR,
-                               components,
-                               coefficients);
-
-    memcpy(fHWPathTexGenSettings[unitIdx].fCoefficients, coefficients,
-           3 * components * sizeof(GrGLfloat));
-}
-
-void GrGpuGL::enablePathTexGen(int unitIdx, PathTexGenComponents components,
-                               const SkMatrix& matrix) {
-    GrGLfloat coefficients[3 * 3];
-    SkASSERT(this->glCaps().pathRenderingSupport());
-    SkASSERT(components >= kS_PathTexGenComponents &&
-             components <= kSTR_PathTexGenComponents);
-
-    coefficients[0] = SkScalarToFloat(matrix[SkMatrix::kMScaleX]);
-    coefficients[1] = SkScalarToFloat(matrix[SkMatrix::kMSkewX]);
-    coefficients[2] = SkScalarToFloat(matrix[SkMatrix::kMTransX]);
-
-    if (components >= kST_PathTexGenComponents) {
-        coefficients[3] = SkScalarToFloat(matrix[SkMatrix::kMSkewY]);
-        coefficients[4] = SkScalarToFloat(matrix[SkMatrix::kMScaleY]);
-        coefficients[5] = SkScalarToFloat(matrix[SkMatrix::kMTransY]);
-    }
-
-    if (components >= kSTR_PathTexGenComponents) {
-        coefficients[6] = SkScalarToFloat(matrix[SkMatrix::kMPersp0]);
-        coefficients[7] = SkScalarToFloat(matrix[SkMatrix::kMPersp1]);
-        coefficients[8] = SkScalarToFloat(matrix[SkMatrix::kMPersp2]);
-    }
-
-    enablePathTexGen(unitIdx, components, coefficients);
-}
-
-void GrGpuGL::flushPathTexGenSettings(int numUsedTexCoordSets) {
-    SkASSERT(this->glCaps().pathRenderingSupport());
-    SkASSERT(this->glCaps().maxFixedFunctionTextureCoords() >= numUsedTexCoordSets);
-
-    // Only write the inactive path tex gens, since active path tex gens were
-    // written when they were enabled.
-
-    SkDEBUGCODE(
-        for (int i = 0; i < numUsedTexCoordSets; i++) {
-            SkASSERT(0 != fHWPathTexGenSettings[i].fNumComponents);
-        }
-    );
-
-    for (int i = numUsedTexCoordSets; i < fHWActivePathTexGenSets; i++) {
-        SkASSERT(0 != fHWPathTexGenSettings[i].fNumComponents);
-
-        this->setTextureUnit(i);
-        fPathRendering->pathTexGen(GR_GL_TEXTURE0 + i, GR_GL_NONE, 0, NULL);
-        fHWPathTexGenSettings[i].fNumComponents = 0;
-    }
-
-    fHWActivePathTexGenSets = numUsedTexCoordSets;
-}
-
 void GrGpuGL::flushMiscFixedFunctionState() {
 
     const GrDrawState& drawState = this->getDrawState();
diff --git a/src/gpu/gl/GrGpuGL.h b/src/gpu/gl/GrGpuGL.h
index b39aedb..40104f8 100644
--- a/src/gpu/gl/GrGpuGL.h
+++ b/src/gpu/gl/GrGpuGL.h
@@ -12,6 +12,7 @@
 #include "GrGLContext.h"
 #include "GrGLIRect.h"
 #include "GrGLIndexBuffer.h"
+#include "GrGLPathRendering.h"
 #include "GrGLProgram.h"
 #include "GrGLStencilBuffer.h"
 #include "GrGLTexture.h"
@@ -24,8 +25,6 @@
 #define PROGRAM_CACHE_STATS
 #endif
 
-class GrGLPathRendering;
-
 class GrGpuGL : public GrGpu {
 public:
     GrGpuGL(const GrGLContext& ctx, GrContext* context);
@@ -40,9 +39,9 @@
     GrGLSLGeneration glslGeneration() const { return fGLContext.glslGeneration(); }
     const GrGLCaps& glCaps() const { return *fGLContext.caps(); }
 
-    GrGLPathRendering* pathRendering() const {
+    GrGLPathRendering* glPathRendering() {
         SkASSERT(glCaps().pathRenderingSupport());
-        return fPathRendering.get();
+        return static_cast<GrGLPathRendering*>(pathRendering());
     }
 
     virtual void discard(GrRenderTarget*) SK_OVERRIDE;
@@ -50,17 +49,7 @@
     // Used by GrGLProgram and GrGLPathTexGenProgramEffects to configure OpenGL
     // state.
     void bindTexture(int unitIdx, const GrTextureParams& params, GrGLTexture* texture);
-    void setProjectionMatrix(const SkMatrix& matrix,
-                             const SkISize& renderTargetSize,
-                             GrSurfaceOrigin renderTargetOrigin);
-    enum PathTexGenComponents {
-        kS_PathTexGenComponents = 1,
-        kST_PathTexGenComponents = 2,
-        kSTR_PathTexGenComponents = 3
-    };
-    void enablePathTexGen(int unitIdx, PathTexGenComponents, const GrGLfloat* coefficients);
-    void enablePathTexGen(int unitIdx, PathTexGenComponents, const SkMatrix& matrix);
-    void flushPathTexGenSettings(int numUsedTexCoordSets);
+
     bool shouldUseFixedFunctionTexturing() const {
         return this->glCaps().pathRenderingSupport();
     }
@@ -131,8 +120,6 @@
                                                  const void* srcData) SK_OVERRIDE;
     virtual GrVertexBuffer* onCreateVertexBuffer(size_t size, bool dynamic) SK_OVERRIDE;
     virtual GrIndexBuffer* onCreateIndexBuffer(size_t size, bool dynamic) SK_OVERRIDE;
-    virtual GrPath* onCreatePath(const SkPath&, const SkStrokeRec&) SK_OVERRIDE;
-    virtual GrPathRange* onCreatePathRange(size_t size, const SkStrokeRec&) SK_OVERRIDE;
     virtual GrTexture* onWrapBackendTexture(const GrBackendTextureDesc&) SK_OVERRIDE;
     virtual GrRenderTarget* onWrapBackendRenderTarget(const GrBackendRenderTargetDesc&) SK_OVERRIDE;
     virtual bool createStencilBufferForRenderTarget(GrRenderTarget* rt,
@@ -160,12 +147,6 @@
 
     virtual void onGpuDraw(const DrawInfo&) SK_OVERRIDE;
 
-    virtual void onGpuStencilPath(const GrPath*, SkPath::FillType) SK_OVERRIDE;
-    virtual void onGpuDrawPath(const GrPath*, SkPath::FillType) SK_OVERRIDE;
-    virtual void onGpuDrawPaths(const GrPathRange*,
-                                const uint32_t indices[], int count,
-                                const float transforms[], PathTransformType,
-                                SkPath::FillType) SK_OVERRIDE;
 
     virtual void clearStencil() SK_OVERRIDE;
     virtual void clearStencilClip(const SkIRect& rect,
@@ -257,7 +238,6 @@
     void flushRenderTarget(const SkIRect* bound);
     void flushStencil(DrawType);
     void flushAAState(DrawType);
-    void flushPathStencilSettings(SkPath::FillType fill);
 
     bool configToGLFormats(GrPixelConfig config,
                            bool getSizedInternal,
@@ -445,11 +425,9 @@
 
     TriState fMSAAEnabled;
 
-    GrGLProgram::MatrixState    fHWProjectionMatrixState;
-
     GrStencilSettings           fHWStencilSettings;
     TriState                    fHWStencilTestEnabled;
-    GrStencilSettings           fHWPathStencilSettings;
+
 
     GrDrawState::DrawFace       fHWDrawFace;
     TriState                    fHWWriteToColor;
@@ -457,22 +435,14 @@
     uint32_t                    fHWBoundRenderTargetUniqueID;
     SkTArray<uint32_t, true>    fHWBoundTextureUniqueIDs;
 
-    struct PathTexGenData {
-        GrGLenum  fMode;
-        GrGLint   fNumComponents;
-        GrGLfloat fCoefficients[3 * 3];
-    };
-    int                         fHWActivePathTexGenSets;
-    SkTArray<PathTexGenData, true>  fHWPathTexGenSettings;
     ///@}
 
     // we record what stencil format worked last time to hopefully exit early
     // from our loop that tries stencil formats and calls check fb status.
     int fLastSuccessfulStencilFmtIdx;
 
-    SkAutoTDelete<GrGLPathRendering> fPathRendering;
-
     typedef GrGpu INHERITED;
+    friend class GrGLPathRendering; // For accessing setTextureUnit.
 };
 
 #endif
diff --git a/src/gpu/gl/GrGpuGL_program.cpp b/src/gpu/gl/GrGpuGL_program.cpp
index beaaa90..c4011e7 100644
--- a/src/gpu/gl/GrGpuGL_program.cpp
+++ b/src/gpu/gl/GrGpuGL_program.cpp
@@ -204,7 +204,7 @@
     fProgramCache->abandon();
     fHWProgramID = 0;
     if (this->glCaps().pathRenderingSupport()) {
-        fPathRendering->abandonGpuResources();
+        this->glPathRendering()->abandonGpuResources();
     }
 }
 
@@ -222,7 +222,7 @@
         const GrRenderTarget* rt = this->getDrawState().getRenderTarget();
         SkISize size;
         size.set(rt->width(), rt->height());
-        this->setProjectionMatrix(drawState.getViewMatrix(), size, rt->origin());
+        this->glPathRendering()->setProjectionMatrix(drawState.getViewMatrix(), size, rt->origin());
     } else {
         this->flushMiscFixedFunctionState();