git-svn-id: http://skia.googlecode.com/svn/trunk@783 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/src/GrContext.cpp b/gpu/src/GrContext.cpp
index 3446e23..e224891 100644
--- a/gpu/src/GrContext.cpp
+++ b/gpu/src/GrContext.cpp
@@ -16,6 +16,7 @@
 

 

 #include "GrContext.h"

+#include "GrTypes.h"

 #include "GrTextureCache.h"

 #include "GrTextStrike.h"

 #include "GrMemory.h"

@@ -343,7 +344,7 @@
 

     if (width >= 0) {

         // TODO: consider making static vertex buffers for these cases.

-        // Hairline could be done by just adding closing vertex to 

+        // Hairline could be done by just adding closing vertex to

         // unitSquareVertexBuffer()

         static const int worstCaseVertCount = 10;

         GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, worstCaseVertCount, 0);

@@ -387,13 +388,13 @@
             m.setAll(rect.width(), 0,             rect.fLeft,

                      0,            rect.height(), rect.fTop,

                      0,            0,             GrMatrix::I()[8]);

-            

+

             if (NULL != matrix) {

                 m.postConcat(*matrix);

             }

 

             fGpu->concatViewMatrix(m);

-        

+

             if (textured) {

                 fGpu->concatTextureMatrix(0, m);

             }

@@ -457,10 +458,10 @@
     GrPoint* pos = geo.positions();

     GrPoint* tex = pos + 1;

     static const size_t stride = 2 * sizeof(GrPoint);

-    pos[0].setRectFan(dstRect.fLeft, dstRect.fTop, 

+    pos[0].setRectFan(dstRect.fLeft, dstRect.fTop,

                       dstRect.fRight, dstRect.fBottom,

                       stride);

-    tex[0].setRectFan(srcRect.fLeft, srcRect.fTop, 

+    tex[0].setRectFan(srcRect.fLeft, srcRect.fTop,

                       srcRect.fRight, srcRect.fBottom,

                       stride);

 

@@ -546,14 +547,11 @@
 

 ////////////////////////////////////////////////////////////////////////////////

 

-#define NEW_EVAL        1   // Use adaptive path tesselation

 #define STENCIL_OFF     0   // Always disable stencil (even when needed)

-#define CPU_TRANSFORM   0   // Transform path verts on CPU

-

-#if NEW_EVAL

-

 #define EVAL_TOL GR_Scalar1

 

+static const uint32_t MAX_POINTS_PER_CURVE = 1 << 10;

+

 static uint32_t quadratic_point_count(const GrPoint points[], GrScalar tol) {

     GrScalar d = points[1].distanceToLineSegmentBetween(points[0], points[2]);

     // TODO: fixed points sqrt

@@ -565,7 +563,7 @@
         // points.

         // 2^(log4(x)) = sqrt(x);

         d = ceilf(sqrtf(d/tol));

-        return GrNextPow2((uint32_t)d);

+        return GrMin(GrNextPow2((uint32_t)d), MAX_POINTS_PER_CURVE);

     }

 }

 

@@ -602,7 +600,7 @@
         return 1;

     } else {

         d = ceilf(sqrtf(d/tol));

-        return GrNextPow2((uint32_t)d);

+        return GrMin(GrNextPow2((uint32_t)d), MAX_POINTS_PER_CURVE);

     }

 }

 

@@ -636,45 +634,8 @@
     return a + b;

 }

 

-#else // !NEW_EVAL

-

-static GrScalar gr_eval_quad(const GrScalar coord[], GrScalar t) {

-    GrScalar A = coord[0] - 2 * coord[2] + coord[4];

-    GrScalar B = 2 * (coord[2] - coord[0]);

-    GrScalar C = coord[0];

-

-    return GrMul(GrMul(A, t) + B, t) + C;

-}

-

-static void gr_eval_quad_at(const GrPoint src[3], GrScalar t, GrPoint* pt) {

-    GrAssert(src);

-    GrAssert(pt);

-    GrAssert(t >= 0 && t <= GR_Scalar1);

-    pt->set(gr_eval_quad(&src[0].fX, t), gr_eval_quad(&src[0].fY, t));

-}

-

-static GrScalar gr_eval_cubic(const GrScalar coord[], GrScalar t) {

-    GrScalar A = coord[6] - coord[0] + 3 * (coord[2] - coord[4]);

-    GrScalar B = 3 * (coord[0] - 2 * coord[2] + coord[4]);

-    GrScalar C = 3 * (coord[2] - coord[0]);

-    GrScalar D = coord[0];

-

-    return GrMul(GrMul(GrMul(A, t) + B, t) + C, t) + D;

-}

-

-static void gr_eval_cubic_at(const GrPoint src[4], GrScalar t, GrPoint* pt) {

-    GrAssert(src);

-    GrAssert(pt);

-    GrAssert(t >= 0 && t <= GR_Scalar1);

-

-    pt->set(gr_eval_cubic(&src[0].fX, t), gr_eval_cubic(&src[0].fY, t));

-}

-

-#endif // !NEW_EVAL

