Revert of Move instanced index buffer creation to flush time (patchset #6 id:100001 of https://codereview.chromium.org/1116943004/)

Reason for revert:
messed up caching, recreating index buffers all the time.

Original issue's description:
> Move instanced index buffer creation to flush time
>
> Committed: https://skia.googlesource.com/skia/+/ab622c7b8cc8c39f0a594e4392b9e31b7e1ddb26

TBR=joshualitt@google.com,robertphillips@google.com
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true

Review URL: https://codereview.chromium.org/1126613003
diff --git a/gm/beziereffects.cpp b/gm/beziereffects.cpp
index 6568422..182d71a 100644
--- a/gm/beziereffects.cpp
+++ b/gm/beziereffects.cpp
@@ -16,7 +16,6 @@
 #include "GrBufferAllocPool.h"
 #include "GrContext.h"
 #include "GrPathUtils.h"
-#include "GrResourceProvider.h"
 #include "GrTest.h"
 #include "GrTestBatch.h"
 #include "SkColorPriv.h"
@@ -67,18 +66,17 @@
     }
 
     void onGenerateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override {
-        SkAutoTUnref<const GrIndexBuffer> indexBuffer(
-            batchTarget->resourceProvider()->refQuadIndexBuffer());
-
         size_t vertexStride = this->geometryProcessor()->getVertexStride();
+
         const GrVertexBuffer* vertexBuffer;
         int firstVertex;
+
         void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
                                                               kVertsPerCubic,
                                                               &vertexBuffer,
                                                               &firstVertex);
 
-        if (!vertices || !indexBuffer) {
+        if (!vertices || !batchTarget->quadIndexBuffer()) {
             SkDebugf("Could not allocate buffers\n");
             return;
         }
@@ -102,7 +100,7 @@
         drawInfo.setVertexCount(kVertsPerCubic);
         drawInfo.setStartIndex(0);
         drawInfo.setIndexCount(kIndicesPerCubic);
-        drawInfo.setIndexBuffer(indexBuffer);
+        drawInfo.setIndexBuffer(batchTarget->quadIndexBuffer());
         batchTarget->draw(drawInfo);
     }
 
@@ -475,10 +473,8 @@
     }
 
     void onGenerateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override {
-        SkAutoTUnref<const GrIndexBuffer> indexBuffer(
-            batchTarget->resourceProvider()->refQuadIndexBuffer());
-
         size_t vertexStride = this->geometryProcessor()->getVertexStride();
+
         const GrVertexBuffer* vertexBuffer;
         int firstVertex;
 
@@ -487,7 +483,7 @@
                                                               &vertexBuffer,
                                                               &firstVertex);
 
-        if (!vertices || !indexBuffer) {
+        if (!vertices || !batchTarget->quadIndexBuffer()) {
             SkDebugf("Could not allocate buffers\n");
             return;
         }
@@ -509,7 +505,7 @@
         drawInfo.setVertexCount(kVertsPerCubic);
         drawInfo.setStartIndex(0);
         drawInfo.setIndexCount(kIndicesPerCubic);
-        drawInfo.setIndexBuffer(indexBuffer);
+        drawInfo.setIndexBuffer(batchTarget->quadIndexBuffer());
         batchTarget->draw(drawInfo);
     }
 
diff --git a/gm/convexpolyeffect.cpp b/gm/convexpolyeffect.cpp
index 60b73c5..07d5fc2 100644
--- a/gm/convexpolyeffect.cpp
+++ b/gm/convexpolyeffect.cpp
@@ -17,7 +17,6 @@
 #include "GrContext.h"
 #include "GrDefaultGeoProcFactory.h"
 #include "GrPathUtils.h"
-#include "GrResourceProvider.h"
 #include "GrTest.h"
 #include "GrTestBatch.h"
 #include "SkColorPriv.h"
@@ -53,10 +52,8 @@
     }
 
     void onGenerateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override {
-        SkAutoTUnref<const GrIndexBuffer> indexBuffer(
-            batchTarget->resourceProvider()->refQuadIndexBuffer());
-
         size_t vertexStride = this->geometryProcessor()->getVertexStride();
+
         const GrVertexBuffer* vertexBuffer;
         int firstVertex;
 
@@ -65,7 +62,7 @@
                                                               &vertexBuffer,
                                                               &firstVertex);
 
-        if (!vertices || !indexBuffer) {
+        if (!vertices || !batchTarget->quadIndexBuffer()) {
             SkDebugf("Could not allocate buffers\n");
             return;
         }
@@ -85,7 +82,7 @@
         drawInfo.setVertexCount(kVertsPerCubic);
         drawInfo.setStartIndex(0);
         drawInfo.setIndexCount(kIndicesPerCubic);
-        drawInfo.setIndexBuffer(indexBuffer);
+        drawInfo.setIndexBuffer(batchTarget->quadIndexBuffer());
         batchTarget->draw(drawInfo);
     }
 
diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi
index 3944a03..4d2549e 100644
--- a/gyp/gpu.gypi
+++ b/gyp/gpu.gypi
@@ -167,8 +167,6 @@
       '<(skia_src_path)/gpu/GrReducedClip.h',
       '<(skia_src_path)/gpu/GrResourceCache.cpp',
       '<(skia_src_path)/gpu/GrResourceCache.h',
-      '<(skia_src_path)/gpu/GrResourceProvider.cpp',
-      '<(skia_src_path)/gpu/GrResourceProvider.h',
       '<(skia_src_path)/gpu/GrStencil.cpp',
       '<(skia_src_path)/gpu/GrStencil.h',
       '<(skia_src_path)/gpu/GrStencilAndCoverPathRenderer.cpp',
diff --git a/include/core/SkOnce.h b/include/core/SkOnce.h
index c7a87f7..a4188d0 100644
--- a/include/core/SkOnce.h
+++ b/include/core/SkOnce.h
@@ -30,7 +30,7 @@
 #include "SkAtomics.h"
 #include "SkSpinlock.h"
 
-// This must be used in a global scope, not in function scope or as a class member.
+// This must be used in a global scope, not in fuction scope or as a class member.
 #define SK_DECLARE_STATIC_ONCE(name) namespace {} static SkOnceFlag name
 
 class SkOnceFlag;
diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h
index 8bdc9f5..dc824d5 100644
--- a/include/gpu/GrContext.h
+++ b/include/gpu/GrContext.h
@@ -539,6 +539,7 @@
     GrLayerCache* getLayerCache() { return fLayerCache.get(); }
     GrTextBlobCache* getTextBlobCache() { return fTextBlobCache; }
     GrDrawTarget* getTextTarget();
+    const GrIndexBuffer* getQuadIndexBuffer() const;
     GrAARectRenderer* getAARectRenderer() { return fAARectRenderer; }
     GrResourceProvider* resourceProvider() { return fResourceProvider; }
     const GrResourceProvider* resourceProvider() const { return fResourceProvider; }
diff --git a/include/gpu/GrResourceKey.h b/include/gpu/GrResourceKey.h
index 50a7145..aecdc70 100644
--- a/include/gpu/GrResourceKey.h
+++ b/include/gpu/GrResourceKey.h
@@ -10,7 +10,6 @@
 #define GrResourceKey_DEFINED
 
 #include "GrTypes.h"
-#include "SkOnce.h"
 #include "SkTemplates.h"
 
 uint32_t GrResourceKeyHash(const uint32_t* data, size_t size);
@@ -267,24 +266,6 @@
     };
 };
 