-

 static int worst_case_point_count(GrPathIter* path,

                                   int* subpaths,

-                                  const GrMatrix& matrix,

                                   GrScalar tol) {

     int pointCount = 0;

     *subpaths = 1;

@@ -691,20 +652,10 @@
                 pointCount += 1;

                 break;

             case GrPathIter::kQuadratic_Command:

-#if NEW_EVAL

-                matrix.mapPoints(pts, pts, 3);

                 pointCount += quadratic_point_count(pts, tol);

-#else

-                pointCount += 9;

-#endif

                 break;

             case GrPathIter::kCubic_Command:

-#if NEW_EVAL

-                matrix.mapPoints(pts, pts, 4);

                 pointCount += cubic_point_count(pts, tol);

-#else

-                pointCount += 17;

-#endif

                 break;

             case GrPathIter::kMove_Command:

                 pointCount += 1;

@@ -752,7 +703,6 @@
 

     GrDrawTarget::AutoStateRestore asr(fGpu);

 

-#if NEW_EVAL

     GrMatrix viewM = fGpu->getViewMatrix();

     // In order to tesselate the path we get a bound on how much the matrix can

     // stretch when mapping to screen coordinates.

@@ -766,22 +716,12 @@
         // TODO: fixed point divide

         GrScalar sinv = 1 / stretch;

         tol = GrMul(tol, sinv);

-        viewM = GrMatrix::I();

     }

     GrScalar tolSqd = GrMul(tol, tol);

-#else

-    // pass to worst_case... but won't be used.

-    static const GrScalar tol = -1;

-#endif

 

     int subpathCnt;

     int maxPts = worst_case_point_count(path,

                                         &subpathCnt,

-#if CPU_TRANSFORM

-                                        cpuMatrix,

-#else

-                                        GrMatrix::I(),

-#endif

                                         tol);

     GrVertexLayout layout = 0;

 

@@ -800,10 +740,10 @@
     path->rewind();

 

     // TODO: use primitve restart if available rather than multiple draws

-    GrDrawTarget::PrimitiveType  type;

-    int                   passCount = 0;

-    GrDrawTarget::StencilPass    passes[3];

-    bool                  reverse = false;

+    GrDrawTarget::PrimitiveType type;

+    int                         passCount = 0;

+    GrDrawTarget::StencilPass   passes[3];

+    bool                        reverse = false;

 

     if (kHairLine_PathFill == fill) {

         type = GrDrawTarget::kLineStrip_PrimitiveType;

@@ -846,11 +786,6 @@
         }

     }

     fGpu->setReverseFill(reverse);

-#if CPU_TRANSFORM

-    GrMatrix cpuMatrix;

-    fGpu->getViewMatrix(&cpuMatrix);

-    fGpu->setViewMatrix(GrMatrix::I());

-#endif

 

     GrPoint pts[4];

 

@@ -859,10 +794,6 @@
 

     for (;;) {

         GrPathIter::Command cmd = path->next(pts);

-#if CPU_TRANSFORM

-        int numPts = GrPathIter::NumCommandPoints(cmd);

-        cpuMatrix.mapPoints(pts, pts, numPts);

-#endif

         switch (cmd) {

             case GrPathIter::kMove_Command:

                 if (!first) {

@@ -878,42 +809,15 @@
                 vert++;

                 break;

             case GrPathIter::kQuadratic_Command: {

-#if NEW_EVAL

-

                 generate_quadratic_points(pts[0], pts[1], pts[2],

                                           tolSqd, &vert,

                                           quadratic_point_count(pts, tol));

-#else

-                const int n = 8;

-                const GrScalar dt = GR_Scalar1 / n;

-                GrScalar t = dt;

-                for (int i = 1; i < n; i++) {

-                    gr_eval_quad_at(pts, t, (GrPoint*)vert);

-                    t += dt;

-                    vert++;

-                }

-                vert->set(pts[2].fX, pts[2].fY);

-                vert++;

-#endif

                 break;

             }

             case GrPathIter::kCubic_Command: {

-#if NEW_EVAL

                 generate_cubic_points(pts[0], pts[1], pts[2], pts[3],

-                                      tolSqd, &vert,

+                                      tolSqd, &vert, 

                                       cubic_point_count(pts, tol));

-#else

-                const int n = 16;

-                const GrScalar dt = GR_Scalar1 / n;

-                GrScalar t = dt;

-                for (int i = 1; i < n; i++) {

-                    gr_eval_cubic_at(pts, t, (GrPoint*)vert);

-                    t += dt;

-                    vert++;

-                }

-                vert->set(pts[3].fX, pts[3].fY);

-                vert++;

-#endif

                 break;

             }

             case GrPathIter::kClose_Command:

@@ -1139,7 +1043,7 @@
     uint32_t bits = 0;

     uint16_t width = key->width();

     uint16_t height = key->height();

-    

+

 

     if (!fGpu->npotTextureTileSupport()) {

         bool isPow2 = GrIsPow2(width) && GrIsPow2(height);

diff --git a/gpu/src/GrGpuGL.cpp b/gpu/src/GrGpuGL.cpp
index d366953..7a83ac8 100644
--- a/gpu/src/GrGpuGL.cpp
+++ b/gpu/src/GrGpuGL.cpp
@@ -47,8 +47,6 @@
     GL_ONE_MINUS_DST_ALPHA,
 };
 
-
-
 ///////////////////////////////////////////////////////////////////////////////
 
 static bool gPrintStartupSpew;
@@ -88,6 +86,14 @@
 }
 
 GrGpuGL::GrGpuGL() {
+
+#if GR_GL_NO_CLIENT_SIDE_ARRAYS
+    fClientArrayVB = NULL;
+    fClientArrayIB = NULL;
+    fOversizeVBDrawCnt = 0;
+    fOversizeIBDrawCnt = 0;
+#endif
+
     if (gPrintStartupSpew) {
         GrPrintf("------------------------- create GrGpuGL %p --------------\n",
                  this);
@@ -366,6 +372,10 @@
 }
 
 GrGpuGL::~GrGpuGL() {
+#if GR_GL_NO_CLIENT_SIDE_ARRAYS
+    GrSafeUnref(fClientArrayVB);
+    GrSafeUnref(fClientArrayIB);
+#endif
 }
 
 void GrGpuGL::resetContextHelper() {
@@ -425,6 +435,7 @@
     fHWGeometryState.fVertexBuffer = NULL;
     GR_GL(BindBuffer(GL_ARRAY_BUFFER, 0));
     GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
+    fHWGeometryState.fArrayPtrsDirty = true;
 
     fHWDrawState.fRenderTarget = NULL;
 }
@@ -434,6 +445,64 @@
     resetContextHelper();
 }
 
+#if GR_GL_NO_CLIENT_SIDE_ARRAYS
+void GrGpuGL::putClientVertexDataInBuffer(const void* vertexData, size_t vertexDataSize) {
+    static const size_t MIN_VB_SIZE = 1 << 11;
+    static const int MAX_OVERSIZE_VB_DRAWS = 100;
+
+    if (NULL != vertexData) {
+        size_t currMinVBSize = GrMax(MIN_VB_SIZE, vertexDataSize);
+        // if we don't have a VB, its too small, or too big, create a new one
+        if (NULL == fClientArrayVB ||
+            fClientArrayVB->size() < currMinVBSize  ||
+            (fOversizeVBDrawCnt >= MAX_OVERSIZE_VB_DRAWS &&
+             currMinVBSize == MIN_VB_SIZE &&
+             fClientArrayVB->size() > MIN_VB_SIZE)) {
+
+            if (fHWGeometryState.fVertexBuffer == fClientArrayVB) {
+                fHWGeometryState.fVertexBuffer = NULL;
+                fHWGeometryState.fArrayPtrsDirty = true;
+            }
+            GrSafeUnref(fClientArrayVB);
+            fClientArrayVB = (GrGLVertexBuffer*)createVertexBuffer(currMinVBSize, true);
+            fOversizeVBDrawCnt = 0;
+                GrPrintf("Realloc VB 0%08x\n", currMinVBSize);
+        }
+        fClientArrayVB->updateData(vertexData, vertexDataSize);
+        if (currMinVBSize == MIN_VB_SIZE && fClientArrayVB->size() > MIN_VB_SIZE) {
+            ++fOversizeVBDrawCnt;
+        }
+    }
+}
+
+void GrGpuGL::putClientIndexDataInBuffer(const void* indexData, size_t indexDataSize) {
+    static const size_t MIN_IB_SIZE = 1 << 8;
+    static const int MAX_OVERSIZE_IB_DRAWS = 100;
+
+    if (NULL != indexData) {
+        size_t currMinIBSize = GrMax(MIN_IB_SIZE, indexDataSize);
+        // if we don't have a IB, its too small, or too big, create a new one
+        if (NULL == fClientArrayIB ||
+            fClientArrayIB->size() < currMinIBSize  ||
+            (fOversizeIBDrawCnt >= MAX_OVERSIZE_IB_DRAWS &&
+             currMinIBSize == MIN_IB_SIZE &&
+             fClientArrayIB->size() > MIN_IB_SIZE)) {
+
+            if (fHWGeometryState.fIndexBuffer == fClientArrayIB) {
+                fHWGeometryState.fIndexBuffer = NULL;
+            }
+            GrSafeUnref(fClientArrayIB);
+            fClientArrayIB = (GrGLIndexBuffer*)createIndexBuffer(currMinIBSize, true);
+            fOversizeIBDrawCnt = 0;
+        }
+        fClientArrayIB->updateData(indexData, indexDataSize);
+        if (currMinIBSize == MIN_IB_SIZE && fClientArrayIB->size() > MIN_IB_SIZE) {
+            ++fOversizeIBDrawCnt;
+        }
+    }
+}
+#endif
+
 GrRenderTarget* GrGpuGL::createPlatformRenderTarget(
                                                 intptr_t platformRenderTarget,
                                                 int width, int height) {
@@ -921,6 +990,7 @@
     GR_GL(GenBuffers(1, &id));
     if (id) {
         GR_GL(BindBuffer(GL_ARRAY_BUFFER, id));
+        fHWGeometryState.fArrayPtrsDirty = true;
         GrGLClearErr();
         // make sure driver can allocate memory for this buffer
         GR_GL_NO_ERR(BufferData(GL_ARRAY_BUFFER, size, NULL,
@@ -1132,12 +1202,20 @@
     GrAssert((size_t)type < GR_ARRAY_COUNT(gPrimitiveType2GLMode));
 
     GLvoid* indices = (GLvoid*)(sizeof(uint16_t) * startIndex);
+
+#if GR_GL_NO_CLIENT_SIDE_ARRAYS
+    if (kBuffer_GeometrySrcType != fGeometrySrc.fIndexSrc) {
+        // we accounted for the startIndex when shoving data into a vb
+        indices = NULL;
+    }
+#else
     if (kReserved_GeometrySrcType == fGeometrySrc.fIndexSrc) {
         indices = (GLvoid*)((intptr_t)indices + (intptr_t)fIndices.get());
     } else if (kArray_GeometrySrcType == fGeometrySrc.fIndexSrc) {
         indices = (GLvoid*)((intptr_t)indices +
                             (intptr_t)fGeometrySrc.fIndexArray);
     }
+#endif
 
     GR_GL(DrawElements(gPrimitiveType2GLMode[type], indexCount,
                        GL_UNSIGNED_SHORT, indices));
@@ -1537,7 +1615,10 @@
 }
 
 void GrGpuGL::notifyVertexBufferBind(const GrGLVertexBuffer* buffer) {
-    fHWGeometryState.fVertexBuffer = buffer;
+    if (fHWGeometryState.fVertexBuffer != buffer) {
+        fHWGeometryState.fArrayPtrsDirty = true;
+        fHWGeometryState.fVertexBuffer = buffer;
+    }
 }
 
 void GrGpuGL::notifyVertexBufferDelete(const GrGLVertexBuffer* buffer) {
@@ -1547,6 +1628,7 @@
     if (fHWGeometryState.fVertexBuffer == buffer) {
         // deleting bound buffer does implied bind to 0
         fHWGeometryState.fVertexBuffer = NULL;
+        fHWGeometryState.fArrayPtrsDirty = true;
     }
 }
 
@@ -1692,3 +1774,85 @@
             return false;
     }
 }
+
+
+const GLvoid* GrGpuGL::setBuffersAndGetVertexStart(int vertexStride, int startVertex,
+                                                   int startIndex, int vertexCount,
+                                                   int indexCount) {
+    const GLvoid* posPtr = (GLvoid*)(vertexStride * startVertex);
+
+    if (kBuffer_GeometrySrcType == fGeometrySrc.fVertexSrc) {
+        GrAssert(NULL != fGeometrySrc.fVertexBuffer);
+        GrAssert(!fGeometrySrc.fVertexBuffer->isLocked());
+        if (fHWGeometryState.fVertexBuffer != fGeometrySrc.fVertexBuffer) {
+            GrGLVertexBuffer* buf =
+                            (GrGLVertexBuffer*)fGeometrySrc.fVertexBuffer;
+            GR_GL(BindBuffer(GL_ARRAY_BUFFER, buf->bufferID()));
+            fHWGeometryState.fArrayPtrsDirty = true;
+            fHWGeometryState.fVertexBuffer = fGeometrySrc.fVertexBuffer;
+        }
+    } else {
+        if (kArray_GeometrySrcType == fGeometrySrc.fVertexSrc) {
+            posPtr = (void*)((intptr_t)fGeometrySrc.fVertexArray +
+                             (intptr_t)posPtr);
+        } else {
+            GrAssert(kReserved_GeometrySrcType == fGeometrySrc.fVertexSrc);
+            posPtr = (void*)((intptr_t)fVertices.get() + (intptr_t)posPtr);
+        }
+    #if GR_GL_NO_CLIENT_SIDE_ARRAYS
+        putClientVertexDataInBuffer(posPtr, vertexCount * vertexStride);
+        posPtr = NULL;
+        if (fHWGeometryState.fVertexBuffer != fClientArrayVB) {
+            GR_GL(BindBuffer(GL_ARRAY_BUFFER, fClientArrayVB->bufferID()));
+            fHWGeometryState.fArrayPtrsDirty = true;
+            fHWGeometryState.fVertexBuffer = fClientArrayVB;
+        }
+    #else
+        if (NULL != fHWGeometryState.fVertexBuffer) {
+            GR_GL(BindBuffer(GL_ARRAY_BUFFER, 0));
+            fHWGeometryState.fArrayPtrsDirty = true;
+            fHWGeometryState.fVertexBuffer = NULL;
+        }
+    #endif
+    }
+
+    if (0 != indexCount) {
+
+        if (kBuffer_GeometrySrcType == fGeometrySrc.fIndexSrc) {
+            GrAssert(NULL != fGeometrySrc.fIndexBuffer);
+            GrAssert(!fGeometrySrc.fIndexBuffer->isLocked());
+            if (fHWGeometryState.fIndexBuffer != fGeometrySrc.fIndexBuffer) {
+                GrGLIndexBuffer* buf =
+                (GrGLIndexBuffer*)fGeometrySrc.fIndexBuffer;
+                GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf->bufferID()));
+                fHWGeometryState.fIndexBuffer = fGeometrySrc.fIndexBuffer;
+            }
+        }
+        #if GR_GL_NO_CLIENT_SIDE_ARRAYS
+        else {
+            const uint16_t* indices;
+            if (kArray_GeometrySrcType == fGeometrySrc.fIndexSrc) {
+                indices = reinterpret_cast<const uint16_t*>(fGeometrySrc.fIndexArray);
+            } else {
+                GrAssert(kReserved_GeometrySrcType == fGeometrySrc.fIndexSrc);
+                indices = reinterpret_cast<const uint16_t*>(fIndices.get());
+            }
+            // we shove just the referenced part of the index data into the begining
+            // of the buffer and drawIndexedHelper ignores startIndex.
+            putClientIndexDataInBuffer(indices + startIndex, indexCount  * sizeof(uint16_t));
+            if (fHWGeometryState.fIndexBuffer != fClientArrayIB) {
+                GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, fClientArrayIB->bufferID()));
+                fHWGeometryState.fIndexBuffer = fClientArrayIB;
+            }
+        }
+        #else
+        else if (NULL != fHWGeometryState.fIndexBuffer) {
+            // we rely on drawIndexedHelper to pass to client side
+            // ptr to DrawElements
+            GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
+            fHWGeometryState.fIndexBuffer = NULL;
+        }
+        #endif
+    }
+    return posPtr;
+}
diff --git a/gpu/src/GrGpuGL.h b/gpu/src/GrGpuGL.h
index 0ba405d..e46c2ce 100644
--- a/gpu/src/GrGpuGL.h
+++ b/gpu/src/GrGpuGL.h
@@ -66,6 +66,7 @@
         GrVertexLayout          fVertexLayout;
         const GrVertexBuffer*   fVertexBuffer;
         const GrIndexBuffer*    fIndexBuffer;