-/**
- * It is common to need a frequently reused GrUniqueKey where the only requirement is that the key
- * is unique. These macros create such a key in a thread safe manner so the key can be truly global
- * and only constructed once.
- */
-
-/** Place outside of function/class definitions. */
-#define GR_DECLARE_STATIC_UNIQUE_KEY(name) SK_DECLARE_STATIC_ONCE(name##_once)
-
-/** Place inside function where the key is used. */
-#define GR_DEFINE_STATIC_UNIQUE_KEY(name)                           \
-    static GrUniqueKey name;                                        \
-    SkOnce(&name##_once, gr_init_static_unique_key_once, &name)
-
-static inline void gr_init_static_unique_key_once(GrUniqueKey* key) {
-    GrUniqueKey::Builder builder(key, GrUniqueKey::GenerateDomain(), 0);
-}
-
 // The cache listens for these messages to purge junk resources proactively.
 class GrUniqueKeyInvalidatedMessage {
 public:
diff --git a/include/gpu/GrTextureProvider.h b/include/gpu/GrTextureProvider.h
index 3f8c760..3e29dab 100644
--- a/include/gpu/GrTextureProvider.h
+++ b/include/gpu/GrTextureProvider.h
@@ -154,12 +154,6 @@
         fGpu = NULL;
     }
 
-    GrResourceCache* cache() { return fCache; }
-    const GrResourceCache* cache() const { return fCache; }
-
-    GrGpu* gpu() { return fGpu; }
-    const GrGpu* gpu() const { return fGpu; }
-
 private:
     bool isAbandoned() const {
         SkASSERT(SkToBool(fGpu) == SkToBool(fCache));
diff --git a/src/gpu/GrAADistanceFieldPathRenderer.cpp b/src/gpu/GrAADistanceFieldPathRenderer.cpp
index ca8c52f..669ec09 100755
--- a/src/gpu/GrAADistanceFieldPathRenderer.cpp
+++ b/src/gpu/GrAADistanceFieldPathRenderer.cpp
@@ -15,7 +15,6 @@
 #include "GrPipelineBuilder.h"
 #include "GrSurfacePriv.h"
 #include "GrSWMaskHelper.h"
-#include "GrResourceProvider.h"
 #include "GrTexturePriv.h"
 #include "GrVertexBuffer.h"
 #include "effects/GrDistanceFieldGeoProc.h"
@@ -195,17 +194,13 @@
 
         this->initDraw(batchTarget, dfProcessor, pipeline);
 
-        static const int kVertsPerQuad = 4;
-        static const int kIndicesPerQuad = 6;
-
-        SkAutoTUnref<const GrIndexBuffer> indexBuffer(
-            batchTarget->resourceProvider()->refQuadIndexBuffer());
-
         // allocate vertices
         size_t vertexStride = dfProcessor->getVertexStride();
         SkASSERT(vertexStride == 2 * sizeof(SkPoint));
+
+        int vertexCount = GrBatchTarget::kVertsPerRect * instanceCount;
+
         const GrVertexBuffer* vertexBuffer;
-        int vertexCount = kVertsPerQuad * instanceCount;
         int firstVertex;
 
         void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
@@ -213,23 +208,24 @@
                                                               &vertexBuffer,
                                                               &firstVertex);
 
-        if (!vertices || !indexBuffer) {
+        if (!vertices) {
             SkDebugf("Could not allocate vertices\n");
             return;
         }
 
         // We may have to flush while uploading path data to the atlas, so we set up the draw here
-        int maxInstancesPerDraw = indexBuffer->maxQuads();
+        const GrIndexBuffer* quadIndexBuffer = batchTarget->quadIndexBuffer();
+        int maxInstancesPerDraw = quadIndexBuffer->maxQuads();
 
         GrDrawTarget::DrawInfo drawInfo;
         drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
         drawInfo.setStartVertex(0);
         drawInfo.setStartIndex(0);
-        drawInfo.setVerticesPerInstance(kVertsPerQuad);
-        drawInfo.setIndicesPerInstance(kIndicesPerQuad);
+        drawInfo.setVerticesPerInstance(GrBatchTarget::kVertsPerRect);
+        drawInfo.setIndicesPerInstance(GrBatchTarget::kIndicesPerRect);
         drawInfo.adjustStartVertex(firstVertex);
         drawInfo.setVertexBuffer(vertexBuffer);
-        drawInfo.setIndexBuffer(indexBuffer);
+        drawInfo.setIndexBuffer(quadIndexBuffer);
 
         int instancesToFlush = 0;
         for (int i = 0; i < instanceCount; i++) {
@@ -284,7 +280,7 @@
 
             // Now set vertices
             intptr_t offset = reinterpret_cast<intptr_t>(vertices);
-            offset += i * kVertsPerQuad * vertexStride;
+            offset += i * GrBatchTarget::kVertsPerRect * vertexStride;
             SkPoint* positions = reinterpret_cast<SkPoint*>(offset);
             this->drawPath(batchTarget,
                            atlas,
diff --git a/src/gpu/GrAAHairLinePathRenderer.cpp b/src/gpu/GrAAHairLinePathRenderer.cpp
index f046af8..ad65500 100644
--- a/src/gpu/GrAAHairLinePathRenderer.cpp
+++ b/src/gpu/GrAAHairLinePathRenderer.cpp
@@ -14,11 +14,11 @@
 #include "GrContext.h"
 #include "GrDefaultGeoProcFactory.h"
 #include "GrDrawTargetCaps.h"
+#include "GrGpu.h"
 #include "GrIndexBuffer.h"
 #include "GrPathUtils.h"
 #include "GrPipelineBuilder.h"
 #include "GrProcessor.h"
-#include "GrResourceProvider.h"
 #include "GrVertexBuffer.h"
 #include "SkGeometry.h"
 #include "SkStroke.h"
@@ -26,8 +26,6 @@
 
 #include "effects/GrBezierEffect.h"
 
-#define PREALLOC_PTARRAY(N) SkSTArray<(N),SkPoint, true>
-
 // quadratics are rendered as 5-sided polys in order to bound the
 // AA stroke around the center-curve. See comments in push_quad_index_buffer and
 // bloat_quad. Quadratics and conics share an index buffer
@@ -63,14 +61,6 @@
 static const int kIdxsPerQuad = SK_ARRAY_COUNT(kQuadIdxBufPattern);
 static const int kQuadNumVertices = 5;
 static const int kQuadsNumInIdxBuffer = 256;
-GR_DECLARE_STATIC_UNIQUE_KEY(gQuadsIndexBufferKey);
-
-static const GrIndexBuffer* ref_quads_index_buffer(GrResourceProvider* resourceProvider) {
-    GR_DEFINE_STATIC_UNIQUE_KEY(gQuadsIndexBufferKey);
-    return resourceProvider->refOrCreateInstancedIndexBuffer(
-        kQuadIdxBufPattern, kIdxsPerQuad, kQuadsNumInIdxBuffer, kQuadNumVertices,
-        gQuadsIndexBufferKey);
-}
 
 
 // Each line segment is rendered as two quads and two triangles.
@@ -97,17 +87,43 @@
 static const int kLineSegNumVertices = 6;
 static const int kLineSegsNumInIdxBuffer = 256;
 
-GR_DECLARE_STATIC_UNIQUE_KEY(gLinesIndexBufferKey);
-
-static const GrIndexBuffer* ref_lines_index_buffer(GrResourceProvider* resourceProvider) {
-    GR_DEFINE_STATIC_UNIQUE_KEY(gLinesIndexBufferKey);
-    return resourceProvider->refOrCreateInstancedIndexBuffer(
-        kLineSegIdxBufPattern, kIdxsPerLineSeg,  kLineSegsNumInIdxBuffer, kLineSegNumVertices,
-        gLinesIndexBufferKey);
+GrPathRenderer* GrAAHairLinePathRenderer::Create(GrContext* context) {
+    GrGpu* gpu = context->getGpu();
+    GrIndexBuffer* qIdxBuf = gpu->createInstancedIndexBuffer(kQuadIdxBufPattern,
+                                                             kIdxsPerQuad,
+                                                             kQuadsNumInIdxBuffer,
+                                                             kQuadNumVertices);
+    SkAutoTUnref<GrIndexBuffer> qIdxBuffer(qIdxBuf);
+    GrIndexBuffer* lIdxBuf = gpu->createInstancedIndexBuffer(kLineSegIdxBufPattern,
+                                                             kIdxsPerLineSeg,
+                                                             kLineSegsNumInIdxBuffer,
+                                                             kLineSegNumVertices);
+    SkAutoTUnref<GrIndexBuffer> lIdxBuffer(lIdxBuf);
+    return SkNEW_ARGS(GrAAHairLinePathRenderer,
+                      (context, lIdxBuf, qIdxBuf));
 }
 
+GrAAHairLinePathRenderer::GrAAHairLinePathRenderer(
+                                        const GrContext* context,
+                                        const GrIndexBuffer* linesIndexBuffer,
+                                        const GrIndexBuffer* quadsIndexBuffer) {
+    fLinesIndexBuffer = linesIndexBuffer;
+    linesIndexBuffer->ref();
+    fQuadsIndexBuffer = quadsIndexBuffer;
+    quadsIndexBuffer->ref();
+}
+
+GrAAHairLinePathRenderer::~GrAAHairLinePathRenderer() {
+    fLinesIndexBuffer->unref();
+    fQuadsIndexBuffer->unref();
+}
+
+namespace {
+
+#define PREALLOC_PTARRAY(N) SkSTArray<(N),SkPoint, true>
+
 // Takes 178th time of logf on Z600 / VC2010
-static int get_float_exp(float x) {
+int get_float_exp(float x) {
     GR_STATIC_ASSERT(sizeof(int) == sizeof(float));
 #ifdef SK_DEBUG
     static bool tested;
@@ -135,7 +151,7 @@
 // found along the curve segment it will return 1 and
 // dst[0] is the original conic. If it returns 2 the dst[0]
 // and dst[1] are the two new conics.
-static int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) {
+int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) {
     SkScalar t = SkFindQuadMaxCurvature(src);
     if (t == 0) {
         if (dst) {
@@ -155,7 +171,7 @@
 // Calls split_conic on the entire conic and then once more on each subsection.
 // Most cases will result in either 1 conic (chop point is not within t range)
 // or 3 points (split once and then one subsection is split again).
-static int chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) {
+int chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) {
     SkConic dstTemp[2];
     int conicCnt = split_conic(src, dstTemp, weight);
     if (2 == conicCnt) {
@@ -170,7 +186,7 @@
 // returns 0 if quad/conic is degen or close to it
 // in this case approx the path with lines
 // otherwise returns 1
-static int is_degen_quad_or_conic(const SkPoint p[3], SkScalar* dsqd) {
+int is_degen_quad_or_conic(const SkPoint p[3], SkScalar* dsqd) {
     static const SkScalar gDegenerateToLineTol = SK_Scalar1;
     static const SkScalar gDegenerateToLineTolSqd =
         SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol);
@@ -191,14 +207,14 @@
     return 0;
 }
 
-static int is_degen_quad_or_conic(const SkPoint p[3]) {
+int is_degen_quad_or_conic(const SkPoint p[3]) {
     SkScalar dsqd;
     return is_degen_quad_or_conic(p, &dsqd);
 }
 
 // we subdivide the quads to avoid huge overfill
 // if it returns -1 then should be drawn as lines
-static int num_quad_subdivs(const SkPoint p[3]) {
+int num_quad_subdivs(const SkPoint p[3]) {
     SkScalar dsqd;
     if (is_degen_quad_or_conic(p, &dsqd)) {
         return -1;
@@ -234,14 +250,14 @@
  * subdivide large quads to reduce over-fill. This subdivision has to be
  * performed before applying the perspective matrix.
  */
-static int gather_lines_and_quads(const SkPath& path,
-                                  const SkMatrix& m,
-                                  const SkIRect& devClipBounds,
-                                  GrAAHairLinePathRenderer::PtArray* lines,
-                                  GrAAHairLinePathRenderer::PtArray* quads,
-                                  GrAAHairLinePathRenderer::PtArray* conics,
-                                  GrAAHairLinePathRenderer::IntArray* quadSubdivCnts,
-                                  GrAAHairLinePathRenderer::FloatArray* conicWeights) {
+int gather_lines_and_quads(const SkPath& path,
+                           const SkMatrix& m,
+                           const SkIRect& devClipBounds,
+                           GrAAHairLinePathRenderer::PtArray* lines,
+                           GrAAHairLinePathRenderer::PtArray* quads,
+                           GrAAHairLinePathRenderer::PtArray* conics,
+                           GrAAHairLinePathRenderer::IntArray* quadSubdivCnts,
+                           GrAAHairLinePathRenderer::FloatArray* conicWeights) {
     SkPath::Iter iter(path, false);
 
     int totalQuadCount = 0;
@@ -425,9 +441,9 @@
 
 GR_STATIC_ASSERT(sizeof(BezierVertex) == 3 * sizeof(SkPoint));
 
-static void intersect_lines(const SkPoint& ptA, const SkVector& normA,
-                            const SkPoint& ptB, const SkVector& normB,
-                            SkPoint* result) {
+void intersect_lines(const SkPoint& ptA, const SkVector& normA,
+                     const SkPoint& ptB, const SkVector& normB,
+                     SkPoint* result) {
 
     SkScalar lineAW = -normA.dot(ptA);
     SkScalar lineBW = -normB.dot(ptB);
@@ -443,14 +459,14 @@
     result->fY = SkScalarMul(result->fY, wInv);
 }
 
-static void set_uv_quad(const SkPoint qpts[3], BezierVertex verts[kQuadNumVertices]) {
+void set_uv_quad(const SkPoint qpts[3], BezierVertex verts[kQuadNumVertices]) {
     // this should be in the src space, not dev coords, when we have perspective
     GrPathUtils::QuadUVMatrix DevToUV(qpts);
     DevToUV.apply<kQuadNumVertices, sizeof(BezierVertex), sizeof(SkPoint)>(verts);
 }
 
-static void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice,
-                       const SkMatrix* toSrc, BezierVertex verts[kQuadNumVertices]) {
+void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice,
+                const SkMatrix* toSrc, BezierVertex verts[kQuadNumVertices]) {
     SkASSERT(!toDevice == !toSrc);
     // original quad is specified by tri a,b,c
     SkPoint a = qpts[0];
@@ -528,8 +544,8 @@
 // f(x, y, w) = f(P) = K^2 - LM
 // K = dot(k, P), L = dot(l, P), M = dot(m, P)
 // k, l, m are calculated in function GrPathUtils::getConicKLM
-static void set_conic_coeffs(const SkPoint p[3], BezierVertex verts[kQuadNumVertices],
-                             const SkScalar weight) {
+void set_conic_coeffs(const SkPoint p[3], BezierVertex verts[kQuadNumVertices],
+                      const SkScalar weight) {
     SkScalar klm[9];
 
     GrPathUtils::getConicKLM(p, weight, klm);
@@ -542,21 +558,21 @@
     }
 }
 
-static void add_conics(const SkPoint p[3],
-                       const SkScalar weight,
-                       const SkMatrix* toDevice,
-                       const SkMatrix* toSrc,
-                       BezierVertex** vert) {
+void add_conics(const SkPoint p[3],
+                const SkScalar weight,
+                const SkMatrix* toDevice,
+                const SkMatrix* toSrc,
+                BezierVertex** vert) {
     bloat_quad(p, toDevice, toSrc, *vert);
     set_conic_coeffs(p, *vert, weight);
     *vert += kQuadNumVertices;
 }
 
-static void add_quads(const SkPoint p[3],
-                      int subdiv,
-                      const SkMatrix* toDevice,
-                      const SkMatrix* toSrc,
-                      BezierVertex** vert) {
+void add_quads(const SkPoint p[3],
+               int subdiv,
+               const SkMatrix* toDevice,
+               const SkMatrix* toSrc,
+               BezierVertex** vert) {
     SkASSERT(subdiv >= 0);
     if (subdiv) {
         SkPoint newP[5];
@@ -570,10 +586,10 @@
     }
 }
 
-static void add_line(const SkPoint p[2],
-                     const SkMatrix* toSrc,
-                     uint8_t coverage,
-                     LineVertex** vert) {
+void add_line(const SkPoint p[2],
+              const SkMatrix* toSrc,
+              uint8_t coverage,
+              LineVertex** vert) {
     const SkPoint& a = p[0];
     const SkPoint& b = p[1];
 
@@ -615,6 +631,8 @@
     *vert += kLineSegNumVertices;
 }
 
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 bool GrAAHairLinePathRenderer::canDrawPath(const GrDrawTarget* target,
@@ -685,8 +703,11 @@
         SkIRect fDevClipBounds;
     };
 
-    static GrBatch* Create(const Geometry& geometry) {
-        return SkNEW_ARGS(AAHairlineBatch, (geometry));
+    // TODO Batch itself should not hold on to index buffers.  Instead, these should live in the
+    // cache.
+    static GrBatch* Create(const Geometry& geometry, const GrIndexBuffer* linesIndexBuffer,
+                           const GrIndexBuffer* quadsIndexBuffer) {
+        return SkNEW_ARGS(AAHairlineBatch, (geometry, linesIndexBuffer, quadsIndexBuffer));
     }
 
     const char* name() const override { return "AAHairlineBatch"; }
@@ -724,7 +745,11 @@
     typedef SkTArray<int, true> IntArray;
     typedef SkTArray<float, true> FloatArray;
 
-    AAHairlineBatch(const Geometry& geometry) {
+    AAHairlineBatch(const Geometry& geometry, const GrIndexBuffer* linesIndexBuffer,
+                    const GrIndexBuffer* quadsIndexBuffer)
+        : fLinesIndexBuffer(linesIndexBuffer)
+        , fQuadsIndexBuffer(quadsIndexBuffer) {
+        SkASSERT(linesIndexBuffer && quadsIndexBuffer);
         this->initClassID<AAHairlineBatch>();
         fGeoData.push_back(geometry);
 
@@ -783,6 +808,8 @@
 
     BatchTracker fBatch;
     SkSTArray<1, Geometry, true> fGeoData;
+    const GrIndexBuffer* fLinesIndexBuffer;
+    const GrIndexBuffer* fQuadsIndexBuffer;
 };
 
 void AAHairlineBatch::generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) {
@@ -853,8 +880,6 @@
 
     // do lines first
     if (lineCount) {
-        SkAutoTUnref<const GrIndexBuffer> linesIndexBuffer(
-            ref_lines_index_buffer(batchTarget->resourceProvider()));
         batchTarget->initDraw(lineGP, pipeline);
 
         // TODO remove this when batch is everywhere
@@ -875,7 +900,7 @@
                                                               &vertexBuffer,
                                                               &firstVertex);
 
-        if (!vertices || !linesIndexBuffer) {
+        if (!vertices) {
             SkDebugf("Could not allocate vertices\n");
             return;
         }
@@ -890,7 +915,7 @@
         {
             GrDrawTarget::DrawInfo info;
             info.setVertexBuffer(vertexBuffer);
-            info.setIndexBuffer(linesIndexBuffer);
+            info.setIndexBuffer(fLinesIndexBuffer);
             info.setPrimitiveType(kTriangles_GrPrimitiveType);
             info.setStartIndex(0);
 
@@ -912,9 +937,6 @@
         const GrVertexBuffer* vertexBuffer;
         int firstVertex;
 
-        SkAutoTUnref<const GrIndexBuffer> quadsIndexBuffer(
-            ref_quads_index_buffer(batchTarget->resourceProvider()));
-
         size_t vertexStride = sizeof(BezierVertex);
         int vertexCount = kQuadNumVertices * quadCount + kQuadNumVertices * conicCount;
         void *vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
@@ -922,7 +944,7 @@
                                                               &vertexBuffer,
                                                               &firstVertex);
 
-        if (!vertices || !quadsIndexBuffer) {
+        if (!vertices) {
             SkDebugf("Could not allocate vertices\n");
             return;
         }
@@ -955,7 +977,7 @@
             {
                GrDrawTarget::DrawInfo info;
                info.setVertexBuffer(vertexBuffer);
-               info.setIndexBuffer(quadsIndexBuffer);
+               info.setIndexBuffer(fQuadsIndexBuffer);
                info.setPrimitiveType(kTriangles_GrPrimitiveType);
                info.setStartIndex(0);
 
@@ -987,7 +1009,7 @@
             {
                 GrDrawTarget::DrawInfo info;
                 info.setVertexBuffer(vertexBuffer);
-                info.setIndexBuffer(quadsIndexBuffer);
+                info.setIndexBuffer(fQuadsIndexBuffer);
                 info.setPrimitiveType(kTriangles_GrPrimitiveType);
                 info.setStartIndex(0);
 
@@ -1011,7 +1033,9 @@
                                       const SkMatrix& viewMatrix,
                                       const SkPath& path,
                                       const GrStrokeInfo& stroke,
-                                      const SkIRect& devClipBounds) {
+                                      const SkIRect& devClipBounds,
+                                      const GrIndexBuffer* linesIndexBuffer,
+                                      const GrIndexBuffer* quadsIndexBuffer) {
     SkScalar hairlineCoverage;
     uint8_t newCoverage = 0xff;
     if (GrPathRenderer::IsStrokeHairlineOrEquivalent(stroke, viewMatrix, &hairlineCoverage)) {
@@ -1025,7 +1049,7 @@
     geometry.fPath = path;
     geometry.fDevClipBounds = devClipBounds;
 
-    return AAHairlineBatch::Create(geometry);
+    return AAHairlineBatch::Create(geometry, linesIndexBuffer, quadsIndexBuffer);
 }
 
 bool GrAAHairLinePathRenderer::onDrawPath(GrDrawTarget* target,
@@ -1035,12 +1059,18 @@
                                           const SkPath& path,
                                           const GrStrokeInfo& stroke,
                                           bool) {
+    if (!fLinesIndexBuffer || !fQuadsIndexBuffer) {
+        SkDebugf("unable to allocate indices\n");
+        return false;
+    }
+
     SkIRect devClipBounds;
     pipelineBuilder->clip().getConservativeBounds(pipelineBuilder->getRenderTarget(),
                                                   &devClipBounds);
 
     SkAutoTUnref<GrBatch> batch(create_hairline_batch(color, viewMatrix, path, stroke,
-                                                      devClipBounds));
+                                                      devClipBounds, fLinesIndexBuffer,
+                                                      fQuadsIndexBuffer));
     target->drawBatch(pipelineBuilder, batch);
 
     return true;
@@ -1051,13 +1081,28 @@
 #ifdef GR_TEST_UTILS
 
 BATCH_TEST_DEFINE(AAHairlineBatch) {
+    // TODO put these in the cache
+    static GrIndexBuffer* gQuadIndexBuffer;
+    static GrIndexBuffer* gLineIndexBuffer;
+    if (!gQuadIndexBuffer) {
+        gQuadIndexBuffer = context->getGpu()->createInstancedIndexBuffer(kQuadIdxBufPattern,
+                                                                         kIdxsPerQuad,
+                                                                         kQuadsNumInIdxBuffer,
+                                                                         kQuadNumVertices);
+        gLineIndexBuffer = context->getGpu()->createInstancedIndexBuffer(kLineSegIdxBufPattern,
+                                                                         kIdxsPerLineSeg,
+                                                                         kLineSegsNumInIdxBuffer,
+                                                                         kLineSegNumVertices);
+    }
+
     GrColor color = GrRandomColor(random);
     SkMatrix viewMatrix = GrTest::TestMatrix(random);
     GrStrokeInfo stroke(SkStrokeRec::kHairline_InitStyle);
     SkPath path = GrTest::TestPath(random);
     SkIRect devClipBounds;
     devClipBounds.setEmpty();
-    return create_hairline_batch(color, viewMatrix, path, stroke, devClipBounds);
+    return create_hairline_batch(color, viewMatrix, path, stroke, devClipBounds, gLineIndexBuffer,
+                                 gQuadIndexBuffer);
 }
 
 #endif
diff --git a/src/gpu/GrAAHairLinePathRenderer.h b/src/gpu/GrAAHairLinePathRenderer.h
index b523493..9f8d8aa 100644
--- a/src/gpu/GrAAHairLinePathRenderer.h
+++ b/src/gpu/GrAAHairLinePathRenderer.h
@@ -13,30 +13,37 @@
 
 class GrAAHairLinePathRenderer : public GrPathRenderer {
 public:
-    static GrPathRenderer* Create()  { return SkNEW(GrAAHairLinePathRenderer); }
+    virtual ~GrAAHairLinePathRenderer();
 
-    bool canDrawPath(const GrDrawTarget*,
-                     const GrPipelineBuilder*,
-                     const SkMatrix& viewMatrix,
-                     const SkPath&,
-                     const GrStrokeInfo&,
-                     bool antiAlias) const override;
+    static GrPathRenderer* Create(GrContext* context);
+
+    virtual bool canDrawPath(const GrDrawTarget*,
+                             const GrPipelineBuilder*,
+                             const SkMatrix& viewMatrix,
+                             const SkPath&,
+                             const GrStrokeInfo&,
+                             bool antiAlias) const override;
 
     typedef SkTArray<SkPoint, true> PtArray;
     typedef SkTArray<int, true> IntArray;
     typedef SkTArray<float, true> FloatArray;
 
 protected:
-    bool onDrawPath(GrDrawTarget*,
-                    GrPipelineBuilder*,
-                    GrColor,
-                    const SkMatrix& viewMatrix,
-                    const SkPath&,
-                    const GrStrokeInfo&,
-                    bool antiAlias) override;
+    virtual bool onDrawPath(GrDrawTarget*,
+                            GrPipelineBuilder*,
+                            GrColor,
+                            const SkMatrix& viewMatrix,
+                            const SkPath&,
+                            const GrStrokeInfo&,
+                            bool antiAlias) override;
 
 private:
-    GrAAHairLinePathRenderer() {}
+    GrAAHairLinePathRenderer(const GrContext* context,
+                             const GrIndexBuffer* fLinesIndexBuffer,
+                             const GrIndexBuffer* fQuadsIndexBuffer);
+
+    const GrIndexBuffer*        fLinesIndexBuffer;
+    const GrIndexBuffer*        fQuadsIndexBuffer;
 
     typedef GrPathRenderer INHERITED;
 };
diff --git a/src/gpu/GrAARectRenderer.cpp b/src/gpu/GrAARectRenderer.cpp
index d1c377a..778205f 100644
--- a/src/gpu/GrAARectRenderer.cpp
+++ b/src/gpu/GrAARectRenderer.cpp
@@ -13,11 +13,10 @@
 #include "GrContext.h"
 #include "GrDefaultGeoProcFactory.h"
 #include "GrGeometryProcessor.h"
+#include "GrGpu.h"
 #include "GrInvariantOutput.h"
-#include "GrResourceKey.h"
-#include "GrResourceProvider.h"
-#include "GrTestUtils.h"
 #include "GrVertexBuffer.h"
+#include "GrTestUtils.h"
 #include "SkColorPriv.h"
 #include "gl/GrGLProcessor.h"
 #include "gl/GrGLGeometryProcessor.h"
@@ -31,6 +30,18 @@
                     r.fRight - dx, r.fBottom - dy, stride);
 }
 
+static const uint16_t gFillAARectIdx[] = {
+    0, 1, 5, 5, 4, 0,
+    1, 2, 6, 6, 5, 1,
+    2, 3, 7, 7, 6, 2,
+    3, 0, 4, 4, 7, 3,
+    4, 5, 6, 6, 7, 4,
+};
+
+static const int kIndicesPerAAFillRect = SK_ARRAY_COUNT(gFillAARectIdx);
+static const int kVertsPerAAFillRect = 8;
+static const int kNumAAFillRectsInIndexBuffer = 256;
+
 static const GrGeometryProcessor* create_fill_rect_gp(bool tweakAlphaForCoverage,
                                                       const SkMatrix& localMatrix) {
     uint32_t flags = GrDefaultGeoProcFactory::kColor_GPType;
@@ -46,8 +57,6 @@
     return gp;
 }
 
-GR_DECLARE_STATIC_UNIQUE_KEY(gAAFillRectIndexBufferKey);
-
 class AAFillRectBatch : public GrBatch {
 public:
     struct Geometry {
@@ -57,8 +66,8 @@
         SkRect fDevRect;
     };
 
-    static GrBatch* Create(const Geometry& geometry) {
-        return SkNEW_ARGS(AAFillRectBatch, (geometry));
+    static GrBatch* Create(const Geometry& geometry, const GrIndexBuffer* indexBuffer) {
+        return SkNEW_ARGS(AAFillRectBatch, (geometry, indexBuffer));
     }
 
     const char* name() const override { return "AAFillRectBatch"; }
@@ -112,23 +121,24 @@
         init.fUsesLocalCoords = this->usesLocalCoords();
         gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
 
-        SkAutoTUnref<const GrIndexBuffer> indexBuffer(this->getIndexBuffer(
-            batchTarget->resourceProvider()));
-
         size_t vertexStride = gp->getVertexStride();
+
         SkASSERT(canTweakAlphaForCoverage ?
                  vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr) :
                  vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr));
+
         int instanceCount = fGeoData.count();
         int vertexCount = kVertsPerAAFillRect * instanceCount;
+
         const GrVertexBuffer* vertexBuffer;
         int firstVertex;
+
         void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
                                                               vertexCount,
                                                               &vertexBuffer,
                                                               &firstVertex);
 
-        if (!vertices || !indexBuffer) {
+        if (!vertices) {
             SkDebugf("Could not allocate vertices\n");
             return;
         }
@@ -153,7 +163,7 @@
         drawInfo.setIndicesPerInstance(kIndicesPerAAFillRect);
         drawInfo.adjustStartVertex(firstVertex);
         drawInfo.setVertexBuffer(vertexBuffer);
-        drawInfo.setIndexBuffer(indexBuffer);
+        drawInfo.setIndexBuffer(fIndexBuffer);
 
         int maxInstancesPerDraw = kNumAAFillRectsInIndexBuffer;
 
@@ -172,33 +182,14 @@
     SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
 
 private:
-    AAFillRectBatch(const Geometry& geometry) {
+    AAFillRectBatch(const Geometry& geometry, const GrIndexBuffer* indexBuffer)
+        : fIndexBuffer(indexBuffer) {
         this->initClassID<AAFillRectBatch>();
         fGeoData.push_back(geometry);
 
         this->setBounds(geometry.fDevRect);
     }
 
-    static const int kNumAAFillRectsInIndexBuffer = 256;
-    static const int kVertsPerAAFillRect = 8;
-    static const int kIndicesPerAAFillRect = 30;
-
-    const GrIndexBuffer* getIndexBuffer(GrResourceProvider* resourceProvider) {
-        GR_DEFINE_STATIC_UNIQUE_KEY(gAAFillRectIndexBufferKey);
-
-        static const uint16_t gFillAARectIdx[] = {
-            0, 1, 5, 5, 4, 0,
-            1, 2, 6, 6, 5, 1,
-            2, 3, 7, 7, 6, 2,
-            3, 0, 4, 4, 7, 3,
-            4, 5, 6, 6, 7, 4,
-        };
-        GR_STATIC_ASSERT(SK_ARRAY_COUNT(gFillAARectIdx) == kIndicesPerAAFillRect);
-        return resourceProvider->refOrCreateInstancedIndexBuffer(gFillAARectIdx,
-            kIndicesPerAAFillRect, kNumAAFillRectsInIndexBuffer, kVertsPerAAFillRect,
-            gAAFillRectIndexBufferKey);
-    }
-
     GrColor color() const { return fBatch.fColor; }
     bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
     bool canTweakAlphaForCoverage() const { return fBatch.fCanTweakAlphaForCoverage; }
@@ -333,6 +324,7 @@
     };
 
     BatchTracker fBatch;
+    const GrIndexBuffer* fIndexBuffer;
     SkSTArray<1, Geometry, true> fGeoData;
 };
 
@@ -344,20 +336,149 @@
 };
 }
 
+void GrAARectRenderer::reset() {
+    SkSafeSetNull(fAAFillRectIndexBuffer);
+    SkSafeSetNull(fAAMiterStrokeRectIndexBuffer);
+    SkSafeSetNull(fAABevelStrokeRectIndexBuffer);
+}
+
+static const uint16_t gMiterStrokeAARectIdx[] = {
+    0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
+    1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
+    2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
+    3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
+
+    0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
+    1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
+    2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
+    3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
+
+    0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
+    1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
+    2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
+    3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
+};
+
+static const int kIndicesPerMiterStrokeRect = SK_ARRAY_COUNT(gMiterStrokeAARectIdx);
+static const int kVertsPerMiterStrokeRect = 16;
+static const int kNumMiterStrokeRectsInIndexBuffer = 256;
+
+/**
+ * As in miter-stroke, index = a + b, and a is the current index, b is the shift
+ * from the first index. The index layout:
+ * outer AA line: 0~3, 4~7
+ * outer edge:    8~11, 12~15
+ * inner edge:    16~19
+ * inner AA line: 20~23
+ * Following comes a bevel-stroke rect and its indices:
+ *
+ *           4                                 7
+ *            *********************************
+ *          *   ______________________________  *
+ *         *  / 12                          15 \  *
+ *        *  /                                  \  *
+ *     0 *  |8     16_____________________19  11 |  * 3
+ *       *  |       |                    |       |  *
+ *       *  |       |  ****************  |       |  *
+ *       *  |       |  * 20        23 *  |       |  *
+ *       *  |       |  *              *  |       |  *
+ *       *  |       |  * 21        22 *  |       |  *
+ *       *  |       |  ****************  |       |  *
+ *       *  |       |____________________|       |  *
+ *     1 *  |9    17                      18   10|  * 2
+ *        *  \                                  /  *
+ *         *  \13 __________________________14/  *
+ *          *                                   *
+ *           **********************************
+ *          5                                  6
+ */
+static const uint16_t gBevelStrokeAARectIdx[] = {
+    // Draw outer AA, from outer AA line to outer edge, shift is 0.
+    0 + 0, 1 + 0, 9 + 0, 9 + 0, 8 + 0, 0 + 0,
+    1 + 0, 5 + 0, 13 + 0, 13 + 0, 9 + 0, 1 + 0,
+    5 + 0, 6 + 0, 14 + 0, 14 + 0, 13 + 0, 5 + 0,
+    6 + 0, 2 + 0, 10 + 0, 10 + 0, 14 + 0, 6 + 0,
+    2 + 0, 3 + 0, 11 + 0, 11 + 0, 10 + 0, 2 + 0,
+    3 + 0, 7 + 0, 15 + 0, 15 + 0, 11 + 0, 3 + 0,
+    7 + 0, 4 + 0, 12 + 0, 12 + 0, 15 + 0, 7 + 0,
+    4 + 0, 0 + 0, 8 + 0, 8 + 0, 12 + 0, 4 + 0,
+
+    // Draw the stroke, from outer edge to inner edge, shift is 8.
+    0 + 8, 1 + 8, 9 + 8, 9 + 8, 8 + 8, 0 + 8,
+    1 + 8, 5 + 8, 9 + 8,
+    5 + 8, 6 + 8, 10 + 8, 10 + 8, 9 + 8, 5 + 8,
+    6 + 8, 2 + 8, 10 + 8,
+    2 + 8, 3 + 8, 11 + 8, 11 + 8, 10 + 8, 2 + 8,
+    3 + 8, 7 + 8, 11 + 8,
+    7 + 8, 4 + 8, 8 + 8, 8 + 8, 11 + 8, 7 + 8,
+    4 + 8, 0 + 8, 8 + 8,
+
+    // Draw the inner AA, from inner edge to inner AA line, shift is 16.
+    0 + 16, 1 + 16, 5 + 16, 5 + 16, 4 + 16, 0 + 16,
+    1 + 16, 2 + 16, 6 + 16, 6 + 16, 5 + 16, 1 + 16,
+    2 + 16, 3 + 16, 7 + 16, 7 + 16, 6 + 16, 2 + 16,
+    3 + 16, 0 + 16, 4 + 16, 4 + 16, 7 + 16, 3 + 16,
+};
+
+static const int kIndicesPerBevelStrokeRect = SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
+static const int kVertsPerBevelStrokeRect = 24;
+static const int kNumBevelStrokeRectsInIndexBuffer = 256;
+
+static int aa_stroke_rect_index_count(bool miterStroke) {
+    return miterStroke ? SK_ARRAY_COUNT(gMiterStrokeAARectIdx) :
+                         SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
+}
+
+static GrIndexBuffer* setup_aa_stroke_rect_indexbuffer(GrIndexBuffer** aaMiterStrokeRectIndexBuffer,
+                                                       GrIndexBuffer** aaBevelStrokeRectIndexBuffer,
+                                                       GrGpu* gpu,
+                                                       bool miterStroke) {
+    if (miterStroke) {
+        if (!*aaMiterStrokeRectIndexBuffer) {
+            *aaMiterStrokeRectIndexBuffer =
+                    gpu->createInstancedIndexBuffer(gMiterStrokeAARectIdx,
+                                                    kIndicesPerMiterStrokeRect,
+                                                    kNumMiterStrokeRectsInIndexBuffer,
+                                                    kVertsPerMiterStrokeRect);
+        }
+        return *aaMiterStrokeRectIndexBuffer;
+    } else {
+        if (!*aaBevelStrokeRectIndexBuffer) {
+            *aaBevelStrokeRectIndexBuffer =
+                    gpu->createInstancedIndexBuffer(gBevelStrokeAARectIdx,
+                                                    kIndicesPerBevelStrokeRect,
+                                                    kNumBevelStrokeRectsInIndexBuffer,
+                                                    kVertsPerBevelStrokeRect);
+        }
+        return *aaBevelStrokeRectIndexBuffer;
+    }
+}
+
 void GrAARectRenderer::geometryFillAARect(GrDrawTarget* target,
                                           GrPipelineBuilder* pipelineBuilder,
                                           GrColor color,
                                           const SkMatrix& viewMatrix,
                                           const SkRect& rect,
                                           const SkRect& devRect) {
+    if (!fAAFillRectIndexBuffer) {
+        fAAFillRectIndexBuffer = fGpu->createInstancedIndexBuffer(gFillAARectIdx,
+                                                                  kIndicesPerAAFillRect,
+                                                                  kNumAAFillRectsInIndexBuffer,
+                                                                  kVertsPerAAFillRect);
+    }
+
+    if (!fAAFillRectIndexBuffer) {
+        SkDebugf("Unable to create index buffer\n");
+        return;
+    }
+
     AAFillRectBatch::Geometry geometry;
     geometry.fRect = rect;
     geometry.fViewMatrix = viewMatrix;
     geometry.fDevRect = devRect;
     geometry.fColor = color;
 
-
-    SkAutoTUnref<GrBatch> batch(AAFillRectBatch::Create(geometry));
+    SkAutoTUnref<GrBatch> batch(AAFillRectBatch::Create(geometry, fAAFillRectIndexBuffer));
     target->drawBatch(pipelineBuilder, batch);
 }
 
@@ -423,9 +544,6 @@
                                devOutsideAssist, devInside, miterStroke);
 }
 
-GR_DECLARE_STATIC_UNIQUE_KEY(gMiterIndexBufferKey);
-GR_DECLARE_STATIC_UNIQUE_KEY(gBevelIndexBufferKey);
-
 class AAStrokeRectBatch : public GrBatch {
 public:
     // TODO support AA rotated stroke rects by copying around view matrices
@@ -437,8 +555,9 @@
         bool fMiterStroke;
     };
 
-    static GrBatch* Create(const Geometry& geometry, const SkMatrix& viewMatrix) {
-        return SkNEW_ARGS(AAStrokeRectBatch, (geometry, viewMatrix));
+    static GrBatch* Create(const Geometry& geometry, const SkMatrix& viewMatrix,
+                           const GrIndexBuffer* indexBuffer) {
+        return SkNEW_ARGS(AAStrokeRectBatch, (geometry, viewMatrix, indexBuffer));
     }
 
     const char* name() const override { return "AAStrokeRect"; }
@@ -485,9 +604,6 @@
 
         batchTarget->initDraw(gp, pipeline);
 
-        const SkAutoTUnref<const GrIndexBuffer> indexBuffer(
-            GetIndexBuffer(batchTarget->resourceProvider(), this->miterStroke()));
-
         // TODO this is hacky, but the only way we have to initialize the GP is to use the
         // GrPipelineInfo struct so we can generate the correct shader.  Once we have GrBatch
         // everywhere we can remove this nastiness
@@ -503,6 +619,7 @@
         SkASSERT(canTweakAlphaForCoverage ?
                  vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr) :
                  vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr));
+
         int innerVertexNum = 4;
         int outerVertexNum = this->miterStroke() ? 4 : 8;
         int totalVertexNum = (outerVertexNum + innerVertexNum) * 2;
@@ -518,7 +635,7 @@
                                                               &vertexBuffer,
                                                               &firstVertex);
 
-        if (!vertices || !indexBuffer) {
+        if (!vertices) {
             SkDebugf("Could not allocate vertices\n");
             return;
         }
@@ -537,19 +654,18 @@
                                                args.fMiterStroke,
                                                canTweakAlphaForCoverage);
         }
-        int indicesPerInstance = this->miterStroke() ? kMiterIndexCnt : kBevelIndexCnt;
+
         GrDrawTarget::DrawInfo drawInfo;
         drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
         drawInfo.setStartVertex(0);
         drawInfo.setStartIndex(0);
         drawInfo.setVerticesPerInstance(totalVertexNum);
-        drawInfo.setIndicesPerInstance(indicesPerInstance);
+        drawInfo.setIndicesPerInstance(aa_stroke_rect_index_count(this->miterStroke()));
         drawInfo.adjustStartVertex(firstVertex);
         drawInfo.setVertexBuffer(vertexBuffer);
-        drawInfo.setIndexBuffer(indexBuffer);
+        drawInfo.setIndexBuffer(fIndexBuffer);
 
-        int maxInstancesPerDraw = this->miterStroke() ? kNumMiterRectsInIndexBuffer :
-                                                        kNumBevelRectsInIndexBuffer;
+        int maxInstancesPerDraw = kNumBevelStrokeRectsInIndexBuffer;
 
         while (instanceCount) {
             drawInfo.setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw));
@@ -566,7 +682,9 @@
     SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
 
 private:
-    AAStrokeRectBatch(const Geometry& geometry, const SkMatrix& viewMatrix)  {
+    AAStrokeRectBatch(const Geometry& geometry, const SkMatrix& viewMatrix,
+                      const GrIndexBuffer* indexBuffer)
+        : fIndexBuffer(indexBuffer) {
         this->initClassID<AAStrokeRectBatch>();
         fBatch.fViewMatrix = viewMatrix;
         fGeoData.push_back(geometry);
@@ -577,106 +695,6 @@
         fBounds.join(geometry.fDevOutsideAssist);
     }
 
-
-    static const int kMiterIndexCnt = 3 * 24;
-    static const int kMiterVertexCnt = 16;
-    static const int kNumMiterRectsInIndexBuffer = 256;
-
-    static const int kBevelIndexCnt = 48 + 36 + 24;
-    static const int kBevelVertexCnt = 24;
-    static const int kNumBevelRectsInIndexBuffer = 256;
-
-    static const GrIndexBuffer* GetIndexBuffer(GrResourceProvider* resourceProvider,
-                                               bool miterStroke) {
-
-        if (miterStroke) {
-            static const uint16_t gMiterIndices[] = {
-                0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
-                1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
-                2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
-                3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
-
-                0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
-                1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
-                2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
-                3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
-
-                0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
-                1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
-                2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
-                3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
-            };
-            GR_STATIC_ASSERT(SK_ARRAY_COUNT(gMiterIndices) == kMiterIndexCnt);
-            GR_DEFINE_STATIC_UNIQUE_KEY(gMiterIndexBufferKey);
-            return resourceProvider->refOrCreateInstancedIndexBuffer(gMiterIndices,
-                kMiterIndexCnt, kNumMiterRectsInIndexBuffer, kMiterVertexCnt,
-                gMiterIndexBufferKey);
-        } else {
-            /**
-             * As in miter-stroke, index = a + b, and a is the current index, b is the shift
-             * from the first index. The index layout:
-             * outer AA line: 0~3, 4~7
-             * outer edge:    8~11, 12~15
-             * inner edge:    16~19
-             * inner AA line: 20~23
-             * Following comes a bevel-stroke rect and its indices:
-             *
-             *           4                                 7
-             *            *********************************
-             *          *   ______________________________  *
-             *         *  / 12                          15 \  *
-             *        *  /                                  \  *
-             *     0 *  |8     16_____________________19  11 |  * 3
-             *       *  |       |                    |       |  *
-             *       *  |       |  ****************  |       |  *
-             *       *  |       |  * 20        23 *  |       |  *
-             *       *  |       |  *              *  |       |  *
-             *       *  |       |  * 21        22 *  |       |  *
-             *       *  |       |  ****************  |       |  *
-             *       *  |       |____________________|       |  *
-             *     1 *  |9    17                      18   10|  * 2
-             *        *  \                                  /  *
-             *         *  \13 __________________________14/  *
-             *          *                                   *
-             *           **********************************
-             *          5                                  6
-             */
-            static const uint16_t gBevelIndices[] = {
-                // Draw outer AA, from outer AA line to outer edge, shift is 0.
-                0 + 0, 1 + 0,  9 + 0,  9 + 0,  8 + 0, 0 + 0,
-                1 + 0, 5 + 0, 13 + 0, 13 + 0,  9 + 0, 1 + 0,
-                5 + 0, 6 + 0, 14 + 0, 14 + 0, 13 + 0, 5 + 0,
-                6 + 0, 2 + 0, 10 + 0, 10 + 0, 14 + 0, 6 + 0,
-                2 + 0, 3 + 0, 11 + 0, 11 + 0, 10 + 0, 2 + 0,
-                3 + 0, 7 + 0, 15 + 0, 15 + 0, 11 + 0, 3 + 0,
-                7 + 0, 4 + 0, 12 + 0, 12 + 0, 15 + 0, 7 + 0,
-                4 + 0, 0 + 0,  8 + 0,  8 + 0, 12 + 0, 4 + 0,
-
-                // Draw the stroke, from outer edge to inner edge, shift is 8.
-                0 + 8, 1 + 8, 9 + 8, 9 + 8, 8 + 8, 0 + 8,
-                1 + 8, 5 + 8, 9 + 8,
-                5 + 8, 6 + 8, 10 + 8, 10 + 8, 9 + 8, 5 + 8,
-                6 + 8, 2 + 8, 10 + 8,
-                2 + 8, 3 + 8, 11 + 8, 11 + 8, 10 + 8, 2 + 8,
-                3 + 8, 7 + 8, 11 + 8,
-                7 + 8, 4 + 8, 8 + 8, 8 + 8, 11 + 8, 7 + 8,
-                4 + 8, 0 + 8, 8 + 8,
-
-                // Draw the inner AA, from inner edge to inner AA line, shift is 16.
-                0 + 16, 1 + 16, 5 + 16, 5 + 16, 4 + 16, 0 + 16,
-                1 + 16, 2 + 16, 6 + 16, 6 + 16, 5 + 16, 1 + 16,
-                2 + 16, 3 + 16, 7 + 16, 7 + 16, 6 + 16, 2 + 16,
-                3 + 16, 0 + 16, 4 + 16, 4 + 16, 7 + 16, 3 + 16,
-            };
-            GR_STATIC_ASSERT(SK_ARRAY_COUNT(gBevelIndices) == kBevelIndexCnt);
-
-            GR_DEFINE_STATIC_UNIQUE_KEY(gBevelIndexBufferKey);
-            return resourceProvider->refOrCreateInstancedIndexBuffer(gBevelIndices,
-                kBevelIndexCnt, kNumBevelRectsInIndexBuffer, kBevelVertexCnt,
-                gBevelIndexBufferKey);
-        }
-    }
-
     GrColor color() const { return fBatch.fColor; }
     bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
     bool canTweakAlphaForCoverage() const { return fBatch.fCanTweakAlphaForCoverage; }
@@ -837,6 +855,7 @@
     };
 
     BatchTracker fBatch;
+    const GrIndexBuffer* fIndexBuffer;
     SkSTArray<1, Geometry, true> fGeoData;
 };
 
@@ -848,6 +867,15 @@
                                             const SkRect& devOutsideAssist,
                                             const SkRect& devInside,
                                             bool miterStroke) {
+    GrIndexBuffer* indexBuffer = setup_aa_stroke_rect_indexbuffer(&fAAMiterStrokeRectIndexBuffer,
+                                                                  &fAABevelStrokeRectIndexBuffer,
+                                                                  fGpu,
+                                                                  miterStroke);
+    if (!indexBuffer) {
+        SkDebugf("Failed to create index buffer!\n");
+        return;
+    }
+
     AAStrokeRectBatch::Geometry geometry;
     geometry.fColor = color;
     geometry.fDevOutside = devOutside;
@@ -855,7 +883,7 @@
     geometry.fDevInside = devInside;
     geometry.fMiterStroke = miterStroke;
 
-    SkAutoTUnref<GrBatch> batch(AAStrokeRectBatch::Create(geometry, viewMatrix));
+    SkAutoTUnref<GrBatch> batch(AAStrokeRectBatch::Create(geometry, viewMatrix, indexBuffer));
     target->drawBatch(pipelineBuilder, batch);
 }
 
@@ -891,12 +919,30 @@
     geo.fViewMatrix = GrTest::TestMatrix(random);
     geo.fRect = GrTest::TestRect(random);
     geo.fDevRect = GrTest::TestRect(random);
-    return AAFillRectBatch::Create(geo);
+
+    static GrIndexBuffer* aaFillRectIndexBuffer = NULL;
+    if (!aaFillRectIndexBuffer) {
+        aaFillRectIndexBuffer =
+                context->getGpu()->createInstancedIndexBuffer(gFillAARectIdx,
+                                                              kIndicesPerAAFillRect,
+                                                              kNumAAFillRectsInIndexBuffer,
+                                                              kVertsPerAAFillRect);
+    }
+
+    return AAFillRectBatch::Create(geo, aaFillRectIndexBuffer);
 }
 
 BATCH_TEST_DEFINE(AAStrokeRectBatch) {
+    static GrIndexBuffer* aaMiterStrokeRectIndexBuffer = NULL;
+    static GrIndexBuffer* aaBevelStrokeRectIndexBuffer = NULL;
+
     bool miterStroke = random->nextBool();
 
+    GrIndexBuffer* indexBuffer = setup_aa_stroke_rect_indexbuffer(&aaMiterStrokeRectIndexBuffer,
+                                                                  &aaBevelStrokeRectIndexBuffer,
+                                                                  context->getGpu(),
+                                                                  miterStroke);
+
     // Create mock stroke rect
     SkRect outside = GrTest::TestRect(random);
     SkScalar minDim = SkMinScalar(outside.width(), outside.height());
@@ -913,7 +959,7 @@
     geo.fDevInside = inside;
     geo.fMiterStroke = miterStroke;
 
-    return AAStrokeRectBatch::Create(geo, GrTest::TestMatrix(random));
+    return AAStrokeRectBatch::Create(geo, GrTest::TestMatrix(random), indexBuffer);
 }
 
 #endif
diff --git a/src/gpu/GrAARectRenderer.h b/src/gpu/GrAARectRenderer.h
index 023eadc..3193f4b 100644
--- a/src/gpu/GrAARectRenderer.h
+++ b/src/gpu/GrAARectRenderer.h
@@ -16,6 +16,7 @@
 
 class GrClip;
 class GrDrawTarget;
+class GrGpu;
 class GrIndexBuffer;
 class GrPipelineBuilder;
 
@@ -26,6 +27,19 @@
 public:
     SK_DECLARE_INST_COUNT(GrAARectRenderer)
 
+    GrAARectRenderer(GrGpu* gpu)
+    : fGpu(gpu)
+    , fAAFillRectIndexBuffer(NULL)
+    , fAAMiterStrokeRectIndexBuffer(NULL)
+    , fAABevelStrokeRectIndexBuffer(NULL) {
+    }
+
+    void reset();
+
+    ~GrAARectRenderer() {
+        this->reset();
+    }
+
     // TODO: potentialy fuse the fill & stroke methods and differentiate
     // between them by passing in stroke (==NULL means fill).
 
@@ -70,6 +84,11 @@
                               const SkRect& devInside,
                               bool miterStroke);
 
+    GrGpu*                      fGpu;
+    GrIndexBuffer*              fAAFillRectIndexBuffer;
+    GrIndexBuffer*              fAAMiterStrokeRectIndexBuffer;
+    GrIndexBuffer*              fAABevelStrokeRectIndexBuffer;
+
     typedef SkRefCnt INHERITED;
 };
 
diff --git a/src/gpu/GrAddPathRenderers_default.cpp b/src/gpu/GrAddPathRenderers_default.cpp
index 0f675ac..06e98a9 100644
--- a/src/gpu/GrAddPathRenderers_default.cpp
+++ b/src/gpu/GrAddPathRenderers_default.cpp
@@ -39,7 +39,7 @@
     if (GrPathRenderer* pr = GrStencilAndCoverPathRenderer::Create(ctx)) {
         chain->addPathRenderer(pr)->unref();
     }
-    if (GrPathRenderer* pr = GrAAHairLinePathRenderer::Create()) {
+    if (GrPathRenderer* pr = GrAAHairLinePathRenderer::Create(ctx)) {
         chain->addPathRenderer(pr)->unref();
     }
     chain->addPathRenderer(SkNEW(GrAAConvexPathRenderer))->unref();
diff --git a/src/gpu/GrAtlasTextContext.cpp b/src/gpu/GrAtlasTextContext.cpp
index 33e4f7e..14930fa 100644
--- a/src/gpu/GrAtlasTextContext.cpp
+++ b/src/gpu/GrAtlasTextContext.cpp
@@ -13,7 +13,6 @@
 #include "GrDrawTarget.h"
 #include "GrFontScaler.h"
 #include "GrIndexBuffer.h"
-#include "GrResourceProvider.h"
 #include "GrStrokeInfo.h"
 #include "GrTextBlobCache.h"
 #include "GrTexturePriv.h"
@@ -1515,16 +1514,14 @@
 
         int glyphCount = this->numGlyphs();
         int instanceCount = fInstanceCount;
-        SkAutoTUnref<const GrIndexBuffer> indexBuffer(
-            batchTarget->resourceProvider()->refQuadIndexBuffer());
-
         const GrVertexBuffer* vertexBuffer;
         int firstVertex;
+
         void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
                                                               glyphCount * kVerticesPerGlyph,
                                                               &vertexBuffer,
                                                               &firstVertex);
-        if (!vertices || !indexBuffer) {
+        if (!vertices) {
             SkDebugf("Could not allocate vertices\n");
             return;
         }
@@ -1532,7 +1529,8 @@
         unsigned char* currVertex = reinterpret_cast<unsigned char*>(vertices);
 
         // setup drawinfo
-        int maxInstancesPerDraw = indexBuffer->maxQuads();
+        const GrIndexBuffer* quadIndexBuffer = batchTarget->quadIndexBuffer();
+        int maxInstancesPerDraw = quadIndexBuffer->maxQuads();
 
         GrDrawTarget::DrawInfo drawInfo;
         drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
@@ -1542,7 +1540,7 @@
         drawInfo.setIndicesPerInstance(kIndicesPerGlyph);
         drawInfo.adjustStartVertex(firstVertex);
         drawInfo.setVertexBuffer(vertexBuffer);
-        drawInfo.setIndexBuffer(indexBuffer);
+        drawInfo.setIndexBuffer(quadIndexBuffer);
 
         // We cache some values to avoid going to the glyphcache for the same fontScaler twice
         // in a row
diff --git a/src/gpu/GrBatchTarget.h b/src/gpu/GrBatchTarget.h
index 97cd2ed..9bd6b94 100644
--- a/src/gpu/GrBatchTarget.h
+++ b/src/gpu/GrBatchTarget.h
@@ -121,7 +121,9 @@
     GrVertexBufferAllocPool* vertexPool() { return fVertexPool; }
     GrIndexBufferAllocPool* indexPool() { return fIndexPool; }
 
-    GrResourceProvider* resourceProvider() const { return fGpu->getContext()->resourceProvider(); }
+    const static int kVertsPerRect = 4;
+    const static int kIndicesPerRect = 6;
+    const GrIndexBuffer* quadIndexBuffer() const { return fGpu->getQuadIndexBuffer(); }
 
     // A helper for draws which overallocate and then return data to the pool
     void putBackIndices(size_t indices) { fIndexPool->putBack(indices * sizeof(uint16_t)); }
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 819774a..4709513 100755
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -125,8 +125,8 @@
 
     fLayerCache.reset(SkNEW_ARGS(GrLayerCache, (this)));
 
-    fAARectRenderer = SkNEW(GrAARectRenderer);
-    fOvalRenderer = SkNEW(GrOvalRenderer);
+    fAARectRenderer = SkNEW_ARGS(GrAARectRenderer, (fGpu));
+    fOvalRenderer = SkNEW_ARGS(GrOvalRenderer, (fGpu));
 
     fDidTestPMConversions = false;
 
@@ -186,6 +186,9 @@
     delete fDrawBufferIBAllocPool;
     fDrawBufferIBAllocPool = NULL;
 
+    fAARectRenderer->reset();
+    fOvalRenderer->reset();
+
     fBatchFontCache->freeAll();
     fLayerCache->freeAll();
     fTextBlobCache->freeAll();
@@ -202,6 +205,9 @@
         fDrawBuffer->purgeResources();
     }
 
+    fAARectRenderer->reset();
+    fOvalRenderer->reset();
+
     fBatchFontCache->freeAll();
     fLayerCache->freeAll();
     // a path renderer may be holding onto resources
@@ -1834,6 +1840,10 @@
     return this->prepareToDraw();
 }
 
+const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
+    return fGpu->getQuadIndexBuffer();
+}
+
 namespace {
 void test_pm_conversions(GrContext* ctx, int* pmToUPMValue, int* upmToPMValue) {
     GrConfigConversionEffect::PMConversion pmToUPM;
diff --git a/src/gpu/GrDashLinePathRenderer.cpp b/src/gpu/GrDashLinePathRenderer.cpp
index 67dc6c7..bd49a72 100644
--- a/src/gpu/GrDashLinePathRenderer.cpp
+++ b/src/gpu/GrDashLinePathRenderer.cpp
@@ -39,6 +39,6 @@
                                         bool useAA) {
     SkPoint pts[2];
     SkAssertResult(path.isLine(pts));
-    return GrDashingEffect::DrawDashLine(target, pipelineBuilder, color,
+    return GrDashingEffect::DrawDashLine(fGpu, target, pipelineBuilder, color,
                                          viewMatrix, pts, useAA, stroke);
 }
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index cdf5226..fdb098a 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -24,11 +24,14 @@
 GrGpu::GrGpu(GrContext* context)
     : fResetTimestamp(kExpiredTimestamp+1)
     , fResetBits(kAll_GrBackendState)
+    , fQuadIndexBuffer(NULL)
     , fGpuTraceMarkerCount(0)
     , fContext(context) {
 }
 
-GrGpu::~GrGpu() {}
+GrGpu::~GrGpu() {
+    SkSafeSetNull(fQuadIndexBuffer);
+}
 
 void GrGpu::contextAbandoned() {}
 
@@ -181,6 +184,39 @@
     return this->onCreateIndexBuffer(size, dynamic);
 }
 
+GrIndexBuffer* GrGpu::createInstancedIndexBuffer(const uint16_t* pattern,
+                                                 int patternSize,
+                                                 int reps,
+                                                 int vertCount,
+                                                 bool isDynamic) {
+    size_t bufferSize = patternSize * reps * sizeof(uint16_t);
+    GrGpu* me = const_cast<GrGpu*>(this);
+    GrIndexBuffer* buffer = me->createIndexBuffer(bufferSize, isDynamic);
+    if (buffer) {
+        uint16_t* data = (uint16_t*) buffer->map();
+        bool useTempData = (NULL == data);
+        if (useTempData) {
+            data = SkNEW_ARRAY(uint16_t, reps * patternSize);
+        }
+        for (int i = 0; i < reps; ++i) {
+            int baseIdx = i * patternSize;
+            uint16_t baseVert = (uint16_t)(i * vertCount);
+            for (int j = 0; j < patternSize; ++j) {
+                data[baseIdx+j] = baseVert + pattern[j];
+            }
+        }
+        if (useTempData) {
+            if (!buffer->updateData(data, bufferSize)) {
+                SkFAIL("Can't get indices into buffer!");
+            }
+            SkDELETE_ARRAY(data);
+        } else {
+            buffer->unmap();
+        }
+    }
+    return buffer;
+}
+
 void GrGpu::clear(const SkIRect* rect,
                   GrColor color,
                   bool canIgnoreRect,
@@ -269,6 +305,29 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
+static const int MAX_QUADS = 1 << 12; // max possible: (1 << 14) - 1;
+
+GR_STATIC_ASSERT(4 * MAX_QUADS <= 65535);
+
+static const uint16_t gQuadIndexPattern[] = {
+  0, 1, 2, 0, 2, 3
+};
+
+const GrIndexBuffer* GrGpu::getQuadIndexBuffer() const {
+    if (NULL == fQuadIndexBuffer || fQuadIndexBuffer->wasDestroyed()) {
+        SkSafeUnref(fQuadIndexBuffer);
+        GrGpu* me = const_cast<GrGpu*>(this);
+        fQuadIndexBuffer = me->createInstancedIndexBuffer(gQuadIndexPattern,
+                                                          6,
+                                                          MAX_QUADS,
+                                                          4);
+    }
+
+    return fQuadIndexBuffer;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
 void GrGpu::draw(const DrawArgs& args, const GrDrawTarget::DrawInfo& info) {
     this->handleDirtyContext();
     this->onDraw(args, info);
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index 3903af6..b2dbec6 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -119,6 +119,34 @@
     GrIndexBuffer* createIndexBuffer(size_t size, bool dynamic);
 
     /**
+     * Creates an index buffer for instance drawing with a specific pattern.
+     *
+     * @param pattern     the pattern to repeat
+     * @param patternSize size in bytes of the pattern
+     * @param reps        number of times to repeat the pattern
+     * @param vertCount   number of vertices the pattern references
+     * @param dynamic     hints whether the data will be frequently changed
+     *                    by either GrIndexBuffer::map() or
+     *                    GrIndexBuffer::updateData().
+     *
+     * @return The index buffer if successful, otherwise NULL.
+     */
+    GrIndexBuffer* createInstancedIndexBuffer(const uint16_t* pattern,
+                                              int patternSize,
+                                              int reps,
+                                              int vertCount,
+                                              bool isDynamic = false);
+
+    /**
+     * Returns an index buffer that can be used to render quads.
+     * Six indices per quad: 0, 1, 2, 0, 2, 3, etc.
+     * The max number of quads can be queried using GrIndexBuffer::maxQuads().
+     * Draw with kTriangles_GrPrimitiveType
+     * @ return the quad index buffer
+     */
+    const GrIndexBuffer* getQuadIndexBuffer() const;
+
+    /**
      * Resolves MSAA.
      */
     void resolveRenderTarget(GrRenderTarget* target);
@@ -492,6 +520,8 @@
 
     ResetTimestamp                                                      fResetTimestamp;
     uint32_t                                                            fResetBits;
+    // these are mutable so they can be created on-demand
+    mutable GrIndexBuffer*                                              fQuadIndexBuffer;
     // To keep track that we always have at least as many debug marker adds as removes
     int                                                                 fGpuTraceMarkerCount;
     GrTraceMarkerSet                                                    fActiveTraceMarkers;
diff --git a/src/gpu/GrInOrderDrawBuffer.cpp b/src/gpu/GrInOrderDrawBuffer.cpp
index 8190ec0..e298be6 100644
--- a/src/gpu/GrInOrderDrawBuffer.cpp
+++ b/src/gpu/GrInOrderDrawBuffer.cpp
@@ -8,7 +8,6 @@
 #include "GrInOrderDrawBuffer.h"
 
 #include "GrDefaultGeoProcFactory.h"
-#include "GrResourceProvider.h"
 #include "GrTemplates.h"
 
 GrInOrderDrawBuffer::GrInOrderDrawBuffer(GrContext* context,
@@ -138,18 +137,17 @@
                  vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr));
 
         int instanceCount = fGeoData.count();
-        SkAutoTUnref<const GrIndexBuffer> indexBuffer(
-            batchTarget->resourceProvider()->refQuadIndexBuffer());
-
         int vertexCount = kVertsPerRect * instanceCount;
+
         const GrVertexBuffer* vertexBuffer;
         int firstVertex;
+
         void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
                                                               vertexCount,
                                                               &vertexBuffer,
                                                               &firstVertex);
 
-        if (!vertices || !indexBuffer) {
+        if (!vertices || !batchTarget->quadIndexBuffer()) {
             SkDebugf("Could not allocate buffers\n");
             return;
         }
@@ -183,6 +181,8 @@
             }
         }
 
+        const GrIndexBuffer* quadIndexBuffer = batchTarget->quadIndexBuffer();
+
         GrDrawTarget::DrawInfo drawInfo;
         drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
         drawInfo.setStartVertex(0);
@@ -191,9 +191,9 @@
         drawInfo.setIndicesPerInstance(kIndicesPerRect);
         drawInfo.adjustStartVertex(firstVertex);
         drawInfo.setVertexBuffer(vertexBuffer);
-        drawInfo.setIndexBuffer(indexBuffer);
+        drawInfo.setIndexBuffer(quadIndexBuffer);
 
-        int maxInstancesPerDraw = indexBuffer->maxQuads();
+        int maxInstancesPerDraw = quadIndexBuffer->maxQuads();
         while (instanceCount) {
             drawInfo.setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw));
             drawInfo.setVertexCount(drawInfo.instanceCount() * drawInfo.verticesPerInstance());
diff --git a/src/gpu/GrOvalRenderer.cpp b/src/gpu/GrOvalRenderer.cpp
index 38efefa..8723d70 100644
--- a/src/gpu/GrOvalRenderer.cpp
+++ b/src/gpu/GrOvalRenderer.cpp
@@ -13,10 +13,10 @@
 #include "GrBufferAllocPool.h"
 #include "GrDrawTarget.h"
 #include "GrGeometryProcessor.h"
+#include "GrGpu.h"
 #include "GrInvariantOutput.h"
 #include "GrPipelineBuilder.h"
 #include "GrProcessor.h"
-#include "GrResourceProvider.h"
 #include "GrVertexBuffer.h"
 #include "SkRRect.h"
 #include "SkStrokeRec.h"
@@ -646,6 +646,11 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
+void GrOvalRenderer::reset() {
+    SkSafeSetNull(fRRectIndexBuffer);
+    SkSafeSetNull(fStrokeRRectIndexBuffer);
+}
+
 bool GrOvalRenderer::drawOval(GrDrawTarget* target,
                               GrPipelineBuilder* pipelineBuilder,
                               GrColor color,
@@ -654,7 +659,8 @@
                               const SkRect& oval,
                               const SkStrokeRec& stroke)
 {
-    bool useCoverageAA = useAA && !pipelineBuilder->getRenderTarget()->isMultisampled();
+    bool useCoverageAA = useAA &&
+        !pipelineBuilder->getRenderTarget()->isMultisampled();
 
     if (!useCoverageAA) {
         return false;
@@ -691,7 +697,9 @@
         SkRect fDevBounds;
     };
 
-    static GrBatch* Create(const Geometry& geometry) { return SkNEW_ARGS(CircleBatch, (geometry)); }
+    static GrBatch* Create(const Geometry& geometry) {
+        return SkNEW_ARGS(CircleBatch, (geometry));
+    }
 
     const char* name() const override { return "CircleBatch"; }
 
@@ -748,8 +756,6 @@
         size_t vertexStride = gp->getVertexStride();
         SkASSERT(vertexStride == sizeof(CircleVertex));
 
-        SkAutoTUnref<const GrIndexBuffer> indexBuffer(
-            batchTarget->resourceProvider()->refQuadIndexBuffer());
         const GrVertexBuffer* vertexBuffer;
         int firstVertex;
 
@@ -758,7 +764,7 @@
                                                               &vertexBuffer,
                                                               &firstVertex);
 
-        if (!vertices || !indexBuffer) {
+        if (!vertices || !batchTarget->quadIndexBuffer()) {
             SkDebugf("Could not allocate buffers\n");
             return;
         }
@@ -798,6 +804,8 @@
             verts += kVertsPerCircle;
         }
 
+        const GrIndexBuffer* quadIndexBuffer = batchTarget->quadIndexBuffer();
+
         GrDrawTarget::DrawInfo drawInfo;
         drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
         drawInfo.setStartVertex(0);
@@ -806,9 +814,9 @@
         drawInfo.setIndicesPerInstance(kIndicesPerCircle);
         drawInfo.adjustStartVertex(firstVertex);
         drawInfo.setVertexBuffer(vertexBuffer);
-        drawInfo.setIndexBuffer(indexBuffer);
+        drawInfo.setIndexBuffer(quadIndexBuffer);
 
-        int maxInstancesPerDraw = indexBuffer->maxQuads();
+        int maxInstancesPerDraw = quadIndexBuffer->maxQuads();
 
         while (instanceCount) {
             drawInfo.setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw));
@@ -1014,8 +1022,6 @@
         SkASSERT(vertexStride == sizeof(EllipseVertex));
 
         const GrVertexBuffer* vertexBuffer;
-        SkAutoTUnref<const GrIndexBuffer> indexBuffer(
-            batchTarget->resourceProvider()->refQuadIndexBuffer());
         int firstVertex;
 
         void *vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
@@ -1023,7 +1029,7 @@
                                                               &vertexBuffer,
                                                               &firstVertex);
 
-        if (!vertices || !indexBuffer) {
+        if (!vertices || !batchTarget->quadIndexBuffer()) {
             SkDebugf("Could not allocate buffers\n");
             return;
         }
@@ -1068,6 +1074,8 @@
             verts += kVertsPerEllipse;
         }
 
+        const GrIndexBuffer* quadIndexBuffer = batchTarget->quadIndexBuffer();
+
         GrDrawTarget::DrawInfo drawInfo;
         drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
         drawInfo.setStartVertex(0);
@@ -1076,9 +1084,9 @@
         drawInfo.setIndicesPerInstance(kIndicesPerEllipse);
         drawInfo.adjustStartVertex(firstVertex);
         drawInfo.setVertexBuffer(vertexBuffer);
-        drawInfo.setIndexBuffer(indexBuffer);
+        drawInfo.setIndexBuffer(quadIndexBuffer);
 
-        int maxInstancesPerDraw = indexBuffer->maxQuads();
+        int maxInstancesPerDraw = quadIndexBuffer->maxQuads();
 
         while (instanceCount) {
             drawInfo.setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw));
@@ -1317,21 +1325,20 @@
         init.fUsesLocalCoords = this->usesLocalCoords();
         gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
 
-        SkAutoTUnref<const GrIndexBuffer> indexBuffer(
-            batchTarget->resourceProvider()->refQuadIndexBuffer());
-
         int instanceCount = fGeoData.count();
         int vertexCount = kVertsPerEllipse * instanceCount;
         size_t vertexStride = gp->getVertexStride();
         SkASSERT(vertexStride == sizeof(DIEllipseVertex));
+
         const GrVertexBuffer* vertexBuffer;
         int firstVertex;
+
         void *vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
                                                               vertexCount,
                                                               &vertexBuffer,
                                                               &firstVertex);
 
-        if (!vertices || !indexBuffer) {
+        if (!vertices || !batchTarget->quadIndexBuffer()) {
             SkDebugf("Could not allocate buffers\n");
             return;
         }
@@ -1372,6 +1379,8 @@
             verts += kVertsPerEllipse;
         }
 
+        const GrIndexBuffer* quadIndexBuffer = batchTarget->quadIndexBuffer();
+
         GrDrawTarget::DrawInfo drawInfo;
         drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
         drawInfo.setStartVertex(0);
@@ -1380,9 +1389,9 @@
         drawInfo.setIndicesPerInstance(kIndicesPerEllipse);
         drawInfo.adjustStartVertex(firstVertex);
         drawInfo.setVertexBuffer(vertexBuffer);
-        drawInfo.setIndexBuffer(indexBuffer);
+        drawInfo.setIndexBuffer(quadIndexBuffer);
 
-        int maxInstancesPerDraw = indexBuffer->maxQuads();
+        int maxInstancesPerDraw = quadIndexBuffer->maxQuads();
 
         while (instanceCount) {
             drawInfo.setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw));
@@ -1570,24 +1579,6 @@
 static const int kVertsPerRRect = 16;
 static const int kNumRRectsInIndexBuffer = 256;
 
-GR_DECLARE_STATIC_UNIQUE_KEY(gStrokeRRectOnlyIndexBufferKey);
-GR_DECLARE_STATIC_UNIQUE_KEY(gRRectOnlyIndexBufferKey);
-static const GrIndexBuffer* ref_rrect_index_buffer(bool strokeOnly,
-                                                   GrResourceProvider* resourceProvider) {
-    GR_DEFINE_STATIC_UNIQUE_KEY(gStrokeRRectOnlyIndexBufferKey);
-    GR_DEFINE_STATIC_UNIQUE_KEY(gRRectOnlyIndexBufferKey);
-    if (strokeOnly) {
-        return resourceProvider->refOrCreateInstancedIndexBuffer(
-            gRRectIndices, kIndicesPerStrokeRRect, kNumRRectsInIndexBuffer, kVertsPerRRect,
-            gStrokeRRectOnlyIndexBufferKey);
-    } else {
-        return resourceProvider->refOrCreateInstancedIndexBuffer(
-            gRRectIndices, kIndicesPerRRect, kNumRRectsInIndexBuffer, kVertsPerRRect,
-            gRRectOnlyIndexBufferKey);
-
-    }
-}
-
 bool GrOvalRenderer::drawDRRect(GrDrawTarget* target,
                                 GrPipelineBuilder* pipelineBuilder,
                                 GrColor color,
@@ -1666,8 +1657,8 @@
         SkRect fDevBounds;
     };
 
-    static GrBatch* Create(const Geometry& geometry) {
-        return SkNEW_ARGS(RRectCircleRendererBatch, (geometry));
+    static GrBatch* Create(const Geometry& geometry, const GrIndexBuffer* indexBuffer) {
+        return SkNEW_ARGS(RRectCircleRendererBatch, (geometry, indexBuffer));
     }
 
     const char* name() const override { return "RRectCircleBatch"; }
@@ -1727,8 +1718,6 @@
         SkASSERT(vertexStride == sizeof(CircleVertex));
 
         const GrVertexBuffer* vertexBuffer;
-        SkAutoTUnref<const GrIndexBuffer> indexBuffer(
-            ref_rrect_index_buffer(this->stroke(), batchTarget->resourceProvider()));
         int firstVertex;
 
         void *vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
@@ -1736,7 +1725,7 @@
                                                               &vertexBuffer,
                                                               &firstVertex);
 
-        if (!vertices || !indexBuffer) {
+        if (!vertices) {
             SkDebugf("Could not allocate vertices\n");
             return;
         }
@@ -1791,6 +1780,7 @@
         int indexCnt = this->stroke() ? SK_ARRAY_COUNT(gRRectIndices) - 6 :
                                         SK_ARRAY_COUNT(gRRectIndices);
 
+
         GrDrawTarget::DrawInfo drawInfo;
         drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
         drawInfo.setStartVertex(0);
@@ -1799,7 +1789,7 @@
         drawInfo.setIndicesPerInstance(indexCnt);
         drawInfo.adjustStartVertex(firstVertex);
         drawInfo.setVertexBuffer(vertexBuffer);
-        drawInfo.setIndexBuffer(indexBuffer);
+        drawInfo.setIndexBuffer(fIndexBuffer);
 
         int maxInstancesPerDraw = kNumRRectsInIndexBuffer;
 
@@ -1818,7 +1808,8 @@
     SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
 
 private:
-    RRectCircleRendererBatch(const Geometry& geometry) {
+    RRectCircleRendererBatch(const Geometry& geometry, const GrIndexBuffer* indexBuffer)
+        : fIndexBuffer(indexBuffer) {
         this->initClassID<RRectCircleRendererBatch>();
         fGeoData.push_back(geometry);
 
@@ -1862,6 +1853,7 @@
 
     BatchTracker fBatch;
     SkSTArray<1, Geometry, true> fGeoData;
+    const GrIndexBuffer* fIndexBuffer;
 };
 
 class RRectEllipseRendererBatch : public GrBatch {
@@ -1877,8 +1869,8 @@
         SkRect fDevBounds;
     };
 
-    static GrBatch* Create(const Geometry& geometry) {
-        return SkNEW_ARGS(RRectEllipseRendererBatch, (geometry));
+    static GrBatch* Create(const Geometry& geometry, const GrIndexBuffer* indexBuffer) {
+        return SkNEW_ARGS(RRectEllipseRendererBatch, (geometry, indexBuffer));
     }
 
     const char* name() const override { return "RRectEllipseRendererBatch"; }
@@ -1938,8 +1930,6 @@
         SkASSERT(vertexStride == sizeof(EllipseVertex));
 
         const GrVertexBuffer* vertexBuffer;
-        SkAutoTUnref<const GrIndexBuffer> indexBuffer(
-            ref_rrect_index_buffer(this->stroke(), batchTarget->resourceProvider()));
         int firstVertex;
 
         void *vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
@@ -1947,7 +1937,7 @@
                                                               &vertexBuffer,
                                                               &firstVertex);
 
-        if (!vertices || !indexBuffer) {
+        if (!vertices) {
             SkDebugf("Could not allocate vertices\n");
             return;
         }
@@ -2021,7 +2011,7 @@
         drawInfo.setIndicesPerInstance(indexCnt);
         drawInfo.adjustStartVertex(firstVertex);
         drawInfo.setVertexBuffer(vertexBuffer);
-        drawInfo.setIndexBuffer(indexBuffer);
+        drawInfo.setIndexBuffer(fIndexBuffer);
 
         int maxInstancesPerDraw = kNumRRectsInIndexBuffer;
 
@@ -2040,7 +2030,8 @@
     SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
 
 private:
-    RRectEllipseRendererBatch(const Geometry& geometry) {
+    RRectEllipseRendererBatch(const Geometry& geometry, const GrIndexBuffer* indexBuffer)
+        : fIndexBuffer(indexBuffer) {
         this->initClassID<RRectEllipseRendererBatch>();
         fGeoData.push_back(geometry);
 
@@ -2084,13 +2075,40 @@
 
     BatchTracker fBatch;
     SkSTArray<1, Geometry, true> fGeoData;
+    const GrIndexBuffer* fIndexBuffer;
 };
 
+static GrIndexBuffer* create_rrect_indexbuffer(GrIndexBuffer** strokeRRectIndexBuffer,
+                                               GrIndexBuffer** rrectIndexBuffer,
+                                               bool isStrokeOnly,
+                                               GrGpu* gpu) {
+    if (isStrokeOnly) {
+        if (NULL == *strokeRRectIndexBuffer) {
+            *strokeRRectIndexBuffer = gpu->createInstancedIndexBuffer(gRRectIndices,
+                                                                      kIndicesPerStrokeRRect,
+                                                                      kNumRRectsInIndexBuffer,
+                                                                      kVertsPerRRect);
+        }
+        return *strokeRRectIndexBuffer;
+    } else {
+        if (NULL == *rrectIndexBuffer) {
+            *rrectIndexBuffer = gpu->createInstancedIndexBuffer(gRRectIndices,
+                                                                kIndicesPerRRect,
+                                                                kNumRRectsInIndexBuffer,
+                                                                kVertsPerRRect);
+        }
+        return *rrectIndexBuffer;
+    }
+}
+
 static GrBatch* create_rrect_batch(GrColor color,
                                    const SkMatrix& viewMatrix,
                                    const SkRRect& rrect,
                                    const SkStrokeRec& stroke,
-                                   SkRect* bounds) {
+                                   SkRect* bounds,
+                                   GrIndexBuffer** strokeRRectIndexBuffer,
+                                   GrIndexBuffer** rrectIndexBuffer,
+                                   GrGpu* gpu) {
     SkASSERT(viewMatrix.rectStaysRect());
     SkASSERT(rrect.isSimple());
     SkASSERT(!rrect.isOval());
@@ -2141,6 +2159,15 @@
         return NULL;
     }
 
+    GrIndexBuffer* indexBuffer = create_rrect_indexbuffer(strokeRRectIndexBuffer,
+                                                          rrectIndexBuffer,
+                                                          isStrokeOnly,
+                                                          gpu);
+    if (NULL == indexBuffer) {
+        SkDebugf("Failed to create index buffer!\n");
+        return NULL;
+    }
+
     // if the corners are circles, use the circle renderer
     if ((!hasStroke || scaledStroke.fX == scaledStroke.fY) && xRadius == yRadius) {
         SkScalar innerRadius = 0.0f;
@@ -2181,7 +2208,8 @@
         geometry.fStroke = isStrokeOnly;
         geometry.fDevBounds = *bounds;
 
-        return RRectCircleRendererBatch::Create(geometry);
+        return RRectCircleRendererBatch::Create(geometry, indexBuffer);
+
     // otherwise we use the ellipse renderer
     } else {
         SkScalar innerXRadius = 0.0f;
@@ -2231,7 +2259,7 @@
         geometry.fStroke = isStrokeOnly;
         geometry.fDevBounds = *bounds;
 
-        return RRectEllipseRendererBatch::Create(geometry);
+        return RRectEllipseRendererBatch::Create(geometry, indexBuffer);
     }
 }
 
@@ -2259,7 +2287,9 @@
     }
 
     SkRect bounds;
-    SkAutoTUnref<GrBatch> batch(create_rrect_batch(color, viewMatrix, rrect, stroke, &bounds));
+    SkAutoTUnref<GrBatch> batch(create_rrect_batch(color, viewMatrix, rrect, stroke, &bounds,
+                                                   &fStrokeRRectIndexBuffer, &fRRectIndexBuffer,
+                                                   fGpu));
     if (!batch) {
         return false;
     }
@@ -2317,8 +2347,11 @@
     GrColor color = GrRandomColor(random);
     const SkRRect& rrect = GrTest::TestRRectSimple(random);
 
+    static GrIndexBuffer* gStrokeRRectIndexBuffer;
+    static GrIndexBuffer* gRRectIndexBuffer;
     SkRect bounds;
-    return create_rrect_batch(color, viewMatrix, rrect, random_strokerec(random), &bounds);
+    return create_rrect_batch(color, viewMatrix, rrect, random_strokerec(random), &bounds,
+                              &gStrokeRRectIndexBuffer, &gRRectIndexBuffer, context->getGpu());
 }
 
 #endif
diff --git a/src/gpu/GrOvalRenderer.h b/src/gpu/GrOvalRenderer.h
index 57ce2a5..f31aa69 100644
--- a/src/gpu/GrOvalRenderer.h
+++ b/src/gpu/GrOvalRenderer.h
@@ -24,6 +24,16 @@
 public:
     SK_DECLARE_INST_COUNT(GrOvalRenderer)
 
+    GrOvalRenderer(GrGpu* gpu)
+        : fGpu(gpu)
+        , fRRectIndexBuffer(NULL)
+        , fStrokeRRectIndexBuffer(NULL) {}
+    ~GrOvalRenderer() {
+        this->reset();
+    }
+
+    void reset();
+
     bool drawOval(GrDrawTarget*,
                   GrPipelineBuilder*,
                   GrColor,
@@ -69,6 +79,10 @@
                     const SkRect& circle,
                     const SkStrokeRec& stroke);
 
+    GrGpu*         fGpu;
+    GrIndexBuffer* fRRectIndexBuffer;
+    GrIndexBuffer* fStrokeRRectIndexBuffer;
+
     typedef SkRefCnt INHERITED;
 };
 
diff --git a/src/gpu/GrResourceProvider.cpp b/src/gpu/GrResourceProvider.cpp
deleted file mode 100644
index 1342ccc..0000000
--- a/src/gpu/GrResourceProvider.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2015 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "GrResourceProvider.h"
-
-#include "GrGpu.h"
-#include "GrResourceCache.h"
-#include "GrResourceKey.h"
-#include "GrVertexBuffer.h"
-
-GR_DECLARE_STATIC_UNIQUE_KEY(gQuadIndexBufferKey);
-
-GrResourceProvider::GrResourceProvider(GrGpu* gpu, GrResourceCache* cache) : INHERITED(gpu, cache) {
-    GR_DEFINE_STATIC_UNIQUE_KEY(gQuadIndexBufferKey);
-    fQuadIndexBufferKey = gQuadIndexBufferKey;
-}
-
-const GrIndexBuffer* GrResourceProvider::createInstancedIndexBuffer(const uint16_t* pattern,
-                                                                    int patternSize,
-                                                                    int reps,
-                                                                    int vertCount,
-                                                                    const GrUniqueKey& key) {
-    size_t bufferSize = patternSize * reps * sizeof(uint16_t);
-
-    GrIndexBuffer* buffer = this->gpu()->createIndexBuffer(bufferSize, /* dynamic = */ false);
-    if (!buffer) {
-        return NULL;
-    }
-    uint16_t* data = (uint16_t*) buffer->map();
-    bool useTempData = (NULL == data);
-    if (useTempData) {
-        data = SkNEW_ARRAY(uint16_t, reps * patternSize);
-    }
-    for (int i = 0; i < reps; ++i) {
-        int baseIdx = i * patternSize;
-        uint16_t baseVert = (uint16_t)(i * vertCount);
-        for (int j = 0; j < patternSize; ++j) {
-            data[baseIdx+j] = baseVert + pattern[j];
-        }
-    }
-    if (useTempData) {
-        if (!buffer->updateData(data, bufferSize)) {
-            buffer->unref();
-            return NULL;
-        }
-        SkDELETE_ARRAY(data);
-    } else {
-        buffer->unmap();
-    }
-    return buffer;
-}
-
-const GrIndexBuffer* GrResourceProvider::createQuadIndexBuffer() {
-    static const int kMaxQuads = 1 << 12; // max possible: (1 << 14) - 1;
-    GR_STATIC_ASSERT(4 * kMaxQuads <= 65535);
-    static const uint16_t kPattern[] = { 0, 1, 2, 0, 2, 3 };
-
-    return this->createInstancedIndexBuffer(kPattern, 6, kMaxQuads, 4, fQuadIndexBufferKey);
-}
-
diff --git a/src/gpu/GrResourceProvider.h b/src/gpu/GrResourceProvider.h
index 0d80cdd..f560afa 100644
--- a/src/gpu/GrResourceProvider.h
+++ b/src/gpu/GrResourceProvider.h
@@ -10,9 +10,6 @@
 
 #include "GrTextureProvider.h"
 
-class GrIndexBuffer;
-class GrVertexBuffer;
-
 /**
  * An extension of the texture provider for arbitrary resource types. This class is intended for
  * use within the Gr code base, not by clients or extensions (e.g. third party GrProcessor
@@ -21,67 +18,12 @@
 class GrResourceProvider : public GrTextureProvider {
 public:
 
-    GrResourceProvider(GrGpu* gpu, GrResourceCache* cache);
-
-    template <typename T> T* findAndRefTByUniqueKey(const GrUniqueKey& key) {
-        return static_cast<T*>(this->findAndRefResourceByUniqueKey(key));
-    }
-
-    /**
-     * Either finds and refs, or creates an index buffer for instanced drawing with a specific
-     * pattern if the index buffer is not found. If the return is non-null, the caller owns
-     * a ref on the returned GrIndexBuffer.
-     *
-     * @param pattern     the pattern of indices to repeat
-     * @param patternSize size in bytes of the pattern
-     * @param reps        number of times to repeat the pattern
-     * @param vertCount   number of vertices the pattern references
-     * @param key         Key to be assigned to the index buffer.
-     *
-     * @return The index buffer if successful, otherwise NULL.
-     */
-    const GrIndexBuffer* refOrCreateInstancedIndexBuffer(const uint16_t* pattern,
-                                                         int patternSize,
-                                                         int reps,
-                                                         int vertCount,
-                                                         const GrUniqueKey& key) {
-        if (GrIndexBuffer* buffer = this->findAndRefTByUniqueKey<GrIndexBuffer>(key)) {
-            return buffer;
-        }
-        return this->createInstancedIndexBuffer(pattern, patternSize, reps, vertCount, key);
-    }
-
-    /**
-     * Returns an index buffer that can be used to render quads.
-     * Six indices per quad: 0, 1, 2, 0, 2, 3, etc.
-     * The max number of quads can be queried using GrIndexBuffer::maxQuads().
-     * Draw with kTriangles_GrPrimitiveType
-     * @ return the quad index buffer
-     */
-    const GrIndexBuffer* refQuadIndexBuffer() {
-        if (GrIndexBuffer* buffer =
-            this->findAndRefTByUniqueKey<GrIndexBuffer>(fQuadIndexBufferKey)) {
-            return buffer;
-        }
-        return this->createQuadIndexBuffer();
-    }
-
+    GrResourceProvider(GrGpu* gpu, GrResourceCache* cache) : INHERITED(gpu, cache) {}
 
     using GrTextureProvider::assignUniqueKeyToResource;
     using GrTextureProvider::findAndRefResourceByUniqueKey;
     using GrTextureProvider::abandon;
 
-private:
-    const GrIndexBuffer* createInstancedIndexBuffer(const uint16_t* pattern,
-                                                    int patternSize,
-                                                    int reps,
-                                                    int vertCount,
-                                                    const GrUniqueKey& key);
-
-    const GrIndexBuffer* createQuadIndexBuffer();
-
-    GrUniqueKey fQuadIndexBufferKey;
-
     typedef GrTextureProvider INHERITED;
 };
 
diff --git a/src/gpu/effects/GrDashingEffect.cpp b/src/gpu/effects/GrDashingEffect.cpp
index fa8b3a2..3f0df67 100644
--- a/src/gpu/effects/GrDashingEffect.cpp
+++ b/src/gpu/effects/GrDashingEffect.cpp
@@ -19,7 +19,6 @@
 #include "GrDrawTargetCaps.h"
 #include "GrInvariantOutput.h"
 #include "GrProcessor.h"
-#include "GrResourceProvider.h"
 #include "GrStrokeInfo.h"
 #include "GrVertexBuffer.h"
 #include "SkGr.h"
@@ -536,17 +535,16 @@
             draw.fHasEndRect = hasEndRect;
         }
 
-        SkAutoTUnref<const GrIndexBuffer> indexBuffer(
-            batchTarget->resourceProvider()->refQuadIndexBuffer());
-
         const GrVertexBuffer* vertexBuffer;
         int firstVertex;
+
         size_t vertexStride = gp->getVertexStride();
         void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
                                                               totalRectCount * kVertsPerDash,
                                                               &vertexBuffer,
                                                               &firstVertex);
-        if (!vertices || !indexBuffer) {
+
+        if (!vertices || !batchTarget->quadIndexBuffer()) {
             SkDebugf("Could not allocate buffers\n");
             return;
         }
@@ -609,6 +607,8 @@
             rectIndex++;
         }
 
+        const GrIndexBuffer* dashIndexBuffer = batchTarget->quadIndexBuffer();
+
         GrDrawTarget::DrawInfo drawInfo;
         drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
         drawInfo.setStartVertex(0);
@@ -617,9 +617,9 @@
         drawInfo.setIndicesPerInstance(kIndicesPerDash);
         drawInfo.adjustStartVertex(firstVertex);
         drawInfo.setVertexBuffer(vertexBuffer);
-        drawInfo.setIndexBuffer(indexBuffer);
+        drawInfo.setIndexBuffer(dashIndexBuffer);
 
-        int maxInstancesPerDraw = indexBuffer->maxQuads();
+        int maxInstancesPerDraw = dashIndexBuffer->maxQuads();
         while (totalRectCount) {
             drawInfo.setInstanceCount(SkTMin(totalRectCount, maxInstancesPerDraw));
             drawInfo.setVertexCount(drawInfo.instanceCount() * drawInfo.verticesPerInstance());
@@ -761,7 +761,7 @@
     return DashBatch::Create(geometry, cap, aaMode, fullDash);
 }
 
-bool GrDashingEffect::DrawDashLine(GrDrawTarget* target,
+bool GrDashingEffect::DrawDashLine(GrGpu* gpu, GrDrawTarget* target,
                                    GrPipelineBuilder* pipelineBuilder, GrColor color,
                                    const SkMatrix& viewMatrix, const SkPoint pts[2],
                                    bool useAA, const GrStrokeInfo& strokeInfo) {
diff --git a/src/gpu/effects/GrDashingEffect.h b/src/gpu/effects/GrDashingEffect.h
index 05b1c90..999abb2 100644
--- a/src/gpu/effects/GrDashingEffect.h
+++ b/src/gpu/effects/GrDashingEffect.h
@@ -15,12 +15,13 @@
 
 class GrClip;
 class GrDrawTarget;
+class GrGpu;
 class GrPaint;
 class GrPipelineBuilder;
 class GrStrokeInfo;
 
 namespace GrDashingEffect {
-    bool DrawDashLine(GrDrawTarget*, GrPipelineBuilder*, GrColor,
+    bool DrawDashLine(GrGpu*, GrDrawTarget*, GrPipelineBuilder*, GrColor,
                       const SkMatrix& viewMatrix, const SkPoint pts[2], bool useAA,
                       const GrStrokeInfo& strokeInfo);
     bool CanDrawDashLine(const SkPoint pts[2], const GrStrokeInfo& strokeInfo,