+        bool                    fArrayPtrsDirty;
     } fHWGeometryState;
 
     DrState   fHWDrawState;
@@ -88,6 +89,12 @@
 
     void setTextureUnit(int unitIdx);
 
+    // binds appropriate vertex and index buffers and returns either the ptr
+    // to client memory or offset into a VB of the first vertex
+    const GLvoid* setBuffersAndGetVertexStart(int vertexStride, int startVertex,
+                                              int startIndex, int vertexCount,
+                                              int indexCount);
+
     // flushes state that is common to fixed and programmable GL
     // dither
     // line smoothing
@@ -111,6 +118,13 @@
 
     GrGLExts fExts;
 
+#if GR_GL_NO_CLIENT_SIDE_ARRAYS
+    void putClientVertexDataInBuffer(const void* vertexData, 
+                                     size_t vertexDataSize);
+    void putClientIndexDataInBuffer(const void* indexData, 
+                                    size_t indexDataSize);
+#endif
+
 private:
     void resetContextHelper();
 
@@ -160,6 +174,13 @@
     int fActiveTextureUnitIdx;
 
     typedef GrGpu INHERITED;
+
+#if GR_GL_NO_CLIENT_SIDE_ARRAYS
+    GrGLVertexBuffer* fClientArrayVB;
+    GrGLIndexBuffer*  fClientArrayIB;
+    int               fOversizeVBDrawCnt;
+    int               fOversizeIBDrawCnt;
+#endif
 };
 
 bool has_gl_extension(const char* ext);
diff --git a/gpu/src/GrGpuGLFixed.cpp b/gpu/src/GrGpuGLFixed.cpp
index 3fd8d5c..a028cba 100644
--- a/gpu/src/GrGpuGLFixed.cpp
+++ b/gpu/src/GrGpuGLFixed.cpp
@@ -263,44 +263,9 @@
                                                     oldTexCoordOffsets,
                                                     &oldColorOffset);
 
-    const GLvoid* posPtr = (GLvoid*)(newStride * startVertex);
-
-    if (kBuffer_GeometrySrcType == fGeometrySrc.fVertexSrc) {
-        GrAssert(NULL != fGeometrySrc.fVertexBuffer);
-        GrAssert(!fGeometrySrc.fVertexBuffer->isLocked());
-        if (fHWGeometryState.fVertexBuffer != fGeometrySrc.fVertexBuffer) {
-            GrGLVertexBuffer* buf =
-                            (GrGLVertexBuffer*)fGeometrySrc.fVertexBuffer;
-            GR_GL(BindBuffer(GL_ARRAY_BUFFER, buf->bufferID()));
-            fHWGeometryState.fVertexBuffer = fGeometrySrc.fVertexBuffer;
-        }
-    } else {
-        if (kArray_GeometrySrcType == fGeometrySrc.fVertexSrc) {
-            posPtr = (void*)((intptr_t)fGeometrySrc.fVertexArray +
-                             (intptr_t)posPtr);
-        } else {
-            GrAssert(kReserved_GeometrySrcType == fGeometrySrc.fVertexSrc);
-            posPtr = (void*)((intptr_t)fVertices.get() + (intptr_t)posPtr);
-        }
-        if (NULL != fHWGeometryState.fVertexBuffer) {
-            GR_GL(BindBuffer(GL_ARRAY_BUFFER, 0));
-            fHWGeometryState.fVertexBuffer = NULL;
-        }
-    }
-
-    if (kBuffer_GeometrySrcType == fGeometrySrc.fIndexSrc) {
-        GrAssert(NULL != fGeometrySrc.fIndexBuffer);
-        GrAssert(!fGeometrySrc.fIndexBuffer->isLocked());
-        if (fHWGeometryState.fIndexBuffer != fGeometrySrc.fIndexBuffer) {
-            GrGLIndexBuffer* buf =
-            (GrGLIndexBuffer*)fGeometrySrc.fIndexBuffer;
-            GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf->bufferID()));
-            fHWGeometryState.fIndexBuffer = fGeometrySrc.fIndexBuffer;
-        }
-    } else if (NULL != fHWGeometryState.fIndexBuffer) {
-        GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
-        fHWGeometryState.fIndexBuffer = NULL;
-    }
+    const GLvoid* posPtr = setBuffersAndGetVertexStart(newStride, startVertex,
+                                                       startIndex, vertexCount,
+                                                       indexCount);
 
     GLenum scalarType;
     if (fGeometrySrc.fVertexLayout & kTextFormat_VertexLayoutBit) {
@@ -317,7 +282,7 @@
     bool strideChange = newStride != oldStride;
     bool posChange = baseChange || scalarChange || strideChange;
 
-    if (posChange) {
+    if (posChange || fHWGeometryState.fArrayPtrsDirty) {
         GR_GL(VertexPointer(2, scalarType, newStride, posPtr));
         fHWGeometryState.fPositionPtr = posPtr;
     }
@@ -330,8 +295,9 @@
             if (oldTexCoordOffsets[s] < 0) {
                 GR_GL(ClientActiveTexture(GL_TEXTURE0+s));
                 GR_GL(EnableClientState(GL_TEXTURE_COORD_ARRAY));
-            }
-            if (posChange || newTexCoordOffsets[s] != oldTexCoordOffsets[s]) {
+                GR_GL(TexCoordPointer(2, scalarType, newStride, texCoordPtr));
+            } else if (fHWGeometryState.fArrayPtrsDirty || posChange ||
+                       newTexCoordOffsets[s] != oldTexCoordOffsets[s]) {
                 GR_GL(ClientActiveTexture(GL_TEXTURE0+s));
                 GR_GL(TexCoordPointer(2, scalarType, newStride, texCoordPtr));
             }
@@ -345,8 +311,9 @@
         GLvoid* colorPtr = (int8_t*)posPtr + newColorOffset;
         if (oldColorOffset <= 0) {
             GR_GL(EnableClientState(GL_COLOR_ARRAY));
-        }
-        if (posChange || newColorOffset != oldColorOffset) {
+            GR_GL(ColorPointer(4, GL_UNSIGNED_BYTE, newStride, colorPtr));
+        } else if (fHWGeometryState.fArrayPtrsDirty || posChange ||
+                   newColorOffset != oldColorOffset) {
             GR_GL(ColorPointer(4, GL_UNSIGNED_BYTE, newStride, colorPtr));
         }
     } else if (oldColorOffset > 0) {
@@ -354,6 +321,7 @@
     }
 
     fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout;
+    fHWGeometryState.fArrayPtrsDirty = false;
 }
 
 #endif
diff --git a/gpu/src/GrGpuGLShaders.cpp b/gpu/src/GrGpuGLShaders.cpp
index 053479f..b3bfc9a 100644
--- a/gpu/src/GrGpuGLShaders.cpp
+++ b/gpu/src/GrGpuGLShaders.cpp
@@ -855,44 +855,9 @@
                                                     oldTexCoordOffsets,
                                                     &oldColorOffset);
 
-    const GLvoid* posPtr = (GLvoid*)(newStride * startVertex);
-
-    if (kBuffer_GeometrySrcType == fGeometrySrc.fVertexSrc) {
-        GrAssert(NULL != fGeometrySrc.fVertexBuffer);
-        GrAssert(!fGeometrySrc.fVertexBuffer->isLocked());
-        if (fHWGeometryState.fVertexBuffer != fGeometrySrc.fVertexBuffer) {
-            GrGLVertexBuffer* buf =
-            (GrGLVertexBuffer*)fGeometrySrc.fVertexBuffer;
-            GR_GL(BindBuffer(GL_ARRAY_BUFFER, buf->bufferID()));
-            fHWGeometryState.fVertexBuffer = fGeometrySrc.fVertexBuffer;
-        }
-    } else {
-        if (kArray_GeometrySrcType == fGeometrySrc.fVertexSrc) {
-            posPtr = (void*)((intptr_t)fGeometrySrc.fVertexArray +
-                             (intptr_t)posPtr);
-        } else {
-            GrAssert(kReserved_GeometrySrcType == fGeometrySrc.fVertexSrc);
-            posPtr = (void*)((intptr_t)fVertices.get() + (intptr_t)posPtr);
-        }
-        if (NULL != fHWGeometryState.fVertexBuffer) {
-            GR_GL(BindBuffer(GL_ARRAY_BUFFER, 0));
-            fHWGeometryState.fVertexBuffer = NULL;
-        }
-    }
-
-    if (kBuffer_GeometrySrcType == fGeometrySrc.fIndexSrc) {
-        GrAssert(NULL != fGeometrySrc.fIndexBuffer);
-        GrAssert(!fGeometrySrc.fIndexBuffer->isLocked());
-        if (fHWGeometryState.fIndexBuffer != fGeometrySrc.fIndexBuffer) {
-            GrGLIndexBuffer* buf =
-            (GrGLIndexBuffer*)fGeometrySrc.fIndexBuffer;
-            GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf->bufferID()));
-            fHWGeometryState.fIndexBuffer = fGeometrySrc.fIndexBuffer;
-        }
-    } else if (NULL != fHWGeometryState.fIndexBuffer) {
-        GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
-        fHWGeometryState.fIndexBuffer = NULL;
-    }
+    const GLvoid* posPtr = setBuffersAndGetVertexStart(newStride, startVertex,
+                                                       startIndex, vertexCount,
+                                                       indexCount);
 
     GLenum scalarType;
     bool texCoordNorm;
@@ -912,7 +877,7 @@
     bool strideChange = newStride != oldStride;
     bool posChange = baseChange || scalarChange || strideChange;
 
-    if (posChange) {
+    if (fHWGeometryState.fArrayPtrsDirty || posChange) {
         GR_GL(VertexAttribPointer(GR_GL_POS_ATTR_LOCATION, 2, scalarType,
                                   false, newStride, posPtr));
         fHWGeometryState.fPositionPtr = posPtr;
@@ -923,8 +888,10 @@
         GLvoid* texCoordPtr = (int8_t*)posPtr + newTexCoordOffsets[0];
         if (oldTexCoordOffsets[0] <= 0) {
             GR_GL(EnableVertexAttribArray(GR_GL_TEX_ATTR_LOCATION));
-        }
-        if (posChange || newTexCoordOffsets[0] != oldTexCoordOffsets[0]) {
+            GR_GL(VertexAttribPointer(GR_GL_TEX_ATTR_LOCATION, 2, scalarType,
+                                      texCoordNorm, newStride, texCoordPtr));
+        } else if (fHWGeometryState.fArrayPtrsDirty || posChange ||
+            newTexCoordOffsets[0] != oldTexCoordOffsets[0]) {
             GR_GL(VertexAttribPointer(GR_GL_TEX_ATTR_LOCATION, 2, scalarType,
                                       texCoordNorm, newStride, texCoordPtr));
         }
@@ -936,8 +903,12 @@
         GLvoid* colorPtr = (int8_t*)posPtr + newColorOffset;
         if (oldColorOffset <= 0) {
             GR_GL(EnableVertexAttribArray(GR_GL_COL_ATTR_LOCATION));
+            GR_GL(VertexAttribPointer(GR_GL_COL_ATTR_LOCATION, 4,
+                                      GL_UNSIGNED_BYTE,
+                                      true, newStride, colorPtr));
         }
-        if (posChange || newColorOffset != oldColorOffset) {
+        if (fHWGeometryState.fArrayPtrsDirty || posChange ||
+            newColorOffset != oldColorOffset) {
             GR_GL(VertexAttribPointer(GR_GL_COL_ATTR_LOCATION, 4,
                                       GL_UNSIGNED_BYTE,
                                       true, newStride, colorPtr));
@@ -947,5 +918,6 @@
     }
 
     fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout;
+    fHWGeometryState.fArrayPtrsDirty = false;
 }
 #endif
diff --git a/gpu/src/GrGpuGLShaders2.cpp b/gpu/src/GrGpuGLShaders2.cpp
index 9aa327a..81f83c9 100644
--- a/gpu/src/GrGpuGLShaders2.cpp
+++ b/gpu/src/GrGpuGLShaders2.cpp
@@ -988,11 +988,11 @@
     if (kPoints_PrimitiveType != primType) {
         desc->fOptFlags |= ProgramDesc::kNotPoints_OptFlagBit;
     }
-#if GR_AGGRESSIVE_SHADER_OPTS

-    if (!(desc->fVertexLayout & kColor_VertexLayoutBit) &&

-        (0xffffffff == fCurrDrawState.fColor)) {

-        desc->fOptFlags |= ProgramDesc::kVertexColorAllOnes_OptFlagBit;

-    }

+#if GR_AGGRESSIVE_SHADER_OPTS
+    if (!(desc->fVertexLayout & kColor_VertexLayoutBit) &&
+        (0xffffffff == fCurrDrawState.fColor)) {
+        desc->fOptFlags |= ProgramDesc::kVertexColorAllOnes_OptFlagBit;
+    }
 #endif
 
     for (int s = 0; s < kNumStages; ++s) {
@@ -1094,7 +1094,7 @@
     fProgram = NULL;
     fProgramCache = new ProgramCache();
 
-#if GR_DEBUG
+#if 0
     ProgramUnitTest();
 #endif
 }
@@ -1332,43 +1332,9 @@
                                                   oldTexCoordOffsets,
                                                   &oldColorOffset);
 
-    const GLvoid* posPtr = (GLvoid*)(newStride * startVertex);
-
-    if (kBuffer_GeometrySrcType == fGeometrySrc.fVertexSrc) {
-        GrAssert(NULL != fGeometrySrc.fVertexBuffer);
-        GrAssert(!fGeometrySrc.fVertexBuffer->isLocked());
-        if (fHWGeometryState.fVertexBuffer != fGeometrySrc.fVertexBuffer) {
-            GrGLVertexBuffer* buf =
-                                (GrGLVertexBuffer*)fGeometrySrc.fVertexBuffer;
-            GR_GL(BindBuffer(GL_ARRAY_BUFFER, buf->bufferID()));
-            fHWGeometryState.fVertexBuffer = fGeometrySrc.fVertexBuffer;
-        }
-    } else {
-        if (kArray_GeometrySrcType == fGeometrySrc.fVertexSrc) {
-            posPtr = (void*)((intptr_t)fGeometrySrc.fVertexArray +
-                             (intptr_t)posPtr);
-        } else {
-            GrAssert(kReserved_GeometrySrcType == fGeometrySrc.fVertexSrc);
-            posPtr = (void*)((intptr_t)fVertices.get() + (intptr_t)posPtr);
-        }
-        if (NULL != fHWGeometryState.fVertexBuffer) {
-            GR_GL(BindBuffer(GL_ARRAY_BUFFER, 0));
-            fHWGeometryState.fVertexBuffer = NULL;
-        }
-    }
-
-    if (kBuffer_GeometrySrcType == fGeometrySrc.fIndexSrc) {
-        GrAssert(NULL != fGeometrySrc.fIndexBuffer);
-        GrAssert(!fGeometrySrc.fIndexBuffer->isLocked());
-        if (fHWGeometryState.fIndexBuffer != fGeometrySrc.fIndexBuffer) {
-            GrGLIndexBuffer* buf = (GrGLIndexBuffer*)fGeometrySrc.fIndexBuffer;
-            GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf->bufferID()));
-            fHWGeometryState.fIndexBuffer = fGeometrySrc.fIndexBuffer;
-        }
-    } else if (NULL != fHWGeometryState.fIndexBuffer) {
-        GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
-        fHWGeometryState.fIndexBuffer = NULL;
-    }
+    const GLvoid* posPtr = setBuffersAndGetVertexStart(newStride, startVertex, 
+                                                       startIndex, vertexCount,
+                                                       indexCount);
 
     GLenum scalarType;
     bool texCoordNorm;
@@ -1388,7 +1354,7 @@
     bool strideChange = newStride != oldStride;
     bool posChange = baseChange || scalarChange || strideChange;
 
-    if (posChange) {
+    if (fHWGeometryState.fArrayPtrsDirty || posChange) {
         GR_GL(VertexAttribPointer(POS_ATTR_LOCATION, 2, scalarType,
                                   false, newStride, posPtr));
         fHWGeometryState.fPositionPtr = posPtr;
@@ -1399,8 +1365,10 @@
             GLvoid* texCoordPtr = (int8_t*)posPtr + newTexCoordOffsets[t];
             if (oldTexCoordOffsets[t] <= 0) {
                 GR_GL(EnableVertexAttribArray(TEX_ATTR_LOCATION(t)));
-            }
-            if (posChange || newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
+                GR_GL(VertexAttribPointer(TEX_ATTR_LOCATION(t), 2, scalarType,
+                                          texCoordNorm, newStride, texCoordPtr));
+            } else if (fHWGeometryState.fArrayPtrsDirty || posChange || 
+                newTexCoordOffsets[t] != oldTexCoordOffsets[t]) {
                 GR_GL(VertexAttribPointer(TEX_ATTR_LOCATION(t), 2, scalarType,
                                           texCoordNorm, newStride, texCoordPtr));
             }
@@ -1413,8 +1381,11 @@
         GLvoid* colorPtr = (int8_t*)posPtr + newColorOffset;
         if (oldColorOffset <= 0) {
             GR_GL(EnableVertexAttribArray(COL_ATTR_LOCATION));
-        }
-        if (posChange || newColorOffset != oldColorOffset) {
+            GR_GL(VertexAttribPointer(COL_ATTR_LOCATION, 4,
+                                      GL_UNSIGNED_BYTE,
+                                      true, newStride, colorPtr));
+        } else if (fHWGeometryState.fArrayPtrsDirty || posChange || 
+            newColorOffset != oldColorOffset) {
             GR_GL(VertexAttribPointer(COL_ATTR_LOCATION, 4,
                                       GL_UNSIGNED_BYTE,
                                       true, newStride, colorPtr));
@@ -1427,3 +1398,4 @@
 }
 #endif
 
+